@script name="SvgDom">
A wrapper object that facilitates access and manipulation of the SVG DOM.
You can use the global ~SVG reference to invoke the functions listed above from within
any drawing aspect.
(c) SAP AG 2003-2006. All rights reserved.
// Global SVG DOM wrapper object
var SVG = {
external: null, // The external SVG embedding object
window: window, // The SVG window object
document: document, // The SVG document object
rootNode: document.documentElement, // The root SVG element
PI1_2: 1.5707963267948965, // Constant = PI/2
PI2: 6.283185307179586, // Constant = PI*2
D2R: 0.017453292519943295, // Constant = degrees-to-radians convertion factor
R2D: 57.29577951308232 // Constant = radians-to-degrees convertion factor
}
<@func name="attachListener">
Attaches a listener object to an element
The SVG element
The listener object
A list of event names to listen to
SVG.attachListener = function(elem, obj, events) {
try {
for (var i=0; i
Attaches a specified behavior to a given element
The behavior constructor
The SVG element
A table of property name-value pairs for initializing the behavior
The newly attached behavior object
SVG.attachBehavior = function(behavior, elem, props) {
try {
return new behavior(elem, props);
} catch (e) { return null; }
}
<@func name="clearElement">
Clears the contents of a given SVG element by removing all its child nodes
The SVG element to clear
The cleared element
SVG.clearElement = function(elem) {
try {
var child=elem.firstChild;
while (child) {
var curr=child;
child = child.nextSibling;
elem.removeChild(curr);
}
return elem;
} catch (e) { return null; }
}
<@func name="createButton">
Creates a button element and appends it to the given parent
The parent element
The id of the symbol to use for the button
A table of property name-value pairs for initializing the button (see SvgClickable behavior)
The newly created element
SVG.createButton = function(parent, symbol, props, behavior) {
try {
if (!props) props={};
if (!props.glyph) props.glyph = 'button';
var x = props.x || 0
var y = props.y || 0
var w = props.width || 16;
var h = props.height || w;
var btn = SVG.createElement(parent, 'a', {'class':'buttonNormal'});
SVG.createElement(btn, 'rect', {x:0, y:0, width:w, height:h, fill:'none', stroke:'none', 'pointer-events':'all'});
SVG.createFragment(btn, '');
var bhv = SVG.attachBehavior(behavior || SvgClickable, btn, props);
if (behavior == SvgFlippable) bhv.symbolObj = btn.lastChild;
return btn;
} catch (e) { return null; }
}
<@func name="createElement">
Creates a new SVG element and appends it to the given parent
The parent element
The tag name of the new element
A table of attribute/property name-value pairs to set on the new element (prefix property names with '$')
The newly created element
SVG.createElement = function(parent, tagName, props) {
try {
if (tagName == 'image' || tagName == 'use') {
var elem = parseXML('<'+tagName+' xlink:href=""/>', document);
if (!parent) return elem;
parent.appendChild(elem);
elem = parent.lastChild;
if (props) SVG.setProperties(elem, props);
return elem;
}
var elem = document.createElement(tagName);
if (tagName == 'text') {
elem.appendChild(document.createTextNode(' '));
}
if (props) SVG.setProperties(elem, props);
if (parent) parent.appendChild(elem);
return elem;
} catch (e) { return null; }
}
<@func name="createFlipper">
Creates a flipper element and appends it to the given parent
The parent element
The id symbol to use for each state of the flipper
A table of property name-value pairs for initializing the button (see SvgClickable behavior)
The newly created element
SVG.createFlipper = function(parent, symbols, props) {
try {
if (!props) props={};
props.symbols = symbols;
var btn = SVG.createButton(parent, symbols[props.state], props, SvgFlippable);
return btn;
} catch (e) { return null; }
}
<@func name="createFragment">
Creates an SVG fragment and appends it to the given parent
The parent element
The SVG source of the new element
The newly created element
SVG.createFragment = function(parent, fragment) {
try {
var elem = parseXML(fragment, document);
if (!parent) return elem;
parent.appendChild(elem);
return parent.lastChild;
} catch (e) { return null; }
}
<@func name="createModelEvent">
Creates an event object for passing event context information
The event type
The newly created event object
SVG.createModelEvent = function(type) {
var evt = SVG.external.document.createEventObject();
evt.type = type;
return evt;
}
<@func name="declareClass">
Declares a new or derived class
The class constructor
The superclass constructor
SVG.declareClass = function(cstor, supercstor) {
if (supercstor) {
cstor.prototype = new supercstor();
cstor.prototype.constructor = cstor;
cstor.superclass = supercstor;
} else {
cstor.prototype.constructor = cstor;
cstor.superclass = null;
}
}
<@func name="detachBehavior">
Detaches a specified behavior from a given element
The behavior constructor
The SVG element
Returns ~true if a behavior was actually detached; otherwise, returns ~false
SVG.detachBehavior = function(behavior, elem) {
try {
if (!elem || !elem.behaviors) return false;
for (var i=0, A=[], B=elem.behaviors, len=B.length; i
Detaches a listener object from an element
The SVG element
The listener object
A list of event names to detach
SVG.detachListener = function(elem, obj, events) {
try {
for (var i=0; i
Shows or hides a specified element
The SVG element
~true=show, ~false=hide
This method affects the specified element and all its contained elements.
When the element is hidden using this method, it stops receiving pointer events.
SVG.display = function(elem, show) {
try {
elem.style.setProperty('display', show ? 'block' : 'none');
elem.isHidden = !show;
} catch (e) { }
}
<@func name="dump">
Dumps an SVG element for debugging
The SVG element
SVG.dump = function(elem) {
try {
alert(printNode(elem));
} catch (e) { alert(e.description); }
}
<@func name="encloses">
Tests whether a point or a rectangle is contained inside another rectangle
Tests whether a point is contained inside the given rectangle
The enclosing rectangle
The point to test
Tests whether the first rectangle is contained inside the second rectangle
The enclosing rectangle
The rectangle to test
The test result
SVG.encloses = function(r1, r2) {
var x1=r1.x, y1=r1.y, w1=r1.w||0, h1=r1.h||0;
var x2=r2.x, y2=r2.y, w2=r2.w||0, h2=r2.h||0;
return x1<=x2 && x1+w1>=x2+w2 && y1<=y2 && y1+h1>=y2+h2;
}
<@func name="getAngle">
Returns the angle of the line between two given points
The first point
The second point
The angle of the line from %0 to %1 (in radians, relative to x-axis)
SVG.getAngle = function(p1, p2) {
return Math.atan2(p2.y-p1.y, p2.x-p1.x);
}
<@func name="getDistance">
Returns the distance between two given points
The first point
The second point
The distance between %0 and %1
SVG.getDistance = function(p1, p2) {
var dx=p1.x-p2.x, dy=p1.y-p2.y;
return Math.sqrt(dx*dx+dy*dy);
}
<@func name="getElement">
Gets a specified element
Id of element to get
The requested element
SVG.getElement = function(id) {
return SVG.rootNode.getElementById(id);
}
<@func name="getMidPoint">
Returns the middle point on the line between two given points
The first point
The second point
The computed midpoint
SVG.getMidPoint = function(p1, p2) {
return {x:(p1.x+p2.x)/2, y:(p1.y+p2.y)/2};
}
<@func name="getProperty">
Gets a specified element attribute or style property
The SVG element
The attribute/property name (prefix style property names with '$')
Default attribute/property value
The requested attribute/property value
SVG.getProperty = function(elem, name, dflt) {
try {
if (!elem || !name) return null;
var val = null;
if (name.charAt(0) == '$') {
val = elem.style.getPropertyValue(name.substring(1));
} else if (name == 'href') {
val = elem.getAttribute('xlink:href');
} else if (name == 'text') {
val = elem.firstChild.nodeValue || '';
} else {
val = elem.getAttribute(name);
}
return val || dflt || null;
} catch (e) { return null; }
}
<@func name="getRect">
Gets the position and size of a specified rectangle element
The SVG rectangle element
The rectangle position and size
SVG.getRect = function(elem) {
try {
return {
x:FLOAT(elem.getAttribute('x')),
y:FLOAT(elem.getAttribute('y')),
w:FLOAT(elem.getAttribute('width')),
h:FLOAT(elem.getAttribute('height'))
};
} catch (e) { return null; }
}
<@func name="hide" also="display">
Hides a specified element
The SVG element
SVG.hide = function(elem) {
try {
elem.style.setProperty('display', 'none');
elem.isHidden = true;
} catch (e) {}
}
<@func name="inflateRect">
Inflates the given rectangle by the given delta values
The rectangle object
The x delta
The y delta (defaults to %1)
The inflated rectangle
SVG.inflateRect = function(r, dx, dy) {
if (!dy) dy=dx;
return {x:r.x-dx, y:r.y-dy, w:r.w+2*dx, h:r.h+2*dy};
}
<@func name="intersection">
Returns the intersection of two rectangles, of line and rectangle or of two lines
Returns the intersection of two rectangles
The first rectangle
The second rectangle
The intersection rectangle or null (if the two rectangles are disjoint)
Returns the intersection point of a rectangle with the line that connects two given points
The rectangle
The first point
The second point
The intersection point of ~rect with line (~p1,~p2), and the direction symbol: R|T|B|L
The method assumes that p1 resp. p2 is inside resp. outside the rectangle
// TODO: Do we need intersection of two lines?
SVG.intersection = function(r1, r2, p2) {
if (r2.w !== undefined) {
// rectangles intersection
var x1 = MAX(r1.x, r2.x), x2 = MIN(r1.x+r1.w, r2.x+r2.w);
var y1 = MAX(r1.y, r2.y), y2 = MIN(r1.y+r1.h, r2.y+r2.h);
return (x1>x2 || y1>y2) ? null : {x:x1, y:y1, w:x2-x1, h:y2-y1};
}
else {
// rect and line intersection
var rect = r1; // rectangle
var p1 = r2; // first point
var x0=p1.x-rect.x, y0=p1.y-rect.y, w=rect.w, h=rect.h;
var a=ATAN2(p2.y-p1.y, p2.x-p1.x), tg=TAN(a), dx, dy, dir;
var a00=ATAN2(0-y0,w-x0), a01=ATAN2(0-y0,0-x0);
var a10=ATAN2(h-y0,w-x0), a11=ATAN2(h-y0,0-x0);
a = ROUND(a*180/Math.PI); var sign = (a < 0) ? -1 : 1;
a00 = ROUND(a00*180/Math.PI); if (a00 == 180) a00 *= sign; // if p1 is on the perimeter, treat andgle of 180 as -180 if 'a' is negative
a01 = ROUND(a01*180/Math.PI); if (a01 == 180) a01 *= sign;
a10 = ROUND(a10*180/Math.PI); if (a10 == 180) a10 *= sign;
a11 = ROUND(a11*180/Math.PI); if (a11 == 180) a11 *= sign;
if (a >= a00 && a <= a10) {
dx=w-x0; dy=tg*dx; dir='R'; // right side
} else if (a > a01 && a < a00) {
dy=-y0; dx=dy/tg; dir='T'; // top side
} else if (a > a10 && a < a11) {
dy=h-y0; dx=dy/tg; dir='B'; // bottom side
} else {
dx=-x0; dy=tg*dx; dir='L'; // left side
}
return {x:rect.x+x0+dx, y:rect.y+y0+dy, dir:dir};
}
}
<@func name="lowerElement">
Lowers a given SVG element by moving it before the first child of its element
The SVG element to lower
The lowered element
SVG.lowerElement = function(elem) {
try {
var parent = elem.parentNode;
if (elem == parent.firstChild) return;
parent.removeChild(elem);
parent.insertBefore(parent.firstChild);
return elem;
} catch (e) { return null; }
}
<@func name="makeRect">
Creates a rectangle from two given points
The first point
The second point
The result rectangle
SVG.makeRect = function(p1, p2) {
if (!p2) return {x:0, y:0, w:ABS(p1.x), h:ABS(p1.y)};
var r={x:p1.x, y:p1.y};
r.w=p2.x-r.x; if (r.w<0) { r.x+=r.w; r.w=-r.w; }
r.h=p2.y-r.y; if (r.h<0) { r.y+=r.h; r.h=-r.h; }
return r;
}
<@func name="normalizeRect">
Normalizes a given rectangle
The rectangle to normalize
Optional snapping unit
The normalized rectangle
SVG.normalizeRect = function(r, snap) {
var x=r.x||0, y=r.y||0, w=r.w||0, h=r.h||0;
if (w<0) { x+=w; w=-w; }
if (h<0) { y+=h; h=-h; }
if (!snap) return {x:x, y:y, w:w, h:h};
return {x:ROUND(x,snap), y:ROUND(y,snap), w:ROUND(w,snap), h:ROUND(h,snap)}
}
<@func name="raiseElement">
Raises a given SVG element by moving it after the last child of its element
The SVG element to raise
The raised element
SVG.raiseElement = function(elem) {
try {
var parent = elem.parentNode;
if (elem == parent.lastChild) return;
parent.removeChild(elem);
parent.appendChild(elem);
return elem;
} catch (e) { return null; }
}
<@func name="removeElement">
Removes a given SVG element
The SVG element to remove
The removed element
SVG.removeElement = function(elem) {
try {
return elem.parentNode.removeChild(elem);
} catch (e) { return null; }
}
<@func name="replaceElement">
Replaces a given SVG element with another element
The SVG element to replace
The replacing SVG element
The replaced element
SVG.replaceElement = function(elem, other) {
try {
return elem.parentNode.replaceChild(elem, other);
} catch (e) { return null; }
}
<@func name="resetProperty">
Resets a specified element attribute or style property
The SVG element
The attribute/property name (prefix property names with '$')
SVG.resetProperty = function(elem, name) {
try {
if (!elem || !name) return;
if (name.charAt(0) == '$') {
elem.style.removeProperty(name.substring(1));
} else if (name == 'href') {
elem.removeAttribute('xlink:href');
} else if (name == 'text') {
elem.removeChild(elem.firstChild);
} else if (name == 'mtext' || name == 'amtext') {
SVG.clearElement(elem);
} else {
elem.removeAttribute(name, value);
}
} catch (e) { return null; }
}
<@func name="resetProperties">
Resets a specified collection of element attributes or style properties
The SVG element
A table of attribute/property name-value pairs (prefix property names with '$')
SVG.resetProperties = function(elem, props) {
try {
if (!elem || !props) return;
for (var name in props) {
if (name.charAt(0) == '$') {
elem.style.removeProperty(name.substring(1));
} else if (name == 'href') {
elem.removeAttribute('xlink:href');
} else if (name == 'text') {
elem.removeChild(elem.firstChild);
} else if (name == 'mtext' || name == 'amtext') {
SVG.clearElement(elem);
} else {
elem.removeAttribute(name, value);
}
}
} catch (e) { return null; }
}
<@func name="rotateAngle">
Rotates a point around a second point by a given angle
The first point
The second point
The rotation angle (in radians)
The rotated point
SVG.rotateAngle = function(p1, p2, angle) {
var l=SVG.getDistance(p1, p2), a=SVG.getAngle(p2, p1);
return {x:p1.x = p2.x+l*COS(a+angle), y:p2.y+l*SIN(a+angle)};
}
<@func name="rotateArc">
Rotates a point around a second point by a given arc length
The first point
The second point
The rotation arc length
The rotated point
SVG.rotateArc = function(p1, p2, length) {
var l=SVG.getDistance(p1, p2), a=SVG.getAngle(p2, p1), angle=length/l;
return {x:p2.x+l*COS(a+angle), y:p2.y+l*SIN(a+angle)};
}
<@func name="setCircle">
Sets the position and radius of a specified circle element
The SVG circle element
The x position of the circle center
The y position of the circle center
The circle radius
SVG.setCircle = function(elem, x, y, r) {
try {
if (x != undefined) elem.setAttribute('cx', x||0);
if (y != undefined) elem.setAttribute('cy', y||0);
if (r != undefined) elem.setAttribute('r', r||0);
} catch (e) { return null; }
}
<@func name="setColor">
Sets the primary color of a specified element
The SVG element
The new color
The color shifting factor
SVG.setColor = function(elem, color, shift) {
try {
if (shift) color = SHIFT_COLOR(color, shift);
elem.style.setProperty('color', color);
} catch (e) { return null; }
}
<@func name="setFill">
Sets the fill property of a specified element
The SVG element
The new fill color
The fill opacity (0.0 - 1.0)
The color shifting factor
SVG.setFill = function(elem, color, opacity, shift) {
try {
if (shift) color = SHIFT_COLOR(color, shift);
elem.style.setProperty('fill', color);
if (opacity != undefined) elem.style.setProperty('fill-opacity', opacity);
} catch (e) { return null; }
}
<@func name="setLine">
Sets the end points of a specified line element
The SVG line element
The new line end points
Flip the x and y axes
The SVG line element
The x position of end point 1
The y position of end point 1
The x position of end point 2
The y position of end point 2
Flip the x and y axes
SVG.setLine = function(elem, x1, y1, x2, y2, flip) {
try {
if (typeof x1 == 'object') flip=y1, y1=x1.y1, x2=x1.x2, y2=x1.y2, x1=x1.x1;
if (flip) flip=x1, x1=y1, y1=flip, flip=x2, x2=y2, y2=flip;
elem.setAttribute('x1', x1||0);
elem.setAttribute('y1', y1||0);
elem.setAttribute('x2', x2||0);
elem.setAttribute('y2', y2||0);
} catch (e) { return null; }
}
<@func name="setHLine">
Sets the end points of a horizontal line element
The SVG line element
The y position of both end points
The x position of end point 1
The x position of end point 2
SVG.setHLine = function(elem, y, x1, x2) {
try {
elem.setAttribute('x1', x1||0);
elem.setAttribute('y1', y||0);
elem.setAttribute('x2', x2||0);
elem.setAttribute('y2', y||0);
} catch (e) { return null; }
}
<@func name="setVLine">
Sets the end points of a vertical line element
The SVG line element
The x position of both end points
The y position of end point 1
The y position of end point 2
SVG.setVLine = function(elem, x, y1, y2) {
try {
elem.setAttribute('x1', x||0);
elem.setAttribute('y1', y1||0);
elem.setAttribute('x2', x||0);
elem.setAttribute('y2', y2||0);
} catch (e) { return null; }
}
<@func name="setPath">
Sets the path data of a specified path element
The SVG path element
The new path data
SVG.setPath = function(elem, data) {
try {
elem.setAttribute('d', data||'');
} catch (e) { return null; }
}
<@func name="setPos">
Sets the x and y position of a specified element
The SVG element
The new position
The SVG element
The new x position
The new y position
SVG.setPos = function(elem, x, y) {
try {
if (typeof x == 'object') { y=x.y; x=x.x; };
elem.setAttribute('x', x||0);
elem.setAttribute('y', y||0);
} catch (e) { return null; }
}
<@func name="setProperty">
Sets a specified element attribute or style property
The SVG element
The attribute/property name (prefix property names with '$')
The attribute/property value to set.
SVG.setProperty = function(elem, name, value) {
try {
if (!elem || !name) return;
if (name.charAt(0) == '$') {
elem.style.setProperty(name.substring(1), value);
} else if (name == 'href') {
elem.setAttribute('xlink:href', value);
} else if (name == 'text') {
elem.firstChild.nodeValue = value || ' ';
} else if (name == 'mtext') {
SVG.setMText(elem, value);
} else if (name == 'amtext') {
SVG.setAMText(elem, value);
} else {
elem.setAttribute(name, value);
}
} catch (e) { }
}
<@func name="setProperties">
Sets a given collection of element attributes or style properties
The SVG element
A table of attribute/property name-value pairs (prefix property names with '$')
SVG.setProperties = function(elem, props) {
try {
if (!elem || !props) return;
for (var name in props) {
var value=props[name];
if (name.charAt(0) == '$') {
elem.style.setProperty(name.substring(1), value);
} else if (name == 'href') {
elem.setAttribute('xlink:href', value);
} else if (name == 'text') {
elem.firstChild.nodeValue = value || ' ';
} else if (name == 'mtext') {
SVG.setMText(elem, value);
} else if (name == 'amtext') {
SVG.setAMText(elem, value);
} else {
elem.setAttribute(name, value);
}
}
} catch (e) { return null; }
}
<@func name="setRect">
Sets the position and size of a specified rectangle element
The SVG rectangle element
The new rectangle position and size
Flip the x and y axes
The SVG rectangle element
The new x position
The new y position
The new width
The new height
Flip the x and y axes
SVG.setRect = function(elem, x, y, w, h, flip) {
try {
if (typeof x == 'object') flip=y, y=x.y, w=x.w, h=x.h, x=x.x;
if (w<0) x+=w, w=-w;
if (h<0) y+=h, h=-h;
if (flip) flip=x, x=y, y=flip, flip=w, w=h, h=flip;
elem.setAttribute('x', x||0);
elem.setAttribute('y', y||0);
elem.setAttribute('width', w||0);
elem.setAttribute('height', h||0);
} catch (e) { return null; }
}
<@func name="setSize">
Sets the width and height of a specified element
The SVG element
The new size
The SVG element
The new width
The new height
SVG.setSize = function(elem, w, h) {
try {
if (typeof w == 'object') { h=w.h; w=w.w; };
elem.setAttribute('width', w||0);
elem.setAttribute('height', h||0);
} catch (e) { return null; }
}
<@func name="setText">
Sets the text value of a specified text element (line breaks are ignored)
The text element
The new text value
SVG.setText = function(elem, text) {
try {
elem.firstChild.nodeValue = (text === undefined || text === null || text === '') ? ' ' : text+'';
} catch (e) { return null; }
}
<@func name="setMText">
Sets the multi-line text contents of a specified text element (line breaks are honored)
The text element
The new text value
SVG.setMText = function(elem, text) {
try {
for (var C=elem.childNodes, i=C.length-1; i>=0; i--) {
elem.removeChild(C.item(i));
}
var text=SPLIT((text||'').replace(/\r/g,''),'\n'), tx=elem.getAttribute('x');
for (var i=0, len=text.length; i
Sets the multi-line text contents of a specified text element (line breaks are honored)
The text element
The new text value
SVG.setAMText = function(elem, text) {
SVG.setMText(elem, JOIN(text, '\n'));
}
<@func name="setViewbox">
Sets the viewbox of a specified container element
The container element
The new viewbox
Flip the x and y axes
The container element
The new viewbox x position
The new viewbox y position
The new viewbox width
The new viewbox height
Flip the x and y axes
SVG.setViewbox = function(elem, x, y, w, h, flip) {
try {
if (typeof x == 'object') flip=y, y=x.y, w=x.w, h=x.h, x=x.x;
if (w<0) x+=w, w=-w;
if (h<0) y+=h, h=-h;
if (flip) flip=x, x=y, y=flip, flip=w, w=h, h=flip;
elem.setAttribute('viewBox', (x||0)+' '+(y||0)+' '+(w||0)+' '+(h||0));
} catch (e) { return null; }
}
<@func name="setupSVGViewer">
Setups the SVG viewer
SVG.setupSVGViewer = function(external) {
SVG.external = external;
// disable default context menu
var menu=contextMenu.documentElement;
for (var i=menu.firstChild, j; i; i = j) {
j = i.nextSibling;
menu.removeChild(i);
}
}
<@func name="transform">
Transforms a specified element
The SVG element
The translated position
The scale factor
The rotation angle
The SVG element
The x translation
The y translation
The scale factor
The rotation angle
SVG.setTransform = function(elem, x, y, s, r) {
try {
if (typeof x == 'object') { r=s; s=y; y=x.y; x=x.x; }
var tx = 'translate('+x+' '+y+')';
if (s && s != 1) tx += ' scale('+s+')';
if (r) tx += ' rotate('+r+')';
elem.setAttribute('transform', tx);
} catch (e) { return null; }
}
<@func name="show" also="display">
Shows a specified element
The SVG element
SVG.show = function(elem) {
try {
elem.style.setProperty('display', 'block');
elem.isHidden = false;
} catch (e) {}
}
<@func name="visible">
Sets a specified element as visible or invisible
The SVG element
~true=visible, ~false=invisible
This method affects only the specified element. The visibility property is not inherited by the contained elements.
When the element is hidden using this method, it can still continue receiving pointer events.
SVG.visible = function(elem, visible) {
try {
elem.style.setProperty('visibility', visible ? 'visible' : 'hidden');
elem.isInvisible = !visible;
} catch (e) { return null; }
}