--- /dev/null
+/* This notice must be untouched at all times.\r
+\r
+wz_jsgraphics.js v. 2.3\r
+The latest version is available at\r
+http://www.walterzorn.com\r
+or http://www.devira.com\r
+or http://www.walterzorn.de\r
+\r
+Copyright (c) 2002-2004 Walter Zorn. All rights reserved.\r
+Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com )\r
+Last modified: 17. 5. 2004\r
+\r
+Performance optimizations for Internet Explorer\r
+by Thomas Frank and John Holdsworth.\r
+fillPolygon method implemented by Matthieu Haller.\r
+\r
+High Performance JavaScript Graphics Library.\r
+Provides methods\r
+- to draw lines, rectangles, ellipses, polygons\r
+ with specifiable line thickness,\r
+- to fill rectangles and ellipses\r
+- to draw text.\r
+NOTE: Operations, functions and branching have rather been optimized\r
+to efficiency and speed than to shortness of source code.\r
+\r
+This program is free software;\r
+you can redistribute it and/or modify it under the terms of the\r
+GNU General Public License as published by the Free Software Foundation;\r
+either version 2 of the License, or (at your option) any later version.\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY;\r
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r
+See the GNU General Public License\r
+at http://www.gnu.org/copyleft/gpl.html for more details.\r
+*/\r
+\r
+\r
+var jg_ihtm, jg_ie, jg_fast, jg_dom, jg_moz,\r
+jg_n4 = (document.layers && typeof document.classes != "undefined");\r
+\r
+\r
+function chkDHTM(x, i)\r
+{\r
+ x = document.body || null;\r
+ jg_ie = x && typeof x.insertAdjacentHTML != "undefined";\r
+ jg_dom = (x && !jg_ie &&\r
+ typeof x.appendChild != "undefined" &&\r
+ typeof document.createRange != "undefined" &&\r
+ typeof (i = document.createRange()).setStartBefore != "undefined" &&\r
+ typeof i.createContextualFragment != "undefined");\r
+ jg_ihtm = !jg_ie && !jg_dom && x && typeof x.innerHTML != "undefined";\r
+ jg_fast = jg_ie && document.all && !window.opera;\r
+ jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined";\r
+}\r
+\r
+\r
+function pntDoc()\r
+{\r
+ this.wnd.document.write(jg_fast? this.htmRpc() : this.htm);\r
+ this.htm = '';\r
+}\r
+\r
+\r
+function pntCnvDom()\r
+{\r
+ var x = document.createRange();\r
+ x.setStartBefore(this.cnv);\r
+ x = x.createContextualFragment(jg_fast? this.htmRpc() : this.htm);\r
+ this.cnv.appendChild(x);\r
+ this.htm = '';\r
+}\r
+\r
+\r
+function pntCnvIe()\r
+{\r
+ this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this.htmRpc() : this.htm);\r
+ this.htm = '';\r
+}\r
+\r
+\r
+function pntCnvIhtm()\r
+{\r
+ this.cnv.innerHTML += this.htm;\r
+ this.htm = '';\r
+}\r
+\r
+\r
+function pntCnv()\r
+{\r
+ this.htm = '';\r
+}\r
+\r
+\r
+function mkDiv(x, y, w, h)\r
+{\r
+ this.htm += '<div style="position:absolute;'+\r
+ 'left:' + x + 'px;'+\r
+ 'top:' + y + 'px;'+\r
+ 'width:' + w + 'px;'+\r
+ 'height:' + h + 'px;'+\r
+ 'clip:rect(0,'+w+'px,'+h+'px,0);'+\r
+ 'background-color:' + this.color +\r
+ (!jg_moz? ';overflow:hidden' : '')+\r
+ ';"><\/div>';\r
+}\r
+\r
+\r
+function mkDivIe(x, y, w, h)\r
+{\r
+ this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';';\r
+}\r
+\r
+\r
+function mkDivPrt(x, y, w, h)\r
+{\r
+ this.htm += '<div style="position:absolute;'+\r
+ 'border-left:' + w + 'px solid ' + this.color + ';'+\r
+ 'left:' + x + 'px;'+\r
+ 'top:' + y + 'px;'+\r
+ 'width:0px;'+\r
+ 'height:' + h + 'px;'+\r
+ 'clip:rect(0,'+w+'px,'+h+'px,0);'+\r
+ 'background-color:' + this.color +\r
+ (!jg_moz? ';overflow:hidden' : '')+\r
+ ';"><\/div>';\r
+}\r
+\r
+\r
+function mkLyr(x, y, w, h)\r
+{\r
+ this.htm += '<layer '+\r
+ 'left="' + x + '" '+\r
+ 'top="' + y + '" '+\r
+ 'width="' + w + '" '+\r
+ 'height="' + h + '" '+\r
+ 'bgcolor="' + this.color + '"><\/layer>\n';\r
+}\r
+\r
+\r
+var regex = /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g;\r
+function htmRpc()\r
+{\r
+ return this.htm.replace(\r
+ regex,\r
+ '<div style="overflow:hidden;position:absolute;background-color:'+\r
+ '$1;left:$2;top:$3;width:$4;height:$5"></div>\n');\r
+}\r
+\r
+\r
+function htmPrtRpc()\r
+{\r
+ return this.htm.replace(\r
+ regex,\r
+ '<div style="overflow:hidden;position:absolute;background-color:'+\r
+ '$1;left:$2;top:$3;width:$4;height:$5;border-left:$4px solid $1"></div>\n');\r
+}\r
+\r
+\r
+function mkLin(x1, y1, x2, y2)\r
+{\r
+ if (x1 > x2)\r
+ {\r
+ var _x2 = x2;\r
+ var _y2 = y2;\r
+ x2 = x1;\r
+ y2 = y1;\r
+ x1 = _x2;\r
+ y1 = _y2;\r
+ }\r
+ var dx = x2-x1, dy = Math.abs(y2-y1),\r
+ x = x1, y = y1,\r
+ yIncr = (y1 > y2)? -1 : 1;\r
+\r
+ if (dx >= dy)\r
+ {\r
+ var pr = dy<<1,\r
+ pru = pr - (dx<<1),\r
+ p = pr-dx,\r
+ ox = x;\r
+ while ((dx--) > 0)\r
+ {\r
+ ++x;\r
+ if (p > 0)\r
+ {\r
+ this.mkDiv(ox, y, x-ox, 1);\r
+ y += yIncr;\r
+ p += pru;\r
+ ox = x;\r
+ }\r
+ else p += pr;\r
+ }\r
+ this.mkDiv(ox, y, x2-ox+1, 1);\r
+ }\r
+\r
+ else\r
+ {\r
+ var pr = dx<<1,\r
+ pru = pr - (dy<<1),\r
+ p = pr-dy,\r
+ oy = y;\r
+ if (y2 <= y1)\r
+ {\r
+ while ((dy--) > 0)\r
+ {\r
+ if (p > 0)\r
+ {\r
+ this.mkDiv(x++, y, 1, oy-y+1);\r
+ y += yIncr;\r
+ p += pru;\r
+ oy = y;\r
+ }\r
+ else\r
+ {\r
+ y += yIncr;\r
+ p += pr;\r
+ }\r
+ }\r
+ this.mkDiv(x2, y2, 1, oy-y2+1);\r
+ }\r
+ else\r
+ {\r
+ while ((dy--) > 0)\r
+ {\r
+ y += yIncr;\r
+ if (p > 0)\r
+ {\r
+ this.mkDiv(x++, oy, 1, y-oy);\r
+ p += pru;\r
+ oy = y;\r
+ }\r
+ else p += pr;\r
+ }\r
+ this.mkDiv(x2, oy, 1, y2-oy+1);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+function mkLin2D(x1, y1, x2, y2)\r
+{\r
+ if (x1 > x2)\r
+ {\r
+ var _x2 = x2;\r
+ var _y2 = y2;\r
+ x2 = x1;\r
+ y2 = y1;\r
+ x1 = _x2;\r
+ y1 = _y2;\r
+ }\r
+ var dx = x2-x1, dy = Math.abs(y2-y1),\r
+ x = x1, y = y1,\r
+ yIncr = (y1 > y2)? -1 : 1;\r
+\r
+ var s = this.stroke;\r
+ if (dx >= dy)\r
+ {\r
+ if (s-3 > 0)\r
+ {\r
+ var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;\r
+ _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;\r
+ }\r
+ else var _s = s;\r
+ var ad = Math.ceil(s/2);\r
+\r
+ var pr = dy<<1,\r
+ pru = pr - (dx<<1),\r
+ p = pr-dx,\r
+ ox = x;\r
+ while ((dx--) > 0)\r
+ {\r
+ ++x;\r
+ if (p > 0)\r
+ {\r
+ this.mkDiv(ox, y, x-ox+ad, _s);\r
+ y += yIncr;\r
+ p += pru;\r
+ ox = x;\r
+ }\r
+ else p += pr;\r
+ }\r
+ this.mkDiv(ox, y, x2-ox+ad+1, _s);\r
+ }\r
+\r
+ else\r
+ {\r
+ if (s-3 > 0)\r
+ {\r
+ var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;\r
+ _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;\r
+ }\r
+ else var _s = s;\r
+ var ad = Math.round(s/2);\r
+\r
+ var pr = dx<<1,\r
+ pru = pr - (dy<<1),\r
+ p = pr-dy,\r
+ oy = y;\r
+ if (y2 <= y1)\r
+ {\r
+ ++ad;\r
+ while ((dy--) > 0)\r
+ {\r
+ if (p > 0)\r
+ {\r
+ this.mkDiv(x++, y, _s, oy-y+ad);\r
+ y += yIncr;\r
+ p += pru;\r
+ oy = y;\r
+ }\r
+ else\r
+ {\r
+ y += yIncr;\r
+ p += pr;\r
+ }\r
+ }\r
+ this.mkDiv(x2, y2, _s, oy-y2+ad);\r
+ }\r
+ else\r
+ {\r
+ while ((dy--) > 0)\r
+ {\r
+ y += yIncr;\r
+ if (p > 0)\r
+ {\r
+ this.mkDiv(x++, oy, _s, y-oy+ad);\r
+ p += pru;\r
+ oy = y;\r
+ }\r
+ else p += pr;\r
+ }\r
+ this.mkDiv(x2, oy, _s, y2-oy+ad+1);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+function mkLinDott(x1, y1, x2, y2)\r
+{\r
+ if (x1 > x2)\r
+ {\r
+ var _x2 = x2;\r
+ var _y2 = y2;\r
+ x2 = x1;\r
+ y2 = y1;\r
+ x1 = _x2;\r
+ y1 = _y2;\r
+ }\r
+ var dx = x2-x1, dy = Math.abs(y2-y1),\r
+ x = x1, y = y1,\r
+ yIncr = (y1 > y2)? -1 : 1,\r
+ drw = true;\r
+ if (dx >= dy)\r
+ {\r
+ var pr = dy<<1,\r
+ pru = pr - (dx<<1),\r
+ p = pr-dx;\r
+ while ((dx--) > 0)\r
+ {\r
+ if (drw) this.mkDiv(x, y, 1, 1);\r
+ drw = !drw;\r
+ if (p > 0)\r
+ {\r
+ y += yIncr;\r
+ p += pru;\r
+ }\r
+ else p += pr;\r
+ ++x;\r
+ }\r
+ if (drw) this.mkDiv(x, y, 1, 1);\r
+ }\r
+\r
+ else\r
+ {\r
+ var pr = dx<<1,\r
+ pru = pr - (dy<<1),\r
+ p = pr-dy;\r
+ while ((dy--) > 0)\r
+ {\r
+ if (drw) this.mkDiv(x, y, 1, 1);\r
+ drw = !drw;\r
+ y += yIncr;\r
+ if (p > 0)\r
+ {\r
+ ++x;\r
+ p += pru;\r
+ }\r
+ else p += pr;\r
+ }\r
+ if (drw) this.mkDiv(x, y, 1, 1);\r
+ }\r
+}\r
+\r
+\r
+function mkOv(left, top, width, height)\r
+{\r
+ var a = width>>1, b = height>>1,\r
+ wod = width&1, hod = (height&1)+1,\r
+ cx = left+a, cy = top+b,\r
+ x = 0, y = b,\r
+ ox = 0, oy = b,\r
+ aa = (a*a)<<1, bb = (b*b)<<1,\r
+ st = (aa>>1)*(1-(b<<1)) + bb,\r
+ tt = (bb>>1) - aa*((b<<1)-1),\r
+ w, h;\r
+ while (y > 0)\r
+ {\r
+ if (st < 0)\r
+ {\r
+ st += bb*((x<<1)+3);\r
+ tt += (bb<<1)*(++x);\r
+ }\r
+ else if (tt < 0)\r
+ {\r
+ st += bb*((x<<1)+3) - (aa<<1)*(y-1);\r
+ tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);\r
+ w = x-ox;\r
+ h = oy-y;\r
+ if (w&2 && h&2)\r
+ {\r
+ this.mkOvQds(cx, cy, -x+2, ox+wod, -oy, oy-1+hod, 1, 1);\r
+ this.mkOvQds(cx, cy, -x+1, x-1+wod, -y-1, y+hod, 1, 1);\r
+ }\r
+ else this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, oy-h+hod, w, h);\r
+ ox = x;\r
+ oy = y;\r
+ }\r
+ else\r
+ {\r
+ tt -= aa*((y<<1)-3);\r
+ st -= (aa<<1)*(--y);\r
+ }\r
+ }\r
+ this.mkDiv(cx-a, cy-oy, a-ox+1, (oy<<1)+hod);\r
+ this.mkDiv(cx+ox+wod, cy-oy, a-ox+1, (oy<<1)+hod);\r
+}\r
+\r
+\r
+function mkOv2D(left, top, width, height)\r
+{\r
+ var s = this.stroke;\r
+ width += s-1;\r
+ height += s-1;\r
+ var a = width>>1, b = height>>1,\r
+ wod = width&1, hod = (height&1)+1,\r
+ cx = left+a, cy = top+b,\r
+ x = 0, y = b,\r
+ aa = (a*a)<<1, bb = (b*b)<<1,\r
+ st = (aa>>1)*(1-(b<<1)) + bb,\r
+ tt = (bb>>1) - aa*((b<<1)-1);\r
+\r
+ if (s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0))\r
+ {\r
+ var ox = 0, oy = b,\r
+ w, h,\r
+ pxl, pxr, pxt, pxb, pxw;\r
+ while (y > 0)\r
+ {\r
+ if (st < 0)\r
+ {\r
+ st += bb*((x<<1)+3);\r
+ tt += (bb<<1)*(++x);\r
+ }\r
+ else if (tt < 0)\r
+ {\r
+ st += bb*((x<<1)+3) - (aa<<1)*(y-1);\r
+ tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);\r
+ w = x-ox;\r
+ h = oy-y;\r
+\r
+ if (w-1)\r
+ {\r
+ pxw = w+1+(s&1);\r
+ h = s;\r
+ }\r
+ else if (h-1)\r
+ {\r
+ pxw = s;\r
+ h += 1+(s&1);\r
+ }\r
+ else pxw = h = s;\r
+ this.mkOvQds(cx, cy, -x+1, ox-pxw+w+wod, -oy, -h+oy+hod, pxw, h);\r
+ ox = x;\r
+ oy = y;\r
+ }\r
+ else\r
+ {\r
+ tt -= aa*((y<<1)-3);\r
+ st -= (aa<<1)*(--y);\r
+ }\r
+ }\r
+ this.mkDiv(cx-a, cy-oy, s, (oy<<1)+hod);\r
+ this.mkDiv(cx+a+wod-s+1, cy-oy, s, (oy<<1)+hod);\r
+ }\r
+\r
+ else\r
+ {\r
+ var _a = (width-((s-1)<<1))>>1,\r
+ _b = (height-((s-1)<<1))>>1,\r
+ _x = 0, _y = _b,\r
+ _aa = (_a*_a)<<1, _bb = (_b*_b)<<1,\r
+ _st = (_aa>>1)*(1-(_b<<1)) + _bb,\r
+ _tt = (_bb>>1) - _aa*((_b<<1)-1),\r
+\r
+ pxl = new Array(),\r
+ pxt = new Array(),\r
+ _pxb = new Array();\r
+ pxl[0] = 0;\r
+ pxt[0] = b;\r
+ _pxb[0] = _b-1;\r
+ while (y > 0)\r
+ {\r
+ if (st < 0)\r
+ {\r
+ st += bb*((x<<1)+3);\r
+ tt += (bb<<1)*(++x);\r
+ pxl[pxl.length] = x;\r
+ pxt[pxt.length] = y;\r
+ }\r
+ else if (tt < 0)\r
+ {\r
+ st += bb*((x<<1)+3) - (aa<<1)*(y-1);\r
+ tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);\r
+ pxl[pxl.length] = x;\r
+ pxt[pxt.length] = y;\r
+ }\r
+ else\r
+ {\r
+ tt -= aa*((y<<1)-3);\r
+ st -= (aa<<1)*(--y);\r
+ }\r
+\r
+ if (_y > 0)\r
+ {\r
+ if (_st < 0)\r
+ {\r
+ _st += _bb*((_x<<1)+3);\r
+ _tt += (_bb<<1)*(++_x);\r
+ _pxb[_pxb.length] = _y-1;\r
+ }\r
+ else if (_tt < 0)\r
+ {\r
+ _st += _bb*((_x<<1)+3) - (_aa<<1)*(_y-1);\r
+ _tt += (_bb<<1)*(++_x) - _aa*(((_y--)<<1)-3);\r
+ _pxb[_pxb.length] = _y-1;\r
+ }\r
+ else\r
+ {\r
+ _tt -= _aa*((_y<<1)-3);\r
+ _st -= (_aa<<1)*(--_y);\r
+ _pxb[_pxb.length-1]--;\r
+ }\r
+ }\r
+ }\r
+\r
+ var ox = 0, oy = b,\r
+ _oy = _pxb[0],\r
+ l = pxl.length,\r
+ w, h;\r
+ for (var i = 0; i < l; i++)\r
+ {\r
+ if (typeof _pxb[i] != "undefined")\r
+ {\r
+ if (_pxb[i] < _oy || pxt[i] < oy)\r
+ {\r
+ x = pxl[i];\r
+ this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, _oy+hod, x-ox, oy-_oy);\r
+ ox = x;\r
+ oy = pxt[i];\r
+ _oy = _pxb[i];\r
+ }\r
+ }\r
+ else\r
+ {\r
+ x = pxl[i];\r
+ this.mkDiv(cx-x+1, cy-oy, 1, (oy<<1)+hod);\r
+ this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);\r
+ ox = x;\r
+ oy = pxt[i];\r
+ }\r
+ }\r
+ this.mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod);\r
+ this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);\r
+ }\r
+}\r
+\r
+\r
+function mkOvDott(left, top, width, height)\r
+{\r
+ var a = width>>1, b = height>>1,\r
+ wod = width&1, hod = height&1,\r
+ cx = left+a, cy = top+b,\r
+ x = 0, y = b,\r
+ aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,\r
+ st = (aa2>>1)*(1-(b<<1)) + bb,\r
+ tt = (bb>>1) - aa2*((b<<1)-1),\r
+ drw = true;\r
+ while (y > 0)\r
+ {\r
+ if (st < 0)\r
+ {\r
+ st += bb*((x<<1)+3);\r
+ tt += (bb<<1)*(++x);\r
+ }\r
+ else if (tt < 0)\r
+ {\r
+ st += bb*((x<<1)+3) - aa4*(y-1);\r
+ tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);\r
+ }\r
+ else\r
+ {\r
+ tt -= aa2*((y<<1)-3);\r
+ st -= aa4*(--y);\r
+ }\r
+ if (drw) this.mkOvQds(cx, cy, -x, x+wod, -y, y+hod, 1, 1);\r
+ drw = !drw;\r
+ }\r
+}\r
+\r
+\r
+function mkRect(x, y, w, h)\r
+{\r
+ var s = this.stroke;\r
+ this.mkDiv(x, y, w, s);\r
+ this.mkDiv(x+w, y, s, h);\r
+ this.mkDiv(x, y+h, w+s, s);\r
+ this.mkDiv(x, y+s, s, h-s);\r
+}\r
+\r
+\r
+function mkRectDott(x, y, w, h)\r
+{\r
+ this.drawLine(x, y, x+w, y);\r
+ this.drawLine(x+w, y, x+w, y+h);\r
+ this.drawLine(x, y+h, x+w, y+h);\r
+ this.drawLine(x, y, x, y+h);\r
+}\r
+\r
+\r
+function jsgFont()\r
+{\r
+ this.PLAIN = 'font-weight:normal;';\r
+ this.BOLD = 'font-weight:bold;';\r
+ this.ITALIC = 'font-style:italic;';\r
+ this.ITALIC_BOLD = this.ITALIC + this.BOLD;\r
+ this.BOLD_ITALIC = this.ITALIC_BOLD;\r
+}\r
+var Font = new jsgFont();\r
+\r
+\r
+function jsgStroke()\r
+{\r
+ this.DOTTED = -1;\r
+}\r
+var Stroke = new jsgStroke();\r
+\r
+\r
+function jsGraphics(id, wnd)\r
+{\r
+ this.setColor = new Function('arg', 'this.color = arg.toLowerCase();');\r
+\r
+ this.setStroke = function(x)\r
+ {\r
+ this.stroke = x;\r
+ if (!(x+1))\r
+ {\r
+ this.drawLine = mkLinDott;\r
+ this.mkOv = mkOvDott;\r
+ this.drawRect = mkRectDott;\r
+ }\r
+ else if (x-1 > 0)\r
+ {\r
+ this.drawLine = mkLin2D;\r
+ this.mkOv = mkOv2D;\r
+ this.drawRect = mkRect;\r
+ }\r
+ else\r
+ {\r
+ this.drawLine = mkLin;\r
+ this.mkOv = mkOv;\r
+ this.drawRect = mkRect;\r
+ }\r
+ };\r
+\r
+\r
+ this.setPrintable = function(arg)\r
+ {\r
+ this.printable = arg;\r
+ if (jg_fast)\r
+ {\r
+ this.mkDiv = mkDivIe;\r
+ this.htmRpc = arg? htmPrtRpc : htmRpc;\r
+ }\r
+ else this.mkDiv = jg_n4? mkLyr : arg? mkDivPrt : mkDiv;\r
+ };\r
+\r
+\r
+ this.setFont = function(fam, sz, sty)\r
+ {\r
+ this.ftFam = fam;\r
+ this.ftSz = sz;\r
+ this.ftSty = sty || Font.PLAIN;\r
+ };\r
+\r
+\r
+ this.drawPolyline = this.drawPolyLine = function(x, y, s)\r
+ {\r
+ for (var i=0 ; i<x.length-1 ; i++ )\r
+ this.drawLine(x[i], y[i], x[i+1], y[i+1]);\r
+ };\r
+\r
+\r
+ this.fillRect = function(x, y, w, h)\r
+ {\r
+ this.mkDiv(x, y, w, h);\r
+ };\r
+\r
+\r
+ this.drawPolygon = function(x, y)\r
+ {\r
+ this.drawPolyline(x, y);\r
+ this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]);\r
+ };\r
+\r
+\r
+ this.drawEllipse = this.drawOval = function(x, y, w, h)\r
+ {\r
+ this.mkOv(x, y, w, h);\r
+ };\r
+\r
+\r
+ this.fillEllipse = this.fillOval = function(left, top, w, h)\r
+ {\r
+ var a = (w -= 1)>>1, b = (h -= 1)>>1,\r
+ wod = (w&1)+1, hod = (h&1)+1,\r
+ cx = left+a, cy = top+b,\r
+ x = 0, y = b,\r
+ ox = 0, oy = b,\r
+ aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,\r
+ st = (aa2>>1)*(1-(b<<1)) + bb,\r
+ tt = (bb>>1) - aa2*((b<<1)-1),\r
+ pxl, dw, dh;\r
+ if (w+1) while (y > 0)\r
+ {\r
+ if (st < 0)\r
+ {\r
+ st += bb*((x<<1)+3);\r
+ tt += (bb<<1)*(++x);\r
+ }\r
+ else if (tt < 0)\r
+ {\r
+ st += bb*((x<<1)+3) - aa4*(y-1);\r
+ pxl = cx-x;\r
+ dw = (x<<1)+wod;\r
+ tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);\r
+ dh = oy-y;\r
+ this.mkDiv(pxl, cy-oy, dw, dh);\r
+ this.mkDiv(pxl, cy+oy-dh+hod, dw, dh);\r
+ ox = x;\r
+ oy = y;\r
+ }\r
+ else\r
+ {\r
+ tt -= aa2*((y<<1)-3);\r
+ st -= aa4*(--y);\r
+ }\r
+ }\r
+ this.mkDiv(cx-a, cy-oy, w+1, (oy<<1)+hod);\r
+ };\r
+\r
+\r
+\r
+/* fillPolygon method, implemented by Matthieu Haller.\r
+This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib.\r
+C source of GD 1.8.4 found at http://www.boutell.com/gd/\r
+\r
+THANKS to Kirsten Schulz for the polygon fixes!\r
+\r
+The intersection finding technique of this code could be improved\r
+by remembering the previous intertersection, and by using the slope.\r
+That could help to adjust intersections to produce a nice\r
+interior_extrema. */\r
+ this.fillPolygon = function(array_x, array_y)\r
+ {\r
+ var i;\r
+ var y;\r
+ var miny, maxy;\r
+ var x1, y1;\r
+ var x2, y2;\r
+ var ind1, ind2;\r
+ var ints;\r
+\r
+ var n = array_x.length;\r
+\r
+ if (!n) return;\r
+\r
+\r
+ miny = array_y[0];\r
+ maxy = array_y[0];\r
+ for (i = 1; i < n; i++)\r
+ {\r
+ if (array_y[i] < miny)\r
+ miny = array_y[i];\r
+\r
+ if (array_y[i] > maxy)\r
+ maxy = array_y[i];\r
+ }\r
+ for (y = miny; y <= maxy; y++)\r
+ {\r
+ var polyInts = new Array();\r
+ ints = 0;\r
+ for (i = 0; i < n; i++)\r
+ {\r
+ if (!i)\r
+ {\r
+ ind1 = n-1;\r
+ ind2 = 0;\r
+ }\r
+ else\r
+ {\r
+ ind1 = i-1;\r
+ ind2 = i;\r
+ }\r
+ y1 = array_y[ind1];\r
+ y2 = array_y[ind2];\r
+ if (y1 < y2)\r
+ {\r
+ x1 = array_x[ind1];\r
+ x2 = array_x[ind2];\r
+ }\r
+ else if (y1 > y2)\r
+ {\r
+ y2 = array_y[ind1];\r
+ y1 = array_y[ind2];\r
+ x2 = array_x[ind1];\r
+ x1 = array_x[ind2];\r
+ }\r
+ else continue;\r
+\r
+ // modified 11. 2. 2004 Walter Zorn\r
+ if ((y >= y1) && (y < y2))\r
+ polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);\r
+\r
+ else if ((y == maxy) && (y > y1) && (y <= y2))\r
+ polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);\r
+ }\r
+ polyInts.sort(integer_compare);\r
+\r
+ for (i = 0; i < ints; i+=2)\r
+ {\r
+ w = polyInts[i+1]-polyInts[i]\r
+ this.mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);\r
+ }\r
+ }\r
+ };\r
+\r
+\r
+ this.drawString = function(txt, x, y)\r
+ {\r
+ this.htm += '<div style="position:absolute;white-space:nowrap;'+\r
+ 'left:' + x + 'px;'+\r
+ 'top:' + y + 'px;'+\r
+ 'font-family:' + this.ftFam + ';'+\r
+ 'font-size:' + this.ftSz + ';'+\r
+ 'color:' + this.color + ';' + this.ftSty + '">'+\r
+ txt +\r
+ '<\/div>';\r
+ }\r
+\r
+\r
+ this.drawImage = function(imgSrc, x, y, w, h)\r
+ {\r
+ this.htm += '<div style="position:absolute;'+\r
+ 'left:' + x + 'px;'+\r
+ 'top:' + y + 'px;'+\r
+ 'width:' + w + ';'+\r
+ 'height:' + h + ';">'+\r
+ '<img src="' + imgSrc + '" width="' + w + '" height="' + h + '">'+\r
+ '<\/div>';\r
+ }\r
+\r
+\r
+ this.clear = function()\r
+ {\r
+ this.htm = "";\r
+ if (this.cnv) this.cnv.innerHTML = this.defhtm;\r
+ };\r
+\r
+\r
+ this.mkOvQds = function(cx, cy, xl, xr, yt, yb, w, h)\r
+ {\r
+ this.mkDiv(xr+cx, yt+cy, w, h);\r
+ this.mkDiv(xr+cx, yb+cy, w, h);\r
+ this.mkDiv(xl+cx, yb+cy, w, h);\r
+ this.mkDiv(xl+cx, yt+cy, w, h);\r
+ };\r
+\r
+ this.setStroke(1);\r
+ this.setFont('verdana,geneva,helvetica,sans-serif', String.fromCharCode(0x31, 0x32, 0x70, 0x78), Font.PLAIN);\r
+ this.color = '#000000';\r
+ this.htm = '';\r
+ this.wnd = wnd || window;\r
+\r
+ if (!(jg_ie || jg_dom || jg_ihtm)) chkDHTM();\r
+ if (typeof id != 'string' || !id) this.paint = pntDoc;\r
+ else\r
+ {\r
+ this.cnv = document.all? (this.wnd.document.all[id] || null)\r
+ : document.getElementById? (this.wnd.document.getElementById(id) || null)\r
+ : null;\r
+ this.defhtm = (this.cnv && this.cnv.innerHTML)? this.cnv.innerHTML : '';\r
+ this.paint = jg_dom? pntCnvDom : jg_ie? pntCnvIe : jg_ihtm? pntCnvIhtm : pntCnv;\r
+ }\r
+\r
+ this.setPrintable(false);\r
+}\r
+\r
+\r
+\r
+function integer_compare(x,y)\r
+{\r
+ return (x < y) ? -1 : ((x > y)*1);\r
+}\r
+\r
--- /dev/null
+(* COCANWIKI - a wiki written in Objective CAML.
+ * Written by Richard W.M. Jones <rich@merjis.com>.
+ * Copyright (C) 2004 Merjis Ltd.
+ * $Id: visualise_links.ml,v 1.1 2004/09/29 09:44:52 rich Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *)
+
+open Apache
+open Registry
+open Cgi
+open Printf
+
+open ExtList
+
+open Cocanwiki
+open Cocanwiki_template
+open Cocanwiki_files
+
+let rec takepairs = function
+ | [] -> []
+ | [x] -> invalid_arg "takepairs: odd number of elements in list"
+ | x :: y :: xs -> (x, y) :: takepairs xs
+
+let run r (q : cgi) (dbh : Dbi.connection) hostid _ _ =
+ let template = get_template dbh hostid "visualise_links.html" in
+
+ (* This function generates a layout using the 'dot' program, part of
+ * GraphViz.
+ *)
+ let gv_layout () =
+ let sth = dbh#prepare_cached "select from_url, to_url from links
+ where hostid = ?" in
+ sth#execute [`Int hostid];
+
+ let edges = sth#map (function [`String from_url; `String to_url] ->
+ from_url, to_url
+ | _ -> assert false) in
+
+ let dotfile =
+ String.concat ""
+ ([ "digraph t {\n";
+ " fill=\"auto\";\n";
+ " center=1;\n"; ] @
+ (List.map (fun (node1, node2) ->
+ sprintf " \"%s\" -> \"%s\";\n" node1 node2)
+ edges) @
+ [ "}\n" ]) in
+
+ let filename = output_tempfile dotfile in
+ let cmd = sprintf "dot -Tplain %s" filename in
+
+ let lines = pget cmd in
+ unlink filename;
+
+ (* For documentation of the output format of 'dot -Tplain', please see:
+ * http://www.research.att.com/%7Eerg/graphviz/info/output.html#d:plain
+ *)
+ (* Split each line up into fields. Unfortunately some fields are
+ * quoted (if they contain spaces or other special characters) so we
+ * have to deal with that.
+ *)
+ let split line =
+ let n = String.length line in
+ let rec skip_spaces i =
+ if i < n && line.[i] = ' ' then skip_spaces (i+1) else i
+ in
+ let rec find i c =
+ if i >= n then -1
+ else if line.[i] = c then i
+ else find (i+1) c
+ in
+ let rec loop i acc =
+ if i >= n then acc
+ else (
+ let c = line.[i] in
+ if c = '"' then ( (* quoted field *)
+ let j = find (i+1) '"' in
+ let field, i =
+ if i < j then String.sub line i (j-i), skip_spaces (j+1)
+ else String.sub line i (n-i), n in
+ loop i (field :: acc)
+ ) else ( (* ordinary field *)
+ let j = find (i+1) ' ' in
+ let field, i =
+ if i < j then String.sub line i (j-i), skip_spaces j
+ else String.sub line i (n-i), n in
+ loop i (field :: acc)
+ )
+ )
+ in
+ List.rev (loop 0 [])
+ in
+ let lines = List.map split lines in
+
+ (* First line is 'graph'. *)
+ let graph_line, lines = List.hd lines, List.tl lines in
+ let width, height =
+ match graph_line with
+ [ "graph"; _; width; height ] ->
+ float_of_string width, float_of_string height
+ | _ -> assert false in
+
+ (* Get the nodes and edges. *)
+ let is_node = function "node" :: _ -> true | _ -> false in
+ let is_edge = function "edge" :: _ -> true | _ -> false in
+ let nodes, edges = List.filter is_node lines, List.filter is_edge lines in
+
+ (* Process the nodes and edges. *)
+ let process_node = function
+ "node" :: url :: x :: y :: width :: height :: _ ->
+ url, (float_of_string x, float_of_string y,
+ float_of_string width, float_of_string height)
+ | _ -> assert false
+ in
+ let nodes = List.map process_node nodes in
+
+ let process_edge = function
+ "edge" :: node1 :: node2 :: n :: rest ->
+ let n = int_of_string n in
+ let points =
+ List.map (fun (x, y) -> float_of_string x, float_of_string y)
+ (takepairs (List.take (n*2) rest)) in
+ node1, node2, points
+ | _ -> assert false
+ in
+ let edges = List.map process_edge edges in
+
+ (* Scale the whole thing to 1000x1000 pixel coordinates. *)
+ let wscale = 1000. /. width in
+ let hscale = 1000. /. height in
+
+ let process_node (url, (x, y, width, height)) =
+ url, (x *. wscale, y *. hscale, width *. wscale, height *. hscale)
+ in
+ let nodes = List.map process_node nodes in
+
+ let process_edge (node1, node2, points) =
+ let process_point (x, y) = x *. wscale, y *. hscale in
+ node1, node2, List.map process_point points
+ in
+ let edges = List.map process_edge edges in
+
+ (* Return the layout. *)
+ let layout = nodes, edges in
+ layout
+ in
+
+ (* XXX In future we are able to load this from the database. *)
+ let nodes, edges = gv_layout () in
+
+ let table =
+ List.map (fun (url, (x, y, width, height)) ->
+ [ "url", Template.VarString url;
+ "x", Template.VarString (string_of_float x);
+ "y", Template.VarString (string_of_float y);
+ "width", Template.VarString (string_of_float width);
+ "height", Template.VarString (string_of_float height) ])
+ nodes in
+
+ template#table "nodes" table;
+
+ let table =
+ List.map (fun (node1, node2, points) ->
+ let xpoints, ypoints = List.split points in
+ let xpoints =
+ List.map (fun x ->
+ [ "x", Template.VarString (string_of_float x) ])
+ xpoints in
+ let ypoints =
+ List.map (fun y ->
+ [ "y", Template.VarString (string_of_float y) ])
+ ypoints in
+
+ [ "node1", Template.VarString node1;
+ "node2", Template.VarString node2;
+ "xpoints", Template.VarTable xpoints;
+ "ypoints", Template.VarTable ypoints; ])
+ edges in
+
+ template#table "edges" table;
+
+
+
+
+
+
+
+ q#template template
+
+let () =
+ register_script ~restrict:[CanEdit] run