Added the "visualise links" script. It's disabled because it doesn't
authorrich <rich>
Wed, 29 Sep 2004 09:44:51 +0000 (09:44 +0000)
committerrich <rich>
Wed, 29 Sep 2004 09:44:51 +0000 (09:44 +0000)
work well at the moment.  We need to find a good way to draw lines on
an HTML div.

debian/control
html/_css/visualise_links.css [new file with mode: 0644]
html/_js/visualise_links.js [new file with mode: 0644]
html/_js/wz_jsgraphics.js [new file with mode: 0644]
scripts/.depend
scripts/Makefile
scripts/visualise_links.ml [new file with mode: 0644]
templates/visualise_links.html [new file with mode: 0644]

index 6cc63a9..add797a 100644 (file)
@@ -10,6 +10,7 @@ Architecture: all
 Depends: libpgsql-ocaml, libdbi-ocaml (>= 0.9.9), libpcre-ocaml,
  ocaml-base-nox-3.08, libapache-mod-caml, libtemplate-ocaml-dev, imagemagick
 Suggests: apache
+Recommends: graphviz
 Description: A Wiki written in Objective CAML (OCaml)
  This is a Wiki written entirely in Objective CAML (OCaml).
  .
diff --git a/html/_css/visualise_links.css b/html/_css/visualise_links.css
new file mode 100644 (file)
index 0000000..cc497ad
--- /dev/null
@@ -0,0 +1,30 @@
+/* $Id: visualise_links.css,v 1.1 2004/09/29 09:44:51 rich Exp $ */
+
+h1 {
+  display: none;
+}
+
+div#canvas {
+  position: absolute;
+  top: 3em;
+  left: 1em;
+  height: 1000px;
+  width: 1000px;
+  border: 1px solid #ccc;
+}
+
+div#buttons {
+  position: absolute;
+  top: 0.5em;
+  left: 1em;
+}
+
+button#layout {
+  margin-left: 2em;
+}
+
+div.node {
+  position: absolute;
+  background-color: yellow;
+  border: 1px solid #ccc;
+}
\ No newline at end of file
diff --git a/html/_js/visualise_links.js b/html/_js/visualise_links.js
new file mode 100644 (file)
index 0000000..8fad2d4
--- /dev/null
@@ -0,0 +1,2 @@
+/* $Id: visualise_links.js,v 1.1 2004/09/29 09:44:52 rich Exp $ */
+
diff --git a/html/_js/wz_jsgraphics.js b/html/_js/wz_jsgraphics.js
new file mode 100644 (file)
index 0000000..1c805f9
--- /dev/null
@@ -0,0 +1,923 @@
+/* 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
index 52b42f7..f4503cf 100644 (file)
@@ -216,6 +216,8 @@ upload_image_form.cmo: cocanwiki.cmo cocanwiki_template.cmi
 upload_image_form.cmx: cocanwiki.cmx cocanwiki_template.cmx 
 users.cmo: cocanwiki.cmo cocanwiki_date.cmo cocanwiki_template.cmi 
 users.cmx: cocanwiki.cmx cocanwiki_date.cmx cocanwiki_template.cmx 
+visualise_links.cmo: cocanwiki.cmo cocanwiki_files.cmo cocanwiki_template.cmi 
+visualise_links.cmx: cocanwiki.cmx cocanwiki_files.cmx cocanwiki_template.cmx 
 what_links_here.cmo: cocanwiki.cmo cocanwiki_template.cmi 
 what_links_here.cmx: cocanwiki.cmx cocanwiki_template.cmx 
 wikilib.cmo: cocanwiki_strings.cmo wikilib.cmi 
index c4c23a5..1008ebf 100644 (file)
@@ -1,5 +1,5 @@
 # Makefile for COCANWIKI.
-# $Id: Makefile,v 1.30 2004/09/28 11:51:38 rich Exp $
+# $Id: Makefile,v 1.31 2004/09/29 09:44:52 rich Exp $
 
 include ../Makefile.config
 
@@ -107,6 +107,9 @@ OBJS := change_password.cmo \
        users.cmo \
        what_links_here.cmo
 
+# Not working:
+#      visualise_links.cmo
+
 ADMIN_OBJS := \
        admin/admin.cmo \
        admin/create_host.cmo \
diff --git a/scripts/visualise_links.ml b/scripts/visualise_links.ml
new file mode 100644 (file)
index 0000000..fe5de8d
--- /dev/null
@@ -0,0 +1,205 @@
+(* 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
diff --git a/templates/visualise_links.html b/templates/visualise_links.html
new file mode 100644 (file)
index 0000000..b37992c
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Visualise links</title>
+<meta name="robots" content="noindex,nofollow"/>
+<meta name="author" content="http://www.merjis.com/" />
+<link rel="stylesheet" href="/_css/visualise_links.css" type="text/css" title="Standard"/>
+<script src="/_js/wz_jsgraphics.js" type="text/javascript"></script>
+<script src="/_js/visualise_links.js" type="text/javascript"></script>
+</head><body>
+
+<h1>Visualise links</h1>
+
+<noscript>
+Sorry, but the <em>visualise links</em> tool is inherently graphical
+and requires both Javascript and a modern graphical browser.
+</noscript>
+
+<div id="canvas">
+::table(nodes)::<div class="node" style="top: ::y::px;left: ::x::px;width: ::width::px;height: ::height::px;"></div>::end::
+</div>
+
+<div id="buttons">
+<button id="save">Save layout</button>
+<button id="close">Close window</button>
+<button id="layout">Refresh layout</button>
+</div>
+
+<script type="text/javascript">//<!--
+var jg = new jsGraphics("canvas");
+::table(edges)::
+var xPoints = new Array(::table(xpoints)::::x::,::end::0);
+var yPoints = new Array(::table(ypoints)::::y::,::end::0);
+jg.drawPolyLine (xPoints, yPoints);
+::end::
+jg.paint ();
+//--></script>
+
+</body>
+</html>
\ No newline at end of file