Difference between revisions of "Animated age pyramid"
From JSXGraph Wiki
A WASSERMANN (talk | contribs) |
A WASSERMANN (talk | contribs) |
||
(26 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=" | + | 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 = '' | + | <jsxgraph width="500" height="600"> |
− | + | 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 | + | 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 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* | + | 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* | + | 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'] | + | brd.create('text',[-300,45,'men'],{strokeColor:'white',fontSize:20}); |
− | brd.create('text',[200,45,'women'] | + | 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 290: | ||
}; | }; | ||
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 299: | ||
}; | }; | ||
− | 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 322: | ||
}; | }; | ||
</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 328: | ||
<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 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"> </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>