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 | } |