1 /* This notice must be untouched at all times.
\r
3 wz_jsgraphics.js v. 2.3
\r
4 The latest version is available at
\r
5 http://www.walterzorn.com
\r
6 or http://www.devira.com
\r
7 or http://www.walterzorn.de
\r
9 Copyright (c) 2002-2004 Walter Zorn. All rights reserved.
\r
10 Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com )
\r
11 Last modified: 17. 5. 2004
\r
13 Performance optimizations for Internet Explorer
\r
14 by Thomas Frank and John Holdsworth.
\r
15 fillPolygon method implemented by Matthieu Haller.
\r
17 High Performance JavaScript Graphics Library.
\r
19 - to draw lines, rectangles, ellipses, polygons
\r
20 with specifiable line thickness,
\r
21 - to fill rectangles and ellipses
\r
23 NOTE: Operations, functions and branching have rather been optimized
\r
24 to efficiency and speed than to shortness of source code.
\r
26 This program is free software;
\r
27 you can redistribute it and/or modify it under the terms of the
\r
28 GNU General Public License as published by the Free Software Foundation;
\r
29 either version 2 of the License, or (at your option) any later version.
\r
30 This program is distributed in the hope that it will be useful,
\r
31 but WITHOUT ANY WARRANTY;
\r
32 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\r
33 See the GNU General Public License
\r
34 at http://www.gnu.org/copyleft/gpl.html for more details.
\r
38 var jg_ihtm, jg_ie, jg_fast, jg_dom, jg_moz,
\r
39 jg_n4 = (document.layers && typeof document.classes != "undefined");
\r
42 function chkDHTM(x, i)
\r
44 x = document.body || null;
\r
45 jg_ie = x && typeof x.insertAdjacentHTML != "undefined";
\r
46 jg_dom = (x && !jg_ie &&
\r
47 typeof x.appendChild != "undefined" &&
\r
48 typeof document.createRange != "undefined" &&
\r
49 typeof (i = document.createRange()).setStartBefore != "undefined" &&
\r
50 typeof i.createContextualFragment != "undefined");
\r
51 jg_ihtm = !jg_ie && !jg_dom && x && typeof x.innerHTML != "undefined";
\r
52 jg_fast = jg_ie && document.all && !window.opera;
\r
53 jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined";
\r
59 this.wnd.document.write(jg_fast? this.htmRpc() : this.htm);
\r
64 function pntCnvDom()
\r
66 var x = document.createRange();
\r
67 x.setStartBefore(this.cnv);
\r
68 x = x.createContextualFragment(jg_fast? this.htmRpc() : this.htm);
\r
69 this.cnv.appendChild(x);
\r
76 this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this.htmRpc() : this.htm);
\r
81 function pntCnvIhtm()
\r
83 this.cnv.innerHTML += this.htm;
\r
94 function mkDiv(x, y, w, h)
\r
96 this.htm += '<div style="position:absolute;'+
\r
97 'left:' + x + 'px;'+
\r
99 'width:' + w + 'px;'+
\r
100 'height:' + h + 'px;'+
\r
101 'clip:rect(0,'+w+'px,'+h+'px,0);'+
\r
102 'background-color:' + this.color +
\r
103 (!jg_moz? ';overflow:hidden' : '')+
\r
108 function mkDivIe(x, y, w, h)
\r
110 this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';';
\r
114 function mkDivPrt(x, y, w, h)
\r
116 this.htm += '<div style="position:absolute;'+
\r
117 'border-left:' + w + 'px solid ' + this.color + ';'+
\r
118 'left:' + x + 'px;'+
\r
119 'top:' + y + 'px;'+
\r
121 'height:' + h + 'px;'+
\r
122 'clip:rect(0,'+w+'px,'+h+'px,0);'+
\r
123 'background-color:' + this.color +
\r
124 (!jg_moz? ';overflow:hidden' : '')+
\r
129 function mkLyr(x, y, w, h)
\r
131 this.htm += '<layer '+
\r
132 'left="' + x + '" '+
\r
133 'top="' + y + '" '+
\r
134 'width="' + w + '" '+
\r
135 'height="' + h + '" '+
\r
136 'bgcolor="' + this.color + '"><\/layer>\n';
\r
140 var regex = /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g;
\r
143 return this.htm.replace(
\r
145 '<div style="overflow:hidden;position:absolute;background-color:'+
\r
146 '$1;left:$2;top:$3;width:$4;height:$5"></div>\n');
\r
150 function htmPrtRpc()
\r
152 return this.htm.replace(
\r
154 '<div style="overflow:hidden;position:absolute;background-color:'+
\r
155 '$1;left:$2;top:$3;width:$4;height:$5;border-left:$4px solid $1"></div>\n');
\r
159 function mkLin(x1, y1, x2, y2)
\r
170 var dx = x2-x1, dy = Math.abs(y2-y1),
\r
172 yIncr = (y1 > y2)? -1 : 1;
\r
177 pru = pr - (dx<<1),
\r
185 this.mkDiv(ox, y, x-ox, 1);
\r
192 this.mkDiv(ox, y, x2-ox+1, 1);
\r
198 pru = pr - (dy<<1),
\r
207 this.mkDiv(x++, y, 1, oy-y+1);
\r
218 this.mkDiv(x2, y2, 1, oy-y2+1);
\r
227 this.mkDiv(x++, oy, 1, y-oy);
\r
233 this.mkDiv(x2, oy, 1, y2-oy+1);
\r
239 function mkLin2D(x1, y1, x2, y2)
\r
250 var dx = x2-x1, dy = Math.abs(y2-y1),
\r
252 yIncr = (y1 > y2)? -1 : 1;
\r
254 var s = this.stroke;
\r
259 var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;
\r
260 _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
\r
263 var ad = Math.ceil(s/2);
\r
266 pru = pr - (dx<<1),
\r
274 this.mkDiv(ox, y, x-ox+ad, _s);
\r
281 this.mkDiv(ox, y, x2-ox+ad+1, _s);
\r
288 var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;
\r
289 _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
\r
292 var ad = Math.round(s/2);
\r
295 pru = pr - (dy<<1),
\r
305 this.mkDiv(x++, y, _s, oy-y+ad);
\r
316 this.mkDiv(x2, y2, _s, oy-y2+ad);
\r
325 this.mkDiv(x++, oy, _s, y-oy+ad);
\r
331 this.mkDiv(x2, oy, _s, y2-oy+ad+1);
\r
337 function mkLinDott(x1, y1, x2, y2)
\r
348 var dx = x2-x1, dy = Math.abs(y2-y1),
\r
350 yIncr = (y1 > y2)? -1 : 1,
\r
355 pru = pr - (dx<<1),
\r
359 if (drw) this.mkDiv(x, y, 1, 1);
\r
369 if (drw) this.mkDiv(x, y, 1, 1);
\r
375 pru = pr - (dy<<1),
\r
379 if (drw) this.mkDiv(x, y, 1, 1);
\r
389 if (drw) this.mkDiv(x, y, 1, 1);
\r
394 function mkOv(left, top, width, height)
\r
396 var a = width>>1, b = height>>1,
\r
397 wod = width&1, hod = (height&1)+1,
\r
398 cx = left+a, cy = top+b,
\r
401 aa = (a*a)<<1, bb = (b*b)<<1,
\r
402 st = (aa>>1)*(1-(b<<1)) + bb,
\r
403 tt = (bb>>1) - aa*((b<<1)-1),
\r
409 st += bb*((x<<1)+3);
\r
410 tt += (bb<<1)*(++x);
\r
414 st += bb*((x<<1)+3) - (aa<<1)*(y-1);
\r
415 tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
\r
420 this.mkOvQds(cx, cy, -x+2, ox+wod, -oy, oy-1+hod, 1, 1);
\r
421 this.mkOvQds(cx, cy, -x+1, x-1+wod, -y-1, y+hod, 1, 1);
\r
423 else this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, oy-h+hod, w, h);
\r
429 tt -= aa*((y<<1)-3);
\r
430 st -= (aa<<1)*(--y);
\r
433 this.mkDiv(cx-a, cy-oy, a-ox+1, (oy<<1)+hod);
\r
434 this.mkDiv(cx+ox+wod, cy-oy, a-ox+1, (oy<<1)+hod);
\r
438 function mkOv2D(left, top, width, height)
\r
440 var s = this.stroke;
\r
443 var a = width>>1, b = height>>1,
\r
444 wod = width&1, hod = (height&1)+1,
\r
445 cx = left+a, cy = top+b,
\r
447 aa = (a*a)<<1, bb = (b*b)<<1,
\r
448 st = (aa>>1)*(1-(b<<1)) + bb,
\r
449 tt = (bb>>1) - aa*((b<<1)-1);
\r
451 if (s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0))
\r
453 var ox = 0, oy = b,
\r
455 pxl, pxr, pxt, pxb, pxw;
\r
460 st += bb*((x<<1)+3);
\r
461 tt += (bb<<1)*(++x);
\r
465 st += bb*((x<<1)+3) - (aa<<1)*(y-1);
\r
466 tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
\r
481 this.mkOvQds(cx, cy, -x+1, ox-pxw+w+wod, -oy, -h+oy+hod, pxw, h);
\r
487 tt -= aa*((y<<1)-3);
\r
488 st -= (aa<<1)*(--y);
\r
491 this.mkDiv(cx-a, cy-oy, s, (oy<<1)+hod);
\r
492 this.mkDiv(cx+a+wod-s+1, cy-oy, s, (oy<<1)+hod);
\r
497 var _a = (width-((s-1)<<1))>>1,
\r
498 _b = (height-((s-1)<<1))>>1,
\r
500 _aa = (_a*_a)<<1, _bb = (_b*_b)<<1,
\r
501 _st = (_aa>>1)*(1-(_b<<1)) + _bb,
\r
502 _tt = (_bb>>1) - _aa*((_b<<1)-1),
\r
506 _pxb = new Array();
\r
514 st += bb*((x<<1)+3);
\r
515 tt += (bb<<1)*(++x);
\r
516 pxl[pxl.length] = x;
\r
517 pxt[pxt.length] = y;
\r
521 st += bb*((x<<1)+3) - (aa<<1)*(y-1);
\r
522 tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
\r
523 pxl[pxl.length] = x;
\r
524 pxt[pxt.length] = y;
\r
528 tt -= aa*((y<<1)-3);
\r
529 st -= (aa<<1)*(--y);
\r
536 _st += _bb*((_x<<1)+3);
\r
537 _tt += (_bb<<1)*(++_x);
\r
538 _pxb[_pxb.length] = _y-1;
\r
542 _st += _bb*((_x<<1)+3) - (_aa<<1)*(_y-1);
\r
543 _tt += (_bb<<1)*(++_x) - _aa*(((_y--)<<1)-3);
\r
544 _pxb[_pxb.length] = _y-1;
\r
548 _tt -= _aa*((_y<<1)-3);
\r
549 _st -= (_aa<<1)*(--_y);
\r
550 _pxb[_pxb.length-1]--;
\r
555 var ox = 0, oy = b,
\r
559 for (var i = 0; i < l; i++)
\r
561 if (typeof _pxb[i] != "undefined")
\r
563 if (_pxb[i] < _oy || pxt[i] < oy)
\r
566 this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, _oy+hod, x-ox, oy-_oy);
\r
575 this.mkDiv(cx-x+1, cy-oy, 1, (oy<<1)+hod);
\r
576 this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
\r
581 this.mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod);
\r
582 this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
\r
587 function mkOvDott(left, top, width, height)
\r
589 var a = width>>1, b = height>>1,
\r
590 wod = width&1, hod = height&1,
\r
591 cx = left+a, cy = top+b,
\r
593 aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,
\r
594 st = (aa2>>1)*(1-(b<<1)) + bb,
\r
595 tt = (bb>>1) - aa2*((b<<1)-1),
\r
601 st += bb*((x<<1)+3);
\r
602 tt += (bb<<1)*(++x);
\r
606 st += bb*((x<<1)+3) - aa4*(y-1);
\r
607 tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);
\r
611 tt -= aa2*((y<<1)-3);
\r
614 if (drw) this.mkOvQds(cx, cy, -x, x+wod, -y, y+hod, 1, 1);
\r
620 function mkRect(x, y, w, h)
\r
622 var s = this.stroke;
\r
623 this.mkDiv(x, y, w, s);
\r
624 this.mkDiv(x+w, y, s, h);
\r
625 this.mkDiv(x, y+h, w+s, s);
\r
626 this.mkDiv(x, y+s, s, h-s);
\r
630 function mkRectDott(x, y, w, h)
\r
632 this.drawLine(x, y, x+w, y);
\r
633 this.drawLine(x+w, y, x+w, y+h);
\r
634 this.drawLine(x, y+h, x+w, y+h);
\r
635 this.drawLine(x, y, x, y+h);
\r
641 this.PLAIN = 'font-weight:normal;';
\r
642 this.BOLD = 'font-weight:bold;';
\r
643 this.ITALIC = 'font-style:italic;';
\r
644 this.ITALIC_BOLD = this.ITALIC + this.BOLD;
\r
645 this.BOLD_ITALIC = this.ITALIC_BOLD;
\r
647 var Font = new jsgFont();
\r
650 function jsgStroke()
\r
654 var Stroke = new jsgStroke();
\r
657 function jsGraphics(id, wnd)
\r
659 this.setColor = new Function('arg', 'this.color = arg.toLowerCase();');
\r
661 this.setStroke = function(x)
\r
666 this.drawLine = mkLinDott;
\r
667 this.mkOv = mkOvDott;
\r
668 this.drawRect = mkRectDott;
\r
672 this.drawLine = mkLin2D;
\r
673 this.mkOv = mkOv2D;
\r
674 this.drawRect = mkRect;
\r
678 this.drawLine = mkLin;
\r
680 this.drawRect = mkRect;
\r
685 this.setPrintable = function(arg)
\r
687 this.printable = arg;
\r
690 this.mkDiv = mkDivIe;
\r
691 this.htmRpc = arg? htmPrtRpc : htmRpc;
\r
693 else this.mkDiv = jg_n4? mkLyr : arg? mkDivPrt : mkDiv;
\r
697 this.setFont = function(fam, sz, sty)
\r
701 this.ftSty = sty || Font.PLAIN;
\r
705 this.drawPolyline = this.drawPolyLine = function(x, y, s)
\r
707 for (var i=0 ; i<x.length-1 ; i++ )
\r
708 this.drawLine(x[i], y[i], x[i+1], y[i+1]);
\r
712 this.fillRect = function(x, y, w, h)
\r
714 this.mkDiv(x, y, w, h);
\r
718 this.drawPolygon = function(x, y)
\r
720 this.drawPolyline(x, y);
\r
721 this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]);
\r
725 this.drawEllipse = this.drawOval = function(x, y, w, h)
\r
727 this.mkOv(x, y, w, h);
\r
731 this.fillEllipse = this.fillOval = function(left, top, w, h)
\r
733 var a = (w -= 1)>>1, b = (h -= 1)>>1,
\r
734 wod = (w&1)+1, hod = (h&1)+1,
\r
735 cx = left+a, cy = top+b,
\r
738 aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,
\r
739 st = (aa2>>1)*(1-(b<<1)) + bb,
\r
740 tt = (bb>>1) - aa2*((b<<1)-1),
\r
742 if (w+1) while (y > 0)
\r
746 st += bb*((x<<1)+3);
\r
747 tt += (bb<<1)*(++x);
\r
751 st += bb*((x<<1)+3) - aa4*(y-1);
\r
754 tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);
\r
756 this.mkDiv(pxl, cy-oy, dw, dh);
\r
757 this.mkDiv(pxl, cy+oy-dh+hod, dw, dh);
\r
763 tt -= aa2*((y<<1)-3);
\r
767 this.mkDiv(cx-a, cy-oy, w+1, (oy<<1)+hod);
\r
772 /* fillPolygon method, implemented by Matthieu Haller.
\r
773 This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib.
\r
774 C source of GD 1.8.4 found at http://www.boutell.com/gd/
\r
776 THANKS to Kirsten Schulz for the polygon fixes!
\r
778 The intersection finding technique of this code could be improved
\r
779 by remembering the previous intertersection, and by using the slope.
\r
780 That could help to adjust intersections to produce a nice
\r
781 interior_extrema. */
\r
782 this.fillPolygon = function(array_x, array_y)
\r
792 var n = array_x.length;
\r
799 for (i = 1; i < n; i++)
\r
801 if (array_y[i] < miny)
\r
804 if (array_y[i] > maxy)
\r
807 for (y = miny; y <= maxy; y++)
\r
809 var polyInts = new Array();
\r
811 for (i = 0; i < n; i++)
\r
823 y1 = array_y[ind1];
\r
824 y2 = array_y[ind2];
\r
827 x1 = array_x[ind1];
\r
828 x2 = array_x[ind2];
\r
832 y2 = array_y[ind1];
\r
833 y1 = array_y[ind2];
\r
834 x2 = array_x[ind1];
\r
835 x1 = array_x[ind2];
\r
839 // modified 11. 2. 2004 Walter Zorn
\r
840 if ((y >= y1) && (y < y2))
\r
841 polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);
\r
843 else if ((y == maxy) && (y > y1) && (y <= y2))
\r
844 polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);
\r
846 polyInts.sort(integer_compare);
\r
848 for (i = 0; i < ints; i+=2)
\r
850 w = polyInts[i+1]-polyInts[i]
\r
851 this.mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);
\r
857 this.drawString = function(txt, x, y)
\r
859 this.htm += '<div style="position:absolute;white-space:nowrap;'+
\r
860 'left:' + x + 'px;'+
\r
861 'top:' + y + 'px;'+
\r
862 'font-family:' + this.ftFam + ';'+
\r
863 'font-size:' + this.ftSz + ';'+
\r
864 'color:' + this.color + ';' + this.ftSty + '">'+
\r
870 this.drawImage = function(imgSrc, x, y, w, h)
\r
872 this.htm += '<div style="position:absolute;'+
\r
873 'left:' + x + 'px;'+
\r
874 'top:' + y + 'px;'+
\r
875 'width:' + w + ';'+
\r
876 'height:' + h + ';">'+
\r
877 '<img src="' + imgSrc + '" width="' + w + '" height="' + h + '">'+
\r
882 this.clear = function()
\r
885 if (this.cnv) this.cnv.innerHTML = this.defhtm;
\r
889 this.mkOvQds = function(cx, cy, xl, xr, yt, yb, w, h)
\r
891 this.mkDiv(xr+cx, yt+cy, w, h);
\r
892 this.mkDiv(xr+cx, yb+cy, w, h);
\r
893 this.mkDiv(xl+cx, yb+cy, w, h);
\r
894 this.mkDiv(xl+cx, yt+cy, w, h);
\r
898 this.setFont('verdana,geneva,helvetica,sans-serif', String.fromCharCode(0x31, 0x32, 0x70, 0x78), Font.PLAIN);
\r
899 this.color = '#000000';
\r
901 this.wnd = wnd || window;
\r
903 if (!(jg_ie || jg_dom || jg_ihtm)) chkDHTM();
\r
904 if (typeof id != 'string' || !id) this.paint = pntDoc;
\r
907 this.cnv = document.all? (this.wnd.document.all[id] || null)
\r
908 : document.getElementById? (this.wnd.document.getElementById(id) || null)
\r
910 this.defhtm = (this.cnv && this.cnv.innerHTML)? this.cnv.innerHTML : '';
\r
911 this.paint = jg_dom? pntCnvDom : jg_ie? pntCnvIe : jg_ihtm? pntCnvIhtm : pntCnv;
\r
914 this.setPrintable(false);
\r
919 function integer_compare(x,y)
\r
921 return (x < y) ? -1 : ((x > y)*1);
\r