Difference between revisions of "Animated age pyramid"

From JSXGraph Wiki
Jump to: navigation, search
 
(29 intermediate revisions by the same 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="500">
+
A much more elaborate version programmed by destatis can be seen [http://www.destatis.de/jetspeed/portal/cms/Sites/destatis/Internet/DE/Content/Statistiken/Bevoelkerung/VorausberechnungBevoelkerung/InteraktiveDarstellung/InteraktiveDarstellung,templateId=renderPrint.psml on their webpage].
var i, t = '', yearIndex = 0, brd;
+
<jsxgraph width="500" height="600">
var stat1 = readFile(dataV1W1EJ);
+
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 29:
 
     }
 
     }
 
     data.reverse();
 
     data.reverse();
     ages = JXG.Math.Matrix.transpose(dataArr);
+
     ages = JXG.Math.transpose(dataArr);
 
     return {matrix:ages, total: data};
 
     return {matrix:ages, total: data};
 
};
 
};
  
brd = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-850,110,850,-10],axis:false});
+
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 47:
 
                 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*yearIndex]*1,-off-xArr[2*yearIndex]*1,-off,-off];
+
                 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 69:
 
                 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*yearIndex+1]*1,off+xArr[2*yearIndex+1]*1,off,off];
+
                 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 93:
 
};
 
};
  
 +
var stat1 = readFile(dataV1W1EJ);
 
brd.suspendUpdate();
 
brd.suspendUpdate();
 
createCurves(stat1,brd,'#658cb2','#b23f8c');
 
createCurves(stat1,brd,'#658cb2','#b23f8c');
brd.create('text',[-300,45,'men'],{color:'white',fontSize:20});
+
brd.create('text',[-300,45,'men'],{strokeColor:'white',fontSize:20});
brd.create('text',[200,45,'women'],{color:'white',fontSize:20});
+
brd.create('text',[200,45,'women'],{strokeColor:'white',fontSize:20});
brd.unsuspendUpdate();
+
 
 +
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);
 +
};
  
function changeYear() {
+
var animate = null;
     yearIndex = document.getElementById('years').selectedIndex;
+
function sliderAnimation() {
     setTextYear();
+
     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">&nbsp; </div>
 +
<div id="output" style="padding:20px; background-color:#dddddd; width:500px; font-family:Arial,Helvetica"> &nbsp;</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*yearIndex]*1,
+
         male = ages[n][2*(slide.Value()-slide._smin)]*1,
         female = ages[n][2*yearIndex+1]*1;
+
         female = ages[n][2*(slide.Value()-slide._smin)+1]*1;
 
     textout.innerHTML = 'age:'+age+
 
     textout.innerHTML = 'age:'+age+
                         ', born in '+(2009+yearIndex-age)+
+
                         ', born in '+(slide.Value()-age)+
 
                         '<br> male:'+male+
 
                         '<br> male:'+male+
 
                         ', female:'+female+
 
                         ', female:'+female+
Line 111: Line 290:
 
};
 
};
 
function setTextYear() {
 
function setTextYear() {
     var n = yearIndex,
+
     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 299:
 
};
 
};
  
function animation() {
+
var animate = null;
     yearIndex = (yearIndex+1)%52;
+
function sliderAnimation() {
     document.getElementById('years').selectedIndex = yearIndex;
+
     var s = slide._smin,
     setTextYear();
+
        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(animation,500);
+
     animate = setTimeout(sliderAnimation,500);
 
};
 
};
  
 
function player(){
 
function player(){
 
     if (!animate) {
 
     if (!animate) {
         document.getElementById('playbutton').value = 'stop';
+
         document.getElementById('playbutton').value = ' stop animation ';
         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 322:
 
};
 
};
 
</jsxgraph>
 
</jsxgraph>
<html>
+
 
 
<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();">
 
</form>
 
</form>
<div id="output2" style="padding:20px; background-color:#bbbbbb; width:500; font-family:Arial,Helvetica">&nbsp; </div>
+
<div id="output2" style="padding:20px; background-color:#bbbbbb; width:500px; font-family:Arial,Helvetica">&nbsp; </div>
<div id="output" style="padding:20px; background-color:#dddddd; width:500; font-family:Arial,Helvetica"> &nbsp;</div>
+
<div id="output" style="padding:20px; background-color:#dddddd; width:500px; font-family:Arial,Helvetica"> &nbsp;</div>
<div id="debug" style="display:block;"></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;
     selectYear = document.getElementById('years');
+
     brd.addHook(setTextYear);
     var opt;
+
     brd.unsuspendUpdate();
    for (i=2009;i<=2060;i++) {
+
</script>
      opt = document.createElement('option');
+
</source>
      opt.text = i;
 
      try {
 
          selectYear.add(opt,null);
 
      } catch(e) {
 
          selectYear.add(opt); // IE
 
      }
 
    }
 
    setTextYear();
 
  
</script>
+
[[Category:Examples]]
</html>
+
[[Category:Charts]]

Latest revision as of 11:45, 17 January 2012

This animation shows data from the 12th coordinated Population Projection from the "Statistisches Bundesamt (destatis)". A much more elaborate version programmed by destatis can be seen on their webpage.

 
 

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">&nbsp; </div>
<div id="output" style="padding:20px; background-color:#dddddd; width:500px; font-family:Arial,Helvetica"> &nbsp;</div>
<script type="text/javascript">
    var textout = document.getElementById('output');
    var textout2 = document.getElementById('output2');
    var animate = null;
    brd.addHook(setTextYear);
    brd.unsuspendUpdate();
</script>