From 73bb20bd4d7579d91922915fd6a5b62d9a6748e7 Mon Sep 17 00:00:00 2001 From: apb Date: Tue, 11 Sep 2012 22:50:31 +0100 Subject: [PATCH] svg update --- src/graphxq.xqm | 120 ++- src/graphxq/app.css | 112 +++ src/graphxq/app.js | 25 + src/graphxq/graphviz.xml | 181 ++++ src/graphxq/graphviz.xqm | 10 +- src/graphxq/graphxq.png | Bin 0 -> 880 bytes src/graphxq/graphxq2.png | Bin 0 -> 880 bytes src/graphxq/jquery.svg.js | 1394 +++++++++++++++++++++++++++++++ src/graphxq/lib/txq.xqm | 45 + src/graphxq/txq.xqm | 46 + src/graphxq/views/about.xml | 44 + src/graphxq/views/dotform.xml | 18 + src/graphxq/views/dotmlform.xml | 13 + src/graphxq/views/layout.xml | 91 ++ src/graphxq/views/page1.xml | 35 + src/graphxq/views/search.xml | 6 + 16 files changed, 2066 insertions(+), 74 deletions(-) create mode 100644 src/graphxq/app.css create mode 100644 src/graphxq/app.js create mode 100644 src/graphxq/graphviz.xml create mode 100644 src/graphxq/graphxq.png create mode 100644 src/graphxq/graphxq2.png create mode 100644 src/graphxq/jquery.svg.js create mode 100644 src/graphxq/lib/txq.xqm create mode 100644 src/graphxq/txq.xqm create mode 100644 src/graphxq/views/about.xml create mode 100644 src/graphxq/views/dotform.xml create mode 100644 src/graphxq/views/dotmlform.xml create mode 100644 src/graphxq/views/layout.xml create mode 100644 src/graphxq/views/page1.xml create mode 100644 src/graphxq/views/search.xml diff --git a/src/graphxq.xqm b/src/graphxq.xqm index fc9856d..64650a9 100644 --- a/src/graphxq.xqm +++ b/src/graphxq.xqm @@ -1,14 +1,19 @@ (:~ -: restxq interface to graphviz +: restxq interface for graphviz : @author andy bunce : @since sept 2012 :) module namespace grxq = 'apb.graphviz.web'; declare default function namespace 'apb.graphviz.web'; + import module namespace gr = 'apb.graphviz' at "graphxq/graphviz.xqm"; +import module namespace txq = 'apb.txq' at "graphxq/lib/txq.xqm"; +import module namespace request = "http://exquery.org/ns/request"; declare namespace rest = 'http://exquery.org/ns/restxq'; +declare variable $grxq:layout:=fn:resolve-uri("graphxq/views/layout.xml"); + declare %rest:GET %rest:path("graphxq") %output:method("html5") @@ -18,77 +23,15 @@ function graphxq($dot,$url) { let $edot:=if($url) then "" else fn:encode-for-uri($dot) let $dot2:=getdot($dot,$url) let $svg:=get-svg($dot) - return - - Graphviz - - - - - - - -

RestXQ interface to graphviz

-

Enter a string in the dot language - Examples: digraph {{ a -> b}}, - another - .

-

Or enter a Url to a xml document examples: - process, - hedgeweb - remote -

-
- - - -

-

Or enter the url to a node XML source -

- -
-

Inline SVG

-
{$svg}
- -

Object referencing svg, - ( download svg)

- - SVG Here - -

SVG xml

-
-		 {fn:serialize($svg)}
-		 
- - -

Layout xml

- -

About

-

Source: @github:, Twitter: - -. -

- - + let $map:=map{"dot":=$dot,"url":=$url,"svg":=$svg,"edot":=$edot} + let $page:=render("graphxq/views/page1.xml",$map) + return $page }; -(:~ @return svg for hedge with download option. +(:~ :) declare -%rest:GET %rest:path("graphxq/svg") +%rest:path("graphxq/svg") %rest:form-param("dot","{$dot}") %rest:form-param("url","{$url}") %rest:form-param("dl","{$dl}") @@ -103,6 +46,36 @@ function graphxq-svg($dot,$url,$dl) { return ($down[$dl],$svg) }; +declare +%rest:GET %rest:path("graphxq/dot") +%output:method("html5") +function dotform(){ + render("graphxq/views/dotform.xml",map{}) +}; + +declare +%rest:GET %rest:path("graphxq/dotml") +%output:method("html5") +function dotmlform(){ + render("graphxq/views/dotmlform.xml",map{}) +}; +declare +%rest:GET %rest:path("graphxq/about") +%output:method("html5") +function about(){ + render("graphxq/views/about.xml",map{}) +}; + +declare +%rest:GET %rest:path("graphxq/search") +%output:method("html5") +%rest:form-param("q", "{$q}") +function search($q ) { + let $map:=map{"q":=$q} + return render("graphxq/views/search.xml",$map) +}; + + (:~ use dot or url :) declare %private function getdot($dot,$url) as xs:string{ if($url) then @@ -114,4 +87,13 @@ else declare %private function get-svg($dot as xs:string) as node(){ let $svgx:=gr:dot($dot,()) return gr:autosize($svgx) -}; \ No newline at end of file +}; + +declare function render($template,$locals){ + let $default:=map{"sidebar":="Sidebar..." , + "usermenu":=
users
, + "title":=request:path(), + "messages":=()} + let $locals:=map:new(($default,$locals)) + return txq:render(fn:resolve-uri($template),$locals,$grxq:layout) +}; \ No newline at end of file diff --git a/src/graphxq/app.css b/src/graphxq/app.css new file mode 100644 index 0000000..a058729 --- /dev/null +++ b/src/graphxq/app.css @@ -0,0 +1,112 @@ +/* app.css */ +body { + padding-top: 50px; +} +@media (max-width: 979px) { + body { + padding-top: 0; + } +} +/* search bar icon */ +.navbar-search .search-query { + padding-left: 29px; +} + +.navbar-search .icon-search { + position: absolute; + top: 7px; + left: 11px; +} + +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding-left: 30px; +} + + +.quick-links { + list-style: none outside none; + margin: 0; + min-height: 30px; + overflow: hidden; + padding: 5px 20px; + text-align: center; +} +.quick-links:first-child { + min-height: 0; +} +.quick-links li { + color: #999999; + display: inline; + margin: 0 8px; +} +.quick-links .github-btn, .quick-links .tweet-btn, .quick-links .follow-btn { + position: relative; + top: 5px; +} + +/* XML verbatim */ +.xmlverb-default { color: #333333; background-color: #ffffff; + font-size: 10pt; + font-family:"Courier New", Courier, mono; } +.xmlverb-element-name { color: #990000 } +.xmlverb-element-nsprefix { color: #666600 } +.xmlverb-attr-name { color: #660000 } +.xmlverb-attr-content { color: #000099; font-weight: bold } +.xmlverb-ns-name { color: #666600 } +.xmlverb-ns-uri { color: #330099 } +.xmlverb-text { color: #000000; font-weight: bold } +.xmlverb-comment { color: #006600; font-style: italic } +.xmlverb-pi-name { color: #006600; font-style: italic } +.xmlverb-pi-content { color: #006666; font-style: italic } +.xd { background-color: #cccccc; margin: 0px } + + #editor { + margin: 0; + padding: 0; + position: relative; + + width:100%; + min-height:10em; + } + + table.ret * th { + border: 1px solid white; + margin: 2px; + padding-left: 5px; + padding-right: 5px; + background-color: #BFCAEB; + text-align: left; +} + table.ret * td { + border: 1px solid white; + margin: 2px; + padding: 2px; + background-color: #EBEEF5; + vertical-align: top; + font-size: 9pt; +} + +table.ret caption { + margin-top: 10px; + margin: 2px; + padding-left: 5px; + padding-right: 5px; + background-color: #EBEEF5; + text-align: left; +} + +table.ret { + border-bottom: 1px solid #BFCAEB; + margin: 0px; + padding: 0px; +} +.break { + word-break: break-all; + -moz-hyphens: auto; + hyphens: auto; +} +.doctype{ + display:inline-block; + width:6em; + text-align: center +} diff --git a/src/graphxq/app.js b/src/graphxq/app.js new file mode 100644 index 0000000..5c34084 --- /dev/null +++ b/src/graphxq/app.js @@ -0,0 +1,25 @@ +// common app js +// sidebar +$(function() { $("time.relative-date").prettyDate(); }); +$(document).ready(function(){ + $("#dotForm").submit( function () { + getsvg(); + return false; + }); + $("#dot").bind({"keyup":getsvg}); +}); + +function getsvg(){ + $.post( + 'svg', + $("#dotForm").serialize(), + function(data){ + console.log(data) + // http://stackoverflow.com/questions/3346106/accessing-a-dom-object-defined-in-an-external-svg-file + var n = document.importNode(data.documentElement,true); + $("#svgdiv").empty().append(n); + } + ); +}; + + diff --git a/src/graphxq/graphviz.xml b/src/graphxq/graphviz.xml new file mode 100644 index 0000000..e0aa250 --- /dev/null +++ b/src/graphxq/graphviz.xml @@ -0,0 +1,181 @@ + + + + box + polygon + ellipse + circle + point + egg + triangle + plaintext + diamond + trapezium + parallelogram + house + hexagon + octagon + doublecircle + doubleoctagon + tripleoctagon + invtriangle + invtrapezium + invhouse + Mdiamond + Msquare + Mcircle + record + Mrecord + + + aliceblue + antiquewhite + aqua + aquamarine + azure + beige + bisque + black + blanchedalmond + blue + blueviolet + brown + burlywood + cadetblue + chartreuse + chocolate + coral + cornflowerblue + cornsilk + crimson + cyan + darkblue + darkcyan + darkgoldenrod + darkgray + darkgreen + darkgrey + darkkhaki + darkmagenta + darkolivegreen + darkorange + darkorchid + darkred + darksalmon + darkseagreen + darkslateblue + darkslategray + darkslategrey + darkturquoise + darkviolet + deeppink + deepskyblue + dimgray + dimgrey + dodgerblue + firebrick + floralwhite + forestgreen + fuchsia + gainsboro + ghostwhite + gold + goldenrod + gray + grey + green + greenyellow + honeydew + hotpink + indianred + indigo + ivory + khaki + lavender + lavenderblush + lawngreen + lemonchiffon + lightblue + lightcoral + lightcyan + lightgoldenrodyellow + lightgray + lightgreen + lightgrey + lightpink + lightsalmon + lightseagreen + lightskyblue + lightslategray + lightslategrey + lightsteelblue + lightyellow + lime + limegreen + linen + magenta + maroon + mediumaquamarine + mediumblue + mediumorchid + mediumpurple + mediumseagreen + mediumslateblue + mediumspringgreen + mediumturquoise + mediumvioletred + midnightblue + mintcream + mistyrose + moccasin + navajowhite + navy + oldlace + olive + olivedrab + orange + orangered + orchid + palegoldenrod + palegreen + paleturquoise + palevioletred + papayawhip + peachpuff + peru + pink + plum + powderblue + purple + red + rosybrown + royalblue + saddlebrown + salmon + sandybrown + seagreen + seashell + sienna + silver + skyblue + slateblue + slategray + slategrey + snow + springgreen + steelblue + tan + teal + thistle + tomato + turquoise + violet + wheat + white + whitesmoke + yellow + yellowgreen + + diff --git a/src/graphxq/graphviz.xqm b/src/graphxq/graphviz.xqm index 1619c19..f475be5 100644 --- a/src/graphxq/graphviz.xqm +++ b/src/graphxq/graphviz.xqm @@ -18,9 +18,9 @@ declare %private variable $gr:dotpath:=if(fn:environment-variable("DOTPATH")) (:~ : folder for temp files :) -declare %private variable $gr:tmpdir:=if(fn:environment-variable("TEMP")) - then fn:environment-variable("TEMP") - else "/tmp"; +declare %private variable $gr:tmpdir:=if(file:dir-separator()="\") + then fn:environment-variable("TEMP") || "\" + else "/tmp/"; declare %private variable $gr:empty:= Px#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^4L^m3s900PKK zL_t(YORZHsZ<0|I=CkE9P=Qb!NFWkQAyGm=poIi5iaMH@FtAVt8k3GJjRqkR>Vgi8 zg_Sg6;2-!08k~%dPHrZC3>t^yeNMwG_yR9Mo1Ad_oO7P%o_o%{ubPNd>-_cmeY(87 zUHu|5KyvACPR9?p0rvm8`i*-@_6$~LAhLxG#U-v&wHr%BF=_2uzWtR zD6&#uJRXzDWTMpV5PhAPiQbEFVORr$4>7AYxl*9nY?4~7rheNbkxxZ{!H1ZQ1={U4 zle~WBk_o(e>S7;aHWoml&1R$Uo`XKVu}UIX1A|Yghl))um&-gkH~daIeR5@31B36M z1wasuMsZpANMKk4QzBn$OcCUAx%fC*tri>B!2XK>rUWxzDwQNctbr*_&{`FQLLstP zEVA7KgHNf7l}+w;yZkH^i$xg`Fr7|Eh}n2d(a5c>EgFqRG7@0$DK&dx1-)L6YPA~g zKAB7|-64F4K`e3>RWc`#N~LIfdz%|L9Z4iFI|BHoamYa~IA-G|fp9p?XPWbP=%skX zDqb(y%w~Sj27`f21Q>i~o0$@i)8u&`q)_UL16)%P7HBjYyz83NNk7Fezv99!gox2- zB=Lcf2>^r7dvQyAP<(9HKPTwmQI@&DDUE5NP~h@D`27+&1io9Xl-}PbyWK7m02YtO z>Drf@k^n@aZ|^b}I3)pmoeTy8ecIif6Zj!^crO@S_^9DFA08f(^V^>aAdqD@X^YcbE&Db2r)TcJrAYiL*V= zX6a1aQlEHl(6mKQ0xpqK(V7VbAW5E$@phD9FkWw73!F6{8~j1j*pL* zjwyVInau$QxMTuTpwsD4wOXZmy}t4Zn4NXRA_uvD-Px#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^4L^m3s900PKK zL_t(YORZHsZ<0|I=CkE9P=Qb!NFWkQAyGm=poIi5iaMH@FtAVt8k3GJjRqkR>Vgi8 zg_Sg6;2-!08k~%dPHrZC3>t^yeNMwG_yR9Mo1Ad_oO7P%o_o%{ubPNd>-_cmeY(87 zUHu|5KyvACPR9?p0rvm8`i*-@_6$~LAhLxG#U-v&wHr%BF=_2uzWtR zD6&#uJRXzDWTMpV5PhAPiQbEFVORr$4>7AYxl*9nY?4~7rheNbkxxZ{!H1ZQ1={U4 zle~WBk_o(e>S7;aHWoml&1R$Uo`XKVu}UIX1A|Yghl))um&-gkH~daIeR5@31B36M z1wasuMsZpANMKk4QzBn$OcCUAx%fC*tri>B!2XK>rUWxzDwQNctbr*_&{`FQLLstP zEVA7KgHNf7l}+w;yZkH^i$xg`Fr7|Eh}n2d(a5c>EgFqRG7@0$DK&dx1-)L6YPA~g zKAB7|-64F4K`e3>RWc`#N~LIfdz%|L9Z4iFI|BHoamYa~IA-G|fp9p?XPWbP=%skX zDqb(y%w~Sj27`f21Q>i~o0$@i)8u&`q)_UL16)%P7HBjYyz83NNk7Fezv99!gox2- zB=Lcf2>^r7dvQyAP<(9HKPTwmQI@&DDUE5NP~h@D`27+&1io9Xl-}PbyWK7m02YtO z>Drf@k^n@aZ|^b}I3)pmoeTy8ecIif6Zj!^crO@S_^9DFA08f(^V^>aAdqD@X^YcbE&Db2r)TcJrAYiL*V= zX6a1aQlEHl(6mKQ0xpqK(V7VbAW5E$@phD9FkWw73!F6{8~j1j*pL* zjwyVInau$QxMTuTpwsD4wOXZmy}t4Zn4NXRA_uvD- 0) { + svg.setAttribute('width', container.clientWidth); + } + if (container.clientHeight > 0) { + svg.setAttribute('height', container.clientHeight); + } + container.appendChild(svg); + } + this._afterLoad(container, svg, settings || {}); + } + catch (e) { + if ($.browser.msie) { + if (!container.id) { + container.id = 'svg' + (this._uuid++); + } + this._settings[container.id] = settings; + container.innerHTML = ''; + } + else { + container.innerHTML = '

' + + this.local.notSupportedText + '

'; + } + } + }, + + /* SVG callback after loading - register SVG root. */ + _registerSVG: function() { + for (var i = 0; i < document.embeds.length; i++) { // Check all + var container = document.embeds[i].parentNode; + if (!$(container).hasClass($.svg.markerClassName) || // Not SVG + $.data(container, PROP_NAME)) { // Already done + continue; + } + var svg = null; + try { + svg = document.embeds[i].getSVGDocument(); + } + catch(e) { + setTimeout($.svg._registerSVG, 250); // Renesis takes longer to load + return; + } + svg = (svg ? svg.documentElement : null); + if (svg) { + $.svg._afterLoad(container, svg); + } + } + }, + + /* Post-processing once loaded. */ + _afterLoad: function(container, svg, settings) { + var settings = settings || this._settings[container.id]; + this._settings[container ? container.id : ''] = null; + var wrapper = new this._wrapperClass(svg, container); + $.data(container || svg, PROP_NAME, wrapper); + try { + if (settings.loadURL) { // Load URL + wrapper.load(settings.loadURL, settings); + } + if (settings.settings) { // Additional settings + wrapper.configure(settings.settings); + } + if (settings.onLoad && !settings.loadURL) { // Onload callback + settings.onLoad.apply(container || svg, [wrapper]); + } + } + catch (e) { + alert(e); + } + }, + + /* Return the SVG wrapper created for a given container. + @param container (string) selector for the container or + (element) the container for the SVG object or + jQuery collection - first entry is the container + @return (SVGWrapper) the corresponding SVG wrapper element, or null if not attached */ + _getSVG: function(container) { + container = (typeof container == 'string' ? $(container)[0] : + (container.jquery ? container[0] : container)); + return $.data(container, PROP_NAME); + }, + + /* Remove the SVG functionality from a div. + @param container (element) the container for the SVG object */ + _destroySVG: function(container) { + var $container = $(container); + if (!$container.hasClass(this.markerClassName)) { + return; + } + $container.removeClass(this.markerClassName); + if (container.namespaceURI != this.svgNS) { + $container.empty(); + } + $.removeData(container, PROP_NAME); + }, + + /* Extend the SVGWrapper object with an embedded class. + The constructor function must take a single parameter that is + a reference to the owning SVG root object. This allows the + extension to access the basic SVG functionality. + @param name (string) the name of the SVGWrapper attribute to access the new class + @param extClass (function) the extension class constructor */ + addExtension: function(name, extClass) { + this._extensions.push([name, extClass]); + }, + + /* Does this node belong to SVG? + @param node (element) the node to be tested + @return (boolean) true if an SVG node, false if not */ + isSVGElem: function(node) { + return (node.nodeType == 1 && node.namespaceURI == $.svg.svgNS); + } +}); + +/* The main SVG interface, which encapsulates the SVG element. + Obtain a reference from $().svg('get') */ +function SVGWrapper(svg, container) { + this._svg = svg; // The SVG root node + this._container = container; // The containing div + for (var i = 0; i < $.svg._extensions.length; i++) { + var extension = $.svg._extensions[i]; + this[extension[0]] = new extension[1](this); + } +} + +$.extend(SVGWrapper.prototype, { + + /* Retrieve the width of the SVG object. */ + _width: function() { + return (this._container ? this._container.clientWidth : this._svg.width); + }, + + /* Retrieve the height of the SVG object. */ + _height: function() { + return (this._container ? this._container.clientHeight : this._svg.height); + }, + + /* Retrieve the root SVG element. + @return the top-level SVG element */ + root: function() { + return this._svg; + }, + + /* Configure a SVG node. + @param node (element, optional) the node to configure + @param settings (object) additional settings for the root + @param clear (boolean) true to remove existing attributes first, + false to add to what is already there (optional) + @return (SVGWrapper) this root */ + configure: function(node, settings, clear) { + if (!node.nodeName) { + clear = settings; + settings = node; + node = this._svg; + } + if (clear) { + for (var i = node.attributes.length - 1; i >= 0; i--) { + var attr = node.attributes.item(i); + if (!(attr.nodeName == 'onload' || attr.nodeName == 'version' || + attr.nodeName.substring(0, 5) == 'xmlns')) { + node.attributes.removeNamedItem(attr.nodeName); + } + } + } + for (var attrName in settings) { + node.setAttribute($.svg._attrNames[attrName] || attrName, settings[attrName]); + } + return this; + }, + + /* Locate a specific element in the SVG document. + @param id (string) the element's identifier + @return (element) the element reference, or null if not found */ + getElementById: function(id) { + return this._svg.ownerDocument.getElementById(id); + }, + + /* Change the attributes for a SVG node. + @param element (SVG element) the node to change + @param settings (object) the new settings + @return (SVGWrapper) this root */ + change: function(element, settings) { + if (element) { + for (var name in settings) { + if (settings[name] == null) { + element.removeAttribute($.svg._attrNames[name] || name); + } + else { + element.setAttribute($.svg._attrNames[name] || name, settings[name]); + } + } + } + return this; + }, + + /* Check for parent being absent and adjust arguments accordingly. */ + _args: function(values, names, optSettings) { + names.splice(0, 0, 'parent'); + names.splice(names.length, 0, 'settings'); + var args = {}; + var offset = 0; + if (values[0] != null && values[0].jquery) { + values[0] = values[0][0]; + } + if (values[0] != null && !(typeof values[0] == 'object' && values[0].nodeName)) { + args['parent'] = null; + offset = 1; + } + for (var i = 0; i < values.length; i++) { + args[names[i + offset]] = values[i]; + } + if (optSettings) { + $.each(optSettings, function(i, value) { + if (typeof args[value] == 'object') { + args.settings = args[value]; + args[value] = null; + } + }); + } + return args; + }, + + /* Add a title. + @param parent (element or jQuery) the parent node for the new title (optional) + @param text (string) the text of the title + @param settings (object) additional settings for the title (optional) + @return (element) the new title node */ + title: function(parent, text, settings) { + var args = this._args(arguments, ['text']); + var node = this._makeNode(args.parent, 'title', args.settings || {}); + node.appendChild(this._svg.ownerDocument.createTextNode(args.text)); + return node; + }, + + /* Add a description. + @param parent (element or jQuery) the parent node for the new description (optional) + @param text (string) the text of the description + @param settings (object) additional settings for the description (optional) + @return (element) the new description node */ + describe: function(parent, text, settings) { + var args = this._args(arguments, ['text']); + var node = this._makeNode(args.parent, 'desc', args.settings || {}); + node.appendChild(this._svg.ownerDocument.createTextNode(args.text)); + return node; + }, + + /* Add a definitions node. + @param parent (element or jQuery) the parent node for the new definitions (optional) + @param id (string) the ID of this definitions (optional) + @param settings (object) additional settings for the definitions (optional) + @return (element) the new definitions node */ + defs: function(parent, id, settings) { + var args = this._args(arguments, ['id'], ['id']); + return this._makeNode(args.parent, 'defs', $.extend( + (args.id ? {id: args.id} : {}), args.settings || {})); + }, + + /* Add a symbol definition. + @param parent (element or jQuery) the parent node for the new symbol (optional) + @param id (string) the ID of this symbol + @param x1 (number) the left coordinate for this symbol + @param y1 (number) the top coordinate for this symbol + @param width (number) the width of this symbol + @param height (number) the height of this symbol + @param settings (object) additional settings for the symbol (optional) + @return (element) the new symbol node */ + symbol: function(parent, id, x1, y1, width, height, settings) { + var args = this._args(arguments, ['id', 'x1', 'y1', 'width', 'height']); + return this._makeNode(args.parent, 'symbol', $.extend({id: args.id, + viewBox: args.x1 + ' ' + args.y1 + ' ' + args.width + ' ' + args.height}, + args.settings || {})); + }, + + /* Add a marker definition. + @param parent (element or jQuery) the parent node for the new marker (optional) + @param id (string) the ID of this marker + @param refX (number) the x-coordinate for the reference point + @param refY (number) the y-coordinate for the reference point + @param mWidth (number) the marker viewport width + @param mHeight (number) the marker viewport height + @param orient (string or int) 'auto' or angle (degrees) (optional) + @param settings (object) additional settings for the marker (optional) + @return (element) the new marker node */ + marker: function(parent, id, refX, refY, mWidth, mHeight, orient, settings) { + var args = this._args(arguments, ['id', 'refX', 'refY', + 'mWidth', 'mHeight', 'orient'], ['orient']); + return this._makeNode(args.parent, 'marker', $.extend( + {id: args.id, refX: args.refX, refY: args.refY, markerWidth: args.mWidth, + markerHeight: args.mHeight, orient: args.orient || 'auto'}, args.settings || {})); + }, + + /* Add a style node. + @param parent (element or jQuery) the parent node for the new node (optional) + @param styles (string) the CSS styles + @param settings (object) additional settings for the node (optional) + @return (element) the new style node */ + style: function(parent, styles, settings) { + var args = this._args(arguments, ['styles']); + var node = this._makeNode(args.parent, 'style', $.extend( + {type: 'text/css'}, args.settings || {})); + node.appendChild(this._svg.ownerDocument.createTextNode(args.styles)); + if ($.browser.opera) { + $('head').append(''); + } + return node; + }, + + /* Add a script node. + @param parent (element or jQuery) the parent node for the new node (optional) + @param script (string) the JavaScript code + @param type (string) the MIME type for the code (optional, default 'text/javascript') + @param settings (object) additional settings for the node (optional) + @return (element) the new script node */ + script: function(parent, script, type, settings) { + var args = this._args(arguments, ['script', 'type'], ['type']); + var node = this._makeNode(args.parent, 'script', $.extend( + {type: args.type || 'text/javascript'}, args.settings || {})); + node.appendChild(this._svg.ownerDocument.createTextNode(args.script)); + if (!$.browser.mozilla) { + $.globalEval(args.script); + } + return node; + }, + + /* Add a linear gradient definition. + Specify all of x1, y1, x2, y2 or none of them. + @param parent (element or jQuery) the parent node for the new gradient (optional) + @param id (string) the ID for this gradient + @param stops (string[][]) the gradient stops, each entry is + [0] is offset (0.0-1.0 or 0%-100%), [1] is colour, + [2] is opacity (optional) + @param x1 (number) the x-coordinate of the gradient start (optional) + @param y1 (number) the y-coordinate of the gradient start (optional) + @param x2 (number) the x-coordinate of the gradient end (optional) + @param y2 (number) the y-coordinate of the gradient end (optional) + @param settings (object) additional settings for the gradient (optional) + @return (element) the new gradient node */ + linearGradient: function(parent, id, stops, x1, y1, x2, y2, settings) { + var args = this._args(arguments, + ['id', 'stops', 'x1', 'y1', 'x2', 'y2'], ['x1']); + var sets = $.extend({id: args.id}, + (args.x1 != null ? {x1: args.x1, y1: args.y1, x2: args.x2, y2: args.y2} : {})); + return this._gradient(args.parent, 'linearGradient', + $.extend(sets, args.settings || {}), args.stops); + }, + + /* Add a radial gradient definition. + Specify all of cx, cy, r, fx, fy or none of them. + @param parent (element or jQuery) the parent node for the new gradient (optional) + @param id (string) the ID for this gradient + @param stops (string[][]) the gradient stops, each entry + [0] is offset, [1] is colour, [2] is opacity (optional) + @param cx (number) the x-coordinate of the largest circle centre (optional) + @param cy (number) the y-coordinate of the largest circle centre (optional) + @param r (number) the radius of the largest circle (optional) + @param fx (number) the x-coordinate of the gradient focus (optional) + @param fy (number) the y-coordinate of the gradient focus (optional) + @param settings (object) additional settings for the gradient (optional) + @return (element) the new gradient node */ + radialGradient: function(parent, id, stops, cx, cy, r, fx, fy, settings) { + var args = this._args(arguments, + ['id', 'stops', 'cx', 'cy', 'r', 'fx', 'fy'], ['cx']); + var sets = $.extend({id: args.id}, (args.cx != null ? + {cx: args.cx, cy: args.cy, r: args.r, fx: args.fx, fy: args.fy} : {})); + return this._gradient(args.parent, 'radialGradient', + $.extend(sets, args.settings || {}), args.stops); + }, + + /* Add a gradient node. */ + _gradient: function(parent, name, settings, stops) { + var node = this._makeNode(parent, name, settings); + for (var i = 0; i < stops.length; i++) { + var stop = stops[i]; + this._makeNode(node, 'stop', $.extend( + {offset: stop[0], stopColor: stop[1]}, + (stop[2] != null ? {stopOpacity: stop[2]} : {}))); + } + return node; + }, + + /* Add a pattern definition. + Specify all of vx, vy, xwidth, vheight or none of them. + @param parent (element or jQuery) the parent node for the new pattern (optional) + @param id (string) the ID for this pattern + @param x (number) the x-coordinate for the left edge of the pattern + @param y (number) the y-coordinate for the top edge of the pattern + @param width (number) the width of the pattern + @param height (number) the height of the pattern + @param vx (number) the minimum x-coordinate for view box (optional) + @param vy (number) the minimum y-coordinate for the view box (optional) + @param vwidth (number) the width of the view box (optional) + @param vheight (number) the height of the view box (optional) + @param settings (object) additional settings for the pattern (optional) + @return (element) the new pattern node */ + pattern: function(parent, id, x, y, width, height, vx, vy, vwidth, vheight, settings) { + var args = this._args(arguments, ['id', 'x', 'y', 'width', 'height', + 'vx', 'vy', 'vwidth', 'vheight'], ['vx']); + var sets = $.extend({id: args.id, x: args.x, y: args.y, + width: args.width, height: args.height}, (args.vx != null ? + {viewBox: args.vx + ' ' + args.vy + ' ' + args.vwidth + ' ' + args.vheight} : {})); + return this._makeNode(args.parent, 'pattern', $.extend(sets, args.settings || {})); + }, + + /* Add a clip path definition. + @param parent (element) the parent node for the new element (optional) + @param id (string) the ID for this path + @param units (string) either 'userSpaceOnUse' (default) or 'objectBoundingBox' (optional) + @return (element) the new clipPath node */ + clipPath: function(parent, id, units, settings) { + var args = this._args(arguments, ['id', 'units']); + args.units = args.units || 'userSpaceOnUse'; + return this._makeNode(args.parent, 'clipPath', $.extend( + {id: args.id, clipPathUnits: args.units}, args.settings || {})); + }, + + /* Add a mask definition. + @param parent (element or jQuery) the parent node for the new mask (optional) + @param id (string) the ID for this mask + @param x (number) the x-coordinate for the left edge of the mask + @param y (number) the y-coordinate for the top edge of the mask + @param width (number) the width of the mask + @param height (number) the height of the mask + @param settings (object) additional settings for the mask (optional) + @return (element) the new mask node */ + mask: function(parent, id, x, y, width, height, settings) { + var args = this._args(arguments, ['id', 'x', 'y', 'width', 'height']); + return this._makeNode(args.parent, 'mask', $.extend( + {id: args.id, x: args.x, y: args.y, width: args.width, height: args.height}, + args.settings || {})); + }, + + /* Create a new path object. + @return (SVGPath) a new path object */ + createPath: function() { + return new SVGPath(); + }, + + /* Create a new text object. + @return (SVGText) a new text object */ + createText: function() { + return new SVGText(); + }, + + /* Add an embedded SVG element. + Specify all of vx, vy, vwidth, vheight or none of them. + @param parent (element or jQuery) the parent node for the new node (optional) + @param x (number) the x-coordinate for the left edge of the node + @param y (number) the y-coordinate for the top edge of the node + @param width (number) the width of the node + @param height (number) the height of the node + @param vx (number) the minimum x-coordinate for view box (optional) + @param vy (number) the minimum y-coordinate for the view box (optional) + @param vwidth (number) the width of the view box (optional) + @param vheight (number) the height of the view box (optional) + @param settings (object) additional settings for the node (optional) + @return (element) the new node */ + svg: function(parent, x, y, width, height, vx, vy, vwidth, vheight, settings) { + var args = this._args(arguments, ['x', 'y', 'width', 'height', + 'vx', 'vy', 'vwidth', 'vheight'], ['vx']); + var sets = $.extend({x: args.x, y: args.y, width: args.width, height: args.height}, + (args.vx != null ? {viewBox: args.vx + ' ' + args.vy + ' ' + + args.vwidth + ' ' + args.vheight} : {})); + return this._makeNode(args.parent, 'svg', $.extend(sets, args.settings || {})); + }, + + /* Create a group. + @param parent (element or jQuery) the parent node for the new group (optional) + @param id (string) the ID of this group (optional) + @param settings (object) additional settings for the group (optional) + @return (element) the new group node */ + group: function(parent, id, settings) { + var args = this._args(arguments, ['id'], ['id']); + return this._makeNode(args.parent, 'g', $.extend({id: args.id}, args.settings || {})); + }, + + /* Add a usage reference. + Specify all of x, y, width, height or none of them. + @param parent (element or jQuery) the parent node for the new node (optional) + @param x (number) the x-coordinate for the left edge of the node (optional) + @param y (number) the y-coordinate for the top edge of the node (optional) + @param width (number) the width of the node (optional) + @param height (number) the height of the node (optional) + @param ref (string) the ID of the definition node + @param settings (object) additional settings for the node (optional) + @return (element) the new node */ + use: function(parent, x, y, width, height, ref, settings) { + var args = this._args(arguments, ['x', 'y', 'width', 'height', 'ref']); + if (typeof args.x == 'string') { + args.ref = args.x; + args.settings = args.y; + args.x = args.y = args.width = args.height = null; + } + var node = this._makeNode(args.parent, 'use', $.extend( + {x: args.x, y: args.y, width: args.width, height: args.height}, + args.settings || {})); + node.setAttributeNS($.svg.xlinkNS, 'href', args.ref); + return node; + }, + + /* Add a link, which applies to all child elements. + @param parent (element or jQuery) the parent node for the new link (optional) + @param ref (string) the target URL + @param settings (object) additional settings for the link (optional) + @return (element) the new link node */ + link: function(parent, ref, settings) { + var args = this._args(arguments, ['ref']); + var node = this._makeNode(args.parent, 'a', args.settings); + node.setAttributeNS($.svg.xlinkNS, 'href', args.ref); + return node; + }, + + /* Add an image. + @param parent (element or jQuery) the parent node for the new image (optional) + @param x (number) the x-coordinate for the left edge of the image + @param y (number) the y-coordinate for the top edge of the image + @param width (number) the width of the image + @param height (number) the height of the image + @param ref (string) the path to the image + @param settings (object) additional settings for the image (optional) + @return (element) the new image node */ + image: function(parent, x, y, width, height, ref, settings) { + var args = this._args(arguments, ['x', 'y', 'width', 'height', 'ref']); + var node = this._makeNode(args.parent, 'image', $.extend( + {x: args.x, y: args.y, width: args.width, height: args.height}, + args.settings || {})); + node.setAttributeNS($.svg.xlinkNS, 'href', args.ref); + return node; + }, + + /* Draw a path. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param path (string or SVGPath) the path to draw + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + path: function(parent, path, settings) { + var args = this._args(arguments, ['path']); + return this._makeNode(args.parent, 'path', $.extend( + {d: (args.path.path ? args.path.path() : args.path)}, args.settings || {})); + }, + + /* Draw a rectangle. + Specify both of rx and ry or neither. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param x (number) the x-coordinate for the left edge of the rectangle + @param y (number) the y-coordinate for the top edge of the rectangle + @param width (number) the width of the rectangle + @param height (number) the height of the rectangle + @param rx (number) the x-radius of the ellipse for the rounded corners (optional) + @param ry (number) the y-radius of the ellipse for the rounded corners (optional) + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + rect: function(parent, x, y, width, height, rx, ry, settings) { + var args = this._args(arguments, ['x', 'y', 'width', 'height', 'rx', 'ry'], ['rx']); + return this._makeNode(args.parent, 'rect', $.extend( + {x: args.x, y: args.y, width: args.width, height: args.height}, + (args.rx ? {rx: args.rx, ry: args.ry} : {}), args.settings || {})); + }, + + /* Draw a circle. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param cx (number) the x-coordinate for the centre of the circle + @param cy (number) the y-coordinate for the centre of the circle + @param r (number) the radius of the circle + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + circle: function(parent, cx, cy, r, settings) { + var args = this._args(arguments, ['cx', 'cy', 'r']); + return this._makeNode(args.parent, 'circle', $.extend( + {cx: args.cx, cy: args.cy, r: args.r}, args.settings || {})); + }, + + /* Draw an ellipse. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param cx (number) the x-coordinate for the centre of the ellipse + @param cy (number) the y-coordinate for the centre of the ellipse + @param rx (number) the x-radius of the ellipse + @param ry (number) the y-radius of the ellipse + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + ellipse: function(parent, cx, cy, rx, ry, settings) { + var args = this._args(arguments, ['cx', 'cy', 'rx', 'ry']); + return this._makeNode(args.parent, 'ellipse', $.extend( + {cx: args.cx, cy: args.cy, rx: args.rx, ry: args.ry}, args.settings || {})); + }, + + /* Draw a line. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param x1 (number) the x-coordinate for the start of the line + @param y1 (number) the y-coordinate for the start of the line + @param x2 (number) the x-coordinate for the end of the line + @param y2 (number) the y-coordinate for the end of the line + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + line: function(parent, x1, y1, x2, y2, settings) { + var args = this._args(arguments, ['x1', 'y1', 'x2', 'y2']); + return this._makeNode(args.parent, 'line', $.extend( + {x1: args.x1, y1: args.y1, x2: args.x2, y2: args.y2}, args.settings || {})); + }, + + /* Draw a polygonal line. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param points (number[][]) the x-/y-coordinates for the points on the line + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + polyline: function(parent, points, settings) { + var args = this._args(arguments, ['points']); + return this._poly(args.parent, 'polyline', args.points, args.settings); + }, + + /* Draw a polygonal shape. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param points (number[][]) the x-/y-coordinates for the points on the shape + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + polygon: function(parent, points, settings) { + var args = this._args(arguments, ['points']); + return this._poly(args.parent, 'polygon', args.points, args.settings); + }, + + /* Draw a polygonal line or shape. */ + _poly: function(parent, name, points, settings) { + var ps = ''; + for (var i = 0; i < points.length; i++) { + ps += points[i].join() + ' '; + } + return this._makeNode(parent, name, $.extend( + {points: $.trim(ps)}, settings || {})); + }, + + /* Draw text. + Specify both of x and y or neither of them. + @param parent (element or jQuery) the parent node for the text (optional) + @param x (number or number[]) the x-coordinate(s) for the text (optional) + @param y (number or number[]) the y-coordinate(s) for the text (optional) + @param value (string) the text content or + (SVGText) text with spans and references + @param settings (object) additional settings for the text (optional) + @return (element) the new text node */ + text: function(parent, x, y, value, settings) { + var args = this._args(arguments, ['x', 'y', 'value']); + if (typeof args.x == 'string' && arguments.length < 4) { + args.value = args.x; + args.settings = args.y; + args.x = args.y = null; + } + return this._text(args.parent, 'text', args.value, $.extend( + {x: (args.x && isArray(args.x) ? args.x.join(' ') : args.x), + y: (args.y && isArray(args.y) ? args.y.join(' ') : args.y)}, + args.settings || {})); + }, + + /* Draw text along a path. + @param parent (element or jQuery) the parent node for the text (optional) + @param path (string) the ID of the path + @param value (string) the text content or + (SVGText) text with spans and references + @param settings (object) additional settings for the text (optional) + @return (element) the new text node */ + textpath: function(parent, path, value, settings) { + var args = this._args(arguments, ['path', 'value']); + var node = this._text(args.parent, 'textPath', args.value, args.settings || {}); + node.setAttributeNS($.svg.xlinkNS, 'href', args.path); + return node; + }, + + /* Draw text. */ + _text: function(parent, name, value, settings) { + var node = this._makeNode(parent, name, settings); + if (typeof value == 'string') { + node.appendChild(node.ownerDocument.createTextNode(value)); + } + else { + for (var i = 0; i < value._parts.length; i++) { + var part = value._parts[i]; + if (part[0] == 'tspan') { + var child = this._makeNode(node, part[0], part[2]); + child.appendChild(node.ownerDocument.createTextNode(part[1])); + node.appendChild(child); + } + else if (part[0] == 'tref') { + var child = this._makeNode(node, part[0], part[2]); + child.setAttributeNS($.svg.xlinkNS, 'href', part[1]); + node.appendChild(child); + } + else if (part[0] == 'textpath') { + var set = $.extend({}, part[2]); + set.href = null; + var child = this._makeNode(node, part[0], set); + child.setAttributeNS($.svg.xlinkNS, 'href', part[2].href); + child.appendChild(node.ownerDocument.createTextNode(part[1])); + node.appendChild(child); + } + else { // straight text + node.appendChild(node.ownerDocument.createTextNode(part[1])); + } + } + } + return node; + }, + + /* Add a custom SVG element. + @param parent (element or jQuery) the parent node for the new element (optional) + @param name (string) the name of the element + @param settings (object) additional settings for the element (optional) + @return (element) the new custom node */ + other: function(parent, name, settings) { + var args = this._args(arguments, ['name']); + return this._makeNode(args.parent, args.name, args.settings || {}); + }, + + /* Create a shape node with the given settings. */ + _makeNode: function(parent, name, settings) { + parent = parent || this._svg; + var node = this._svg.ownerDocument.createElementNS($.svg.svgNS, name); + for (var name in settings) { + var value = settings[name]; + if (value != null && value != null && + (typeof value != 'string' || value != '')) { + node.setAttribute($.svg._attrNames[name] || name, value); + } + } + parent.appendChild(node); + return node; + }, + + /* Add an existing SVG node to the diagram. + @param parent (element or jQuery) the parent node for the new node (optional) + @param node (element) the new node to add or + (string) the jQuery selector for the node or + (jQuery collection) set of nodes to add + @return (SVGWrapper) this wrapper */ + add: function(parent, node) { + var args = this._args((arguments.length == 1 ? [null, parent] : arguments), ['node']); + var svg = this; + args.parent = args.parent || this._svg; + args.node = (args.node.jquery ? args.node : $(args.node)); + try { + if ($.svg._renesis) { + throw 'Force traversal'; + } + args.parent.appendChild(args.node.cloneNode(true)); + } + catch (e) { + args.node.each(function() { + var child = svg._cloneAsSVG(this); + if (child) { + args.parent.appendChild(child); + } + }); + } + return this; + }, + + /* Clone an existing SVG node and add it to the diagram. + @param parent (element or jQuery) the parent node for the new node (optional) + @param node (element) the new node to add or + (string) the jQuery selector for the node or + (jQuery collection) set of nodes to add + @return (element[]) collection of new nodes */ + clone: function(parent, node) { + var svg = this; + var args = this._args((arguments.length == 1 ? [null, parent] : arguments), ['node']); + args.parent = args.parent || this._svg; + args.node = (args.node.jquery ? args.node : $(args.node)); + var newNodes = []; + args.node.each(function() { + var child = svg._cloneAsSVG(this); + if (child) { + child.id = ''; + args.parent.appendChild(child); + newNodes.push(child); + } + }); + return newNodes; + }, + + /* SVG nodes must belong to the SVG namespace, so clone and ensure this is so. + @param node (element) the SVG node to clone + @return (element) the cloned node */ + _cloneAsSVG: function(node) { + var newNode = null; + if (node.nodeType == 1) { // element + newNode = this._svg.ownerDocument.createElementNS( + $.svg.svgNS, this._checkName(node.nodeName)); + for (var i = 0; i < node.attributes.length; i++) { + var attr = node.attributes.item(i); + if (attr.nodeName != 'xmlns' && attr.nodeValue) { + if (attr.prefix == 'xlink') { + newNode.setAttributeNS($.svg.xlinkNS, + attr.localName || attr.baseName, attr.nodeValue); + } + else { + newNode.setAttribute(this._checkName(attr.nodeName), attr.nodeValue); + } + } + } + for (var i = 0; i < node.childNodes.length; i++) { + var child = this._cloneAsSVG(node.childNodes[i]); + if (child) { + newNode.appendChild(child); + } + } + } + else if (node.nodeType == 3) { // text + if ($.trim(node.nodeValue)) { + newNode = this._svg.ownerDocument.createTextNode(node.nodeValue); + } + } + else if (node.nodeType == 4) { // CDATA + if ($.trim(node.nodeValue)) { + try { + newNode = this._svg.ownerDocument.createCDATASection(node.nodeValue); + } + catch (e) { + newNode = this._svg.ownerDocument.createTextNode( + node.nodeValue.replace(/&/g, '&'). + replace(//g, '>')); + } + } + } + return newNode; + }, + + /* Node names must be lower case and without SVG namespace prefix. */ + _checkName: function(name) { + name = (name.substring(0, 1) >= 'A' && name.substring(0, 1) <= 'Z' ? + name.toLowerCase() : name); + return (name.substring(0, 4) == 'svg:' ? name.substring(4) : name); + }, + + /* Load an external SVG document. + @param url (string) the location of the SVG document or + the actual SVG content + @param settings (boolean) see addTo below or + (function) see onLoad below or + (object) additional settings for the load with attributes below: + addTo (boolean) true to add to what's already there, + or false to clear the canvas first + changeSize (boolean) true to allow the canvas size to change, + or false to retain the original + onLoad (function) callback after the document has loaded, + 'this' is the container, receives SVG object and + optional error message as a parameter + parent (string or element or jQuery) the parent to load + into, defaults to top-level svg element + @return (SVGWrapper) this root */ + load: function(url, settings) { + settings = (typeof settings == 'boolean' ? {addTo: settings} : + (typeof settings == 'function' ? {onLoad: settings} : + (typeof settings == 'string' ? {parent: settings} : + (typeof settings == 'object' && settings.nodeName ? {parent: settings} : + (typeof settings == 'object' && settings.jquery ? {parent: settings} : + settings || {}))))); + if (!settings.parent && !settings.addTo) { + this.clear(false); + } + var size = [this._svg.getAttribute('width'), this._svg.getAttribute('height')]; + var wrapper = this; + // Report a problem with the load + var reportError = function(message) { + message = $.svg.local.errorLoadingText + ': ' + message; + if (settings.onLoad) { + settings.onLoad.apply(wrapper._container || wrapper._svg, [wrapper, message]); + } + else { + wrapper.text(null, 10, 20, message); + } + }; + // Create a DOM from SVG content + var loadXML4IE = function(data) { + var xml = new ActiveXObject('Microsoft.XMLDOM'); + xml.validateOnParse = false; + xml.resolveExternals = false; + xml.async = false; + xml.loadXML(data); + if (xml.parseError.errorCode != 0) { + reportError(xml.parseError.reason); + return null; + } + return xml; + }; + // Load the SVG DOM + var loadSVG = function(data) { + if (!data) { + return; + } + if (data.documentElement.nodeName != 'svg') { + var errors = data.getElementsByTagName('parsererror'); + var messages = (errors.length ? errors[0].getElementsByTagName('div') : []); // Safari + reportError(!errors.length ? '???' : + (messages.length ? messages[0] : errors[0]).firstChild.nodeValue); + return; + } + var parent = (settings.parent ? $(settings.parent)[0] : wrapper._svg); + var attrs = {}; + for (var i = 0; i < data.documentElement.attributes.length; i++) { + var attr = data.documentElement.attributes.item(i); + if (!(attr.nodeName == 'version' || attr.nodeName.substring(0, 5) == 'xmlns')) { + attrs[attr.nodeName] = attr.nodeValue; + } + } + wrapper.configure(parent, attrs, !settings.parent); + var nodes = data.documentElement.childNodes; + for (var i = 0; i < nodes.length; i++) { + try { + if ($.svg._renesis) { + throw 'Force traversal'; + } + parent.appendChild(wrapper._svg.ownerDocument.importNode(nodes[i], true)); + if (nodes[i].nodeName == 'script') { + $.globalEval(nodes[i].textContent); + } + } + catch (e) { + wrapper.add(parent, nodes[i]); + } + } + if (!settings.changeSize) { + wrapper.configure(parent, {width: size[0], height: size[1]}); + } + if (settings.onLoad) { + settings.onLoad.apply(wrapper._container || wrapper._svg, [wrapper]); + } + }; + if (url.match(''; + } + else { // Element + svgDoc = '<' + node.nodeName; + if (node.attributes) { + for (var i = 0; i < node.attributes.length; i++) { + var attr = node.attributes.item(i); + if (!($.trim(attr.nodeValue) == '' || attr.nodeValue.match(/^\[object/) || + attr.nodeValue.match(/^function/))) { + svgDoc += ' ' + (attr.namespaceURI == $.svg.xlinkNS ? 'xlink:' : '') + + attr.nodeName + '="' + attr.nodeValue + '"'; + } + } + } + if (node.firstChild) { + svgDoc += '>'; + var child = node.firstChild; + while (child) { + svgDoc += this._toSVG(child); + child = child.nextSibling; + } + svgDoc += ''; + } + else { + svgDoc += '/>'; + } + } + return svgDoc; + } +}); + +/* Helper to generate an SVG path. + Obtain an instance from the SVGWrapper object. + String calls together to generate the path and use its value: + var path = root.createPath(); + root.path(null, path.move(100, 100).line(300, 100).line(200, 300).close(), {fill: 'red'}); + or + root.path(null, path.move(100, 100).line([[300, 100], [200, 300]]).close(), {fill: 'red'}); */ +function SVGPath() { + this._path = ''; +} + +$.extend(SVGPath.prototype, { + /* Prepare to create a new path. + @return (SVGPath) this path */ + reset: function() { + this._path = ''; + return this; + }, + + /* Move the pointer to a position. + @param x (number) x-coordinate to move to or + (number[][]) x-/y-coordinates to move to + @param y (number) y-coordinate to move to (omitted if x is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + move: function(x, y, relative) { + relative = (isArray(x) ? y : relative); + return this._coords((relative ? 'm' : 'M'), x, y); + }, + + /* Draw a line to a position. + @param x (number) x-coordinate to move to or + (number[][]) x-/y-coordinates to move to + @param y (number) y-coordinate to move to (omitted if x is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + line: function(x, y, relative) { + relative = (isArray(x) ? y : relative); + return this._coords((relative ? 'l' : 'L'), x, y); + }, + + /* Draw a horizontal line to a position. + @param x (number) x-coordinate to draw to or + (number[]) x-coordinates to draw to + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + horiz: function(x, relative) { + this._path += (relative ? 'h' : 'H') + (isArray(x) ? x.join(' ') : x); + return this; + }, + + /* Draw a vertical line to a position. + @param y (number) y-coordinate to draw to or + (number[]) y-coordinates to draw to + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + vert: function(y, relative) { + this._path += (relative ? 'v' : 'V') + (isArray(y) ? y.join(' ') : y); + return this; + }, + + /* Draw a cubic Bézier curve. + @param x1 (number) x-coordinate of beginning control point or + (number[][]) x-/y-coordinates of control and end points to draw to + @param y1 (number) y-coordinate of beginning control point (omitted if x1 is array) + @param x2 (number) x-coordinate of ending control point (omitted if x1 is array) + @param y2 (number) y-coordinate of ending control point (omitted if x1 is array) + @param x (number) x-coordinate of curve end (omitted if x1 is array) + @param y (number) y-coordinate of curve end (omitted if x1 is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + curveC: function(x1, y1, x2, y2, x, y, relative) { + relative = (isArray(x1) ? y1 : relative); + return this._coords((relative ? 'c' : 'C'), x1, y1, x2, y2, x, y); + }, + + /* Continue a cubic Bézier curve. + Starting control point is the reflection of the previous end control point. + @param x2 (number) x-coordinate of ending control point or + (number[][]) x-/y-coordinates of control and end points to draw to + @param y2 (number) y-coordinate of ending control point (omitted if x2 is array) + @param x (number) x-coordinate of curve end (omitted if x2 is array) + @param y (number) y-coordinate of curve end (omitted if x2 is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + smoothC: function(x2, y2, x, y, relative) { + relative = (isArray(x2) ? y2 : relative); + return this._coords((relative ? 's' : 'S'), x2, y2, x, y); + }, + + /* Draw a quadratic Bézier curve. + @param x1 (number) x-coordinate of control point or + (number[][]) x-/y-coordinates of control and end points to draw to + @param y1 (number) y-coordinate of control point (omitted if x1 is array) + @param x (number) x-coordinate of curve end (omitted if x1 is array) + @param y (number) y-coordinate of curve end (omitted if x1 is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + curveQ: function(x1, y1, x, y, relative) { + relative = (isArray(x1) ? y1 : relative); + return this._coords((relative ? 'q' : 'Q'), x1, y1, x, y); + }, + + /* Continue a quadratic Bézier curve. + Control point is the reflection of the previous control point. + @param x (number) x-coordinate of curve end or + (number[][]) x-/y-coordinates of points to draw to + @param y (number) y-coordinate of curve end (omitted if x is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + smoothQ: function(x, y, relative) { + relative = (isArray(x) ? y : relative); + return this._coords((relative ? 't' : 'T'), x, y); + }, + + /* Generate a path command with (a list of) coordinates. */ + _coords: function(cmd, x1, y1, x2, y2, x3, y3) { + if (isArray(x1)) { + for (var i = 0; i < x1.length; i++) { + var cs = x1[i]; + this._path += (i == 0 ? cmd : ' ') + cs[0] + ',' + cs[1] + + (cs.length < 4 ? '' : ' ' + cs[2] + ',' + cs[3] + + (cs.length < 6 ? '': ' ' + cs[4] + ',' + cs[5])); + } + } + else { + this._path += cmd + x1 + ',' + y1 + + (x2 == null ? '' : ' ' + x2 + ',' + y2 + + (x3 == null ? '' : ' ' + x3 + ',' + y3)); + } + return this; + }, + + /* Draw an arc to a position. + @param rx (number) x-radius of arc or + (number/boolean[][]) x-/y-coordinates and flags for points to draw to + @param ry (number) y-radius of arc (omitted if rx is array) + @param xRotate (number) x-axis rotation (degrees, clockwise) (omitted if rx is array) + @param large (boolean) true to draw the large part of the arc, + false to draw the small part (omitted if rx is array) + @param clockwise (boolean) true to draw the clockwise arc, + false to draw the anti-clockwise arc (omitted if rx is array) + @param x (number) x-coordinate of arc end (omitted if rx is array) + @param y (number) y-coordinate of arc end (omitted if rx is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + arc: function(rx, ry, xRotate, large, clockwise, x, y, relative) { + relative = (isArray(rx) ? ry : relative); + this._path += (relative ? 'a' : 'A'); + if (isArray(rx)) { + for (var i = 0; i < rx.length; i++) { + var cs = rx[i]; + this._path += (i == 0 ? '' : ' ') + cs[0] + ',' + cs[1] + ' ' + + cs[2] + ' ' + (cs[3] ? '1' : '0') + ',' + + (cs[4] ? '1' : '0') + ' ' + cs[5] + ',' + cs[6]; + } + } + else { + this._path += rx + ',' + ry + ' ' + xRotate + ' ' + + (large ? '1' : '0') + ',' + (clockwise ? '1' : '0') + ' ' + x + ',' + y; + } + return this; + }, + + /* Close the current path. + @return (SVGPath) this path */ + close: function() { + this._path += 'z'; + return this; + }, + + /* Return the string rendering of the specified path. + @return (string) stringified path */ + path: function() { + return this._path; + } +}); + +SVGPath.prototype.moveTo = SVGPath.prototype.move; +SVGPath.prototype.lineTo = SVGPath.prototype.line; +SVGPath.prototype.horizTo = SVGPath.prototype.horiz; +SVGPath.prototype.vertTo = SVGPath.prototype.vert; +SVGPath.prototype.curveCTo = SVGPath.prototype.curveC; +SVGPath.prototype.smoothCTo = SVGPath.prototype.smoothC; +SVGPath.prototype.curveQTo = SVGPath.prototype.curveQ; +SVGPath.prototype.smoothQTo = SVGPath.prototype.smoothQ; +SVGPath.prototype.arcTo = SVGPath.prototype.arc; + +/* Helper to generate an SVG text object. + Obtain an instance from the SVGWrapper object. + String calls together to generate the text and use its value: + var text = root.createText(); + root.text(null, x, y, text.string('This is '). + span('red', {fill: 'red'}).string('!'), {fill: 'blue'}); */ +function SVGText() { + this._parts = []; // The components of the text object +} + +$.extend(SVGText.prototype, { + /* Prepare to create a new text object. + @return (SVGText) this text */ + reset: function() { + this._parts = []; + return this; + }, + + /* Add a straight string value. + @param value (string) the actual text + @return (SVGText) this text object */ + string: function(value) { + this._parts[this._parts.length] = ['text', value]; + return this; + }, + + /* Add a separate text span that has its own settings. + @param value (string) the actual text + @param settings (object) the settings for this text + @return (SVGText) this text object */ + span: function(value, settings) { + this._parts[this._parts.length] = ['tspan', value, settings]; + return this; + }, + + /* Add a reference to a previously defined text string. + @param id (string) the ID of the actual text + @param settings (object) the settings for this text + @return (SVGText) this text object */ + ref: function(id, settings) { + this._parts[this._parts.length] = ['tref', id, settings]; + return this; + }, + + /* Add text drawn along a path. + @param id (string) the ID of the path + @param value (string) the actual text + @param settings (object) the settings for this text + @return (SVGText) this text object */ + path: function(id, value, settings) { + this._parts[this._parts.length] = ['textpath', value, + $.extend({href: id}, settings || {})]; + return this; + } +}); + +/* Attach the SVG functionality to a jQuery selection. + @param command (string) the command to run (optional, default 'attach') + @param options (object) the new settings to use for these SVG instances + @return jQuery (object) for chaining further calls */ +$.fn.svg = function(options) { + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && options == 'get') { + return $.svg['_' + options + 'SVG'].apply($.svg, [this[0]].concat(otherArgs)); + } + return this.each(function() { + if (typeof options == 'string') { + $.svg['_' + options + 'SVG'].apply($.svg, [this].concat(otherArgs)); + } + else { + $.svg._attachSVG(this, options || {}); + } + }); +}; + +/* Determine whether an object is an array. */ +function isArray(a) { + return (a && a.constructor == Array); +} + +// Singleton primary SVG interface +$.svg = new SVGManager(); + +})(jQuery); diff --git a/src/graphxq/lib/txq.xqm b/src/graphxq/lib/txq.xqm new file mode 100644 index 0000000..b3666c8 --- /dev/null +++ b/src/graphxq/lib/txq.xqm @@ -0,0 +1,45 @@ +(:~ +: A(nother) templating Engine for XQuery (BaseX 7.5 specific) +: +: @author andy bunce +: @since sept 2012 +:) + +module namespace txq = 'apb.txq'; +declare default function namespace 'apb.txq'; +import module namespace xquery = "http://basex.org/modules/xquery"; + +(:~ +: template function +: @param template url to fill +: @param map name and value to apply +: @return updated doc from map +:) +declare function render($template as xs:string,$map as map(*)){ + let $map:=map:new(($map,map{"partial":=partial(?,?,?,$map,$template)})) + return xquery:invoke($template,$map) +}; + +(:~ +: template function with wrapping layout +: @param layout +: @return updated doc from map +:) +declare function render($template as xs:string,$map as map(*),$layout as xs:string){ + let $content:=render($template,$map) + let $map:=map:new(($map,map{"body":=$content})) + return render($layout,$map) +}; + + + +(:~ +: partial template function: evaluate part for each value in sequence +: @return updated doc from map +:) +declare function partial($part as xs:string,$name,$seq,$map,$base){ + for $s in $seq + let $map:=map:new(($map,map{$name:=$s})) + return render($map,fn:resolve-uri($part,$base)) +}; + diff --git a/src/graphxq/txq.xqm b/src/graphxq/txq.xqm new file mode 100644 index 0000000..4c2e36d --- /dev/null +++ b/src/graphxq/txq.xqm @@ -0,0 +1,46 @@ +(:~ +: A(nother) templating Engine for XQuery (BaseX 7.5+(or -) specific) +: +: @author andy bunce +: @since sept 2012 +:) + +module namespace txq = 'apb.txq'; +declare default function namespace 'apb.txq'; +import module namespace xquery = "http://basex.org/modules/xquery"; + + +(:~ +: template function +: @return updated doc from map +:) +declare function render($map as map(*),$layout as xs:string,$file as xs:string) +{ + let $content:=render($map,$file) + let $map:=map:new(($map,map{"body":=$content})) + return render($map,$layout) + +}; + +(:~ +: template function +: @return updated doc from map +:) +declare function render($layout as xs:string,$map as map(*)) +{ + let $map:=map:new(($map,map{"partial":=partial(?,?,?,$map,$layout)})) + return xquery:invoke($layout,$map) + +}; + +(:~ +: partial template function: evaluate part for each value in sequence +: @return updated doc from map +:) +declare function partial($part as xs:string,$name,$seq,$map,$base) +{ + for $s in $seq + let $map:=map:new(($map,map{$name:=$s})) + return render($map,fn:resolve-uri($part,$base)) +}; + diff --git a/src/graphxq/views/about.xml b/src/graphxq/views/about.xml new file mode 100644 index 0000000..a293426 --- /dev/null +++ b/src/graphxq/views/about.xml @@ -0,0 +1,44 @@ +
+ + +
\ No newline at end of file diff --git a/src/graphxq/views/dotform.xml b/src/graphxq/views/dotform.xml new file mode 100644 index 0000000..3823f8e --- /dev/null +++ b/src/graphxq/views/dotform.xml @@ -0,0 +1,18 @@ +
+ +
+ + + +
+ +
+
+ +
+
svg here
+
+ +
\ No newline at end of file diff --git a/src/graphxq/views/dotmlform.xml b/src/graphxq/views/dotmlform.xml new file mode 100644 index 0000000..61a9c7e --- /dev/null +++ b/src/graphxq/views/dotmlform.xml @@ -0,0 +1,13 @@ +
+
+
+ + + + +
+
+
+
?
+
+
\ No newline at end of file diff --git a/src/graphxq/views/layout.xml b/src/graphxq/views/layout.xml new file mode 100644 index 0000000..442c58c --- /dev/null +++ b/src/graphxq/views/layout.xml @@ -0,0 +1,91 @@ + + + + {$title} + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
{$body}
+ +
+ +
+ + + \ No newline at end of file diff --git a/src/graphxq/views/page1.xml b/src/graphxq/views/page1.xml new file mode 100644 index 0000000..f7c2308 --- /dev/null +++ b/src/graphxq/views/page1.xml @@ -0,0 +1,35 @@ + +
+

RestXQ interface to graphviz

+

Enter a string in the dot language + Examples: digraph {{ a -> b}}, + another + .

+

Or enter a Url to a xml document examples: + process, + hedgeweb + remote +

+
+ + + +

+

Or enter the url to a node XML source +

+ +
+

Inline SVG

+
{$svg}
+ +

Object referencing svg, + ( download svg)

+ + SVG Here + +

SVG xml

+
+		 {fn:serialize($svg)}
+		 
+
\ No newline at end of file diff --git a/src/graphxq/views/search.xml b/src/graphxq/views/search.xml new file mode 100644 index 0000000..fd2071a --- /dev/null +++ b/src/graphxq/views/search.xml @@ -0,0 +1,6 @@ +
+ +

No Search Results yet

+

Search results for: {$q} In collection:

+
    +
    \ No newline at end of file