<@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; } }