Subversion Repositories wimsdev

Rev

Rev 20 | Details | Compare with Previous | Last modification | View Log | RSS feed

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