3 JavaScript routines to dynamically generate Scalable Vector Graphics
\r
4 using a mathematical xy-coordinate system (y increases upwards) and
\r
5 very intuitive JavaScript commands (no programming experience required).
\r
6 ASCIIsvg.js is good for learning math and illustrating online math texts.
\r
7 Works with Internet Explorer+Adobe SVGviewer and SVG enabled Mozilla/Firefox.
\r
9 Ver 1.2.7 Oct 13, 2005 (c) Peter Jipsen http://www.chapman.edu/~jipsen
\r
10 Latest version at http://www.chapman.edu/~jipsen/svg/ASCIIsvg.js
\r
11 If you use it on a webpage, please send the URL to jipsen@chapman.edu
\r
13 This program is free software; you can redistribute it and/or modify
\r
14 it under the terms of the GNU General Public License as published by
\r
15 the Free Software Foundation; either version 2 of the License, or (at
\r
16 your option) any later version.
\r
18 This program is distributed in the hope that it will be useful,
\r
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
21 General Public License (at http://www.gnu.org/copyleft/gpl.html)
\r
24 var checkIfSVGavailable = true;
\r
25 var notifyIfNoSVG = true;
\r
26 var alertIfNoSVG = false;
\r
27 var xunitlength = 20; // pixels
\r
28 var yunitlength = 20; // pixels
\r
29 var origin = [0,0]; // in pixels (default is bottom left corner)
\r
30 var defaultwidth = 300; defaultheight = 200; defaultborder = 0;
\r
31 var border = defaultborder;
\r
32 var strokewidth, strokedasharray, stroke, fill;
\r
33 var fontstyle, fontfamily, fontsize, fontweight, fontstroke, fontfill;
\r
34 var markerstrokewidth = "1";
\r
35 var markerstroke = "black";
\r
36 var markerfill = "yellow";
\r
37 var marker = "none";
\r
38 var arrowfill = stroke;
\r
41 var axesstroke = "black";
\r
42 var gridstroke = "grey";
\r
43 var pointerpos = null;
\r
44 var coordinates = null;
\r
45 var above = "above";
\r
46 var below = "below";
\r
48 var right = "right";
\r
49 var aboveleft = "aboveleft";
\r
50 var aboveright = "aboveright";
\r
51 var belowleft = "belowleft";
\r
52 var belowright = "belowright";
\r
53 var cpi = "\u03C0", ctheta = "\u03B8";
\r
54 var pi = Math.PI, ln = Math.log, e = Math.E;
\r
55 var arcsin = Math.asin, arccos = Math.acos, arctan = Math.atan;
\r
56 var sec = function(x) { return 1/Math.cos(x) };
\r
57 var csc = function(x) { return 1/Math.sin(x) };
\r
58 var cot = function(x) { return 1/Math.tan(x) };
\r
59 var xmin, xmax, ymin, ymax, xscl, yscl,
\r
60 xgrid, ygrid, xtick, ytick, initialized;
\r
61 var isIE = document.createElementNS==null;
\r
62 var picture, svgpicture, doc, width, height, a, b, c, d, i, n, p, t, x, y;
\r
63 var arcsec = function(x) { return arccos(1/x) };
\r
64 var arccsc = function(x) { return arcsin(1/x) };
\r
65 var arccot = function(x) { return arctan(1/x) };
\r
66 var sinh = function(x) { return (Math.exp(x)-Math.exp(-x))/2 };
\r
67 var cosh = function(x) { return (Math.exp(x)+Math.exp(-x))/2 };
\r
69 function(x) { return (Math.exp(x)-Math.exp(-x))/(Math.exp(x)+Math.exp(-x)) };
\r
70 var sech = function(x) { return 1/cosh(x) };
\r
71 var csch = function(x) { return 1/sinh(x) };
\r
72 var coth = function(x) { return 1/tanh(x) };
\r
73 var arcsinh = function(x) { return ln(x+Math.sqrt(x*x+1)) };
\r
74 var arccosh = function(x) { return ln(x+Math.sqrt(x*x-1)) };
\r
75 var arctanh = function(x) { return ln((1+x)/(1-x))/2 };
\r
76 var sech = function(x) { return 1/cosh(x) };
\r
77 var csch = function(x) { return 1/sinh(x) };
\r
78 var coth = function(x) { return 1/tanh(x) };
\r
79 var arcsech = function(x) { return arccosh(1/x) };
\r
80 var arccsch = function(x) { return arcsinh(1/x) };
\r
81 var arccoth = function(x) { return arctanh(1/x) };
\r
82 var sign = function(x) { return (x==0?0:(x<0?-1:1)) };
\r
84 function factorial(x,n) {
\r
86 for (var i=x-n; i>0; i-=n) x*=i;
\r
87 return (x<0?NaN:(x==0?1:x));
\r
92 for (var i=0; i<k; i++) res*=(x-i)/(k-i);
\r
96 function chop(x,n) {
\r
98 return Math.floor(x*Math.pow(10,n))/Math.pow(10,n);
\r
101 function ran(a,b,n) {
\r
103 return chop((b+Math.pow(10,-n)-a)*Math.random()+a,n);
\r
106 function myCreateElementXHTML(t) {
\r
107 if (isIE) return document.createElement(t);
\r
108 else return document.createElementNS("http://www.w3.org/1999/xhtml",t);
\r
111 function isSVGavailable() {
\r
112 var ua = navigator.userAgent;
\r
113 if (ua.match("AppleWebKit")) {
\r
116 if (navigator.appName.slice(0,5)=="Opera") {
\r
119 var nd = myCreateElementXHTML("center");
\r
120 nd.appendChild(document.createTextNode("To view the "));
\r
121 var an = myCreateElementXHTML("a");
\r
122 an.appendChild(document.createTextNode("ASCIIsvg"));
\r
123 an.setAttribute("href","http://www.chapman.edu/~jipsen/asciisvg.html");
\r
124 nd.appendChild(an);
\r
125 nd.appendChild(document.createTextNode(" images use Internet Explorer 6+"));
\r
126 an = myCreateElementXHTML("a");
\r
127 an.appendChild(document.createTextNode("Adobe SVGviewer 3.02"));
\r
128 an.setAttribute("href","http://www.adobe.com/svg");
\r
129 nd.appendChild(an);
\r
130 nd.appendChild(document.createTextNode(" or "));
\r
131 an = myCreateElementXHTML("a");
\r
132 an.appendChild(document.createTextNode("SVG enabled Mozilla/Firefox"));
\r
133 an.setAttribute("href",
\r
134 "http://www.chapman.edu/~jipsen/svg/svgenabledmozillafirefox.html");
\r
135 nd.appendChild(an);
\r
136 if (navigator.appName.slice(0,8)=="Netscape")
\r
137 if (window['SVGElement']) return null;
\r
139 else if (navigator.appName.slice(0,9)=="Microsoft")
\r
141 var oSVG=eval("new ActiveXObject('Adobe.SVGCtl.3');");
\r
150 function less(x,y) { return x < y } // used for scripts in XML files
\r
151 // since IE does not handle CDATA well
\r
152 function setText(st,id) {
\r
153 var node = document.getElementById(id);
\r
155 if (node.childNodes.length!=0) node.childNodes[0].nodeValue = st;
\r
156 else node.appendChild(document.createTextNode(st));
\r
159 function myCreateElementSVG(t) {
\r
160 if (isIE) return doc.createElement(t);
\r
161 else return doc.createElementNS("http://www.w3.org/2000/svg",t);
\r
165 return (doc.getElementById("pointerpos").getAttribute("cx")-origin[0])/xunitlength;
\r
169 return (height-origin[1]-doc.getElementById("pointerpos").getAttribute("cy"))/yunitlength;
\r
172 function mousemove_listener(evt) {
\r
173 if (svgpicture.getAttribute("xbase")!=null)
\r
174 pointerpos.cx.baseVal.value = evt.clientX-svgpicture.getAttribute("xbase");
\r
175 if (svgpicture.getAttribute("ybase")!=null)
\r
176 pointerpos.cy.baseVal.value = evt.clientY-svgpicture.getAttribute("ybase");
\r
179 function top_listener(evt) {
\r
180 svgpicture.setAttribute("ybase",evt.clientY);
\r
183 function bottom_listener(evt) {
\r
184 svgpicture.setAttribute("ybase",evt.clientY-height+1);
\r
187 function left_listener(evt) {
\r
188 svgpicture.setAttribute("xbase",evt.clientX);
\r
191 function right_listener(evt) {
\r
192 svgpicture.setAttribute("xbase",evt.clientX-width+1);
\r
195 function drawPictures() { // main routine; called after webpage has loaded
\r
196 var src, id, dsvg, onmov, nd, node, ht, index;
\r
197 var pictures = document.getElementsByTagName("textarea");
\r
198 for (index = 0; index<pictures.length; index++)
\r
199 if (pictures[index].className=="ASCIIsvg"){
\r
200 pictures[index].style.display="none"; // hide the textarea
\r
202 pictures = document.getElementsByTagName("embed");
\r
203 var len = pictures.length;
\r
204 if (checkIfSVGavailable) {
\r
205 nd = isSVGavailable();
\r
206 if (nd != null && notifyIfNoSVG && len>0)
\r
208 alert("To view the SVG pictures in Internet Explorer\n\
\r
209 download the free Adobe SVGviewer from www.adobe.com/svg or\n\
\r
210 use Firefox 1.5 preview (called Deerpark)");
\r
212 var ASbody = document.getElementsByTagName("body")[0];
\r
213 ASbody.insertBefore(nd,ASbody.childNodes[0]);
\r
217 for (index = 0; index < len; index++) {
\r
218 xmin = null; xmax = null; ymin = null; ymax = null;
\r
219 xscl = null; xgrid = null; yscl = null; ygrid = null;
\r
220 initialized = false;
\r
221 picture = (isIE ? pictures[index] : pictures[0]);
\r
222 src = picture.getAttribute("script");
\r
223 if (src==null) src = "";
\r
224 ht = picture.getAttribute("height");
\r
225 if (ht==null) ht ="";
\r
226 if (ht!="") defaultborder = 25;
\r
227 if (ht=="" || src=="")
\r
228 if (document.getElementById("picture"+(index+1)+"input")==null) {
\r
229 if (isIE && src.indexOf("nobutton()")==-1)
\r
230 picture.parentNode.insertBefore(myCreateElementXHTML("br"),picture);
\r
231 node = myCreateElementXHTML("textarea");
\r
232 node.setAttribute("rows","10");
\r
233 node.setAttribute("cols","60");
\r
234 // node.setAttribute("style","display:block");
\r
235 if (isIE) src = src.replace(/([^\r])\n/g,"$1\r").slice(1);
\r
236 node.appendChild(document.createTextNode(src));
\r
237 if (src.indexOf("showcode()")==-1) node.style.display = "none";
\r
238 node.setAttribute("id","picture"+(index+1)+"input");
\r
239 picture.parentNode.insertBefore(node,picture);
\r
241 if (src.indexOf("nobutton()")==-1) {
\r
242 picture.parentNode.insertBefore(myCreateElementXHTML("br"),picture);
\r
244 node = myCreateElementXHTML("button");
\r
245 if (isIE) node.onclick = function() { showHideCode(this) };
\r
246 else node.setAttribute("onclick","showHideCode(this)");
\r
247 node.appendChild(document.createTextNode("Show/Hide"));
\r
248 picture.parentNode.insertBefore(node,picture);
\r
250 node = myCreateElementXHTML("button");
\r
251 if (isIE) node.onclick = ASfn[index];
\r
252 else node.setAttribute("onclick","updatePicture("+index+")");
\r
253 node.appendChild(document.createTextNode("Update"));
\r
254 if (src.indexOf("showCode()")==-1) node.style.display = "none";
\r
255 picture.parentNode.insertBefore(node,picture);
\r
257 /* node = myCreateElementXHTML("span");
\r
258 // node.setAttribute("id","AScoord"+index);
\r
259 node.appendChild(document.createTextNode("(x,y)"));
\r
260 picture.parentNode.insertBefore(node,picture);
\r
262 picture.parentNode.insertBefore(myCreateElementXHTML("br"),picture);
\r
264 if (isIE) picture.onmousemove = ASupdateCoords[index];
\r
265 else picture.setAttribute("onmousemove","updateCoords"+index+"()");
\r
266 } else src = document.getElementById("picture"+(index+1)+"input").value;
\r
267 src = src.replace(/plot\(\x20*([^\"f\[][^\n\r]+?)\,/g,"plot\(\"$1\",");
\r
268 src = src.replace(/plot\(\x20*([^\"f\[][^\n\r]+)\)/g,"plot(\"$1\")");
\r
269 src = src.replace(/([0-9])([a-zA-Z])/g,"$1*$2");
\r
270 src = src.replace(/\)([\(0-9a-zA-Z])/g,"\)*$1");
\r
271 // eval(src.replace(/\s\s/g,";")); //for XML version
\r
272 id = picture.getAttribute("id");
\r
273 dsvg = picture.getAttribute("src");
\r
274 onmov = picture.getAttribute("onmousemove");
\r
275 if (id == null || id == "") {
\r
276 id = "picture"+(index+1);
\r
277 picture.setAttribute("id",id);
\r
280 with (Math) eval(src);
\r
281 } catch(err) {alert(err+"\n"+src)}
\r
282 if (isIE) src = src.replace(/([^\r])\n/g,"$1\r");
\r
283 setText("<embed width=\""+width+"\" height=\""+height+"\" src=\""+
\r
284 dsvg+"\" "+(onmov!=null?"onmousemove=\""+onmov+"\"":"")+
\r
285 (isIE?"\r":"\n")+"script=\'"+src+"\'>",id+"script");
\r
286 // setText(src.replace(/\s\s/g,"\r"),id+"script"); //for XML version
\r
291 function switchTo(id) {
\r
293 picture = document.getElementById(id);
\r
294 width = picture.getAttribute("width")-0;
\r
295 height = picture.getAttribute("height")-0;
\r
296 strokewidth = "1" // pixel
\r
297 stroke = "black"; // default line color
\r
298 fill = "none"; // default fill color
\r
300 if ((picture.nodeName == "EMBED" || picture.nodeName == "embed") && isIE) {
\r
301 svgpicture = picture.getSVGDocument().getElementById("root");
\r
302 doc = picture.getSVGDocument();
\r
304 picture.setAttribute("onmousemove","updateCoords"+(id.slice(id.length-1)-1)+"()");
\r
305 //alert(picture.getAttribute("onmousemove")+"***");
\r
306 svgpicture = picture;
\r
309 xunitlength = svgpicture.getAttribute("xunitlength")-0;
\r
310 yunitlength = svgpicture.getAttribute("yunitlength")-0;
\r
311 xmin = svgpicture.getAttribute("xmin")-0;
\r
312 xmax = svgpicture.getAttribute("xmax")-0;
\r
313 ymin = svgpicture.getAttribute("ymin")-0;
\r
314 ymax = svgpicture.getAttribute("ymax")-0;
\r
315 origin = [svgpicture.getAttribute("ox")-0,svgpicture.getAttribute("oy")-0];
\r
318 function updatePicture(obj) {
\r
319 //alert(typeof obj)
\r
320 var src = document.getElementById((typeof obj=="string"?
\r
321 obj:"picture"+(obj+1)+"input")).value;
\r
322 xmin = null; xmax = null; ymin = null; ymax = null;
\r
323 xscl = null; xgrid = null; yscl = null; ygrid = null;
\r
324 initialized = false;
\r
325 switchTo((typeof obj=="string"?obj.slice(0,8):"picture"+(obj+1)));
\r
326 src = src.replace(/plot\(\x20*([^\"f\[][^\n\r]+?)\,/g,"plot\(\"$1\",");
\r
327 src = src.replace(/plot\(\x20*([^\"f\[][^\n\r]+)\)/g,"plot(\"$1\")");
\r
328 src = src.replace(/([0-9])([a-zA-Z])/g,"$1*$2");
\r
329 src = src.replace(/\)([\(0-9a-zA-Z])/g,"\)*$1");
\r
332 with (Math) eval(src);
\r
333 } catch(err) {alert(err+"\n"+src)}
\r
336 function showHideCode(obj) {
\r
337 var node = obj.nextSibling;
\r
338 while (node != null && node.nodeName != "BUTTON" &&
\r
339 node.nodeName != "button") node = node.nextSibling;
\r
340 if (node.style.display == "none") node.style.display = "";
\r
341 else node.style.display = "none";
\r
342 while (node != null && node.nodeName != "TEXTAREA" &&
\r
343 node.nodeName != "textarea") node = node.previousSibling;
\r
344 if (node.style.display == "none") node.style.display = "";
\r
345 else node.style.display = "none";
\r
346 // updatePicture(node.getAttribute("id"));
\r
349 function hideCode() { //do nothing
\r
352 function showcode() { //do nothing
\r
355 function nobutton() { //do nothing
\r
358 function setBorder(x) { border = x }
\r
360 function initPicture(x_min,x_max,y_min,y_max) {
\r
361 if (!initialized) {
\r
362 strokewidth = "1"; // pixel
\r
363 strokedasharray = null;
\r
364 stroke = "black"; // default line color
\r
365 fill = "none"; // default fill color
\r
366 fontstyle = "italic"; // default shape for text labels
\r
367 fontfamily = "times"; // default font
\r
368 fontsize = "16"; // default size
\r
369 fontweight = "normal";
\r
370 fontstroke = "none"; // default font outline color
\r
371 fontfill = "none"; // default font color
\r
373 initialized = true;
\r
374 if (x_min!=null) xmin = x_min;
\r
375 if (x_max!=null) xmax = x_max;
\r
376 if (y_min!=null) ymin = y_min;
\r
377 if (y_max!=null) ymax = y_max;
\r
378 if (xmin==null) xmin = -5;
\r
379 if (xmax==null) xmax = 5;
\r
380 if (typeof xmin != "number" || typeof xmax != "number" || xmin >= xmax)
\r
381 alert("Picture requires at least two numbers: xmin < xmax");
\r
382 else if (y_max != null && (typeof y_min != "number" ||
\r
383 typeof y_max != "number" || y_min >= y_max))
\r
384 alert("initPicture(xmin,xmax,ymin,ymax) requires numbers ymin < ymax");
\r
386 if (width==null) width = picture.getAttribute("width");
\r
387 else picture.setAttribute("width",width);
\r
388 if (width==null || width=="") width=defaultwidth;
\r
389 if (height==null) height = picture.getAttribute("height");
\r
390 else picture.setAttribute("height",height);
\r
391 if (height==null || height=="") height=defaultheight;
\r
392 xunitlength = (width-2*border)/(xmax-xmin);
\r
393 yunitlength = xunitlength;
\r
394 //alert(xmin+" "+xmax+" "+ymin+" "+ymax)
\r
396 origin = [-xmin*xunitlength+border,height/2];
\r
397 ymin = -(height-2*border)/(2*yunitlength);
\r
400 if (ymax!=null) yunitlength = (height-2*border)/(ymax-ymin);
\r
401 else ymax = (height-2*border)/yunitlength + ymin;
\r
402 origin = [-xmin*xunitlength+border,-ymin*yunitlength+border];
\r
404 // if (true ||picture.nodeName == "EMBED" || picture.nodeName == "embed") {
\r
406 svgpicture = picture.getSVGDocument().getElementById("root");
\r
407 while (svgpicture.childNodes.length()>5)
\r
408 svgpicture.removeChild(svgpicture.lastChild);
\r
409 svgpicture.setAttribute("width",width);
\r
410 svgpicture.setAttribute("height",height);
\r
411 doc = picture.getSVGDocument();
\r
413 var qnode = document.createElementNS("http://www.w3.org/2000/svg","svg");
\r
414 qnode.setAttribute("id",picture.getAttribute("id"));
\r
415 qnode.setAttribute("style","display:inline");
\r
416 qnode.setAttribute("width",picture.getAttribute("width"));
\r
417 qnode.setAttribute("height",picture.getAttribute("height"));
\r
418 if (picture.parentNode!=null)
\r
419 picture.parentNode.replaceChild(qnode,picture);
\r
421 svgpicture.parentNode.replaceChild(qnode,svgpicture);
\r
422 svgpicture = qnode;
\r
424 pointerpos = doc.getElementById("pointerpos");
\r
425 if (pointerpos==null) {
\r
426 pointerpos = myCreateElementSVG("circle");
\r
427 pointerpos.setAttribute("id","pointerpos");
\r
428 pointerpos.setAttribute("cx",0);
\r
429 pointerpos.setAttribute("cy",0);
\r
430 pointerpos.setAttribute("r",0.5);
\r
431 pointerpos.setAttribute("fill","red");
\r
432 svgpicture.appendChild(pointerpos);
\r
436 // svgpicture = picture;
\r
439 svgpicture.setAttribute("xunitlength",xunitlength);
\r
440 svgpicture.setAttribute("yunitlength",yunitlength);
\r
441 svgpicture.setAttribute("xmin",xmin);
\r
442 svgpicture.setAttribute("xmax",xmax);
\r
443 svgpicture.setAttribute("ymin",ymin);
\r
444 svgpicture.setAttribute("ymax",ymax);
\r
445 svgpicture.setAttribute("ox",origin[0]);
\r
446 svgpicture.setAttribute("oy",origin[1]);
\r
447 var node = myCreateElementSVG("rect");
\r
448 node.setAttribute("x","0");
\r
449 node.setAttribute("y","0");
\r
450 node.setAttribute("width",width);
\r
451 node.setAttribute("height",height);
\r
452 node.setAttribute("style","stroke-width:1;fill:white");
\r
453 svgpicture.appendChild(node);
\r
454 if (!isIE && picture.getAttribute("onmousemove")!=null) {
\r
455 svgpicture.addEventListener("mousemove", mousemove_listener, true);
\r
456 var st = picture.getAttribute("onmousemove");
\r
457 svgpicture.addEventListener("mousemove", eval(st.slice(0,st.indexOf("("))), true);
\r
458 node = myCreateElementSVG("polyline");
\r
459 node.setAttribute("points","0,0 "+width+",0");
\r
460 node.setAttribute("style","stroke:white; stroke-width:3");
\r
461 node.addEventListener("mousemove", top_listener, true);
\r
462 svgpicture.appendChild(node);
\r
463 node = myCreateElementSVG("polyline");
\r
464 node.setAttribute("points","0,"+height+" "+width+","+height);
\r
465 node.setAttribute("style","stroke:white; stroke-width:3");
\r
466 node.addEventListener("mousemove", bottom_listener, true);
\r
467 svgpicture.appendChild(node);
\r
468 node = myCreateElementSVG("polyline");
\r
469 node.setAttribute("points","0,0 0,"+height);
\r
470 node.setAttribute("style","stroke:white; stroke-width:3");
\r
471 node.addEventListener("mousemove", left_listener, true);
\r
472 svgpicture.appendChild(node);
\r
473 node = myCreateElementSVG("polyline");
\r
474 node.setAttribute("points",(width-1)+",0 "+(width-1)+","+height);
\r
475 node.setAttribute("style","stroke:white; stroke-width:3");
\r
476 node.addEventListener("mousemove", right_listener, true);
\r
477 svgpicture.appendChild(node);
\r
479 border = defaultborder;
\r
484 function line(p,q,id) { // segment connecting points p,q (coordinates in units)
\r
486 if (id!=null) node = doc.getElementById(id);
\r
488 node = myCreateElementSVG("path");
\r
489 node.setAttribute("id", id);
\r
490 svgpicture.appendChild(node);
\r
492 node.setAttribute("d","M"+(p[0]*xunitlength+origin[0])+","+
\r
493 (height-p[1]*yunitlength-origin[1])+" "+
\r
494 (q[0]*xunitlength+origin[0])+","+(height-q[1]*yunitlength-origin[1]));
\r
495 node.setAttribute("stroke-width", strokewidth);
\r
496 if (strokedasharray!=null)
\r
497 node.setAttribute("stroke-dasharray", strokedasharray);
\r
498 node.setAttribute("stroke", stroke);
\r
499 node.setAttribute("fill", fill);
\r
500 if (marker=="dot" || marker=="arrowdot") {
\r
501 ASdot(p,4,markerstroke,markerfill);
\r
502 if (marker=="arrowdot") arrowhead(p,q);
\r
503 ASdot(q,4,markerstroke,markerfill);
\r
504 } else if (marker=="arrow") arrowhead(p,q);
\r
507 function path(plist,id,c) {
\r
510 if (id!=null) node = doc.getElementById(id);
\r
512 node = myCreateElementSVG("path");
\r
513 node.setAttribute("id", id);
\r
514 svgpicture.appendChild(node);
\r
516 if (typeof plist == "string") st = plist;
\r
519 st += (plist[0][0]*xunitlength+origin[0])+","+
\r
520 (height-plist[0][1]*yunitlength-origin[1])+" "+c;
\r
521 for (i=1; i<plist.length; i++)
\r
522 st += (plist[i][0]*xunitlength+origin[0])+","+
\r
523 (height-plist[i][1]*yunitlength-origin[1])+" ";
\r
525 node.setAttribute("d", st);
\r
526 node.setAttribute("stroke-width", strokewidth);
\r
527 if (strokedasharray!=null)
\r
528 node.setAttribute("stroke-dasharray", strokedasharray);
\r
529 node.setAttribute("stroke", stroke);
\r
530 node.setAttribute("fill", fill);
\r
531 if (marker=="dot" || marker=="arrowdot")
\r
532 for (i=0; i<plist.length; i++)
\r
533 if (c!="C" && c!="T" || i!=1 && i!=2)
\r
534 ASdot(plist[i],4,markerstroke,markerfill);
\r
537 function curve(plist,id) {
\r
538 path(plist,id,"T");
\r
541 function circle(center,radius,id) { // coordinates in units
\r
543 if (id!=null) node = doc.getElementById(id);
\r
545 node = myCreateElementSVG("circle");
\r
546 node.setAttribute("id", id);
\r
547 svgpicture.appendChild(node);
\r
549 node.setAttribute("cx",center[0]*xunitlength+origin[0]);
\r
550 node.setAttribute("cy",height-center[1]*yunitlength-origin[1]);
\r
551 node.setAttribute("r",radius*xunitlength);
\r
552 node.setAttribute("stroke-width", strokewidth);
\r
553 node.setAttribute("stroke", stroke);
\r
554 node.setAttribute("fill", fill);
\r
557 function loop(p,d,id) {
\r
558 // d is a direction vector e.g. [1,0] means loop starts in that direction
\r
559 if (d==null) d=[1,0];
\r
560 path([p,[p[0]+d[0],p[1]+d[1]],[p[0]-d[1],p[1]+d[0]],p],id,"C");
\r
561 if (marker=="arrow" || marker=="arrowdot")
\r
562 arrowhead([p[0]+Math.cos(1.4)*d[0]-Math.sin(1.4)*d[1],
\r
563 p[1]+Math.sin(1.4)*d[0]+Math.cos(1.4)*d[1]],p);
\r
566 function arc(start,end,radius,id) { // coordinates in units
\r
568 //alert([fill, stroke, origin, xunitlength, yunitlength, height])
\r
569 if (id!=null) node = doc.getElementById(id);
\r
570 if (radius==null) {
\r
571 v=[end[0]-start[0],end[1]-start[1]];
\r
572 radius = Math.sqrt(v[0]*v[0]+v[1]*v[1]);
\r
575 node = myCreateElementSVG("path");
\r
576 node.setAttribute("id", id);
\r
577 svgpicture.appendChild(node);
\r
579 node.setAttribute("d","M"+(start[0]*xunitlength+origin[0])+","+
\r
580 (height-start[1]*yunitlength-origin[1])+" A"+radius*xunitlength+","+
\r
581 radius*yunitlength+" 0 0,0 "+(end[0]*xunitlength+origin[0])+","+
\r
582 (height-end[1]*yunitlength-origin[1]));
\r
583 node.setAttribute("stroke-width", strokewidth);
\r
584 node.setAttribute("stroke", stroke);
\r
585 node.setAttribute("fill", fill);
\r
586 if (marker=="arrow" || marker=="arrowdot") {
\r
587 u = [(end[1]-start[1])/4,(start[0]-end[0])/4];
\r
588 v = [(end[0]-start[0])/2,(end[1]-start[1])/2];
\r
590 v = [start[0]+v[0]+u[0],start[1]+v[1]+u[1]];
\r
591 } else v=[start[0],start[1]];
\r
592 if (marker=="dot" || marker=="arrowdot") {
\r
593 ASdot(start,4,markerstroke,markerfill);
\r
594 if (marker=="arrowdot") arrowhead(v,end);
\r
595 ASdot(end,4,markerstroke,markerfill);
\r
596 } else if (marker=="arrow") arrowhead(v,end);
\r
599 function ellipse(center,rx,ry,id) { // coordinates in units
\r
601 if (id!=null) node = doc.getElementById(id);
\r
603 node = myCreateElementSVG("ellipse");
\r
604 node.setAttribute("id", id);
\r
605 svgpicture.appendChild(node);
\r
607 node.setAttribute("cx",center[0]*xunitlength+origin[0]);
\r
608 node.setAttribute("cy",height-center[1]*yunitlength-origin[1]);
\r
609 node.setAttribute("rx",rx*xunitlength);
\r
610 node.setAttribute("ry",ry*yunitlength);
\r
611 node.setAttribute("stroke-width", strokewidth);
\r
612 node.setAttribute("stroke", stroke);
\r
613 node.setAttribute("fill", fill);
\r
616 function rect(p,q,id,rx,ry) { // opposite corners in units, rounded by radii
\r
618 if (id!=null) node = doc.getElementById(id);
\r
620 node = myCreateElementSVG("rect");
\r
621 node.setAttribute("id", id);
\r
622 svgpicture.appendChild(node);
\r
624 node.setAttribute("x",p[0]*xunitlength+origin[0]);
\r
625 node.setAttribute("y",height-q[1]*yunitlength-origin[1]);
\r
626 node.setAttribute("width",(q[0]-p[0])*xunitlength);
\r
627 node.setAttribute("height",(q[1]-p[1])*yunitlength);
\r
628 if (rx!=null) node.setAttribute("rx",rx*xunitlength);
\r
629 if (ry!=null) node.setAttribute("ry",ry*yunitlength);
\r
630 node.setAttribute("stroke-width", strokewidth);
\r
631 node.setAttribute("stroke", stroke);
\r
632 node.setAttribute("fill", fill);
\r
635 function text(p,st,pos,id,fontsty) {
\r
636 var textanchor = "middle";
\r
637 var dx = 0; var dy = fontsize/3;
\r
639 if (pos.slice(0,5)=="above") dy = -fontsize/2;
\r
640 if (pos.slice(0,5)=="below") dy = fontsize-0;
\r
641 if (pos.slice(0,5)=="right" || pos.slice(5,10)=="right") {
\r
642 textanchor = "start";
\r
645 if (pos.slice(0,4)=="left" || pos.slice(5,9)=="left") {
\r
646 textanchor = "end";
\r
651 if (id!=null) node = doc.getElementById(id);
\r
653 node = myCreateElementSVG("text");
\r
654 node.setAttribute("id", id);
\r
655 svgpicture.appendChild(node);
\r
656 node.appendChild(doc.createTextNode(st));
\r
658 node.lastChild.nodeValue = st;
\r
659 node.setAttribute("x",p[0]*xunitlength+origin[0]+dx);
\r
660 node.setAttribute("y",height-p[1]*yunitlength-origin[1]+dy);
\r
661 node.setAttribute("font-style",(fontsty!=null?fontsty:fontstyle));
\r
662 node.setAttribute("font-family",fontfamily);
\r
663 node.setAttribute("font-size",fontsize);
\r
664 node.setAttribute("font-weight",fontweight);
\r
665 node.setAttribute("text-anchor",textanchor);
\r
666 if (fontstroke!="none") node.setAttribute("stroke",fontstroke);
\r
667 if (fontfill!="none") node.setAttribute("fill",fontfill);
\r
671 function ASdot(center,radius,s,f) { // coordinates in units, radius in pixel
\r
672 if (s==null) s = stroke; if (f==null) f = fill;
\r
673 var node = myCreateElementSVG("circle");
\r
674 node.setAttribute("cx",center[0]*xunitlength+origin[0]);
\r
675 node.setAttribute("cy",height-center[1]*yunitlength-origin[1]);
\r
676 node.setAttribute("r",radius);
\r
677 node.setAttribute("stroke-width", strokewidth);
\r
678 node.setAttribute("stroke", s);
\r
679 node.setAttribute("fill", f);
\r
680 svgpicture.appendChild(node);
\r
683 function dot(center, typ, label, pos, id) {
\r
685 var cx = center[0]*xunitlength+origin[0];
\r
686 var cy = height-center[1]*yunitlength-origin[1];
\r
687 if (id!=null) node = doc.getElementById(id);
\r
688 if (typ=="+" || typ=="-" || typ=="|") {
\r
690 node = myCreateElementSVG("path");
\r
691 node.setAttribute("id", id);
\r
692 svgpicture.appendChild(node);
\r
695 node.setAttribute("d",
\r
696 " M "+(cx-ticklength)+" "+cy+" L "+(cx+ticklength)+" "+cy+
\r
697 " M "+cx+" "+(cy-ticklength)+" L "+cx+" "+(cy+ticklength));
\r
698 node.setAttribute("stroke-width", .5);
\r
699 node.setAttribute("stroke", axesstroke);
\r
701 if (typ=="-") node.setAttribute("d",
\r
702 " M "+(cx-ticklength)+" "+cy+" L "+(cx+ticklength)+" "+cy);
\r
703 else node.setAttribute("d",
\r
704 " M "+cx+" "+(cy-ticklength)+" L "+cx+" "+(cy+ticklength));
\r
705 node.setAttribute("stroke-width", strokewidth);
\r
706 node.setAttribute("stroke", stroke);
\r
710 node = myCreateElementSVG("circle");
\r
711 node.setAttribute("id", id);
\r
712 svgpicture.appendChild(node);
\r
714 node.setAttribute("cx",cx);
\r
715 node.setAttribute("cy",cy);
\r
716 node.setAttribute("r",dotradius);
\r
717 node.setAttribute("stroke-width", strokewidth);
\r
718 node.setAttribute("stroke", stroke);
\r
719 node.setAttribute("fill", (typ=="open"?"white":stroke));
\r
722 text(center,label,(pos==null?"below":pos),(id==null?id:id+"label"))
\r
725 function arrowhead(p,q) { // draw arrowhead at q (in units)
\r
727 var v = [p[0]*xunitlength+origin[0],height-p[1]*yunitlength-origin[1]];
\r
728 var w = [q[0]*xunitlength+origin[0],height-q[1]*yunitlength-origin[1]];
\r
729 var u = [w[0]-v[0],w[1]-v[1]];
\r
730 var d = Math.sqrt(u[0]*u[0]+u[1]*u[1]);
\r
731 if (d > 0.00000001) {
\r
732 u = [u[0]/d, u[1]/d];
\r
734 var node = myCreateElementSVG("path");
\r
735 node.setAttribute("d","M "+(w[0]-15*u[0]-4*up[0])+" "+
\r
736 (w[1]-15*u[1]-4*up[1])+" L "+(w[0]-3*u[0])+" "+(w[1]-3*u[1])+" L "+
\r
737 (w[0]-15*u[0]+4*up[0])+" "+(w[1]-15*u[1]+4*up[1])+" z");
\r
738 node.setAttribute("stroke-width", markerstrokewidth);
\r
739 node.setAttribute("stroke", stroke); /*was markerstroke*/
\r
740 node.setAttribute("fill", stroke); /*was arrowfill*/
\r
741 svgpicture.appendChild(node);
\r
745 function chopZ(st) {
\r
746 var k = st.indexOf(".");
\r
747 if (k==-1) return st;
\r
748 for (var i=st.length-1; i>k && st.charAt(i)=="0"; i--);
\r
750 return st.slice(0,i+1);
\r
753 function grid(dx,dy) { // for backward compatibility
\r
754 axes(dx,dy,null,dx,dy)
\r
757 function noaxes() {
\r
758 if (!initialized) initPicture();
\r
761 function axes(dx,dy,labels,gdx,gdy) {
\r
762 //xscl=x is equivalent to xtick=x; xgrid=x; labels=true;
\r
763 var x, y, ldx, ldy, lx, ly, lxp, lyp, pnode, st;
\r
764 if (!initialized) initPicture();
\r
765 if (typeof dx=="string") { labels = dx; dx = null; }
\r
766 if (typeof dy=="string") { gdx = dy; dy = null; }
\r
767 if (xscl!=null) {dx = xscl; gdx = xscl; labels = dx}
\r
768 if (yscl!=null) {dy = yscl; gdy = yscl}
\r
769 if (xtick!=null) {dx = xtick}
\r
770 if (ytick!=null) {dy = ytick}
\r
772 dx = (dx==null?xunitlength:dx*xunitlength);
\r
773 dy = (dy==null?dx:dy*yunitlength);
\r
774 fontsize = Math.min(dx/2,dy/2,16);//alert(fontsize)
\r
775 ticklength = fontsize/4;
\r
776 if (xgrid!=null) gdx = xgrid;
\r
777 if (ygrid!=null) gdy = ygrid;
\r
779 gdx = (typeof gdx=="string"?dx:gdx*xunitlength);
\r
780 gdy = (gdy==null?dy:gdy*yunitlength);
\r
781 pnode = myCreateElementSVG("path");
\r
783 for (x = origin[0]; x<width; x = x+gdx)
\r
784 st += " M"+x+",0"+" "+x+","+height;
\r
785 for (x = origin[0]-gdx; x>0; x = x-gdx)
\r
786 st += " M"+x+",0"+" "+x+","+height;
\r
787 for (y = height-origin[1]; y<height; y = y+gdy)
\r
788 st += " M0,"+y+" "+width+","+y;
\r
789 for (y = height-origin[1]-gdy; y>0; y = y-gdy)
\r
790 st += " M0,"+y+" "+width+","+y;
\r
791 pnode.setAttribute("d",st);
\r
792 pnode.setAttribute("stroke-width", .5);
\r
793 pnode.setAttribute("stroke", gridstroke);
\r
794 pnode.setAttribute("fill", fill);
\r
795 svgpicture.appendChild(pnode);
\r
797 pnode = myCreateElementSVG("path");
\r
798 st="M0,"+(height-origin[1])+" "+width+","+
\r
799 (height-origin[1])+" M"+origin[0]+",0 "+origin[0]+","+height;
\r
800 for (x = origin[0]+dx; x<width; x = x+dx)
\r
801 st += " M"+x+","+(height-origin[1]+ticklength)+" "+x+","+
\r
802 (height-origin[1]-ticklength);
\r
803 for (x = origin[0]-dx; x>0; x = x-dx)
\r
804 st += " M"+x+","+(height-origin[1]+ticklength)+" "+x+","+
\r
805 (height-origin[1]-ticklength);
\r
806 for (y = height-origin[1]+dy; y<height; y = y+dy)
\r
807 st += " M"+(origin[0]+ticklength)+","+y+" "+(origin[0]-ticklength)+","+y;
\r
808 for (y = height-origin[1]-dy; y>0; y = y-dy)
\r
809 st += " M"+(origin[0]+ticklength)+","+y+" "+(origin[0]-ticklength)+","+y;
\r
810 if (labels!=null) with (Math) {
\r
811 ldx = dx/xunitlength;
\r
812 ldy = dy/yunitlength;
\r
813 lx = (xmin>0 || xmax<0?xmin:0);
\r
814 ly = (ymin>0 || ymax<0?ymin:0);
\r
815 lxp = (ly==0?"below":"above");
\r
816 lyp = (lx==0?"left":"right");
\r
817 var ddx = floor(1.1-log(ldx)/log(10))+1;
\r
818 var ddy = floor(1.1-log(ldy)/log(10))+1;
\r
819 for (x = ldx; x<=xmax; x = x+ldx)
\r
820 text([x,ly],chopZ(x.toFixed(ddx)),lxp);
\r
821 for (x = -ldx; xmin<=x; x = x-ldx)
\r
822 text([x,ly],chopZ(x.toFixed(ddx)),lxp);
\r
823 for (y = ldy; y<=ymax; y = y+ldy)
\r
824 text([lx,y],chopZ(y.toFixed(ddy)),lyp);
\r
825 for (y = -ldy; ymin<=y; y = y-ldy)
\r
826 text([lx,y],chopZ(y.toFixed(ddy)),lyp);
\r
828 pnode.setAttribute("d",st);
\r
829 pnode.setAttribute("stroke-width", .5);
\r
830 pnode.setAttribute("stroke", axesstroke);
\r
831 pnode.setAttribute("fill", fill);
\r
832 svgpicture.appendChild(pnode);
\r
835 function mathjs(st) {
\r
836 //translate a math formula to js function notation
\r
837 // a^b --> pow(a,b)
\r
839 // (...)d --> (...)*d
\r
840 // n! --> factorial(n)
\r
841 // sin^-1 --> arcsin etc.
\r
842 //while ^ in string, find term on left and right
\r
843 //slice and concat new formula string
\r
844 st = st.replace(/\s/g,"");
\r
845 if (st.indexOf("^-1")!=-1) {
\r
846 st = st.replace(/sin\^-1/g,"arcsin");
\r
847 st = st.replace(/cos\^-1/g,"arccos");
\r
848 st = st.replace(/tan\^-1/g,"arctan");
\r
849 st = st.replace(/sec\^-1/g,"arcsec");
\r
850 st = st.replace(/csc\^-1/g,"arccsc");
\r
851 st = st.replace(/cot\^-1/g,"arccot");
\r
852 st = st.replace(/sinh\^-1/g,"arcsinh");
\r
853 st = st.replace(/cosh\^-1/g,"arccosh");
\r
854 st = st.replace(/tanh\^-1/g,"arctanh");
\r
855 st = st.replace(/sech\^-1/g,"arcsech");
\r
856 st = st.replace(/csch\^-1/g,"arccsch");
\r
857 st = st.replace(/coth\^-1/g,"arccoth");
\r
859 st = st.replace(/^e$/g,"(E)");
\r
860 st = st.replace(/^e([^a-zA-Z])/g,"(E)$1");
\r
861 st = st.replace(/([^a-zA-Z])e([^a-zA-Z])/g,"$1(E)$2");
\r
862 st = st.replace(/([0-9])([\(a-zA-Z])/g,"$1*$2");
\r
863 st = st.replace(/\)([\(0-9a-zA-Z])/g,"\)*$1");
\r
864 var i,j,k, ch, nested;
\r
865 while ((i=st.indexOf("^"))!=-1) {
\r
866 //find left argument
\r
867 if (i==0) return "Error: missing argument";
\r
870 if (ch>="0" && ch<="9") {// look for (decimal) number
\r
872 while (j>=0 && (ch=st.charAt(j))>="0" && ch<="9") j--;
\r
875 while (j>=0 && (ch=st.charAt(j))>="0" && ch<="9") j--;
\r
877 } else if (ch==")") {// look for matching opening bracket and function name
\r
880 while (j>=0 && nested>0) {
\r
882 if (ch=="(") nested--;
\r
883 else if (ch==")") nested++;
\r
886 while (j>=0 && (ch=st.charAt(j))>="a" && ch<="z" || ch>="A" && ch<="Z")
\r
888 } else if (ch>="a" && ch<="z" || ch>="A" && ch<="Z") {// look for variable
\r
890 while (j>=0 && (ch=st.charAt(j))>="a" && ch<="z" || ch>="A" && ch<="Z")
\r
893 return "Error: incorrect syntax in "+st+" at position "+j;
\r
895 //find right argument
\r
896 if (i==st.length-1) return "Error: missing argument";
\r
899 if (ch>="0" && ch<="9" || ch=="-") {// look for signed (decimal) number
\r
901 while (k<st.length && (ch=st.charAt(k))>="0" && ch<="9") k++;
\r
904 while (k<st.length && (ch=st.charAt(k))>="0" && ch<="9") k++;
\r
906 } else if (ch=="(") {// look for matching closing bracket and function name
\r
909 while (k<st.length && nested>0) {
\r
911 if (ch=="(") nested++;
\r
912 else if (ch==")") nested--;
\r
915 } else if (ch>="a" && ch<="z" || ch>="A" && ch<="Z") {// look for variable
\r
917 while (k<st.length && (ch=st.charAt(k))>="a" && ch<="z" ||
\r
918 ch>="A" && ch<="Z") k++;
\r
920 return "Error: incorrect syntax in "+st+" at position "+k;
\r
922 st = st.slice(0,j+1)+"pow("+st.slice(j+1,i)+","+st.slice(i+1,k)+")"+
\r
925 while ((i=st.indexOf("!"))!=-1) {
\r
926 //find left argument
\r
927 if (i==0) return "Error: missing argument";
\r
930 if (ch>="0" && ch<="9") {// look for (decimal) number
\r
932 while (j>=0 && (ch=st.charAt(j))>="0" && ch<="9") j--;
\r
935 while (j>=0 && (ch=st.charAt(j))>="0" && ch<="9") j--;
\r
937 } else if (ch==")") {// look for matching opening bracket and function name
\r
940 while (j>=0 && nested>0) {
\r
942 if (ch=="(") nested--;
\r
943 else if (ch==")") nested++;
\r
946 while (j>=0 && (ch=st.charAt(j))>="a" && ch<="z" || ch>="A" && ch<="Z")
\r
948 } else if (ch>="a" && ch<="z" || ch>="A" && ch<="Z") {// look for variable
\r
950 while (j>=0 && (ch=st.charAt(j))>="a" && ch<="z" || ch>="A" && ch<="Z")
\r
953 return "Error: incorrect syntax in "+st+" at position "+j;
\r
955 st = st.slice(0,j+1)+"factorial("+st.slice(j+1,i)+")"+st.slice(i+1);
\r
960 function plot(fun,x_min,x_max,points,id) {
\r
962 var f = function(x) { return x }, g = fun;
\r
964 if (typeof fun=="string")
\r
965 eval("g = function(x){ with(Math) return "+mathjs(fun)+" }");
\r
966 else if (typeof fun=="object") {
\r
967 eval("f = function(t){ with(Math) return "+mathjs(fun[0])+" }");
\r
968 eval("g = function(t){ with(Math) return "+mathjs(fun[1])+" }");
\r
970 if (typeof x_min=="string") { name = x_min; x_min = xmin }
\r
972 var min = (x_min==null?xmin:x_min);
\r
973 var max = (x_max==null?xmax:x_max);
\r
974 var inc = max-min-0.000001*(max-min);
\r
975 inc = (points==null?inc/200:inc/points);
\r
977 //alert(typeof g(min))
\r
978 for (var t = min; t <= max; t += inc) {
\r
980 if (!(isNaN(gt)||Math.abs(gt)=="Infinity")) pth[pth.length] = [f(t), gt];
\r
986 function slopefield(fun,dx,dy) {
\r
988 if (typeof fun=="string")
\r
989 eval("g = function(x,y){ with(Math) return "+mathjs(fun)+" }");
\r
990 var gxy,x,y,u,v,dz;
\r
991 if (dx==null) dx=1;
\r
992 if (dy==null) dy=1;
\r
993 dz = Math.sqrt(dx*dx+dy*dy)/6;
\r
994 var x_min = Math.ceil(xmin/dx);
\r
995 var y_min = Math.ceil(ymin/dy);
\r
996 for (x = x_min; x <= xmax; x += dx)
\r
997 for (y = y_min; y <= ymax; y += dy) {
\r
1000 if (Math.abs(gxy)=="Infinity") {u = 0; v = dz;}
\r
1001 else {u = dz/Math.sqrt(1+gxy*gxy); v = gxy*u;}
\r
1002 line([x-u,y-v],[x+u,y+v]);
\r
1007 function updateCoords(ind) {
\r
1008 switchTo("picture"+(ind+1));
\r
1009 var gx=getX(), gy=getY();
\r
1010 if ((xmax-gx)*xunitlength > 6*fontsize || (gy-ymin)*yunitlength > 2*fontsize)
\r
1011 text([xmax,ymin],"("+gx.toFixed(2)+", "+gy.toFixed(2)+")",
\r
1012 "aboveleft","AScoord"+ind,"");
\r
1013 else text([xmax,ymin]," ","aboveleft","AScoord"+ind,"");
\r
1016 function updateCoords0() {updateCoords(0)}
\r
1017 function updateCoords1() {updateCoords(1)}
\r
1018 function updateCoords2() {updateCoords(2)}
\r
1019 function updateCoords3() {updateCoords(3)}
\r
1020 function updateCoords4() {updateCoords(4)}
\r
1021 function updateCoords5() {updateCoords(5)}
\r
1022 function updateCoords6() {updateCoords(6)}
\r
1023 function updateCoords7() {updateCoords(7)}
\r
1024 function updateCoords8() {updateCoords(8)}
\r
1025 function updateCoords9() {updateCoords(9)}
\r
1026 ASfn = [function() {updatePicture(0)},
\r
1027 function() {updatePicture(1)},
\r
1028 function() {updatePicture(2)},
\r
1029 function() {updatePicture(3)},
\r
1030 function() {updatePicture(4)},
\r
1031 function() {updatePicture(5)},
\r
1032 function() {updatePicture(6)},
\r
1033 function() {updatePicture(7)},
\r
1034 function() {updatePicture(8)},
\r
1035 function() {updatePicture(9)}];
\r
1036 ASupdateCoords = [function() {updateCoords(0)},
\r
1037 function() {updateCoords(1)},
\r
1038 function() {updateCoords(2)},
\r
1039 function() {updateCoords(3)},
\r
1040 function() {updateCoords(4)},
\r
1041 function() {updateCoords(5)},
\r
1042 function() {updateCoords(6)},
\r
1043 function() {updateCoords(7)},
\r
1044 function() {updateCoords(8)},
\r
1045 function() {updateCoords(9)}];
\r
1047 // GO1.1 Generic onload by Brothercake
\r
1048 // http://www.brothercake.com/
\r
1050 function generic()
\r
1054 //setup onload function
\r
1055 if(typeof window.addEventListener != 'undefined')
\r
1057 //.. gecko, safari, konqueror and standard
\r
1058 window.addEventListener('load', generic, false);
\r
1060 else if(typeof document.addEventListener != 'undefined')
\r
1063 document.addEventListener('load', generic, false);
\r
1065 else if(typeof window.attachEvent != 'undefined')
\r
1068 window.attachEvent('onload', generic);
\r
1070 //** remove this condition to degrade older browsers
\r
1073 //.. mac/ie5 and anything else that gets this far
\r
1074 //if there's an existing onload function
\r
1075 if(typeof window.onload == 'function')
\r
1078 var existing = onload;
\r
1079 //add new onload handler
\r
1080 window.onload = function()
\r
1082 //call existing onload function
\r
1084 //call generic onload function
\r
1090 //setup onload function
\r
1091 window.onload = generic;
\r