Animated age pyramid: Difference between revisions
From JSXGraph Wiki
| A WASSERMANN (talk | contribs) No edit summary | Andrewbaker (talk | contribs)  Removed the link to the Destatis version, as it was leading to a 404 page. | ||
| (29 intermediate revisions by one other user not shown) | |||
| Line 2: | Line 2: | ||
| <script type="text/javascript" src="/ajax/ageV1W1EJ.js"></script> | <script type="text/javascript" src="/ajax/ageV1W1EJ.js"></script> | ||
| </html> | </html> | ||
| This animation shows data from the 12th coordinated Population Projection from the "[http://destatis.de Statistisches Bundesamt]". | This animation shows data from the 12th coordinated Population Projection from the "[http://destatis.de Statistisches Bundesamt (destatis)]". | ||
| <jsxgraph width="500" height=" | <jsxgraph width="500" height="600"> | ||
| var i, t = '' | var i, t = '', brd; | ||
| /** | |||
|  * Read the data from the JavaScript file, which was converted "by hand" from the csv file. | |||
|  */ | |||
| function readFile(dataArr) { | function readFile(dataArr) { | ||
|      var len = dataArr.length,   |      var len = dataArr.length,   | ||
| Line 26: | Line 28: | ||
|      } |      } | ||
|      data.reverse(); |      data.reverse(); | ||
|      ages = JXG.Math |      ages = JXG.Math.transpose(dataArr); | ||
|      return {matrix:ages, total: data}; |      return {matrix:ages, total: data}; | ||
| }; | }; | ||
| brd = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-850,110,850,- | brd = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-850,110,850,-20],axis:false}); | ||
| var slide = brd.create('slider',[[-700,-5],[300,-5],[2009,2009,2060]],{name:'year',snapWidth:1}); | |||
| function createCurves(stat,brd, c1, c2) { | function createCurves(stat,brd, c1, c2) { | ||
|      var i, m = [], w = [], |      var i, m = [], w = [], | ||
| Line 42: | Line 46: | ||
|                  strokeWidth:1, |                  strokeWidth:1, | ||
|                  highlightFillColor:'yellow',highlightStrokeColor:'yellow'}); |                  highlightFillColor:'yellow',highlightStrokeColor:'yellow'}); | ||
|          m[i].updateDataArray = (function(xArr, y) { return function() { |          m[i].updateDataArray = (function(xArr, y) { return function() { | ||
|                  this.dataX = [-off,-off-xArr[2* |                  this.dataX = [-off,-off-xArr[2*(slide.Value()-slide._smin)]*1,-off-xArr[2*(slide.Value()-slide._smin)]*1,-off,-off]; | ||
|                  this.dataY = [y,y,y+1,y+1,y]; |                  this.dataY = [y,y,y+1,y+1,y]; | ||
|              }; })(stat.matrix[i], i); |              }; })(stat.matrix[i], i);        | ||
|          JXG.addEvent(m[i].rendNode, 'mouseover',   |          JXG.addEvent(m[i].rendNode, 'mouseover',   | ||
|              (function(g,d){ return function(){ |              (function(g,d){ return function(){ | ||
| Line 63: | Line 68: | ||
|                  highlightFillColor:'yellow',highlightStrokeColor:'yellow'}); |                  highlightFillColor:'yellow',highlightStrokeColor:'yellow'}); | ||
|          w[i].updateDataArray = (function(xArr, y) { return function() { |          w[i].updateDataArray = (function(xArr, y) { return function() { | ||
|                  this.dataX = [off,off+xArr[2* |                  this.dataX = [off,off+xArr[2*(slide.Value()-slide._smin)+1]*1,off+xArr[2*(slide.Value()-slide._smin)+1]*1,off,off]; | ||
|                  this.dataY = [y,y,y+1,y+1,y]; |                  this.dataY = [y,y,y+1,y+1,y]; | ||
|              }; }    )(stat.matrix[i], i); |              }; }    )(stat.matrix[i], i); | ||
| Line 87: | Line 92: | ||
| }; | }; | ||
| var stat1 = readFile(dataV1W1EJ); | |||
| brd.suspendUpdate(); | brd.suspendUpdate(); | ||
| createCurves(stat1,brd,'#658cb2','#b23f8c'); | createCurves(stat1,brd,'#658cb2','#b23f8c'); | ||
| brd.create('text',[-300,45,'men'],{strokeColor:'white',fontSize:20}); | |||
| brd.create('text',[200,45,'women'],{strokeColor:'white',fontSize:20}); | |||
| function  | function setText(n) { | ||
|      var age = n, | |||
|         male = ages[n][2*(slide.Value()-slide._smin)]*1, | |||
|         female = ages[n][2*(slide.Value()-slide._smin)+1]*1; | |||
|     textout.innerHTML = 'age:'+age+ | |||
|                         ', born in '+(slide.Value()-age)+ | |||
|                         '<br> male:'+male+ | |||
|                         ', female:'+female+ | |||
|                         ', together:'+(male+female)+ | |||
|                         ' (thousand)<br> ratio w/m:'+(female/male).toFixed(2); | |||
| }; | |||
| function setTextYear() { | |||
|     var n = slide.Value()-slide._smin, | |||
|         data = stat1.total; | |||
|     textout2.innerHTML = 'Year:'+data[n][0]+ | |||
|                         '<br> male:'+data[n][1]+ | |||
|                         ', female:'+data[n][2]+ | |||
|                         ', together:'+(data[n][1]+data[n][2])+ | |||
|                         ' (million)<br> ratio w/m:'+(data[n][2]/data[n][1]).toFixed(3); | |||
| }; | |||
| var animate = null; | |||
| function sliderAnimation() { | |||
|     var s = slide._smin, | |||
|         e = slide._smax, | |||
|         sdiff = e-s, | |||
|         newval = slide.Value()+2; | |||
|     slide.position = (newval-s)/sdiff; | |||
|      if (slide.position>1.0) slide.position = 0.0; | |||
|      brd.update(); |      brd.update(); | ||
|     animate = setTimeout(sliderAnimation,500); | |||
| }; | }; | ||
| function player(){ | |||
|     if (!animate) { | |||
|         document.getElementById('playbutton').value = ' stop animation '; | |||
|         sliderAnimation(); | |||
|     } else { | |||
|         document.getElementById('playbutton').value = ' play animation '; | |||
|         clearTimeout(animate); | |||
|         animate = null; | |||
|     } | |||
| }; | |||
| </jsxgraph> | |||
| <html> | |||
| <input type="button" id="playbutton" value=" play animation " onClick="player();"> | |||
| </form> | |||
| <div id="output2" style="padding:20px; background-color:#bbbbbb; width:500px; font-family:Arial,Helvetica">  </div> | |||
| <div id="output" style="padding:20px; background-color:#dddddd; width:500px; font-family:Arial,Helvetica">  </div> | |||
| <div id="debug" style="display:block;"></div> | |||
| <script type="text/javascript"> | |||
|     var textout = document.getElementById('output'); | |||
|     var textout2 = document.getElementById('output2'); | |||
|     var animate = null; | |||
|     brd.addHook(setTextYear); | |||
|     brd.unsuspendUpdate(); | |||
| </script> | |||
| </html> | |||
| ===How to create this animation=== | |||
| * Download the data from [https://www-ec.destatis.de/csp/shop/sfg/bpm.html.cms.cBroker.cls?CSPCHD=0080000100004517mg7C0000001aNX9fOZSV45NMNmJCrMrg--&cmspath=struktur,vollanzeige.csp&ID=1024891 destatis.de] | |||
| * Save the table which should be displayed as csv file. | |||
| * Transform the csv file into a JavaScript file containing a 2 dimensional array: | |||
| <source lang="javascript"> | |||
| dataV1W1EJ = [["2009"," ","m"," 40 070 ","  341 ","  350 ","  353 ","  348 ",...,"  2 "], | |||
| ["    "," ","w"," 41 665 ","  323 ","  333 ","  335 ","  329 ",...,"  12 "], | |||
| ["    "," ","i"," 81 735 ","  663 ","  683 ","  688 ","  677 ",...,"  13 "], | |||
| ["2010"," ","m"," 39 987 ","  339 ","  341 ","  350 ","  353 ",...,"  2 "], | |||
|    . | |||
|    . | |||
|    . | |||
| [" "," ","i"," 64 651 ","  465 ","  470 ","  476 ","  481 ",...,"  169 "]]; | |||
| </source> | |||
| Every third row labeled by 'i' in the third column will be deleted later on. | |||
| * Now read the data | |||
| <source lang="javascript"> | |||
| function readFile(dataArr) { | |||
|     var len = dataArr.length,  | |||
|         i, male, female, y, | |||
|         data = []; | |||
|     for (i=len-1;i>=0;i--) { | |||
|         if (i%3==2) { | |||
|             dataArr.splice(i,1); | |||
|         } else { | |||
|             if (i%3==1) { | |||
|                 female = dataArr[i][3].replace(/ /g,'')*1; | |||
|             } else if (i%3==0) { | |||
|                 y = dataArr[i][0]*1; | |||
|                 male = dataArr[i][3].replace(/ /g,'')*1; | |||
|                 data.push([y,male,female]); | |||
|             }  | |||
|             dataArr[i].splice(0,4); // year,'',m/w,no, | |||
|         } | |||
|     } | |||
|     data.reverse(); | |||
|     ages = JXG.Math.transpose(dataArr); | |||
|     return {matrix:ages, total: data}; | |||
| }; | |||
| var stat1 = readFile(dataV1W1EJ); | |||
| </source> | |||
| * Create the filled rectangles (men, women) | |||
| <source lang="javascript"> | |||
| brd = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-850,110,850,-10],axis:false}); | |||
| createCurves(stat1,brd,'#658cb2','#b23f8c'); | |||
| </source> | |||
| ===The complete JavaScript code=== | |||
| <source lang="xml"> | |||
| <script type="text/javascript" src="/ajax/ageV1W1EJ.js"></script> | |||
| <jsxgraph width="500" height="500"> | |||
| brd = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-850,110,850,-20],axis:false}); | |||
| var slide = brd.create('slider',[[-700,-5],[300,-5],[2009,2009,2060]],{name:'year',snapWidth:1}); | |||
| function createCurves(stat,brd, c1, c2) { | |||
|     var i, m = [], w = [], | |||
|         op = 1, | |||
|         off = 80, | |||
|         len = stat.matrix.length; | |||
|     for (i=0;i<len;i++) { | |||
|         m[i] = brd.create('curve',[[0],[0]], | |||
|                 {fillColor:c1,strokeColor:c1, | |||
|                 strokeOpacity:op,fillOpacity:op, | |||
|                 strokeWidth:1, | |||
|                 highlightFillColor:'yellow',highlightStrokeColor:'yellow'}); | |||
|         m[i].updateDataArray = (function(xArr, y) { return function() { | |||
|                 this.dataX = [-off,-off-xArr[2*(slide.Value()-slide._smin)]*1,-off-xArr[2*(slide.Value()-slide._smin)]*1,-off,-off]; | |||
|                 this.dataY = [y,y,y+1,y+1,y]; | |||
|             }; })(stat.matrix[i], i); | |||
|         JXG.addEvent(m[i].rendNode, 'mouseover',  | |||
|             (function(g,d){ return function(){ | |||
|                                 g.highlight(); w[g._number].highlight(); setText(g._number); | |||
|                             };})(m[i]), m[i]); | |||
|         JXG.addEvent(m[i].rendNode, 'mouseout',  | |||
|             (function(g){ return function(){ | |||
|                                 g.noHighlight(); w[g._number].noHighlight();  | |||
|                             };})(m[i]), m[i]); | |||
|         m[i].hasPoint = function(){return false;}; | |||
|         m[i]._number = i; | |||
|         w[i] = brd.create('curve',[[0],[0]], | |||
|                 {fillColor:c2,strokeColor:c2, | |||
|                 strokeWidth:1, | |||
|                 strokeOpacity:op,fillOpacity:op, | |||
|                 highlightFillColor:'yellow',highlightStrokeColor:'yellow'}); | |||
|         w[i].updateDataArray = (function(xArr, y) { return function() { | |||
|                 this.dataX = [off,off+xArr[2*(slide.Value()-slide._smin)+1]*1,off+xArr[2*(slide.Value()-slide._smin)+1]*1,off,off]; | |||
|                 this.dataY = [y,y,y+1,y+1,y]; | |||
|             }; }    )(stat.matrix[i], i); | |||
|         JXG.addEvent(w[i].rendNode, 'mouseover',  | |||
|             (function(g,d){ return function(){ | |||
|                                 g.highlight(); m[g._number].highlight(); setText(g._number); | |||
|                             };})(w[i]), w[i]); | |||
|         JXG.addEvent(w[i].rendNode, 'mouseout',   | |||
|             (function(g){ return function(){ | |||
|                                 g.noHighlight(); m[g._number].noHighlight(); | |||
|                             };})(w[i]), w[i]); | |||
|         w[i].hasPoint = function(){return false;}; | |||
|         w[i]._number = i; | |||
|     } | |||
|     var t = brd.create('turtle',[],{strokeColor:'#999999', highlightStrokeColor:'#999999'}); t.ht().pu().rt(90); | |||
|     for (i=0;i<=90;i+=10) {  | |||
|         t.moveTo([-750,i]).penDown().forward(750-off+10).penUp(); | |||
|         t.moveTo([off-10,i]).penDown().forward(750-off+10).penUp(); | |||
|         brd.create('text',[-15,i,i.toFixed(0)]); | |||
|     } | |||
|     return [m,w]; | |||
| }; | |||
| var stat1 = readFile(dataV1W1EJ); | |||
| brd.suspendUpdate(); | |||
| createCurves(stat1,brd,'#658cb2','#b23f8c'); | |||
| brd.create('text',[-300,45,'men'],{strokeColor:'white',fontSize:20}); | |||
| brd.create('text',[200,45,'women'],{strokeColor:'white',fontSize:20}); | |||
| function setText(n) { | function setText(n) { | ||
|      var age = n, |      var age = n, | ||
|          male = ages[n][2* |          male = ages[n][2*(slide.Value()-slide._smin)]*1, | ||
|          female = ages[n][2* |          female = ages[n][2*(slide.Value()-slide._smin)+1]*1; | ||
|      textout.innerHTML = 'age:'+age+ |      textout.innerHTML = 'age:'+age+ | ||
|                          ', born in '+( |                          ', born in '+(slide.Value()-age)+ | ||
|                          '<br> male:'+male+ |                          '<br> male:'+male+ | ||
|                          ', female:'+female+ |                          ', female:'+female+ | ||
| Line 111: | Line 289: | ||
| }; | }; | ||
| function setTextYear() { | function setTextYear() { | ||
|      var n =  |      var n = slide.Value()-slide._smin, | ||
|          data = stat1.total; |          data = stat1.total; | ||
|      textout2.innerHTML = 'Year:'+data[n][0]+ |      textout2.innerHTML = 'Year:'+data[n][0]+ | ||
| Line 120: | Line 298: | ||
| }; | }; | ||
| function  | var animate = null; | ||
| function sliderAnimation() { | |||
|      var s = slide._smin, | |||
|         e = slide._smax, | |||
|         sdiff = e-s, | |||
|         newval = slide.Value()+2; | |||
|      slide.position = (newval-s)/sdiff; | |||
|      if (slide.position>1.0) slide.position = 0.0; | |||
|      brd.update(); |      brd.update(); | ||
|      animate = setTimeout( |      animate = setTimeout(sliderAnimation,500); | ||
| }; | }; | ||
| function player(){ | function player(){ | ||
|      if (!animate) { |      if (!animate) { | ||
|          document.getElementById('playbutton').value = 'stop'; |          document.getElementById('playbutton').value = ' stop animation '; | ||
|          sliderAnimation(); | |||
|      } else { |      } else { | ||
|          document.getElementById('playbutton').value = 'play'; |          document.getElementById('playbutton').value = ' play animation '; | ||
|          clearTimeout(animate); |          clearTimeout(animate); | ||
|          animate = null; |          animate = null; | ||
| Line 139: | Line 321: | ||
| }; | }; | ||
| </jsxgraph> | </jsxgraph> | ||
| <form><select id="years" onChange="changeYear()"></select> | <form><select id="years" onChange="changeYear()"></select> | ||
| <input type="button" id="playbutton" value="play" onClick="player();"> | <input type="button" id="playbutton" value="play" onClick="player();"> | ||
| Line 145: | Line 327: | ||
| <div id="output2" style="padding:20px; background-color:#bbbbbb; width:500px; font-family:Arial,Helvetica">  </div> | <div id="output2" style="padding:20px; background-color:#bbbbbb; width:500px; font-family:Arial,Helvetica">  </div> | ||
| <div id="output" style="padding:20px; background-color:#dddddd; width:500px; font-family:Arial,Helvetica">  </div> | <div id="output" style="padding:20px; background-color:#dddddd; width:500px; font-family:Arial,Helvetica">  </div> | ||
| <script type="text/javascript"> | <script type="text/javascript"> | ||
|      var textout = document.getElementById('output'); |      var textout = document.getElementById('output'); | ||
|      var textout2 = document.getElementById('output2'); |      var textout2 = document.getElementById('output2'); | ||
|      var animate = null; |      var animate = null; | ||
|      brd.addHook(setTextYear); | |||
|      brd.unsuspendUpdate(); | |||
| </script> | |||
| </source> | |||
| [[Category:Examples]] | |||
| [[Category:Charts]] | |||
Latest revision as of 21:02, 17 November 2020
This animation shows data from the 12th coordinated Population Projection from the "Statistisches Bundesamt (destatis)".
How to create this animation
- Download the data from destatis.de
- Save the table which should be displayed as csv file.
- Transform the csv file into a JavaScript file containing a 2 dimensional array:
dataV1W1EJ = [["2009"," ","m"," 40 070 ","  341 ","  350 ","  353 ","  348 ",...,"  2 "],
["    "," ","w"," 41 665 ","  323 ","  333 ","  335 ","  329 ",...,"  12 "],
["    "," ","i"," 81 735 ","  663 ","  683 ","  688 ","  677 ",...,"  13 "],
["2010"," ","m"," 39 987 ","  339 ","  341 ","  350 ","  353 ",...,"  2 "],
   .
   .
   .
[" "," ","i"," 64 651 ","  465 ","  470 ","  476 ","  481 ",...,"  169 "]];
Every third row labeled by 'i' in the third column will be deleted later on.
- Now read the data
function readFile(dataArr) {
    var len = dataArr.length, 
        i, male, female, y,
        data = [];
    for (i=len-1;i>=0;i--) {
        if (i%3==2) {
            dataArr.splice(i,1);
        } else {
            if (i%3==1) {
                female = dataArr[i][3].replace(/ /g,'')*1;
            } else if (i%3==0) {
                y = dataArr[i][0]*1;
                male = dataArr[i][3].replace(/ /g,'')*1;
                data.push([y,male,female]);
            } 
            dataArr[i].splice(0,4); // year,'',m/w,no,
        }
    }
    data.reverse();
    ages = JXG.Math.transpose(dataArr);
    return {matrix:ages, total: data};
};
var stat1 = readFile(dataV1W1EJ);
- Create the filled rectangles (men, women)
brd = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-850,110,850,-10],axis:false});
createCurves(stat1,brd,'#658cb2','#b23f8c');
The complete JavaScript code
<script type="text/javascript" src="/ajax/ageV1W1EJ.js"></script>
<jsxgraph width="500" height="500">
brd = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-850,110,850,-20],axis:false});
var slide = brd.create('slider',[[-700,-5],[300,-5],[2009,2009,2060]],{name:'year',snapWidth:1});
function createCurves(stat,brd, c1, c2) {
    var i, m = [], w = [],
        op = 1,
        off = 80,
        len = stat.matrix.length;
    for (i=0;i<len;i++) {
        m[i] = brd.create('curve',[[0],[0]],
                {fillColor:c1,strokeColor:c1,
                strokeOpacity:op,fillOpacity:op,
                strokeWidth:1,
                highlightFillColor:'yellow',highlightStrokeColor:'yellow'});
                
        m[i].updateDataArray = (function(xArr, y) { return function() {
                this.dataX = [-off,-off-xArr[2*(slide.Value()-slide._smin)]*1,-off-xArr[2*(slide.Value()-slide._smin)]*1,-off,-off];
                this.dataY = [y,y,y+1,y+1,y];
            }; })(stat.matrix[i], i);
            
        JXG.addEvent(m[i].rendNode, 'mouseover', 
            (function(g,d){ return function(){
                                g.highlight(); w[g._number].highlight(); setText(g._number);
                            };})(m[i]), m[i]);
        JXG.addEvent(m[i].rendNode, 'mouseout', 
            (function(g){ return function(){
                                g.noHighlight(); w[g._number].noHighlight(); 
                            };})(m[i]), m[i]);
        m[i].hasPoint = function(){return false;};
        m[i]._number = i;
    
        w[i] = brd.create('curve',[[0],[0]],
                {fillColor:c2,strokeColor:c2,
                strokeWidth:1,
                strokeOpacity:op,fillOpacity:op,
                highlightFillColor:'yellow',highlightStrokeColor:'yellow'});
        w[i].updateDataArray = (function(xArr, y) { return function() {
                this.dataX = [off,off+xArr[2*(slide.Value()-slide._smin)+1]*1,off+xArr[2*(slide.Value()-slide._smin)+1]*1,off,off];
                this.dataY = [y,y,y+1,y+1,y];
            }; }    )(stat.matrix[i], i);
        JXG.addEvent(w[i].rendNode, 'mouseover', 
            (function(g,d){ return function(){
                                g.highlight(); m[g._number].highlight(); setText(g._number);
                            };})(w[i]), w[i]);
        JXG.addEvent(w[i].rendNode, 'mouseout',  
            (function(g){ return function(){
                                g.noHighlight(); m[g._number].noHighlight();
                            };})(w[i]), w[i]);
        w[i].hasPoint = function(){return false;};
        w[i]._number = i;
        
    }
    var t = brd.create('turtle',[],{strokeColor:'#999999', highlightStrokeColor:'#999999'}); t.ht().pu().rt(90);
    for (i=0;i<=90;i+=10) { 
        t.moveTo([-750,i]).penDown().forward(750-off+10).penUp();
        t.moveTo([off-10,i]).penDown().forward(750-off+10).penUp();
        brd.create('text',[-15,i,i.toFixed(0)]);
    }
    return [m,w];
};
var stat1 = readFile(dataV1W1EJ);
brd.suspendUpdate();
createCurves(stat1,brd,'#658cb2','#b23f8c');
brd.create('text',[-300,45,'men'],{strokeColor:'white',fontSize:20});
brd.create('text',[200,45,'women'],{strokeColor:'white',fontSize:20});
function setText(n) {
    var age = n,
        male = ages[n][2*(slide.Value()-slide._smin)]*1,
        female = ages[n][2*(slide.Value()-slide._smin)+1]*1;
    textout.innerHTML = 'age:'+age+
                        ', born in '+(slide.Value()-age)+
                        '<br> male:'+male+
                        ', female:'+female+
                        ', together:'+(male+female)+
                        ' (thousand)<br> ratio w/m:'+(female/male).toFixed(2);
};
function setTextYear() {
    var n = slide.Value()-slide._smin,
        data = stat1.total;
    textout2.innerHTML = 'Year:'+data[n][0]+
                        '<br> male:'+data[n][1]+
                        ', female:'+data[n][2]+
                        ', together:'+(data[n][1]+data[n][2])+
                        ' (million)<br> ratio w/m:'+(data[n][2]/data[n][1]).toFixed(3);
};
var animate = null;
function sliderAnimation() {
    var s = slide._smin,
        e = slide._smax,
        sdiff = e-s,
        newval = slide.Value()+2;
    slide.position = (newval-s)/sdiff;
    if (slide.position>1.0) slide.position = 0.0;
    brd.update();
    animate = setTimeout(sliderAnimation,500);
};
function player(){
    if (!animate) {
        document.getElementById('playbutton').value = ' stop animation ';
        sliderAnimation();
    } else {
        document.getElementById('playbutton').value = ' play animation ';
        clearTimeout(animate);
        animate = null;
    }
};
</jsxgraph>
<form><select id="years" onChange="changeYear()"></select>
<input type="button" id="playbutton" value="play" onClick="player();">
</form>
<div id="output2" style="padding:20px; background-color:#bbbbbb; width:500px; font-family:Arial,Helvetica">  </div>
<div id="output" style="padding:20px; background-color:#dddddd; width:500px; font-family:Arial,Helvetica">  </div>
<script type="text/javascript">
    var textout = document.getElementById('output');
    var textout2 = document.getElementById('output2');
    var animate = null;
    brd.addHook(setTextYear);
    brd.unsuspendUpdate();
</script>
