// Copyright (c) 2002-2016, Nirvana Research // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Idea and first implementation - Leo Baschy <srguiwiz12 AT nrvr DOT com> // Contributor - Hans Baschy
// Project contact: <adj.project AT nrvr DOT com>
// Public repository - https://github.com/srguiwiz/adj-js
// Stable releases (recent) - https://github.com/srguiwiz/adj-js/releases // // Blog - http://leosbog.nrvr.com/category/adj/ // // Commit list - https://github.com/srguiwiz/adj-js/commits/master
If you have seen a demo or attended a class, and quickly want to get started on your own, consider:
adj.js
file here or from this project's repositoryAdj commands modify SVG.
One significant feature is "relative constraints".
It is possible to execute all Adj modification of SVG on the SVG document author's workstation, then save the document and let other users view it.
Alternatively, it is possible to allow execution of Adj modification of SVG when a user is viewing, possibly interacting with an SVG document.
As implemented, it builds on SVG and contemporary browsers.
The original purpose of the Adj framework has been to facilitate creation and long-term maintenance of system diagrams.
Adj has been designed specifically for diagrams of large complexity.
Because of its general nature, other uses may be possible.
Other attempts had been made at enhancing drawing tools, e.g. an Adobe Illustrator plug-in. Still there were good reasons to implement Adj.
Adj leverages several existing technologies:
Additional highlights:
SVG WYSIWYG editors at the time Adj has been developed have been found to be suboptimal in reliability and ease of use, and have not effectively supported JavaScript manipulation of SVG.
Adj commands modify SVG:
source | <svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:verticalList gap="5"/> <rect width="45" height="30" fill="#000"/> <rect width="40" height="25" fill="#444"/> <rect width="35" height="20" fill="#888"/> </g> </svg> |
image before being processed by Adj | |
becomes | <svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:verticalList gap="5"/> <rect width="45" height="30" fill="#000" transform="translate(5,5)"/> <rect width="40" height="25" fill="#444" transform="translate(5,40)"/> <rect width="35" height="20" fill="#888" transform="translate(5,70)"/> </g> </svg> |
image after processing by Adj |
With some modifications, authoring coordinates are stored away for reuse by authors and algorithms:
source | <svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#444"/> <rect adj:id="other" x="145" y="35" width="40" height="30" fill="#aaa"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"> <adj:connection from="one % 1, 0.5" to="other % 0, 0.5"/> </path> </svg> |
becomes | <svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#444"/> <rect adj:id="other" x="145" y="35" width="40" height="30" fill="#aaa"/> <path d="M45,20q22.127,17.078 50,15t50,15" stroke="#777" stroke-width="2" fill="none" adj:d="M5,100 q40,10 80,0 t80,0"> <adj:connection from="one % 1, 0.5" to="other % 0, 0.5"/> </path> </svg> |
With some modifications, original attributes are stored away for reuse by
algorithms. E.g. SVG attribute display
may be stored away in an
attribute adj:originalDisplay
.
Command paragraph
makes small changes to
the content of its text
element.
TODO: explain command paragraph, emphasize what we need browsers to keep providing consistently to remain compatible
The main commands shown by simple examples:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:horizontalList gap="5"/> <rect width="45" height="30" fill="#000"/> <rect width="40" height="25" fill="#444"/> <rect width="35" height="20" fill="#888"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:verticalList gap="5"/> <rect width="45" height="30" fill="#000"/> <rect width="40" height="25" fill="#444"/> <rect width="35" height="20" fill="#888"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:horizontalList gap="5"/> <rect fill="none" stroke="black" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> <rect width="45" height="30" fill="#000"/> <rect width="40" height="25" fill="#444"/> <rect width="35" height="20" fill="#888"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g font-size="12"> <adj:textBreaks wordBreaks="true"/> <adj:horizontalList maxWidth="170" gap="5" centerGap="3" topGap="10" leftGap="10"/> <text>This is a sentence of text that will wrap.</text> <text>Here is more.</text> <rect fill="none" stroke="lightgray" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#444"/> <rect adj:id="other" x="145" y="35" width="40" height="30" fill="#aaa"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"> <adj:connection from="one % 1, 0.5" to="other % 0, 0.5"/> </path> <path d="M5,100 q40,10 80,0 t80,0" stroke="lightgray" stroke-width="2" fill="none" /> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#000"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#aaa"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"/> <rect width="30" height="20" fill="#444"> <adj:rider at="0.5"/> </rect> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <rect x="30" y="30" width="50" height="20" fill="#000"/> <circle r="5" stroke="gray" fill="gray" fill-opacity="0.2"> <adj:circleForParent/> </circle> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <rect x="30" y="30" width="50" height="20" fill="#000"/> <ellipse rx="5" ry="5" stroke="gray" fill="gray" fill-opacity="0.2"> <adj:ellipseForParent/> </ellipse> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="140" fill="linen"/> <g> <adj:circularList gap="5"/> <circle r="10" fill="#000"/> <rect width="30" height="20" fill="#222"/> <rect width="30" height="20" fill="#444"/> <rect width="30" height="20" fill="#666"/> <rect width="30" height="20" fill="#888"/> <rect width="30" height="20" fill="#aaa"/> <rect width="30" height="20" fill="#bbb"/> <rect width="30" height="20" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="130" fill="linen"/> <g> <adj:verticalTree/> <text adj:id="r-1">R1</text> <text adj:id="l-1-1" adj:treeParent="r-1">L11</text> <text adj:id="n-1-2" adj:treeParent="r-1">N12</text> <text adj:id="n-1-2-1" adj:treeParent="n-1-2">N121</text> <text adj:id="l-1-2-1-1" adj:treeParent="n-1-2-1">L1211</text> <text adj:id="l-1-2-1-2" adj:treeParent="n-1-2-1">L1212</text> <text adj:id="l-1-2-2" adj:treeParent="n-1-2">L122</text> <text adj:id="l-1-3" adj:treeParent="r-1">L13</text> <line stroke="#666"> <adj:connection from="r-1%0.2,1" to="l-1-1%0.8,0"/> </line> … </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="140" fill="linen"/> <g> <adj:horizontalTree/> <text adj:id="r-1">R1</text> <text adj:id="l-1-1" adj:treeParent="r-1">L11</text> <text adj:id="n-1-2" adj:treeParent="r-1">N12</text> <text adj:id="n-1-2-1" adj:treeParent="n-1-2">N121</text> <text adj:id="l-1-2-1-1" adj:treeParent="n-1-2-1">L1211</text> <text adj:id="l-1-2-1-2" adj:treeParent="n-1-2-1">L1212</text> <text adj:id="l-1-2-2" adj:treeParent="n-1-2">L122</text> <text adj:id="l-1-3" adj:treeParent="r-1">L13</text> <line stroke="#666"> <adj:connection from="r-1%1,0.2" to="l-1-1%0,0.8"/> </line> … </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="180" fill="linen"/> <g> <adj:verticalTree leftGap="20" centerGap="30" childlessGap="10" middleGap="40"/> <rect adj:id="o1" width="40" height="30" fill="#000"/> <rect adj:id="o2" adj:treeParent="o1" width="30" height="20" fill="#666"/> <rect adj:id="o3" adj:treeParent="o2" width="25" height="15" fill="#888"/> <rect adj:id="o4" adj:treeParent="o2" width="25" height="15" fill="#aaa"/> <rect adj:id="o5" adj:treeParent="o1" width="30" height="20" fill="#bbb"/> <rect adj:id="o6" adj:treeParent="o5" width="25" height="15" fill="#ccc"/> <rect adj:id="o7" adj:treeParent="o5" width="25" height="15" fill="#ddd"/> </g> <path d="M0,0" stroke="#777" stroke-width="2" fill="none" adj:d="M ~o1#x - 10, ~o1#yh C ~o1#x - 10, ~o1#yh + 10 ~o2#x - 10, ~o2#y%-0.3 ~o2#x - 10, ~o2#yc S ~o3#x - 10, ~o3#y%-0.3 ~o3#x - 10, ~o3#yc C ~o3#x - 10, ~o3#yh + 10 ~o3#x, ~o3#yh + 10 ~o3#xc, ~o3#yh + 10 S ~o4#x, ~o4#yh + 10 ~o4#xc, ~o4#yh + 10 S ~o4#xw + 10, ~o4#yh + 10 ~o4#xw + 10, ~o4#yc C ~o4#xw + 10, ~o4#y * 0.5 + ~o2#yh * 0.5 ~o2#xw, ~o2#yh * 0.5 + ~o4#y * 0.5 + 10 ~o2#xw, ~o2#yh * 0.5 + ~o4#y * 0.5 S ~o2#xw, ~o2#yh * 0.5 + ~o5#yh * 0.5 + 10 ~o2#xw * 0.5 + ~o5#x * 0.5, ~o2#yh * 0.5 + ~o5#yh * 0.5 + 10"> <adj:vine/> </path> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="160" fill="linen"/> <g> <rect adj:id="one" x="15" y="65" width="40" height="30" fill="#000"/> <rect adj:id="other" x="95" y="15" width="40" height="30" fill="#666"/> <rect adj:id="another" x="145" y="115" width="40" height="30" fill="#aaa"/> <path d="M0,0 l40,0 -20,-50 z" fill="#444"> <adj:floater at="~one#xc*0.333+~other#xc*0.333+~another#xc*0.333,~one#yc*0.333+~other#yc*0.333+~another#yc*0.333"/> </path> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <style type="text/css"><![CDATA[ circle { stroke: black; stroke-width: 1; } ]]></style> <rect width="200" height="150" fill="linen"/> <g adj:command="horizontalList" adj:makeGrid="true" adj:maxWidth="200" adj:gap="10" adj:hAlign="center" adj:vAlign="middle"> <circle fill="#444" r="25"/> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:maxHeight="20"/> </g> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:maxWidth="40" adj:maxHeight="30"/> </g> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:maxWidth="100"/> </g> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:height="70"/> </g> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:width="120" adj:height="80" adj:maxWidth="40"/> </g> </g> <g adj:command="floater" adj:at="0,0" adj:pin="0,0"> <adj:variable name="w" value="200"/> <adj:variable name="h" value="150"/> <path adj:command="vine" stroke="#777" stroke-width="1" opacity="0.2" fill="none" d=" M 0,10 h ^w M 0,20 h ^w … "/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:stackFrames stacking="3, -5, 5" inset="-1"/> <rect fill="white" stroke="black" stroke-width="2" width="30" height="20"/> <ellipse cx="60" cy="40" rx="40" ry="20" fill="#666"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <rect x="5" y="5" width="30" height="20" stroke="black" stroke-width="1" fill="#000"/> <rect width="45" height="35" stroke="gray" stroke-width="1" fill="white" opacity="0.5"> <adj:zoomFrames/> </rect> <rect x="135" y="65" width="60" height="50" stroke="black" stroke-width="1" fill="#888"/> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g adj:command="skimpyList"> <g> <rect width="50" height="70" stroke="black" stroke-width="1" fill="#888"> <adj:tilt alpha="15"/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:pinnedList/> <g> <rect width="40" height="40" stroke="black" stroke-width="1" fill="#aaa" adj:id="top"> <adj:tilt alpha="30" beta="60"/> </rect> </g> <g adj:pinThis="front % 0.5, 0.0" adj:pinTo="top % 0.5, 1.0"> <rect width="40" height="40" stroke="black" stroke-width="1" fill="#888" adj:id="front"> <adj:tilt alpha="30"/> </rect> </g> <g adj:pinThis="side % 0.5, 0.0" adj:pinTo="top % 1.0, 0.5"> <rect width="40" height="40" stroke="black" stroke-width="1" fill="#666" adj:id="side"> <adj:tilt alpha="-30"/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="170" fill="linen"/> <g> <adj:telescopicTree gap="5"/> <rect width="30" height="20" fill="#000" adj:id="id1"/> <adj:boom/> <rect width="32" height="22" fill="#222"/> <adj:boom angle="east"/> <rect width="34" height="24" fill="#444"/> <adj:boom from="id1" angle="90" gap="15"/> <rect width="36" height="26" fill="#666" adj:id="id2"/> <adj:boom angle="10"/> <rect width="38" height="28" fill="#888"/> <rect width="40" height="30" fill="#aaa"/> <adj:boom from="id2%0.5,1" to="0.5,0" angle="100" gap="~id2#h * 0.5"/><!-- --> <rect width="42" height="32" fill="#bbb"/> <adj:boom angle="-10"/> <rect width="44" height="34" fill="#ccc"/> <adj:boom angle="10"/> <rect width="46" height="36" fill="#ddd"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:verticalList/> <text adj:command="paragraph" adj:maxWidth="155"> This is a sentence of text that will wrap. Here is more. </text> <rect fill="none" stroke="lightgray" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="80" fill="linen"/> <path d="M15,20 q30,0 30,30 l50,0 30,-30 30,0" stroke="none" fill="none"/> <path d="M0,0" adj:d="M50,25 l5,-5 ,-5,-5 0,0 20,0 0,0 5,5 ,-5,5 0,0 z" stroke="black" stroke-width="1" fill="white"> <adj:pathArrow/> </path> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="170" fill="linen"/> <g> <adj:rcGrid/> <g adj:rcGridPart="row"> <circle r="10" fill="none" stroke="#000"/> <circle r="4" fill="#222"/> <circle r="6" fill="#444"/> <circle r="8" fill="#666"/> <circle r="10" fill="#888"/> </g> <g adj:rcGridPart="column"> <rect width="10" height="10" fill="#000"/> <rect width="14" height="12" fill="#222"/> … </g> … <g adj:rcGridPart="column"/> <g adj:rcGridPart="column"> <rect width="22" height="16" fill="#000"/> … </g> <g adj:rcGridPart="row"> <g/> <circle r="4" fill="#222"/> <circle r="6" fill="#444"/> … </g> … </g> </svg> |
|
You can view the
SVG by itself and drag
the |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="80" fill="linen"/> <g transform="translate(20,20)"> <rect x="0" y="0" width="140" height="20" fill="white" stroke="dimgrey"/> <rect x="6" y="6" width="128" height="8" fill="lightgrey" stroke="dimgrey"/> <g> <adj:sliderKnob/> <rect x="0" y="0" width="20" height="20" fill="gainsboro" stroke="black"/> <rect x="3" y="3" width="14" height="14" fill="lightgrey" stroke="none"/> </g> </g> <text id="setme" style="font-size:10;font-family:sans-serif;" transform="translate(20,60)">0</text> <script><![CDATA[ document.addEventListener("change", function (event) { var elementToSet = document.getElementById("setme"); elementToSet.textContent = event.detail.value; Adj.doSvg(); }); ]]></script> </svg> |
You can view the
SVG by itself and
click the |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="140" fill="linen"/> <g> <adj:skimpyList/> <g> <rect width="70" height="100" stroke="black" stroke-width="1" fill="darkgrey"/> <g> <adj:tilt alpha="0"/> <rect width="70" height="100" stroke="dimgrey" stroke-width="1" fill="lightgrey"/> <g adj:id="lockIt"> <adj:floater at="45,50"/> <adj:toggleButton/> <path adj:alternativeValue="lock" title="click to flip" d="M0,0 l0,-30 30,0 0,30 z M5,-30 l0,-10 q0,-10 10,-10 10,0 10,10 … z" fill="darkgrey" stroke="black"/> <path adj:alternativeValue="unlock" title="click to flip" d="M0,0 l0,-30 30,0 0,30 z M22,-30 l0,-10 q0,-10 10,-10 10,0 10,10 … z" fill="darkgrey" stroke="black"/> </g> </g> </g> </g> <script><![CDATA[ Adj.getElementById("lockIt").addEventListener("change", function (event) { var newToggle = event.detail.value; document.querySelector("[alpha]").setAttribute("alpha", newToggle === "lock" ? "0" : "15"); Adj.doSvg(); }); ]]></script> </svg> |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:horizontalList gap="5"/> <rect width="45" height="30" fill="#000"/> <rect width="40" height="25" fill="#444" adj:hide="true"/> <rect width="35" height="20" fill="#888"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj" xmlns:xlink="http://www.w3.org/1999/xlink"> <rect width="200" height="140" fill="linen"/> <g adj:command="horizontalList" adj:gap="2" adj:itemsH2V="1"> <rect width="40" height="80" fill="#222"/> <g> <adj:include xlink:href="subdir-080/adj-ex-080-include-to-include.svg"/> </g> <rect width="40" height="40" fill="#444"/> <rect width="80" height="40" fill="#888"/> </g> </svg> |
Most commands take optional parameters.
Optional parameters of horizontalList
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <adj:horizontalList gap="5"/> <rect width="30" height="20" fill="#000"/> <rect width="32" height="22" fill="#222"/> <rect width="34" height="24" fill="#444"/> <rect width="36" height="26" fill="#666"/> <rect width="38" height="28" fill="#888"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <adj:horizontalList maxPerRow="3" gap="5"/> <rect width="30" height="20" fill="#000"/> <rect width="32" height="22" fill="#222"/> <rect width="34" height="24" fill="#444"/> <rect width="36" height="26" fill="#666"/> <rect width="38" height="28" fill="#888"/> <rect width="40" height="30" fill="#aaa"/> <rect width="42" height="32" fill="#bbb"/> <rect width="44" height="34" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="150" fill="linen"/> <g> <adj:horizontalList maxWidth="120" gap="5"/> <rect width="30" height="20" fill="#000"/> <rect width="32" height="22" fill="#222"/> <rect width="34" height="24" fill="#444"/> <rect width="36" height="26" fill="#666"/> <rect width="38" height="28" fill="#888"/> <rect width="40" height="30" fill="#aaa"/> <rect width="42" height="32" fill="#bbb"/> <rect width="44" height="34" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <adj:horizontalList makeGrid="true" maxPerRow="3" gap="5"/> <rect width="30" height="20" fill="#000"/> <rect width="32" height="22" fill="#222"/> <rect width="34" height="24" fill="#444"/> <rect width="36" height="26" fill="#666"/> <rect width="38" height="28" fill="#888"/> <rect width="40" height="30" fill="#aaa"/> <rect width="42" height="32" fill="#bbb"/> <rect width="44" height="34" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <adj:horizontalList makeGrid="true" hAlign="center" vAlign="middle" maxPerRow="3" gap="5"/> <rect width="30" height="20" fill="#000"/> <rect width="32" height="22" fill="#222"/> <rect width="34" height="24" fill="#444"/> <rect width="36" height="26" fill="#666"/> <rect width="38" height="28" fill="#888"/> <rect width="40" height="30" fill="#aaa"/> <rect width="42" height="32" fill="#bbb"/> <rect width="44" height="34" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <adj:horizontalList maxPerRow="4" horizontalGap="15" verticalGap="3"/> <rect width="30" height="20" fill="#000"/> <rect width="30" height="20" fill="#222"/> <rect width="30" height="20" fill="#444"/> <rect width="30" height="20" fill="#666"/> <rect width="30" height="20" fill="#888"/> <rect width="30" height="20" fill="#999"/> <rect width="30" height="20" fill="#aaa"/> <rect width="30" height="20" fill="#bbb"/> <rect width="30" height="20" fill="#ccc"/> <rect width="30" height="20" fill="#ddd"/> <rect fill="none" stroke="lightgray" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <adj:horizontalList maxPerRow="4" leftGap="20" centerGap="5" rightGap="12" topGap="10" middleGap="3" bottomGap="7"/> <rect width="30" height="20" fill="#000"/> <rect width="30" height="20" fill="#222"/> <rect width="30" height="20" fill="#444"/> <rect width="30" height="20" fill="#666"/> <rect width="30" height="20" fill="#888"/> <rect width="30" height="20" fill="#999"/> <rect width="30" height="20" fill="#aaa"/> <rect width="30" height="20" fill="#bbb"/> <rect width="30" height="20" fill="#ccc"/> <rect width="30" height="20" fill="#ddd"/> <rect fill="none" stroke="lightgray" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:horizontalList itemsH2V="1.5" gap="5"/> <rect width="20" height="20" fill="#000"/> <rect width="20" height="20" fill="#222"/> <rect width="20" height="20" fill="#444"/> <rect width="20" height="20" fill="#666"/> <rect width="20" height="20" fill="#888"/> <rect width="20" height="20" fill="#999"/> <rect width="20" height="20" fill="#aaa"/> <rect width="20" height="20" fill="#bbb"/> <rect width="20" height="20" fill="#ccc"/> <rect width="20" height="20" fill="#ddd"/> </g> </svg> |
The fractions in parameters hAlign
(horizontally align) and
vAlign
(vertically align) accept decimal numbers, but they also
recognize some symbols (strings in JavaScript).
hAlign | left | 0.0 |
center | 0.5 | |
right | 1.0 | |
vAlign | top | 0.0 |
middle | 0.5 | |
bottom | 1.0 |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:verticalList gap="5"/> <rect width="45" height="30" fill="#000"/> <rect width="40" height="25" fill="#444"/> <rect width="35" height="20" fill="#888"/> </g> </svg> |
Optional parameters of verticalList
are very similar to
optional parameters of horizontalList
.
Notably different, there is maxHeight
(instead of maxWidth
, duh) and
maxPerColumn
(instead of
maxPerRow
).
Optional parameters of frameForParent
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:horizontalList gap="10"/> <rect fill="none" stroke="black" stroke-width="4" width="0" height="0" rx="4" ry="4"> <adj:frameForParent inset="2"/> </rect> <rect fill="none" stroke="gray" stroke-width="2" width="0" height="0" rx="2" ry="2"> <adj:frameForParent horizontalInset="4" verticalInset="3"/> </rect> <rect width="45" height="30" fill="#000"/> <rect width="40" height="25" fill="#444"/> <rect width="35" height="20" fill="#888"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:horizontalList gap="10"/> <rect fill="none" stroke="black" stroke-width="4" width="0" height="0"> <adj:frameForParent leftInset="2" rightInset="0" topInset="2" bottomInset="0"/> </rect> <rect fill="none" stroke="gray" stroke-width="4" width="0" height="0"> <adj:frameForParent inset="3"/> </rect> <rect width="45" height="30" fill="#000"/> <rect width="40" height="25" fill="#444"/> <rect width="35" height="20" fill="#888"/> </g> </svg> |
Optional parameters of textBreaks
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g font-size="12"> <adj:textBreaks wordBreaks="true"/> <adj:horizontalList maxWidth="190" gap="5" centerGap="3" topGap="10" leftGap="10"/> <text>Source line one, source line two.</text> <text>And source line three.</text> <rect fill="none" stroke="lightgray" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g font-size="12"> <adj:textBreaks lineBreaks="true"/> <adj:horizontalList maxPerRow="1" gap="5" topGap="10" leftGap="10"/> <text>Source line one, source line two.</text> <text>And source line three.</text> <rect fill="none" stroke="lightgray" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> </g> </svg> |
If not given, default values are wordBreaks="false"
and
lineBreaks="true"
.
Optional parameters of connection
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" stroke="#000" fill="#aaa"/> <rect adj:id="other" x="145" y="55" width="40" height="30" stroke="#000" fill="#ccc"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#000" stroke-width="2" fill="none"> <adj:connection from="one" to="other"/> </path> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" stroke="#000" fill="#aaa"/> <rect adj:id="other" x="145" y="55" width="40" height="30" stroke="#000" fill="#ccc"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#000" stroke-width="2" fill="none"> <adj:connection from="one%1,0.5" to="other%0,0.5"/> </path> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" stroke="#000" fill="#aaa"/> <rect adj:id="other" x="145" y="55" width="40" height="30" stroke="#000" fill="#ccc"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <line x1="5" y1="100" x2="185" y2="100"/> <path d="M15,100 l-10,-10 20,0 5,5 135,0 0,-5 20,10 -20,10 0,-5 -135,0 -5,5 -20,0 z" stroke="#000" stroke-width="1" fill-opacity="0.5" fill="#888"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" stroke="#000" fill="#aaa"/> <rect adj:id="other" x="145" y="55" width="40" height="30" stroke="#000" fill="#ccc"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5" vector="1"/> <path d="M15,100 l-10,-10 20,0 5,5 135,0 0,-5 20,10 -20,10 0,-5 -135,0 -5,5 -20,0 z" stroke="#000" stroke-width="1" fill-opacity="0.5" fill="#888"/> <line x1="5" y1="100" x2="185" y2="100"/> </g> </svg> |
In parameters from
and to
an expression
identifier % decimal , decimal
means from the element referenced by the identifier determine coordinates with
0,0
being its bounding box x,y
and 1,1
being its x+width,y+height
. With decimal number values often
between 0.0 and 1.0 they also can be outside that range.
As implemented, connection
works for simplified cases
line
and path
, and for general case group
g
containing one line
(or path
) as
vector
(default first, i.e. index 0) and any number of lines and
paths as children of that group.
Optional parameters of rider
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#000"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#aaa"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"/> <rect width="30" height="20" fill="#444"> <adj:rider/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#000"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#aaa"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"/> <rect width="30" height="20" fill="#444"> <adj:rider at="0.7"/> </rect> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#000"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#aaa"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"/> <rect width="30" height="20" fill="#444"> <adj:rider at="0.2,0.7"/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#000"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#aaa"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"/> <rect width="30" height="20" fill="#444"> <adj:rider at="0.2,0.7" adjust="near"/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#000"/> <rect x="85" y="15" width="40" height="30" fill="#666"/> <rect x="25" y="45" width="40" height="30" fill="#888"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#aaa"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"/> <rect width="30" height="20" fill="#444"> <adj:rider/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#000"/> <rect x="85" y="15" width="40" height="30" fill="#666"/> <rect x="25" y="45" width="40" height="30" fill="#888"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#aaa"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"/> <rect width="30" height="20" fill="#444"> <adj:rider at="0.2,0.7" adjust="near" gap="2"/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#000"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#aaa"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"/> <rect width="30" height="20" fill="#444"> <adj:rider pin="0.0,1.0"/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#000"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#aaa"/> <path adj:id="connect" d="M5,100 q40,10 80,0 t80,0" stroke="#777" stroke-width="2" fill="none"> <adj:connection from="one%1,0.5" to="other%0,0.5"/> </path> <rect width="30" height="20" fill="#444"> <adj:rider path="connect"/> </rect> </g> </svg> |
The fraction or fraction pair in parameter at
accepts decimal
numbers. With values often between 0.0 and 1.0 they also can be outside that
range.
Parameter adjust
accepts some symbols (strings in
JavaScript).
adjust | clear |
near | |
none |
If given no at
and no adjust
then at
defaults from 0.0 to 1.0 and adjust
defaults to
clear
. If given no at
but adjust
given
near
then at
defaults from 0.0 to 0.5.
If given one decimal number for at
then adjust
defaults to none
.
If given two decimal numbers for at
then adjust
defaults to clear
.
The fraction pair in parameter pin
accepts decimal numbers.
With values often between 0.0 and 1.0 they also can be outside that range.
As implemented, rider
tries to stay clear of its group's
siblings, or to stay clear of its own siblings if given a path
attribute.
Parameter steps
should not be set in most circumstances. It
accepts an integer number and defaults to 10. It does not correspond to the
final resolution of adjusting coordinates.
An optional parameter of circleForParent
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <rect x="30" y="30" width="50" height="20" fill="#000"/> <circle r="5" stroke="gray" stroke-width="4" fill="gray" fill-opacity="0.2"> <adj:circleForParent inset="-2"/> </circle> </g> </svg> |
Optional parameters of ellipseForParent
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <rect x="30" y="30" width="50" height="20" fill="#000"/> <ellipse rx="5" ry="5" stroke="gray" stroke-width="4" fill="gray" fill-opacity="0.2"> <adj:ellipseForParent inset="-2"/> </ellipse> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <rect x="30" y="30" width="50" height="20" fill="#000"/> <ellipse rx="5" ry="5" stroke="gray" stroke-width="4" fill="gray" fill-opacity="0.2"> <adj:ellipseForParent horizontalInset="-3" verticalInset="-1"/> </ellipse> </g> </svg> |
Optional parameters of circularList
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="130" fill="linen"/> <g> <adj:circularList gap="5"/> <rect width="20" height="20" fill="#000"/> <rect width="20" height="20" fill="#222"/> <rect width="20" height="20" fill="#444"/> <rect width="20" height="20" fill="#666"/> <rect width="20" height="20" fill="#888"/> <rect width="20" height="20" fill="#aaa"/> <rect width="20" height="20" fill="#bbb"/> <rect width="20" height="20" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="140" fill="linen"/> <g> <adj:circularList rGap="5" cGap="15"/> <rect width="20" height="20" fill="#000"/> <rect width="20" height="20" fill="#222"/> <rect width="20" height="20" fill="#444"/> <rect width="20" height="20" fill="#666"/> <rect width="20" height="20" fill="#888"/> <rect width="20" height="20" fill="#aaa"/> <rect width="20" height="20" fill="#bbb"/> <rect width="20" height="20" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:circularList fromAngle="225" toAngle="315" cGap="4" horizontalGap="5" verticalGap="20"/> <g/> <rect width="15" height="15" fill="#000"/> <rect width="15" height="15" fill="#222"/> <rect width="15" height="15" fill="#444"/> <rect width="15" height="15" fill="#666"/> <rect width="15" height="15" fill="#888"/> <rect width="15" height="15" fill="#aaa"/> <rect width="15" height="15" fill="#bbb"/> <rect width="15" height="15" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <adj:circularList rAlign="inside" gap="2" leftGap="10" topGap="10" rightGap="5" bottomGap="5"/> <circle r="20" fill="#000"/> <rect width="3" height="3" fill="#222"/> <rect width="6" height="6" fill="#444"/> <rect width="9" height="9" fill="#666"/> <rect width="12" height="12" fill="#888"/> <rect width="15" height="15" fill="#aaa"/> <rect width="18" height="18" fill="#bbb"/> <rect width="21" height="21" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="140" fill="linen"/> <g> <adj:circularList fromAngle="0" toAngle="90" packArc="true"/> <circle r="20" fill="#000"/> <rect width="3" height="3" fill="#222"/> <rect width="6" height="6" fill="#444"/> <rect width="9" height="9" fill="#666"/> <rect width="12" height="12" fill="#888"/> <rect width="36" height="36" fill="#aaa"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="90" fill="linen"/> <g> <adj:circularList fromAngle="0" toAngle="90" packArc="true" cAlign="from"/> <circle r="20" fill="#000"/> <rect width="3" height="3" fill="#222"/> <rect width="6" height="6" fill="#444"/> <rect width="9" height="9" fill="#666"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:circularList fromAngle="135" toAngle="45" dullness="0.8"/> <rect width="15" height="15" fill="#000"/> <rect width="15" height="15" fill="#222"/> <rect width="15" height="15" fill="#444"/> <rect width="15" height="15" fill="#666"/> <rect width="15" height="15" fill="#888"/> <rect width="15" height="15" fill="#aaa"/> <rect width="15" height="15" fill="#bbb"/> <rect width="15" height="15" fill="#ccc"/> </g> </svg> |
First element is trunk in the center, remaining elements are branches. First element could be an empty group.
The fractions in parameters rAlign
(radially align),
cAlign
(circumferentially align), and dullness
accept
decimal numbers, but they also recognize some symbols (strings in
JavaScript).
rAlign | inside | 0.0 |
median | 0.5 | |
outside | 1.0 | |
cAlign | from | 0.0 |
halfway | 0.5 | |
to | 1.0 | |
dullness | pointed | 0.0 |
dull | 1.0 |
Optional parameters of verticalTree
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="130" fill="linen"/> <g> <adj:verticalTree/> <text adj:id="r-1">R1</text> <text adj:id="l-1-1" adj:treeParent="r-1">L11</text> <text adj:id="n-1-2" adj:treeParent="r-1">N12</text> <text adj:id="n-1-2-1" adj:treeParent="n-1-2">N121</text> <text adj:id="l-1-2-1-1" adj:treeParent="n-1-2-1">L1211</text> <text adj:id="l-1-2-1-2" adj:treeParent="n-1-2-1">L1212</text> <text adj:id="l-1-2-2" adj:treeParent="n-1-2">L122</text> <text adj:id="l-1-3" adj:treeParent="r-1">L13</text> <line stroke="#666"> <adj:connection from="r-1%0.2,1" to="l-1-1%0.8,0"/> </line> … </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="130" fill="linen"/> <g> <adj:verticalTree autoParrots="true"/> <text adj:id="r-1">R1</text> <text adj:id="r-2">R2</text> <text adj:id="l-1-1" adj:treeParent="r-1">L11</text> <text adj:id="n-1-2" adj:treeParent="r-1">N12</text> <text adj:id="n-1-2-1" adj:treeParent="n-1-2">N121</text> <text adj:id="l-1-2-1-1" adj:treeParent="n-1-2-1">L1211</text> <text adj:id="l-1-2-1-2" adj:treeParent="n-1-2-1">L1212</text> <text adj:id="l-1-2-1-3" adj:treeParent="n-1-2-1">L1213</text> <text adj:id="l-1-2-2" adj:treeParent="n-1-2">L122</text> <text adj:id="l-1-2-3" adj:treeParent="n-1-2">L123</text> <text adj:id="l-1-3" adj:treeParent="r-1">L13</text> <line stroke="#666"> <adj:connection from="r-1%0.2,1" to="l-1-1%0.8,0"/> </line> … </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="160" fill="linen"/> <g> <adj:verticalTree autoParrots="true" hAlign="left" vAlign="0.2" gap="12"/> <text adj:id="r-1" font-size="25">R1</text> <text adj:id="r-2">R2</text> <text adj:id="l-1-1" font-size="20" adj:treeParent="r-1">L11</text> <text adj:id="n-1-2" font-size="15" adj:treeParent="r-1">N12</text> <text adj:id="n-1-2-1" font-size="12" adj:treeParent="n-1-2">N121</text> <text adj:id="l-1-2-1-1" adj:treeParent="n-1-2-1">L1211</text> <text adj:id="l-1-2-1-2" adj:treeParent="n-1-2-1">L1212</text> <text adj:id="l-1-2-1-3" adj:treeParent="n-1-2-1">L1213</text> <text adj:id="l-1-2-2" adj:treeParent="n-1-2">L122</text> <text adj:id="l-1-2-3" adj:treeParent="n-1-2">L123</text> <text adj:id="l-1-3" adj:treeParent="r-1">L13</text> <line stroke="#666"> <adj:connection from="r-1%0.2,1" to="l-1-1%0.2,0"/> </line> … </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="210" fill="linen"/> <g> <adj:verticalTree autoParrots="true" horizontalGap="15" verticalGap="30"/> <text adj:id="r-1">R1</text> <text adj:id="r-2">R2</text> <text adj:id="l-1-1" adj:treeParent="r-1">L11</text> <text adj:id="n-1-2" adj:treeParent="r-1">N12</text> <text adj:id="n-1-2-1" adj:treeParent="n-1-2">N121</text> <text adj:id="l-1-2-1-1" adj:treeParent="n-1-2-1">L1211</text> <text adj:id="l-1-2-1-2" adj:treeParent="n-1-2-1">L1212</text> <text adj:id="l-1-2-1-3" adj:treeParent="n-1-2-1">L1213</text> <text adj:id="l-1-2-2" adj:treeParent="n-1-2">L122</text> <text adj:id="l-1-2-3" adj:treeParent="n-1-2">L123</text> <text adj:id="l-1-3" adj:treeParent="r-1">L13</text> <line stroke="#666"> <adj:connection from="r-1%0.2,1" to="l-1-1%0.8,0"/> </line> … </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="210" fill="linen"/> <g> <adj:verticalTree autoParrots="true" leftGap="5" centerGap="20" rightGap="5" topGap="5" middleGap="40" bottomGap="5" childlessGap="10" earGap="30"/> <text adj:id="r-1">R1</text> <text adj:id="r-2">R2</text> <text adj:id="l-1-1" adj:treeParent="r-1">L11</text> <text adj:id="n-1-2" adj:treeParent="r-1">N12</text> <text adj:id="n-1-2-1" adj:treeParent="n-1-2">N121</text> <text adj:id="l-1-2-1-1" adj:treeParent="n-1-2-1">L1211</text> <text adj:id="l-1-2-1-2" adj:treeParent="n-1-2-1">L1212</text> <text adj:id="l-1-2-1-3" adj:treeParent="n-1-2-1">L1213</text> <text adj:id="l-1-2-2" adj:treeParent="n-1-2">L122</text> <text adj:id="l-1-2-3" adj:treeParent="n-1-2">L123</text> <text adj:id="l-1-3" adj:treeParent="r-1">L13</text> <line stroke="#666"> <adj:connection from="r-1%0.2,1" to="l-1-1%0.8,0"/> </line> … </g> </svg> |
Only layout is provided. This allows the most freedom for illustrating
anything. Examples provided here use instances of command
connection
to indicate relationships.
Relationships in verticalTree
are defined by child element
attributes adj:treeParent
pointing at their sibling element
attributes adj:id
.
Nodes intentionally are elements at the same level in SVG. To be clear: There is not SVG element nesting corresponding to the tree structure.
Multiple roots are possible.
Several optional parameters of verticalTree
are similar to
optional parameters of horizontalList
. These include
gap
, horizontalGap
, leftGap
,
centerGap
, rightGap
, verticalGap
,
topGap
, middleGap
, bottomGap
, and
vAlign
.
Parameter hAlign
aligns a node relative to its children. The
fraction in parameter hAlign
accepts decimal numbers, but it also
recognizes some symbols (strings in JavaScript), similar to parameter
hAlign
of horizontalList
.
Parameter autoParrots
lets siblings that have no child sit on
the shoulders of subtrees headed by siblings that do have children.
Parameter earGap
is in effect instead of centerGap
between the head of a subtree and its adjacent siblings if they sit on its
shoulders.
Parameter childlessGap
is in effect instead of
centerGap
when all siblings have no child.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="140" fill="linen"/> <g> <adj:horizontalTree/> <text adj:id="r-1">R1</text> <text adj:id="l-1-1" adj:treeParent="r-1">L11</text> <text adj:id="n-1-2" adj:treeParent="r-1">N12</text> <text adj:id="n-1-2-1" adj:treeParent="n-1-2">N121</text> <text adj:id="l-1-2-1-1" adj:treeParent="n-1-2-1">L1211</text> <text adj:id="l-1-2-1-2" adj:treeParent="n-1-2-1">L1212</text> <text adj:id="l-1-2-2" adj:treeParent="n-1-2">L122</text> <text adj:id="l-1-3" adj:treeParent="r-1">L13</text> <line stroke="#666"> <adj:connection from="r-1%1,0.2" to="l-1-1%0,0.8"/> </line> … </g> </svg> |
Optional parameters of horizontalTree
are very similar to
optional parameters of verticalTree
.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="180" fill="linen"/> <g> <adj:verticalTree leftGap="20" centerGap="30" childlessGap="10" middleGap="40"/> <rect adj:id="o1" width="40" height="30" fill="#000"/> <rect adj:id="o2" adj:treeParent="o1" width="30" height="20" fill="#666"/> <rect adj:id="o3" adj:treeParent="o2" width="25" height="15" fill="#888"/> <rect adj:id="o4" adj:treeParent="o2" width="25" height="15" fill="#aaa"/> <rect adj:id="o5" adj:treeParent="o1" width="30" height="20" fill="#bbb"/> <rect adj:id="o6" adj:treeParent="o5" width="25" height="15" fill="#ccc"/> <rect adj:id="o7" adj:treeParent="o5" width="25" height="15" fill="#ddd"/> </g> <path d="M0,0" stroke="#777" stroke-width="2" fill="none" adj:d="M ~o1#x - 10, ~o1#yh C ~o1#x - 10, ~o1#yh + 10 ~o2#x - 10, ~o2#y%-0.3 ~o2#x - 10, ~o2#yc S ~o3#x - 10, ~o3#y%-0.3 ~o3#x - 10, ~o3#yc C ~o3#x - 10, ~o3#yh + 10 ~o3#x, ~o3#yh + 10 ~o3#xc, ~o3#yh + 10 S ~o4#x, ~o4#yh + 10 ~o4#xc, ~o4#yh + 10 S ~o4#xw + 10, ~o4#yh + 10 ~o4#xw + 10, ~o4#yc C ~o4#xw + 10, ~o4#y * 0.5 + ~o2#yh * 0.5 ~o2#xw, ~o2#yh * 0.5 + ~o4#y * 0.5 + 10 ~o2#xw, ~o2#yh * 0.5 + ~o4#y * 0.5 S ~o2#xw, ~o2#yh * 0.5 + ~o5#yh * 0.5 + 10 ~o2#xw * 0.5 + ~o5#x * 0.5, ~o2#yh * 0.5 + ~o5#yh * 0.5 + 10"> <adj:vine/> </path> </svg> |
As implemented, vine
works for path
.
Command vine
evaluates simple arithmetic into plain decimal
numbers.
An expression ~ identifier # axis % decimal
means from the
element referenced by the identifier determine a
coordinate with 0.0
being its bounding box x
or
y
and 1.0
being its x+width
or
y+height
. With decimal number values often between 0.0 and 1.0
they also can be outside that range.
fine control, absolute x or y |
~ identifier # x % decimal |
x + decimal * width |
~ identifier # y % decimal |
y + decimal * height |
|
shortcuts, absolute x or y |
~ identifier # x |
#x%0 , left |
~ identifier # y |
#y%0 , top |
|
~ identifier # xw |
#x%1 , which would be x+width , right |
|
~ identifier # yh |
#y%1 , which would be y+height , bottom |
|
~ identifier # xc |
#x%.5 , same as #x%0.5 , which would be
x+width/2 , horizontal center |
|
~ identifier # yc |
#y%.5 , same as #y%0.5 , which would be
y+height/2 , vertical center |
|
relative w, h, or d |
~ identifier # w |
width |
~ identifier # h |
height |
|
~ identifier # d |
diagonal |
Linear polynomial expressions are evaluated with normal order of operations.
Addition +
, subtraction -
, and multiplication
*
are supported.
As an example, to get the horizontal coordinate exactly in the middle
between the right edge of element one
and the left edge of element
other
, a possible expression is
~one#xw*0.5+~other#x*0.5
. That would be the equivalent of
((one.x + one.width) + other.x) / 2
.
Parentheses are not needed and parentheses are not supported.
Command vine
also performs substitution of
variables.
-
Minus SignAfter a space separating path coordinates, one must
not start with a -
minus sign.
For example, if trying to achieve
adj:d="M 50,50 c 20,20 60,20 80,0 c -20,30 -60,30 -80,0 m 40,10 c 40,0 10,60 0,60 s -40,-60 0,-60"
the problem is Adj.evaluateArithmetic
would evaluate
adj:d="M 50,50 c 20,20 60,20 80,0 c -20,(30 -60),(30 -80),0 m 40,10 c 40,0 10,60 0,60 s -40,-60 0,-60"
which would give
adj:d="M 50,50 c 20,20 60,20 80,0 c -20,-30,-50,0 m 40,10 c 40,0 10,60 0,60 s -40,-60 0,-60"
which is not a valid path.
Therefore, one can for example write
adj:d="M 50,50 c 20,20 60,20 80,0 c -20,30 0-60,30 0-80,0 m 40,10 c 40,0 10,60 0,60 s -40,-60 0,-60"
The problem has several possible solutions.
intention, but doesn't work this way, don't do
this results in unintended evaluation, not a valid path, bad result |
c -20,30 -60,30 -80,0 c -20,-30,-50,0 |
one possibility, write extra zeros | c -20,30 0-60,30 0-80,0 |
other possibility, write extra commas | c -20,30, -60,30, -80,0 |
variations of spacing are allowed | c -20,30 , -60,30 ,-80,0 |
Command floater
required parameter at
evaluates
simple arithmetic very similar to command vine
.
An optional parameter of floater
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="160" fill="linen"/> <g> <rect adj:id="one" x="15" y="65" width="40" height="30" fill="#000"/> <rect adj:id="other" x="95" y="15" width="40" height="30" fill="#666"/> <rect adj:id="another" x="145" y="115" width="40" height="30" fill="#aaa"/> <path d="M0,0 l40,0 -20,-50 z" fill="#444"> <adj:floater pin="0.5,0" at="~one#xc*0.333+~other#xc*0.333+~another#xc*0.333,~one#yc*0.333+~other#yc*0.333+~another#yc*0.333"/> </path> </g> </svg> |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <style type="text/css"><![CDATA[ circle { stroke: black; stroke-width: 1; } ]]></style> <rect width="200" height="150" fill="linen"/> <g adj:command="horizontalList" adj:makeGrid="true" adj:maxWidth="200" adj:gap="10" adj:hAlign="center" adj:vAlign="middle"> <circle fill="#444" r="25"/> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:maxHeight="20"/> </g> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:maxWidth="40" adj:maxHeight="30"/> </g> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:maxWidth="100"/> </g> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:height="70"/> </g> <g> <circle fill="#ccc" r="25" adj:command="fit" adj:width="120" adj:height="80" adj:maxWidth="40"/> </g> </g> <g adj:command="floater" adj:at="0,0" adj:pin="0,0"> <adj:variable name="w" value="200"/> <adj:variable name="h" value="150"/> <path adj:command="vine" stroke="#777" stroke-width="1" opacity="0.2" fill="none" d=" M 0,10 h ^w M 0,20 h ^w … "/> </g> </svg> |
All command fit
parameters are optional.
Scaling is done proportionally for horizontal and vertical. Always the
smallest scale is picked to fulfill all constraints. If parameter
maxWidth
and parameter maxHeight
would cause two
different scales, the smaller scale is picked.
Other than parameters maxWidth
and maxHeight
,
parameters width
and height
can cause a scale larger
than 1.0. Parameters maxWidth
and maxHeight
never
cause an increase of scale, while parameters width
and
height
can cause an increase of scale.
Parameters maxWidth
and maxHeight
can further
constrain than parameters width
and height
, in case
they have been given along the same axis.
Optional parameters of stackFrames
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:stackFrames stacking="3, -5, 5" inset="-1"/> <rect fill="white" stroke="black" stroke-width="2" width="30" height="20"/> <ellipse cx="60" cy="40" rx="40" ry="20" fill="#666"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:stackFrames stacking="3, -5, 5" inset="-1" frame="1" subject="3"/> <circle cx="140" cy="40" r="20" fill="#000"/> <rect fill="white" stroke="black" stroke-width="2" width="60" height="20"/> <circle cx="140" cy="40" r="10" fill="#888"/> <ellipse cx="60" cy="40" rx="40" ry="20" fill="#666"/> </g> </svg> |
Optional inset
family parameters of stackFrames
are equivalent to optional inset
family parameters of frameForParent
.
Optional parameters of zoomFrames
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <rect x="5" y="5" width="30" height="20" stroke="black" stroke-width="1" fill="#000"/> <rect width="45" height="35" stroke="gray" stroke-width="1" fill="white" opacity="0.5"> <adj:zoomFrames/> </rect> <rect x="135" y="65" width="60" height="50" stroke="black" stroke-width="1" fill="#888"/> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <rect width="200" height="120" fill="linen"/> <rect x="5" y="5" width="30" height="20" stroke="black" stroke-width="1" fill="#000" adj:id="small"/> <rect x="155" y="5" width="40" height="30" stroke="black" stroke-width="1" fill="#444"/> <rect x="5" y="75" width="50" height="40" stroke="black" stroke-width="1" fill="#666"/> <rect width="45" height="35" stroke="lightgray" stroke-width="1" fill="white" opacity="0.75"> <adj:zoomFrames adj:from="small" adj:step="20"/> </rect> <rect x="135" y="65" width="60" height="50" stroke="black" stroke-width="1" fill="#888"/> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <rect width="200" height="120" fill="linen"/> <rect x="5" y="5" width="30" height="20" stroke="black" stroke-width="1" fill="#000"/> <rect width="45" height="35" stroke="gray" stroke-width="1" fill="none"> <adj:zoomFrames adj:to="big" adj:step="60"/> </rect> <rect x="155" y="5" width="40" height="30" stroke="black" stroke-width="1" fill="#444"/> <rect x="5" y="75" width="50" height="40" stroke="black" stroke-width="1" fill="#666"/> <rect x="135" y="65" width="60" height="50" stroke="black" stroke-width="1" fill="#888" adj:id="big"/> </svg> |
Optional parameters of tilt
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g adj:command="skimpyList"> <g> <rect width="50" height="70" stroke="black" stroke-width="1" fill="#888"> <adj:tilt alpha="15"/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g adj:command="skimpyList"> <g> <rect width="90" height="60" stroke="black" stroke-width="1" fill="#888"> <adj:tilt alpha="15" beta="10"/> </rect> </g> </g> </svg> |
Different than with other lists, within pinnedList
respective
placement parameters pinThis
and pinTo
are found
within individual elements of the list. By allowing pinning to hinge on
elements further nested inside elements of the list, this works great for
isometric drawings.
Optional parameters of pinnedList
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:pinnedList/> <g> <rect width="40" height="40" stroke="black" stroke-width="1" fill="#aaa" adj:id="top"> <adj:tilt alpha="30" beta="60"/> </rect> </g> <g adj:pinThis="front % 0.5, 0.0" adj:pinTo="top % 0.5, 1.0"> <rect width="40" height="40" stroke="black" stroke-width="1" fill="#888" adj:id="front"> <adj:tilt alpha="30"/> </rect> </g> <g adj:pinThis="side % 0.5, 0.0" adj:pinTo="top % 1.0, 0.5"> <rect width="40" height="40" stroke="black" stroke-width="1" fill="#666" adj:id="side"> <adj:tilt alpha="-30"/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g adj:command="pinnedList" adj:gap="10"> <g> <rect width="40" height="40" stroke="black" stroke-width="1" fill="#aaa" adj:tilt="true" adj:alpha="30" adj:beta="60" adj:id="top"/> </g> <g adj:pinThis="front % 0.5, 0.0" adj:pinTo="top % 0.5, 1.0"> <rect width="40" height="40" stroke="black" stroke-width="1" fill="#888" adj:tilt="true" adj:alpha="30" adj:id="front"/> </g> <g adj:pinThis="side % 0.5, 0.0" adj:pinTo="top % 1.0, 0.5"> <rect width="40" height="40" stroke="black" stroke-width="1" fill="#666" adj:tilt="true" adj:alpha="30" adj:id="side"/> </g> </g> </svg> |
Optional parameters gap
, horizontalGap
,
leftGap
, rightGap
, verticalGap
,
topGap
, bottomGap
are equivalent to optional
parameters of horizontalList
, yet effecting
padding for the whole list only rather than between elements.
Different than with other trees or lists, within telescopicTree
placement is mostly defined by optional boom
elements listed
between individual elements of the tree.
Optional parameters of telescopicTree
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="170" fill="linen"/> <g> <adj:telescopicTree gap="5"/> <rect width="30" height="20" fill="#000" adj:id="id1"/> <adj:boom/> <rect width="32" height="22" fill="#222"/> <adj:boom angle="east"/> <rect width="34" height="24" fill="#444"/> <adj:boom from="id1" angle="90" gap="15"/> <rect width="36" height="26" fill="#666" adj:id="id2"/> <adj:boom angle="10"/> <rect width="38" height="28" fill="#888"/> <rect width="40" height="30" fill="#aaa"/> <adj:boom from="id2%0.5,1" to="0.5,0" angle="100" gap="~id2#h * 0.5"/><!-- --> <rect width="42" height="32" fill="#bbb"/> <adj:boom angle="-10"/> <rect width="44" height="34" fill="#ccc"/> <adj:boom angle="10"/> <rect width="46" height="36" fill="#ddd"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="150" fill="linen"/> <g> <adj:telescopicTree gap="5" from="0,0" to="0,0"/> <rect width="30" height="20" fill="#000" adj:id="id1"/> <adj:boom angle="east"/> <rect width="32" height="22" fill="#222"/> <rect width="34" height="24" fill="#444"/> <adj:boom from="id1" angle="south" gap="15"/> <rect width="36" height="26" fill="#666" adj:id="id2"/> <adj:boom angle="east"/> <rect width="38" height="28" fill="#888"/> <rect width="40" height="30" fill="#aaa"/> <adj:boom from="id2" angle="south" gap="15"/> <rect width="42" height="32" fill="#bbb"/> <adj:boom angle="east"/> <rect width="44" height="34" fill="#ccc"/> <rect width="46" height="36" fill="#ddd"/> </g> </svg> |
Optional telescopicTree
parameter gap
is the
default value for boom
parameter gap
.
Optional telescopicTree
parameters from
and
to
are default values for boom
parameters
from
and to
. They default to middle
0.5,0.5
. An identifier must not be given to
telescopicTree
parameters from
and
to
.
When no boom
is specificed between two elements, the most
recent angle
and gap
will be used again.
If not given an identifier, optional boom
parameter
from
defaults to the preceeding element, which commonly can be
anonymous. An identifier must not be given to optional boom
parameter to
, which always implies the following element.
The degree value of boom
parameter angle
accepts
decimal numbers, but also recognizes some symbols (strings in JavaScript).
angle | east | 0 |
south | 90 | |
west | 180 | |
north | 270 |
This at first experimental command works great for a number of uses.
Another example of command telescopicTree
is 075-002.
As implemented, command telescopicTree
may still be subject to
minor changes in how it places under some circumstances, because the
implementation at the time has been optimized for speed rather than ideal
coverage of all possible cases.
Optional parameters of paragraph
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:verticalList/> <text adj:command="paragraph" adj:maxWidth="155"> This is a sentence of text that will wrap. Here is more. </text> <rect fill="none" stroke="lightgray" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:verticalList gap="15"/> <text> <adj:paragraph maxWidth="160" lineGap="2" hAlign="center"/> Source line one is here, source line <tspan font-style="italic">t<tspan font-weight="bolder">w</tspan>o</tspan> is <a xlink:href="#"><tspan fill="blue">here</tspan></a> too. And then there is more text.</text> <rect fill="none" stroke="lightgray" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:verticalList/> <text adj:command="paragraph" adj:maxWidth="160" adj:indent="8"> This is a sentence of text that will wrap with the first line indented. </text> <rect fill="none" stroke="lightgray" stroke-width="2" width="0" height="0"> <adj:frameForParent inset="1"/> </rect> </g> </svg> |
The fraction in parameter hAlign
accepts decimal numbers, but
it also recognizes some symbols (strings in JavaScript), similar to parameter
hAlign
of horizontalList
.
As implemented, command paragraph
handles nested
tspan
and a
. It is not
known to handle tref
, altGlyph
, or
textPath
.
A known workaround: As implemented, it is known that extraneous whitespace
near a hyperlink a
element can cause line height calculation on
Firefox to be wrong. The workaround is not to have extraneous whitespace near a
hyperlink a
element inside a text
element which uses
command paragraph
.
Command pathArrow
takes a path given as arrow shape and
stretches and bends its shaft along another path given to follow.
The path given as arrow shape has to be defined clockwise:
l0,0
, thenl0,0
, thenl0,0
, thenThe distance between the nock's two points of connection to the shaft must be equal to the distance between the point's two points of connection to the shaft.
Optional parameters of pathArrow
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="80" fill="linen"/> <path d="M15,20 q30,0 30,30 l50,0 30,-30 30,0" stroke="none" fill="none"/> <path d="M0,0" adj:d="M50,25 l5,-5 ,-5,-5 0,0 20,0 0,0 5,5 ,-5,5 0,0 z" stroke="black" stroke-width="1" fill="white"> <adj:pathArrow/> </path> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="80" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#444"/> <rect adj:id="other" x="145" y="35" width="40" height="30" fill="#aaa"/> <path d="M15,50 q40,-15 80,0" stroke="none" fill="none"> <adj:connection from="one % 1, 0.5" to="other % 0, 0.5"/> </path> <path d="M0,0" adj:d="M50,60 l-5,5 ,-15,0 10,-10 ,-10,-10 15,0 5,5 0,0 30,0 0,0 0,-5 20,10 ,-20,10 0,-5 0,0 ,-30,0 z" stroke="black" stroke-width="1" fill="white"> <adj:pathArrow setback="10"/> </path> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="80" fill="linen"/> <path d="M15,20 c20,0 30,10 30,30 h20 v-30 q30,0 45,15 t45,15" stroke="none" fill="none" transform="translate(0,15) rotate(-10)"/> <path d="M0,0" adj:d="M50,25 c3,0 5,-2 5,-5 s-2,-5 ,-5,-5 l0,0 20,0 0,0 q5,0 5,5 t-5,5 l0,0 z" stroke="black" stroke-width="1" fill="white"> <adj:pathArrow nockSetback="-2" pointSetback="3"/> </path> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="80" fill="linen"/> <path d="M0,0" adj:d="M50,25 l0,-10 0,0 20,0 0,0 0,10 0,0 z" stroke="black" stroke-width="1" fill="white"> <adj:pathArrow path="p1"/> </path> <path adj:id="p1" d="M15,20 C35,20 45,30 45,50 H65 V20 c30,0 30,0 45,15 s15,15 45,15" stroke="none" fill="none"/> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="80" fill="linen"/> <adj:variable name="ratio" value="0.5"/> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#444"/> <rect adj:id="other" x="145" y="35" width="40" height="30" fill="#aaa"/> <path d="M15,50 q40,-15 80,0" stroke="none" fill="none"> <adj:connection from="one % 0.8, 0.5" to="other % 0.2, 0.5"/> </path> <path d="M0,0" adj:d="M50,25 l0,-~one#h*^ratio 0,0 20,0 0,0 0,~one#h*^ratio 0,0 z" stroke="gray" stroke-width="1" fill="white" opacity="0.75"> <adj:pathArrow/> </path> </svg> |
Optionally, command pathArrow
for coordinates of the shape of
the nock and the point of the arrow can evaluate simple arithmetic into plain
decimal numbers, similar to command vine
.
Same caveat regarding -
minus sign
applies.
For best results, to avoid unintended application of respectively different
transformations, the path given to follow and the path
given as arrow shape often should be together inside the same
SVG group element g
, even if this is the only raison
d'être for that group.
Optional parameters of rcGrid
:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="170" fill="linen"/> <g> <adj:rcGrid/> <g adj:rcGridPart="row"> <circle r="10" fill="none" stroke="#000"/> <circle r="4" fill="#222"/> <circle r="6" fill="#444"/> <circle r="8" fill="#666"/> <circle r="10" fill="#888"/> </g> <g adj:rcGridPart="column"> <rect width="10" height="10" fill="#000"/> <rect width="14" height="12" fill="#222"/> … </g> … <g adj:rcGridPart="column"/> <g adj:rcGridPart="column"> <rect width="22" height="16" fill="#000"/> … </g> <g adj:rcGridPart="row"> <g/> <circle r="4" fill="#222"/> <circle r="6" fill="#444"/> … </g> … </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="200" fill="linen"/> <g> <adj:rcGrid rcGridPart="column" gap="5"/> <rect fill="#fff" width="0" height="0"> <adj:frameForParent/> </rect> <g adj:rcGridPart="row" adj:vAlign="bottom"> <circle r="10" fill="none" stroke="#000"/> <circle r="4" fill="#222"/> … </g> <g adj:rcGridPart="column" adj:hAlign="right"> <rect fill="#eee" width="0" height="0"> <adj:frameForParent/> </rect> <rect width="10" height="10" fill="#000"/> <rect width="14" height="12" fill="#222"/> … </g> <g adj:hAlign="left"> … </g> … <g adj:rcGridPart="column" adj:cellLeftGap="10" adj:cellRightGap="2" adj:cellTopGap="8" adj:cellBottomGap="2"> <rect width="26" height="18" fill="#000"/> … </g> … </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="140" fill="linen"/> <g> <adj:rcGrid gap="5"/> <g adj:vAlign="bottom"> <circle r="10" fill="none" stroke="#000"/> <circle r="4" fill="#222"/> <circle r="6" fill="#444"/> </g> <adj:rcGridCellTemplates> <adj:rcGridCellTemplate hAlign="right"/> <adj:rcGridCellTemplate hAlign="left"/> </adj:rcGridCellTemplates> <g> <rect width="10" height="10" fill="#000"/> <rect width="14" height="12" fill="#000"/> <rect width="18" height="14" fill="#000"/> </g> <g> <rect width="14" height="12" fill="#222"/> <rect width="18" height="14" fill="#222"/> <rect width="22" height="16" fill="#222"/> </g> … <adj:rcGridCellTemplates/> <g> <circle r="10" fill="none" stroke="#000"/> <circle r="4" fill="#222"/> <circle r="6" fill="#444"/> </g> </g> </svg> |
An adj:rcGrid
group element g
must have children
which are group elements g
with attribute
adj:rcGridPart
having value row
or
column
.
Optional parameters gap
, horizontalGap
,
leftGap
, centerGap
, rightGap
,
verticalGap
, topGap
, middleGap
,
bottomGap
, hAlign
, vAlign
are similar to
optional parameters of horizontalList
.
Optional parameters hAlign
, vAlign
,
cellLeftGap
, cellRightGap
, cellTopGap
,
cellBottomGap
, rcGridPart
can be specified per grid
and per grid part. Per part specification, if present, overrides whole grid
specification.
Optional elements adj:rcGridCellTemplates
listing elements
adj:rcGridCellTemplate
are in effect for following parts until the
next switch between row
and column
either way.
Optional parameters hAlign
, vAlign
,
cellLeftGap
, cellRightGap
, cellTopGap
,
cellBottomGap
, can be specified per
adj:rcGridCellTemplate
. Per cell template specification, if
present, overrides per part specification. Lack of specification means a level
up is in effect, up to default values. Consequentially an empty
adj:rcGridCellTemplates
can be used to end the effect of an
earlier adj:rcGridCellTemplates
.
Rules of combination are defined by implementation.
Another example of command rcGrid
is in 090-002.
TODO: neat examples
Optional parameters of sliderKnob
:
You can view the
SVG by itself and drag
the |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="80" fill="linen"/> <g transform="translate(20,20)"> <rect x="0" y="0" width="140" height="20" fill="white" stroke="dimgrey"/> <rect x="6" y="6" width="128" height="8" fill="lightgrey" stroke="dimgrey"/> <g> <adj:sliderKnob/> <rect x="0" y="0" width="20" height="20" fill="gainsboro" stroke="black"/> <rect x="3" y="3" width="14" height="14" fill="lightgrey" stroke="none"/> </g> </g> <text id="setme" style="font-size:10;font-family:sans-serif;" transform="translate(20,60)">0</text> <script><![CDATA[ document.addEventListener("change", function (event) { var elementToSet = document.getElementById("setme"); elementToSet.textContent = event.detail.value; Adj.doSvg(); }); ]]></script> </svg> |
You can view the
SVG by itself and
drag the |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="160" fill="linen"/> <g> <adj:verticalList gap="20" hAlign="center"/> <g> <rect x="0" y="0" width="140" height="20" rx="10" ry="10" fill="white" stroke="dimgrey"/> <rect x="6" y="6" width="128" height="8" rx="4" ry="4" fill="lightgrey" stroke="dimgrey"/> <g> <adj:sliderKnob min="0.3" max="5.0" step="0.1" preset="2.0"/> <rect x="0" y="0" width="20" height="20" rx="10" ry="10" fill="gainsboro" stroke="black"/> <rect x="7" y="3" width="6" height="14" rx="3" ry="7" fill="lightgrey" stroke="none"/> </g> </g> <g id="setme"> <adj:horizontalList gap="2" itemsH2V="2"/> <rect width="10" height="10" fill="#000" transform="translate(2,2)"/> <rect width="10" height="10" fill="#111" transform="translate(14,2)"/> <rect width="10" height="10" fill="#222" transform="translate(26,2)"/> … </g> </g> <script><![CDATA[ document.addEventListener("change", function (event) { var elementToSet = document.getElementById("setme").firstElementChild; elementToSet.setAttribute("itemsH2V", event.detail.value); Adj.doSvg(); }); ]]></script> </svg> |
The knob moves within the rectangular size of its parent element, the
slider. The slider's size for example may be defined by the size of a child
rect
, a sibling of the knob.
There is no default look of sliders and knobs made with
sliderKnob
. An author has broad freedom of choice.
More examples of command sliderKnob
are 093-001, and 093-003.
TODO: better document command sliderKnob, event, nesting in slider, widths and heights of groups, many appearances possible, detection of horizontal or vertical
Optional parameters of toggleButton
:
You can view the
SVG by itself and
click the |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="140" fill="linen"/> <g> <adj:skimpyList/> <g> <rect width="70" height="100" stroke="black" stroke-width="1" fill="darkgrey"/> <g> <adj:tilt alpha="0"/> <rect width="70" height="100" stroke="dimgrey" stroke-width="1" fill="lightgrey"/> <g adj:id="lockIt"> <adj:floater at="45,50"/> <adj:toggleButton/> <path adj:alternativeValue="lock" title="click to flip" d="M0,0 l0,-30 30,0 0,30 z M5,-30 l0,-10 q0,-10 10,-10 10,0 10,10 … z" fill="darkgrey" stroke="black"/> <path adj:alternativeValue="unlock" title="click to flip" d="M0,0 l0,-30 30,0 0,30 z M22,-30 l0,-10 q0,-10 10,-10 10,0 10,10 … z" fill="darkgrey" stroke="black"/> </g> </g> </g> </g> <script><![CDATA[ Adj.getElementById("lockIt").addEventListener("change", function (event) { var newToggle = event.detail.value; document.querySelector("[alpha]").setAttribute("alpha", newToggle === "lock" ? "0" : "15"); Adj.doSvg(); }); ]]></script> </svg> |
You can view the
SVG by
itself and click the |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <defs> <radialGradient id="rg" gradientUnits="objectBoundingBox" cx="50%" cy="50%" r="50%"> <stop stop-color="#0000FF" offset="0"/> <stop stop-color="#ffff00" offset="1"/> </radialGradient> </defs> <g> <adj:verticalList gap="20"/> <g adj:id="switchIt"> <adj:horizontalList gap="0" centerGap="5" vAlign="middle"/> <adj:toggleButton preset="white" congruent="true"/> <rect adj:alternativeValue="white" title="click to switch" width="12" height="12" fill="white" stroke="dimgrey"/> <rect adj:alternativeValue="grey" title="click to switch" width="12" height="12" fill="grey" stroke="dimgrey"/> <rect adj:alternativeValue="colorful" title="click to switch" width="12" height="12" fill="url(#rg)" stroke="dimgrey"/> <rect adj:alternativeValue="black" title="click to switch" width="12" height="12" fill="black" stroke="dimgrey"/> <text>switch</text> </g> <rect adj:id="switchThis" width="40" height="20" fill="white" stroke="dimgrey"/> </g> <script><![CDATA[ Adj.getElementById("switchIt").addEventListener("change", function (event) { var newToggle = event.detail.value; var alternativeValueElement = Adj.getElementById("switchIt").adjS.toggleButtonRecord.getAlternative(newToggle); Adj.getElementById("switchThis").setAttribute("fill", alternativeValueElement.getAttribute("fill")); }); ]]></script> </svg> |
Optional boolean parameter congruent
should be set
true
if and only if all alternatives in their own coordinate
system have the same location and size, e.g. all x=0, y=0, width=12, height=12.
One benefit is avoiding on change an automatic invocation of
Adj.doSvg()
, which may or may not matter to an author. It is OK to
not use parameter congruent
.
Another example of command toggleButton
is in 087-001.
TODO: better document command toggleButton, event, many appearances possible, detection of value, alternative
Command hide
has no options:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:horizontalList gap="5"/> <rect width="45" height="30" fill="#000"/> <rect width="40" height="25" fill="#444" adj:hide="true"/> <rect width="35" height="20" fill="#888"/> </g> </svg> |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj" xmlns:xlink="http://www.w3.org/1999/xlink"> <rect width="200" height="140" fill="linen"/> <g adj:command="horizontalList" adj:gap="2" adj:itemsH2V="1"> <rect width="40" height="80" fill="#222"/> <g> <adj:include xlink:href="subdir-080/adj-ex-080-include-to-include.svg"/> </g> <rect width="40" height="40" fill="#444"/> <rect width="80" height="40" fill="#888"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj" xmlns:xlink="http://www.w3.org/1999/xlink"> <rect width="200" height="140" fill="linen"/> <g adj:command="horizontalList" adj:gap="2" adj:itemsH2V="1"> <rect width="40" height="80" fill="#222"/> <g> <adj:include xlink:href="subdir-080/adj-ex-080-include-to-include.svg#four"/> </g> <rect width="40" height="40" fill="#444"/> <rect width="80" height="40" fill="#888"/> </g> </svg> |
Command include
parameter xlink:href
is required.
Note the required XLink namespace, as
is commonly used in SVG.
Command include
causes asynchronous execution when invoking
Adj.doSvg()
.
There is or should be no problem, no special attention required, with
http
links on the same server.
As implemented, include
is subject to browser imposed
restrictions of cross-origin HTTP requests, via XMLHttpRequest
. A
mechanism often used in this context is Cross-Origin Resource Sharing (CORS).
For best productivity when using URI scheme file
, a Firefox
add-on File URI Scheme GET from Page Script,
from https://addons.mozilla.org/en-US/firefox/addon/file-scheme-get-from-script/, e.g. 1.0.4, is available.
Notably, the same document can be stored without (before) or with the result of (after) invoking
Adj. If inspecting in browser development tools, with command
include
a large difference in verbosity and hence size between
such two documents as stored should be easy to recognize by viewing the sources
of the documents respectively. Once processed by Adj, which in case there is a
command include
may mostly be paced by time it takes to remotely
get an included document, once processed by Adj the two versions of the
document should be identical. Their DOM trees then should be identical.
Adj command include
has been implemented if so stored then to
display the stored included result of an earlier invocation, until a current
inclusion completes successfully. This should give greater certainty that
something useful will be displayed even in case the origin of an inclusion
becomes unavailable.
An optional parameter explain
inserts explanatory elements.
As implemented, explain
inserts explanatory elements for
verticalList
, horizontalList
,
connection
, rider
, circularList
,
verticalTree
, vine
, floater
,
telescopicTree
, paragraph
, pathArrow
,
and rcGrid
.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> … <g> <adj:horizontalList makeGrid="true" gap="5" maxPerRow="3" hAlign="center" explain="true"/> <g adj:id="subject-editor"> <adj:horizontalList gap="10"/> <rect width="0" height="0" class="subject"> <adj:frameForParent inset="1"/> </rect> <text>XML editor</text> </g> <g/> … </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#aaa"/> <rect adj:id="other" x="145" y="55" width="40" height="30" fill="#ccc"/> <path d="M5,100 q40,10 80,0 t80,0" stroke="#666" stroke-width="2" fill="none"> <adj:connection from="one%1,0.5" to="other%0,0.5" explain="true"/> </path> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#ddd"/> <rect x="85" y="15" width="40" height="30" fill="#ccc"/> <rect x="25" y="45" width="40" height="30" fill="#ccc"/> <rect adj:id="other" x="145" y="75" width="40" height="30" fill="#bbb"/> <g> <adj:connection from="one%1,0.5" to="other%0,0.5"/> <path d="M45,20q19.265,25.692 50,35t50,35" stroke="#666" stroke-width="2" fill="none"/> <rect width="30" height="20" fill="#aaa"> <adj:rider at="0.2,0.7" adjust="near" gap="2" explain="true"/> </rect> </g> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:circularList rAlign="inside" gap="2" explain="true"/> <circle r="20" fill="#000"/> <rect width="3" height="3" fill="#222"/> <rect width="6" height="6" fill="#444"/> <rect width="9" height="9" fill="#666"/> <rect width="12" height="12" fill="#888"/> <rect width="15" height="15" fill="#aaa"/> <rect width="18" height="18" fill="#bbb"/> <rect width="21" height="21" fill="#ccc"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="160" fill="linen"/> <g> <adj:verticalTree autoParrots="true" hAlign="0.1" vAlign="0.2" gap="12" explain="true"/> <text adj:id="r-1" font-size="20">R1</text> <text adj:id="r-2">R2</text> <text adj:id="l-1-1" font-size="20" adj:treeParent="r-1">L11</text> <text adj:id="n-1-2" font-size="15" adj:treeParent="r-1">N12</text> <text adj:id="n-1-2-1" font-size="12" adj:treeParent="n-1-2">N121</text> <text adj:id="l-1-2-1-1" adj:treeParent="n-1-2-1">L1211</text> <text adj:id="l-1-2-1-2" adj:treeParent="n-1-2-1">L1212</text> <text adj:id="l-1-2-1-3" adj:treeParent="n-1-2-1">L1213</text> <text adj:id="l-1-2-2" adj:treeParent="n-1-2">L122</text> <text adj:id="l-1-2-3" adj:treeParent="n-1-2">L123</text> <text adj:id="l-1-3" adj:treeParent="r-1">L13</text> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="180" fill="linen"/> <g> <adj:verticalTree leftGap="20" centerGap="30" childlessGap="10" middleGap="40"/> <rect adj:id="o1" width="40" height="30" fill="#000"/> <rect adj:id="o2" adj:treeParent="o1" width="30" height="20" fill="#666"/> <rect adj:id="o3" adj:treeParent="o2" width="25" height="15" fill="#888"/> <rect adj:id="o4" adj:treeParent="o2" width="25" height="15" fill="#aaa"/> <rect adj:id="o5" adj:treeParent="o1" width="30" height="20" fill="#bbb"/> <rect adj:id="o6" adj:treeParent="o5" width="25" height="15" fill="#ccc"/> <rect adj:id="o7" adj:treeParent="o5" width="25" height="15" fill="#ddd"/> </g> <path d="M0,0" stroke="#777" stroke-width="2" fill="none" adj:d="M ~o1#x - 10, ~o1#yh C ~o1#x - 10, ~o1#yh + 10 ~o2#x - 10, ~o2#y%-0.3 ~o2#x - 10, ~o2#yc S ~o3#x - 10, ~o3#y%-0.3 ~o3#x - 10, ~o3#yc C ~o3#x - 10, ~o3#yh + 10 ~o3#x, ~o3#yh + 10 ~o3#xc, ~o3#yh + 10 S ~o4#x, ~o4#yh + 10 ~o4#xc, ~o4#yh + 10 S ~o4#xw + 10, ~o4#yh + 10 ~o4#xw + 10, ~o4#yc C ~o4#xw + 10, ~o4#y * 0.5 + ~o2#yh * 0.5 ~o2#xw, ~o2#yh * 0.5 + ~o4#y * 0.5 + 10 ~o2#xw, ~o2#yh * 0.5 + ~o4#y * 0.5 S ~o2#xw, ~o2#yh * 0.5 + ~o5#yh * 0.5 + 10 ~o2#xw * 0.5 + ~o5#x * 0.5, ~o2#yh * 0.5 + ~o5#yh * 0.5 + 10"> <adj:vine explain="true"/> </path> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="160" fill="linen"/> <g> <rect adj:id="one" x="15" y="65" width="40" height="30" fill="#000"/> <rect adj:id="other" x="95" y="15" width="40" height="30" fill="#666"/> <rect adj:id="another" x="145" y="115" width="40" height="30" fill="#aaa"/> <path d="M0,0 l40,0 -20,-50 z" fill="#ccc"> <adj:floater pin="0.5,0" at="~one#xc*0.333+~other#xc*0.333+~another#xc*0.333,~one#yc*0.333+~other#yc*0.333+~another#yc*0.333" explain="true"/> </path> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="170" fill="linen"/> <g> <adj:telescopicTree gap="5" explain="true"/> <rect width="30" height="20" fill="#000" adj:id="id1"/> <adj:boom/> <rect width="32" height="22" fill="#222"/> <adj:boom angle="east"/> <rect width="34" height="24" fill="#444"/> <adj:boom from="id1" angle="90" gap="15"/> <rect width="36" height="26" fill="#666" adj:id="id2"/> <adj:boom angle="10"/> <rect width="38" height="28" fill="#888"/> <rect width="40" height="30" fill="#aaa"/> <adj:boom from="id2%0.5,1" to="0.5,0" angle="100" gap="~id2#h * 0.5"/><!-- --> <rect width="42" height="32" fill="#bbb"/> <adj:boom angle="-10"/> <rect width="44" height="34" fill="#ccc"/> <adj:boom angle="10"/> <rect width="46" height="36" fill="#ddd"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:verticalList/> <text adj:command="paragraph" adj:maxWidth="155" adj:explain="true"> This is a sentence of text that will wrap. Here is more. </text> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="80" fill="linen"/> <rect adj:id="one" x="5" y="5" width="40" height="30" fill="#444"/> <rect adj:id="other" x="145" y="35" width="40" height="30" fill="#aaa"/> <path d="M15,50 q40,-15 80,0" stroke="none" fill="none"> <adj:connection from="one % 1, 0.5" to="other % 0, 0.5"/> </path> <path d="M0,0" adj:d="M50,60 l-5,5 ,-15,0 10,-10 ,-10,-10 15,0 5,5 0,0 30,0 0,0 0,-5 20,10 ,-20,10 0,-5 0,0 ,-30,0 z" stroke="black" stroke-width="1" fill="white"> <adj:pathArrow setback="10" explain="true"/> </path> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="170" fill="linen"/> <g> <adj:rcGrid explain="true"/> <g adj:rcGridPart="row"> <circle r="10" fill="none" stroke="#000"/> <circle r="4" fill="#222"/> <circle r="6" fill="#444"/> <circle r="8" fill="#666"/> <circle r="10" fill="#888"/> </g> <g adj:rcGridPart="column"> <rect width="10" height="10" fill="#000"/> <rect width="14" height="12" fill="#222"/> … </g> … </g> </svg> |
Similar to optional parameter explain
,
command explain
inserts explanatory elements for an SVG
path
element.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <path stroke="#777" stroke-width="2" fill="none" d="M 20,20 c 20,20 60,20 80,0 c -20,30 -60,30 -80,0 m 40,10 c 40,0 10,60 0,60 s -40,-60 0,-60"> <adj:explain/> </path> </svg> |
Command relativate
converts the coordinates of a path into
relative coordinates. Can be useful when editing.
Command skimpyList
may be easier to comprehend than would be
similar use of horizontalList
for a single
element. One use may be to align to 0,0
the top left corner of an
Adj modified SVG element which has no further Adj modified SVG ancestors. Can
be useful when top left corner coordinates are not easily known at the time of
authoring, e.g. when using tilt
.
Slightly different for multiple elements.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g adj:command="skimpyList"> <rect x="-30" y="-20" width="80" height="30" stroke="black" stroke-width="1" fill="#666"/> <rect x="30" y="20" width="80" height="30" stroke="black" stroke-width="1" fill="#aaa"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g adj:command="skimpyList" adj:gap="10"> <rect adj:command="frameForParent" fill="none" stroke="black" stroke-width="1" width="60" height="40"/> <rect x="-30" y="-20" width="80" height="30" stroke="black" stroke-width="1" fill="#666"/> <rect x="30" y="20" width="80" height="30" stroke="black" stroke-width="1" fill="#aaa"/> </g> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <g> <adj:skimpyList minWidth="100" minHeight="40" hAlign="left" vAlign="middle"/> <rect fill="white" stroke="black" stroke-width="1" width="20" height="5"><adj:frameForParent/></rect> <text>Joe</text> </g> </svg> |
Optional parameters gap
, horizontalGap
,
leftGap
, rightGap
, verticalGap
,
topGap
, bottomGap
, hAlign
, vAlign
are equivalent to optional parameters of
horizontalList
, yet effecting
padding for the whole list only rather than between elements.
Auxiliary function Adj.toggleHide(element)
hides or unhides an
element.
As implemented, toggleHide
inserts or removes an instance of
command hide
.
An optional second parameter tells whether to invoke
Adj.doSvg()
.
Similarly there are functions Adj.hide(element)
and
Adj.unhide(element)
.
Auxiliary function toggleHideSiblingsFollowing
hides or unhides
siblings.
As implemented, toggleHideSiblingsFollowing
inserts or removes
instances of command hide
.
You can view the
SVG by itself and
click elements having |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="120" fill="linen"/> <g adj:command="horizontalList" adj:gap="5"> <rect class="frame" adj:command="frameForParent" width="0" height="0"/> <g adj:command="verticalList"> <rect class="frame" adj:command="frameForParent" width="0" height="0"/> <text class="heading" onclick="Adj.toggleHideSiblingsFollowing(this, true);">fruits</text> <text>apple</text> <text>banana</text> <text>cantaloupe</text> </g> <g adj:command="verticalList"> <rect class="frame" adj:command="frameForParent" width="0" height="0"/> <text class="heading" onclick="Adj.toggleHideSiblingsFollowing(this, true);">vegetables</text> <text>asparagus</text> <text>beet</text> <text>cauliflower</text> </g> </g> </svg> |
The optional second parameter tells whether to invoke
Adj.doSvg()
.
Similarly there are functions hideSiblingsFollowing
and
unhideSiblingsFollowing
.
Using identifier attribute adj:id
is simple.
In contrast, here it is explained with more correctness, completeness, and detail than you were hoping for.
Some commands refer to elements by identifier. These include:
connection |
parameters from and to |
rider |
parameter path |
verticalTree |
child element attribute adj:treeParent |
horizontalTree |
child element attribute adj:treeParent |
vine |
when evaluating element attribute adj:d |
floater |
when evaluating parameter at |
fit |
when evaluating parameters width , height ,
maxWidth , maxHeight |
telescopicTree |
a boom element's parameter from |
pathArrow |
parameter path , and when evaluating element attribute
adj:d |
include |
in case element attribute xlink:href references a
fragment in another document |
The recommended kind of identifier to use is attribute
adj:id
.
For attribute adj:id
there is no strict
uniqueness requirement. At least not per document. Hence,
adj:id
is not of XML attribute type
ID
. Values of attribute adj:id
should match the XML
Name production.
In addition, Adj version 3.3 still recognizes plain id
attributes. Future versions of Adj may or may not recognize plain
id
attributes for identifying elements to commands.
As implemented, some commands are using JavaScript
functionAdj.getElementByIdNearby
. These include:
connection |
parameters from and to |
rider |
parameter path |
vine |
when evaluating element attribute adj:d |
floater |
when evaluating parameter at |
fit |
when evaluating parameters width , height ,
maxWidth , maxHeight |
pathArrow |
parameter path , and when evaluating element attribute
adj:d |
include |
in case element attribute xlink:href references a
fragment in another document |
Function Adj.getElementByIdNearby
finds the element with a
given identifier that is nearest to the referencing element, rather than
another element with the same identifier that is further away in the same
document.
A simplified description of an implementation goes: If there is more than one element with the same identifier, then for each of those elements with the same identifier their respective common ancestor with the referencing element is determined, and the one which is the least number of steps away is it.
One benefit is, when copying a fragment of SVG and pasting it into the same document, references to "nearby" elements within the same structure should still resolve as one could intuitively expect – to nearby elements. Hence, graphics structures with Adj commands referring to "nearby" elements within the same structure should remain intact, even when pasting another copy into the same document.
Authors could be less worried when creating large documents, by hand or from a script. Multiple copies of the same structure should not require fixing up identifiers that are used only within such structure.
An illustration of function Adj.getElementByIdNearby
finding
instances of attribute adj:id
:
Command verticalTree
child element attribute
adj:treeParent
is only looking for identifiers among siblings of
the referencing element. That is more narrow of a search than function
Adj.getElementByIdNearby
.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="100" fill="linen"/> <adj:variable name="myvar" value="10" desc="optional description of variable"/> <rect adj:id="one" x="15" y="45" width="40" height="10" fill="#000"/> <rect adj:id="other" x="95" y="15" width="40" height="10" fill="#666"/> <rect adj:id="another" x="145" y="75" width="40" height="10" fill="#aaa"/> <path adj:command="vine" stroke="#777" stroke-width="2" fill="none" d="M0,0" adj:d=" M ~one#xw + ^myvar, ~one#yc C ~one#xw + ^myvar, ~one#yc - 20 ~other#xc - 20, ~other#yh + ^myvar ~other#xc, ~other#yh + ^myvar S ~another#x - ^myvar, ~another#yc - 20 ~another#x - ^myvar, ~another#yc"/> </svg> |
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj"> <rect width="200" height="200" fill="linen"/> <adj:variable name="myvar" value="10" desc="in outer scope"/> <g> <adj:variable name="myvar" value="3" desc="in inner scope #1"/> <rect adj:id="one" x="15" y="45" width="40" height="10" fill="#000"/> <rect adj:id="other" x="95" y="15" width="40" height="10" fill="#666"/> <rect adj:id="another" x="145" y="75" width="40" height="10" fill="#aaa"/> <path adj:command="vine" stroke="#777" stroke-width="2" fill="none" d="M0,0" adj:d=" M ~one#xw + ^myvar, ~one#yc C ~one#xw + ^myvar, ~one#yc - 20 ~other#xc - 20, ~other#yh + ^myvar ~other#xc, ~other#yh + ^myvar S ~another#x - ^myvar, ~another#yc - 20 ~another#x - ^myvar, ~another#yc"/> </g> <g transform="translate(0,100)"> <adj:variable name="myvar" value="17" desc="in inner scope #2"/> <rect adj:id="one" x="15" y="45" width="40" height="10" fill="#000"/> <rect adj:id="other" x="95" y="15" width="40" height="10" fill="#666"/> <rect adj:id="another" x="145" y="75" width="40" height="10" fill="#aaa"/> <path adj:command="vine" stroke="#777" stroke-width="2" fill="none" d="M0,0" adj:d=" M ~one#xw + ^myvar, ~one#yc C ~one#xw + ^myvar, ~one#yc - 20 ~other#xc - 20, ~other#yh + ^myvar ~other#xc, ~other#yh + ^myvar S ~another#x - ^myvar, ~another#yc - 20 ~another#x - ^myvar, ~another#yc"/> </g> </svg> |
The scope of an adj:variable
is all descendants of the SVG
element in which it is defined. It is not defined whether an
adj:variable
is or is not available in the very SVG element in
which it is defined.
Multiple definitions of a variable by the same name in the same document are possible, with values of their own. If so, then each one by itself has as scope all descendants of the SVG element in which it is defined. In case of nested scopes of variables of the same name, the value used will be the one found first when searching from use upwards through ancestors.
Substitution of variables also evaluates simple arithmetic into plain decimal numbers.
Only some parameters of some commands substitute variables:
horizontalList |
gap , horizontalGap , leftGap ,
centerGap , rightGap ,
verticalGap , topGap , middleGap ,
bottomGap , maxWidth , maxPerRow ,
itemsH2V , hAlign , vAlign |
verticalList |
gap , horizontalGap , leftGap ,
centerGap , rightGap ,
verticalGap , topGap , middleGap ,
bottomGap , maxHeight ,
maxPerColumn , itemsH2V , hAlign ,
vAlign |
frameForParent |
inset , horizontalInset ,
leftInset , rightInset ,
verticalInset , topInset ,
bottomInset |
rider |
gap |
circleForParent |
inset |
ellipseForParent |
inset , horizontalInset ,
verticalInset |
circularList |
gap , rGap , cGap ,
fromAngle , toAngle , rAlign ,
cAlign , dullness , horizontalGap ,
leftGap , rightGap , verticalGap ,
topGap , bottomGap |
verticalTree |
gap , horizontalGap , leftGap ,
centerGap , rightGap ,
childlessGap , earGap ,
verticalGap , topGap , middleGap ,
bottomGap , hAlign , vAlign |
horizontalTree |
gap , horizontalGap , leftGap ,
centerGap , rightGap ,
verticalGap , topGap , middleGap ,
bottomGap , childlessGap , earGap ,
hAlign , vAlign |
vine |
d |
floater |
at |
fit |
maxWidth , maxHeight , width ,
height |
stackFrames |
inset , horizontalInset ,
leftInset , rightInset ,
verticalInset , topInset ,
bottomInset , stacking |
zoomFrames |
step |
tilt |
alpha , beta |
pinnedList |
gap , horizontalGap , leftGap ,
rightGap , verticalGap , topGap ,
bottomGap |
telescopicTree |
gap , and a boom element's
gap |
paragraph |
maxWidth , lineGap , hAlign ,
indent |
pathArrow |
d , setback , nockSetback ,
pointSetback |
rcGrid |
gap , horizontalGap , leftGap ,
centerGap , rightGap ,
verticalGap , topGap , middleGap ,
bottomGap , hAlign , vAlign ,
cellLeftGap , cellRightGap ,
cellTopGap , cellBottomGap |
sliderKnob |
min , max , step ,
preset |
skimpyList |
gap , horizontalGap , leftGap ,
rightGap , verticalGap , topGap ,
bottomGap |
Some parameters of some commands substitute variables with boolean
true
or false
:
horizontalList |
makeGrid , explain |
verticalList |
makeGrid , explain |
connection |
explain |
rider |
explain |
circularList |
packArc , explain |
verticalTree |
autoParrots , explain |
horizontalTree |
autoParrots , explain |
vine |
explain |
floater |
explain |
telescopicTree |
explain |
paragraph |
explain |
pathArrow |
explain |
rcGrid |
explain |
toggleButton |
congruent |
There is at least one real use example file with substitution of variables.
Some special global variables have been predefined:
windowInnerWidth |
dynamically window.innerWidth |
windowInnerHeight |
dynamically window.innerHeight |
A newly implemented alternative syntax allows Adj commands to be attributes of SVG elements instead of requiring them to be XML elements of their own. This can be convenient for an author. Arguably there are distinct flavors of clarity in using the two different syntaxes. Both syntaxes are supported in the foreseeable future.
|
<g> <adj:verticalList hAlign="center"/> <rect width="60" height="40"> <adj:frameForParent inset="0.5"/> </rect> <text>innermost</text> <text>one</text> </g> |
adj: attributesnew, OK to write |
<g adj:command="verticalList" adj:hAlign="center"> <rect adj:command="frameForParent" adj:inset="0.5" width="60" height="40"/> <text>innermost</text> <text>one</text> </g> |
This user guide contains at least one set of images which while similar in
content have been written one
with commands via adj:
attributes versus the other with commands via
adj:
elements. More examples of commands via adj:
attributes are here.
Despite at least a theoretical, but also avoidable, risk involving identical
parameter names in future extensions, the benefits of commands via
adj:
attributes appear to be worth it.
Some commands make sense to combine for the same SVG element. Others don't make sense, and others would be plain impossible.
It makes sense to combine textBreaks
and
horizontalList
, for the same SVG element.
It could make sense, for example, to combine verticalList
or
horizontalList
with rider
or floater
.
Obviously it would not make sense to combine
horizontalList
and verticalList
, for the same SVG
element. It wouldn't make sense to combine connection
and
rider
, for the same SVG element. It wouldn't make sense to combine
rider
and floater
, for the same SVG element.
Mentioned because maybe not obvious: It makes no sense to combine vine
and
floater
.
There is no complete list. Factual feedback about noteworthy combinations, maybe example files, from an author using Adj is welcome.
Commands textBreaks
, rider
, floater
,
fit
, tilt
, hide
, and
explain
instead of being written e.g. as
adj:command="textBreaks"
alternatively can be written as
adj:textBreaks="true"
.
This allows command combinations via adj:
attributes, as shown
by example:
|
<g> <adj:verticalList/> <adj:textBreaks/> <text>line one line two</text> </g> |
adj: attribute and elementOK to write |
<g adj:command="verticalList"> <adj:textBreaks/> <text>line one line two</text> </g> |
adj: attributes onlynewest, OK to write |
<g adj:command="verticalList" adj:textBreaks="true">
<text>line one
line two</text>
</g>
|
This alleviates the fact it is not possible to combine two
adj:command
attributes as such for a single element, as in XML an
attribute name must not appear more than once in the same element.
An author can increase productivity by using browser add-ons.
Those who don't like using existing Firefox add-ons could implement alternate workflows and tools, e.g. Chrome extensions. Resulting images should not depend on the brand authoring tools used.
An example workflow:
adj.js
that is a copy of the
essential adj.js
file from this
projectA diagram of this example workflow:
Only a PNG here to accommodate a browser limitation, with a link to SVG.
TODO: make short video how simple and fun this workflow is to use and to set up
Invoking Adj is relatively simple, once you decide which option works best for you.
For the sake of completeness, other choices are explained too.
As implemented, Adj is a JavaScript library. Hence, most straight forward, Adj can be invoked explicitly, e.g. like
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-flat-20030114.dtd"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj" xmlns:xlink="http://www.w3.org/1999/xlink" onload="Adj.doSvg();"> <script type="text/javascript" xlink:href="js/adj.js"/> <g>…
Obviously, there must be a correct reference (path) to a copy of the essential adj.js
file from this project.
For best results for most users, Adj can be invoked explicitely and the processed document can be saved.
Benefits:
Most SVG files in this documentation have been processed this way. You can look at their source code.
SVG files in this documentation so far have been finalized with the help of Firefox add-on Save Back to File from DOM. It has become an easy habit to work this way.
An example workflow combining explicit invocation and saving processed documents has been described above.
If chosen to do so, with an author saving a processed document, invocation in users' browsers can be avoided.
As an example implementation, the Firefox add-on Save Back to File from DOM can do the necessary saving, obviating invocation.
Avoiding invocation in users' browsers may mean less problems with viewing in users' browsers that are set not to allow script invocation. This may be an antiquated concern: Allowing JavaScript has become normal.
Avoiding invocation in users' browsers also means no need to distribute the Adj JavaScript library. One downside, however, of not distributing the Adj JavaScript library is inability to dynamically adjust, e.g. to different fonts available in a different browser instance. This may be an acceptable compromise.
With script injection, explicit invocation can be avoided. Probably not worth the trouble.
The complete API of function Adj.doSvg()
is
doSvg (documentNodeOrAnSvgElement, doSvgDoneCallback)
Adj.doSvg()
accommodates sloppy parameter passing: Either
parameter or both parameters can be omitted.
If not given a documentNodeOrAnSvgElement
then
Adj.doSvg()
defaults to doing all SVG elements in the
document
.
This allows for concise onload="Adj.doSvg();"
to work for an
SVG document proper and also for an HTML document with SVG inlined.
Adj.doSvg()
runs asynchronously. Therefore, optionally a
callback function can be given.
In this example note the sequence when running
Adj.doSvg(function () { console.log('done') }); console.log('starting');
The callback function optionally may use the SVG element or array of SVG elements it will be passed. For example
Adj.doSvg(function (svg) { console.log('done with', svg) });
As Adj.doSvg()
runs asynchronously, there is little benefit to
catching exceptions.
Judicious use of SVG group elements g
makes Adj quite
practical.
TODO: some good examples
When Adj inserts a transform
attribute it overwrites a
preexisting transform
attribute, if any.
This is actually quite practical when transformations are changing, and the preexisting transformation has been the older version.
If indeed a separate transformation is needed, one possible solution seems
to be applying it as appropriate at a parent or child element, possibly at a
dedicate group element g
.
TODO: a good example
For a connection
its content may be scaled
and rotated. This is different than merely moving around an element, which can
be and is done by an arguably simpler translation transformation.
Other changes to paths are performed by vine
, and more complex changes to paths are
performed by pathArrow
.
For transforming an SVG path
or line
element in a
connection
Adj changes the coordinates of its points. For
transforming an SVG path
or line
element in a
connection
Adj does not insert transform
attributes.
This has been implemented this way because scaling effectively changes stroke width, which is undesirable. The issue of scaling and stroke width has been discussed for SVG version 2, which is far out.
Essential authoring coordinates are stored away in Adj namespace attributes, for reuse by authors and algorithms.
Algorithms which store away authoring coordinates also look for authoring coordinates in Adj namespace attributes, and if present use the values of Adj namespace attributes rather than equivalent SVG attributes.
As implemented, other than straight lines and curves, arcs in an SVG
path
element in a connection
or in a
pathArrow
don't get handled correctly by Adj. As implemented, Adj
replaces such arcs, if any, by straight lines. This could be improved.
A visual display is provided instead of the expected SVG in case a
JavaScript exception occurs in an invocation of Adj.doSvg();
.
As a matter of practicality, if authors reload documents after each change, they should be able to quickly know whether their most recent incremental change has the desired effect, doesn't have the desired effect, has bad syntax, or is otherwise defective.
Some cases are handled well already. This works with a visual display of exceptions.
Bad command handling can further be improved with feedback from authors using Adj. Frequent, puzzling, time consuming, and painful cases should have priority.
It should be considered though, absolute perfection in bad command handling may not be a goal: A library providing help for every theoretically possible authoring issue would be significantly larger, which means more expensive to produce, to maintain, and using more resources and time to download, and to execute.
When defining an SVG rect
element which will be sized and
positioned by Adj, e.g. by a frameForParent
, it is possible to be
minimalist.
An SVG rect
element only needs a width
and
height
attribute, which can be zero. An SVG rect
element needs neither an x
nor a y
attribute.
TODO: describe special limitations or benefits, if any
For standards compliant extension of SVG, Adj uses XML namespace
http://www.nrvr.com/2012/adj
with preferred prefix
adj
, as declared in
xmlns:adj="http://www.nrvr.com/2012/adj"
.
It is expected that authors will prefer the concise form Adj syntax, which is prevalently used in this documentation, over more verbose JavaScript function calls.
Nevertheless, via JavaScript function calls someone interested could invoke the Adj JavaScript library as needed, partially or wholly.
One entry point could be explicit invocation with
Adj.doSvg();
.
Another kind of entry point could be the setting of algorithms to be applied to an element. E.g. the concise form Adj command
<adj:horizontalList makeGrid="true" hAlign="center" vAlign="middle" maxPerRow="3" gap="5"/>
actually gets converted into, could have been written as, and gets interpreted as JavaScript
Adj.setAlgorithm(this, 'horizontalList', {makeGrid:true, hAlign:'center', vAlign:'middle', maxPerRow:3, gap:5});
Some details of the syntax of Adj may change after feedback from authors using it.
This may matter to some authors.
How Adj is implemented partially has been a function of what needs it was supposed to fulfill. Drawing, specifically in engineering, often has meant abstraction. Photographic realism has its place, but it is not a topic here. Available size of drawing surfaces often has been a limitation. Limitations of medium effect limitations of content represented. On large drawing boards of past centuries the area available often was an order of magnitude larger than on contemporary computer displays. Adj has been designed to facilitate creation and long-term maintenance of system diagrams, specifically for diagrams of large complexity. This is a different motivation and sets different priorities than what for nontechnical and technical users has been prevalent since the second half of the twentieth century: The low resolutions and small sizes of television screens, computer monitors, cell phones, and more recently mobile tablets. Arguably those screens combined with software such as PowerPoint have influenced the thinking of many.
Adj prioritizes the showing of all necessary information. Adj facilitates representation and communication of complexity.
How to organize rich sets of relevant detail?
In Adj the metaphor is a large sheet that expands as needed, when more information gets added. Expansion is in both dimensions, x and y.
In contrast, in word processing, the metaphor is a sufficiently long scroll of paper, continuous for a webpage, paginated for printing: When more information gets inserted, the scroll gets longer, the webpage gets longer, more pages will be printed. In most presentation programs, detail must go on other slides, or might be rephrased to fit.
Change happens.
To accommodate change, Adj facilitates diagrams being updated in ways that maintain perfect looks. Adj facilitates automated propagation of change, both change of content and change of appearance.
In contrast, without Adj, large and complex diagrams, and large sets of diagrams, could become outdated too quickly. The cost of updating diagrams can become prohibitive. Editing change into a diagram too easily can destroy an appearance of perfection that has been achieved in a first version.
Adj also may facilitate linking, scripting, and folding.
Undeniably, while Adj users will enjoy using large and very large computer displays, large images for some users will require panning, zooming, and possibly folding.
One of the first patterns implemented in Adj has been collections of graphics objects, such as lists in different shapes. As implemented, on purpose, these collections resize to accommodate the size, number, and desired relative positions of their contents elements.
before | |
insertion | |
after |
Instead of "these collections resize" one could think "these collections are resized". Whether one considers collections resizing themselves or being resized by Adj depends on one's point of view: Whether one focuses on the effect, a user's, a graphics author's, an SVG point of view (resize), versus whether one pays attention to details of how it is done, an implementer's, a programmer's, a JavaScript point of view (are resized).
The size of the smallest parts, the leaves of the SVG element tree, which are not collections themselves, e.g. text, are found by asking SVG for the bounding box. Only when the sizes of all siblings are known then they can be laid out within their parent (the collection) and then the parent's (the collection's) size can be known. Adj collections automatically do such sizing, so authors don't have to.
With nested collections the size of the smallest parts, the leaves of the SVG element tree, which are not collections themselves, e.g. text, are found by asking SVG for the bounding box. When walking the SVG element tree, only when the sizes of all siblings are known then they can be laid out within their parent (the collection) and then the parent's (the collection's) size can be known.
Hence, in a first walk of the SVG element tree Adj collections are laid out.
To perform all commands, Adj walks the SVG element tree 4 times, in 4 phases:
phaseHandlerName | algorithmName |
---|---|
adjPhase1Down |
textBreaks , paragraph ,
relativate , include ,
toggleButton |
adjPhase1Up |
verticalList , horizontalList ,
circularList , verticalTree ,
horizontalTree , fit ,
stackFrames , tilt , skimpyList ,
pinnedList , telescopicTree ,
rcGrid , sliderKnob |
adjPhase3 with processSubtreeOnlyInPhaseHandler |
floater |
adjPhase5Down |
frameForParent , circleForParent ,
ellipseForParent , zoomFrames |
adjPhase5Up |
connection |
adjPhase7 with processSubtreeOnlyInPhaseHandler |
rider |
adjPhase7Up |
vine , pathArrow , explain |
The 4 phases adjPhase1
, adjPhase3
,
adjPhase5
, and adjPhase7
are known to developers of
Adj commands (algorithms). Their numbers have been spaced out without impending
necessity.
In addition, there are unnamed administrative walks of the SVG element tree.
Phases have been a simple solution to ensure order of execution. Regrettably, phases impose some limitations of what can be done. A list of limitations has not been compiled yet. To get one started, factual feedback about noteworthy limitations, if encountered, preferably with example files, is welcome.
A future implementation may or may not be structured differently, hopefully with less limitations. For the foreseeable future, however, this is it. Required effort and consideration for authors with existing documents are reducing the probability of gratuitous changes.
There should be more architectural information, implementation insights, and usage hints available from the original authors. Ask specific questions to justify the effort of documenting more details.
A first example of extending Adj with commands (algorithms) has been given
in the user-docs/contrib
directory with command randomTilt
.
There should be more information, insights, and hints available from the original authors. Ask specific questions to justify the effort of documenting more details.
To facilitate continuing compatibility as both Adj and browsers are moving along with new code, an automated test suite has been implemented here.
For a set of prepared test documents, freshly computed results of Adj processing are compared with expected results.
Images that are made from graphic elements without text, hence not using fonts, should achieve exactly the same results each time in each browser. Variations in less significant digits do occur and are tolerated in order to pass.
Furthermore, for images that contain text, an explicitly provided font should, someday hopefully will, allow achieving the same results each time in each browser too. Out of necessity, however, for now, when text is present, larger variations are tolerated in order to pass.
For contributing to increasing the number of test cases, or with questions, please use contact and/or repository info provided above.
An additional test case can be made by steps:
test-adj-ex-002-verticalList.svg
.onload="Adj.doSvg();"
with differently
named attribute onclick="Adj.doSvg();"
.script
element loading adj.js
add a
second script
element loading adj-tests.js
.<svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj" xmlns:xlink="http://www.w3.org/1999/xlink" onclick="Adj.doSvg();"> <script type="text/javascript" xlink:href="../js/adj.js"/> <script type="text/javascript" xlink:href="../js/adj-tests.js"/> …
test-adj-ex-002-verticalList.svg test-adj-ex-002-verticalList-result.svg
At the time of the first writing of this section, for the release of Adj version 3.0, there had been compatibility problems with Internet Explorer.
By the time of the release of Adj version 4.0, improvements in Internet Explorer 11 appear to have been achieved.
Good results have been achieved with Firefox, Chrome, Safari, and Opera.
While problems may exist, it passes the test suite.
Because of security settings of Internet Explorer, one may have to explicitly click to approve the Adj JavaScript library to run.
Support of Internet Explorer 10 and older versions has ended 2016-01-12. Adj is no longer suported for Internet Explorer 10 and earlier.
Adj version 6.0.1 is no longer compatible with Internet Explorer 9 and earlier.
Apparently inside a text
element extraneous whitespace near a
hyperlink a
element can cause line height calculation on Firefox
to be wrong. See command paragraph
.
Support for SVG inline in HTML is a relatively new addition since Adj 5.0.1.
A simple first example is in JS Bin at http://jsbin.com/limeba/edit?html,output, which should let you experiment, clone, etc..
Some leftover examples from QA are 002, 023, 063, 075, 080, 081, 090, 091, 092, 093, and more.
TODO: document Adj in SVG inline in HTML, with compelling examples, description of limitations and caveats
The source code, before processing, of this older version
of above diagram of the example workflow:
<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:adj="http://www.nrvr.com/2012/adj" xmlns:xlink="http://www.w3.org/1999/xlink" onload="Adj.doSvg();" width="200" height="120"> <script type="text/javascript" xlink:href="../js/adj.js"/> <title>Example Workflow</title> <!-- Illustration idea and first version - Leo Baschy <srguiwiz12 AT nrvr DOT com> --> <style type="text/css"><![CDATA[ svg { font-size: 12px; font-family: sans-serif; } .subject { fill: lightgray; opacity: 0.5; stroke: gray; } .arrow { stroke: gray; fill: none; } ]]></style> <defs> <marker id="arrowhead" class="arrow" markerUnits="strokeWidth" orient="auto" viewBox="-4 -2 5 4" refX="0" refY="0" markerWidth="5" markerHeight="4" stroke-width="1" fill="none"> <path d="M -3 1 L 0 0 L -3 -1"/> </marker> </defs> <g> <adj:horizontalList makeGrid="true" gap="5" maxPerRow="3" hAlign="center"/> <g adj:id="subject-editor"> <adj:horizontalList gap="10"/> <rect width="0" height="0" class="subject"> <adj:frameForParent inset="1"/> </rect> <text>XML editor</text> </g> <g/> <g/> <g/> <g> <rect width="50" height="50" fill="none"/> </g> <g/> <g adj:id="subject-disk"> <adj:horizontalList gap="10"/> <rect width="0" height="0" class="subject"> <adj:frameForParent inset="1"/> </rect> <text>disk</text> </g> <g/> <g adj:id="subject-author"> <adj:horizontalList gap="10"/> <rect width="0" height="0" class="subject"> <adj:frameForParent inset="1"/> </rect> <text>author</text> </g> <g/> <g> <rect width="50" height="150" fill="none"/> </g> <g/> <g adj:id="subject-firefox"> <adj:horizontalList gap="10"/> <rect width="0" height="0" class="subject"> <adj:frameForParent inset="1"/> </rect> <text>Firefox</text> <g> <adj:horizontalList gap="10"/> <g adj:id="add-on-auto-reload"> <adj:verticalList gap="5"/> <rect width="0" height="0" class="subject"> <adj:frameForParent inset="1"/> </rect> <text>Auto Reload</text> <text>add-on</text> </g> <g adj:id="add-on-save-back"> <adj:verticalList gap="5"/> <rect width="0" height="0" class="subject"> <adj:frameForParent inset="1"/> </rect> <text>Save Back to File</text> <text>from DOM</text> <text>add-on</text> </g> </g> </g> <g> <adj:connection from="subject-editor % 0.2, 1.2" to="subject-disk % 0.2, -0.2"/> <path class="arrow" d="M0,0 q50,10 100,0" stroke-width="3" marker-end="url(#arrowhead)"/> <g> <adj:rider at="0.4" pin="1.1,0.5"/> <adj:verticalList gap="1"/> <text>saves</text> </g> </g> <g> <adj:connection from="subject-disk % 0.2, 1.2" to="subject-firefox % 0.1, -0.2"/> <path class="arrow" d="M0,0 q50,10 100,0" stroke-width="3" marker-end="url(#arrowhead)"/> <g> <adj:rider at="0.4" pin="1,1"/> <adj:verticalList gap="1"/> <text>first time</text> <text>opens</text> </g> </g> <g> <adj:connection from="subject-disk % 0.4, 1.2" to="add-on-auto-reload % 0.6, -0.1"/> <path class="arrow" d="M0,0 q50,10 100,0" stroke-width="3" marker-end="url(#arrowhead)"/> <g> <adj:rider at="0.9" pin="1,1"/> <adj:verticalList gap="1"/> <text>auto</text> <text>reloads</text> </g> </g> <g> <adj:connection from="add-on-save-back % 0.6, -0.05" to="subject-disk % 0.6, 1.2"/> <path class="arrow" d="M0,0 q50,10 100,0" stroke-width="3" marker-end="url(#arrowhead)"/> <g> <adj:rider at="0.1" pin="0,1"/> <adj:verticalList gap="1"/> <text>can</text> <text>save</text> <text>back</text> </g> </g> <g> <adj:connection from="subject-author % 0.0, -0.2" to="subject-editor % 1.2, 1.0"/> <path class="arrow" d="M0,0 q50,10 100,0" stroke-width="3" marker-end="url(#arrowhead)"/> <g> <adj:rider at="0.4" pin="0,1.1"/> <adj:verticalList gap="1"/> <text>edits</text> </g> </g> <g> <adj:connection from="subject-author % 0.0, 1.2" to="subject-firefox % 1.05, 0.0"/> <path class="arrow" d="M0,0 q70,-30 100,0" stroke-width="3" marker-end="url(#arrowhead)"/> <g> <adj:rider at="0.4" pin="-0.1,0"/> <adj:verticalList gap="1"/> <text>views</text> </g> </g> </g> </svg>
An example:
An example:
An example: