summaryrefslogtreecommitdiff
path: root/src/js/shape/mxShape.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/shape/mxShape.js')
-rw-r--r--src/js/shape/mxShape.js2045
1 files changed, 0 insertions, 2045 deletions
diff --git a/src/js/shape/mxShape.js b/src/js/shape/mxShape.js
deleted file mode 100644
index 44ba3e7..0000000
--- a/src/js/shape/mxShape.js
+++ /dev/null
@@ -1,2045 +0,0 @@
-/**
- * $Id: mxShape.js,v 1.173 2012-07-31 11:46:53 gaudenz Exp $
- * Copyright (c) 2006-2010, JGraph Ltd
- */
-/**
- * Class: mxShape
- *
- * Base class for all shapes. A shape in mxGraph is a
- * separate implementation for SVG, VML and HTML. Which
- * implementation to use is controlled by the <dialect>
- * property which is assigned from within the <mxCellRenderer>
- * when the shape is created. The dialect must be assigned
- * for a shape, and it does normally depend on the browser and
- * the confiuration of the graph (see <mxGraph> rendering hint).
- *
- * For each supported shape in SVG and VML, a corresponding
- * shape exists in mxGraph, namely for text, image, rectangle,
- * rhombus, ellipse and polyline. The other shapes are a
- * combination of these shapes (eg. label and swimlane)
- * or they consist of one or more (filled) path objects
- * (eg. actor and cylinder). The HTML implementation is
- * optional but may be required for a HTML-only view of
- * the graph.
- *
- * Custom Shapes:
- *
- * To extend from this class, the basic code looks as follows.
- * In the special case where the custom shape consists only of
- * one filled region or one filled region and an additional stroke
- * the <mxActor> and <mxCylinder> should be subclassed,
- * respectively. These implement <redrawPath> in order to create
- * the path expression for VML and SVG via a unified API (see
- * <mxPath>). <mxCylinder.redrawPath> has an additional boolean
- * argument to draw the foreground and background separately.
- *
- * (code)
- * function CustomShape() { }
- *
- * CustomShape.prototype = new mxShape();
- * CustomShape.prototype.constructor = CustomShape;
- * (end)
- *
- * To register a custom shape in an existing graph instance,
- * one must register the shape under a new name in the graph's
- * cell renderer as follows:
- *
- * (code)
- * graph.cellRenderer.registerShape('customShape', CustomShape);
- * (end)
- *
- * The second argument is the name of the constructor.
- *
- * In order to use the shape you can refer to the given name above
- * in a stylesheet. For example, to change the shape for the default
- * vertex style, the following code is used:
- *
- * (code)
- * var style = graph.getStylesheet().getDefaultVertexStyle();
- * style[mxConstants.STYLE_SHAPE] = 'customShape';
- * (end)
- *
- * Constructor: mxShape
- *
- * Constructs a new shape.
- */
-function mxShape() { };
-
-/**
- * Variable: SVG_STROKE_TOLERANCE
- *
- * Event-tolerance for SVG strokes (in px). Default is 8.
- */
-mxShape.prototype.SVG_STROKE_TOLERANCE = 8;
-
-/**
- * Variable: scale
- *
- * Holds the scale in which the shape is being painted.
- */
-mxShape.prototype.scale = 1;
-
-/**
- * Variable: dialect
- *
- * Holds the dialect in which the shape is to be painted.
- * This can be one of the DIALECT constants in <mxConstants>.
- */
-mxShape.prototype.dialect = null;
-
-/**
- * Variable: crisp
- *
- * Special attribute for SVG rendering to set the shape-rendering attribute to
- * crispEdges in the output. This is ignored in IE. Default is false. To
- * disable antialias in IE, the explorer.css file can be changed as follows:
- *
- * [code]
- * v\:* {
- * behavior: url(#default#VML);
- * antialias: false;
- * }
- * [/code]
- */
-mxShape.prototype.crisp = false;
-
-/**
- * Variable: roundedCrispSvg
- *
- * Specifies if crisp rendering should be enabled for rounded shapes.
- * Default is true.
- */
-mxShape.prototype.roundedCrispSvg = true;
-
-/**
- * Variable: mixedModeHtml
- *
- * Specifies if <createHtml> should be used in mixed Html mode.
- * Default is true.
- */
-mxShape.prototype.mixedModeHtml = true;
-
-/**
- * Variable: preferModeHtml
- *
- * Specifies if <createHtml> should be used in prefer Html mode.
- * Default is true.
- */
-mxShape.prototype.preferModeHtml = true;
-
-/**
- * Variable: bounds
- *
- * Holds the <mxRectangle> that specifies the bounds of this shape.
- */
-mxShape.prototype.bounds = null;
-
-/**
- * Variable: points
- *
- * Holds the array of <mxPoints> that specify the points of this shape.
- */
-mxShape.prototype.points = null;
-
-/**
- * Variable: node
- *
- * Holds the outermost DOM node that represents this shape.
- */
-mxShape.prototype.node = null;
-
-/**
- * Variable: label
- *
- * Reference to the DOM node that should contain the label. This is null
- * if the label should be placed inside <node> or <innerNode>.
- */
-mxShape.prototype.label = null;
-
-/**
- * Variable: innerNode
- *
- * Holds the DOM node that graphically represents this shape. This may be
- * null if the outermost DOM <node> represents this shape.
- */
-mxShape.prototype.innerNode = null;
-
-/**
- * Variable: style
- *
- * Holds the style of the cell state that corresponds to this shape. This may
- * be null if the shape is used directly, without a cell state.
- */
-mxShape.prototype.style = null;
-
-/**
- * Variable: startOffset
- *
- * Specifies the offset in pixels from the first point in <points> and
- * the actual start of the shape.
- */
-mxShape.prototype.startOffset = null;
-
-/**
- * Variable: endOffset
- *
- * Specifies the offset in pixels from the last point in <points> and
- * the actual start of the shape.
- */
-mxShape.prototype.endOffset = null;
-
-/**
- * Variable: boundingBox
- *
- * Contains the bounding box of the shape, that is, the smallest rectangle
- * that includes all pixels of the shape.
- */
-mxShape.prototype.boundingBox = null;
-
-/**
- * Variable: vmlNodes
- *
- * Array if VML node names to fix in IE8 standards mode.
- */
-mxShape.prototype.vmlNodes = ['node', 'strokeNode', 'fillNode', 'shadowNode'];
-
-/**
- * Variable: vmlScale
- *
- * Internal scaling for VML using coordsize for better precision.
- */
-mxShape.prototype.vmlScale = 1;
-
-/**
- * Variable: strokewidth
- *
- * Holds the current strokewidth. Default is 1.
- */
-mxShape.prototype.strokewidth = 1;
-
-/**
- * Function: setCursor
- *
- * Sets the cursor on the given shape.
- *
- * Parameters:
- *
- * cursor - The cursor to be used.
- */
-mxShape.prototype.setCursor = function(cursor)
-{
- if (cursor == null)
- {
- cursor = '';
- }
-
- this.cursor = cursor;
-
- if (this.innerNode != null)
- {
- this.innerNode.style.cursor = cursor;
- }
-
- if (this.node != null)
- {
- this.node.style.cursor = cursor;
- }
-
- if (this.pipe != null)
- {
- this.pipe.style.cursor = cursor;
- }
-};
-
-/**
- * Function: getCursor
- *
- * Returns the current cursor.
- */
-mxShape.prototype.getCursor = function()
-{
- return this.cursor;
-};
-
-/**
- * Function: init
- *
- * Initializes the shape by creaing the DOM node using <create>
- * and adding it into the given container.
- *
- * Parameters:
- *
- * container - DOM node that will contain the shape.
- */
-mxShape.prototype.init = function(container)
-{
- if (this.node == null)
- {
- this.node = this.create(container);
-
- if (container != null)
- {
- container.appendChild(this.node);
-
- // Workaround for broken VML in IE8 standards mode. This gives an ID to
- // each element that is referenced from this instance. After adding the
- // DOM to the document, the outerHTML is overwritten to fix the VML
- // rendering and the references are restored.
- if (document.documentMode == 8 && mxUtils.isVml(this.node))
- {
- this.reparseVml();
- }
- }
- }
-
- // Gradients are inserted late when the owner SVG element is known
- if (this.insertGradientNode != null)
- {
- this.insertGradient(this.insertGradientNode);
- this.insertGradientNode = null;
- }
-};
-
-/**
- * Function: reparseVml
- *
- * Forces a parsing of the outerHTML of this node and restores all references specified in <vmlNodes>.
- * This is a workaround for the VML rendering bug in IE8 standards mode.
- */
-mxShape.prototype.reparseVml = function()
-{
- // Assigns temporary IDs to VML nodes so that references can be restored when
- // inserted into the DOM as a string
- for (var i = 0; i < this.vmlNodes.length; i++)
- {
- if (this[this.vmlNodes[i]] != null)
- {
- this[this.vmlNodes[i]].setAttribute('id', 'mxTemporaryReference-' + this.vmlNodes[i]);
- }
- }
-
- this.node.outerHTML = this.node.outerHTML;
-
- // Restores references to the actual DOM nodes
- for (var i = 0; i < this.vmlNodes.length; i++)
- {
- if (this[this.vmlNodes[i]] != null)
- {
- this[this.vmlNodes[i]] = this.node.ownerDocument.getElementById('mxTemporaryReference-' + this.vmlNodes[i]);
- this[this.vmlNodes[i]].removeAttribute('id');
- }
- }
-};
-
-/**
- * Function: insertGradient
- *
- * Inserts the given gradient node.
- */
-mxShape.prototype.insertGradient = function(node)
-{
- // Gradients are inserted late when the owner SVG element is known
- if (node != null)
- {
- // Checks if the given gradient already exists inside the SVG element
- // that also contains the node that represents this shape. If the gradient
- // with the same ID exists in another SVG element, then this will add
- // a copy of the gradient with a different ID to the SVG element and update
- // the reference accordingly. This is required in Firefox because if the
- // referenced fill element is removed from the DOM the shape appears black.
- var count = 0;
- var id = node.getAttribute('id');
- var gradient = document.getElementById(id);
-
- while (gradient != null && gradient.ownerSVGElement != this.node.ownerSVGElement)
- {
- count++;
- id = node.getAttribute('id') + '-' + count;
- gradient = document.getElementById(id);
- }
-
- // According to specification, gradients should be put in a defs
- // section in the first child of the owner SVG element. However,
- // it turns out that gradients only work when added as follows.
- if (gradient == null)
- {
- node.setAttribute('id', id);
- this.node.ownerSVGElement.appendChild(node);
- gradient = node;
- }
-
- if (gradient != null)
- {
- var ref = 'url(#' + id + ')';
- var tmp = (this.innerNode != null) ? this.innerNode : this.node;
-
- if (tmp != null && tmp.getAttribute('fill') != ref)
- {
- tmp.setAttribute('fill', ref);
- }
- }
- }
-};
-
-/**
- * Function: isMixedModeHtml
- *
- * Used to determine if a shape can be rendered using <createHtml> in mixed
- * mode Html without compromising the display accuracy. The default
- * implementation will check if the shape is not rounded or rotated and has
- * no gradient, and will use a DIV if that is the case. It will also check
- * if <mxShape.mixedModeHtml> is true, which is the default settings.
- * Subclassers can either override <mixedModeHtml> or this function if the
- * result depends on dynamic values. The graph's dialect is available via
- * <dialect>.
- */
-mxShape.prototype.isMixedModeHtml = function()
-{
- return this.mixedModeHtml && !this.isRounded && !this.isShadow && this.gradient == null &&
- mxUtils.getValue(this.style, mxConstants.STYLE_GLASS, 0) == 0 &&
- mxUtils.getValue(this.style, mxConstants.STYLE_ROTATION, 0) == 0;
-};
-
-/**
- * Function: create
- *
- * Creates and returns the DOM node(s) for the shape in
- * the given container. This implementation invokes
- * <createSvg>, <createHtml> or <createVml> depending
- * on the <dialect> and style settings.
- *
- * Parameters:
- *
- * container - DOM node that will contain the shape.
- */
-mxShape.prototype.create = function(container)
-{
- var node = null;
-
- if (this.dialect == mxConstants.DIALECT_SVG)
- {
- node = this.createSvg();
- }
- else if (this.dialect == mxConstants.DIALECT_STRICTHTML ||
- (this.preferModeHtml && this.dialect == mxConstants.DIALECT_PREFERHTML) ||
- (this.isMixedModeHtml() && this.dialect == mxConstants.DIALECT_MIXEDHTML))
- {
- node = this.createHtml();
- }
- else
- {
- node = this.createVml();
- }
-
- return node;
-};
-
-/**
- * Function: createHtml
- *
- * Creates and returns the HTML DOM node(s) to represent
- * this shape. This implementation falls back to <createVml>
- * so that the HTML creation is optional.
- */
-mxShape.prototype.createHtml = function()
-{
- var node = document.createElement('DIV');
- this.configureHtmlShape(node);
-
- return node;
-};
-
-/**
- * Function: destroy
- *
- * Destroys the shape by removing it from the DOM and releasing the DOM
- * node associated with the shape using <mxEvent.release>.
- */
-mxShape.prototype.destroy = function()
-{
- if (this.node != null)
- {
- mxEvent.release(this.node);
-
- if (this.node.parentNode != null)
- {
- this.node.parentNode.removeChild(this.node);
- }
-
- if (this.node.glassOverlay)
- {
- this.node.glassOverlay.parentNode.removeChild(this.node.glassOverlay);
- this.node.glassOverlay = null;
- }
-
- this.node = null;
- }
-};
-
-/**
- * Function: apply
- *
- * Applies the style of the given <mxCellState> to the shape. This
- * implementation assigns the following styles to local fields:
- *
- * - <mxConstants.STYLE_FILLCOLOR> => fill
- * - <mxConstants.STYLE_GRADIENTCOLOR> => gradient
- * - <mxConstants.STYLE_GRADIENT_DIRECTION> => gradientDirection
- * - <mxConstants.STYLE_OPACITY> => opacity
- * - <mxConstants.STYLE_STROKECOLOR> => stroke
- * - <mxConstants.STYLE_STROKEWIDTH> => strokewidth
- * - <mxConstants.STYLE_SHADOW> => isShadow
- * - <mxConstants.STYLE_DASHED> => isDashed
- * - <mxConstants.STYLE_SPACING> => spacing
- * - <mxConstants.STYLE_STARTSIZE> => startSize
- * - <mxConstants.STYLE_ENDSIZE> => endSize
- * - <mxConstants.STYLE_ROUNDED> => isRounded
- * - <mxConstants.STYLE_STARTARROW> => startArrow
- * - <mxConstants.STYLE_ENDARROW> => endArrow
- * - <mxConstants.STYLE_ROTATION> => rotation
- * - <mxConstants.STYLE_DIRECTION> => direction
- *
- * This keeps a reference to the <style>. If you need to keep a reference to
- * the cell, you can override this method and store a local reference to
- * state.cell or the <mxCellState> itself.
- *
- * Parameters:
- *
- * state - <mxCellState> of the corresponding cell.
- */
-mxShape.prototype.apply = function(state)
-{
- var style = state.style;
- this.style = style;
-
- if (style != null)
- {
- this.fill = mxUtils.getValue(style, mxConstants.STYLE_FILLCOLOR, this.fill);
- this.gradient = mxUtils.getValue(style, mxConstants.STYLE_GRADIENTCOLOR, this.gradient);
- this.gradientDirection = mxUtils.getValue(style, mxConstants.STYLE_GRADIENT_DIRECTION, this.gradientDirection);
- this.opacity = mxUtils.getValue(style, mxConstants.STYLE_OPACITY, this.opacity);
- this.stroke = mxUtils.getValue(style, mxConstants.STYLE_STROKECOLOR, this.stroke);
- this.strokewidth = mxUtils.getNumber(style, mxConstants.STYLE_STROKEWIDTH, this.strokewidth);
- this.isShadow = mxUtils.getValue(style, mxConstants.STYLE_SHADOW, this.isShadow);
- this.isDashed = mxUtils.getValue(style, mxConstants.STYLE_DASHED, this.isDashed);
- this.spacing = mxUtils.getValue(style, mxConstants.STYLE_SPACING, this.spacing);
- this.startSize = mxUtils.getNumber(style, mxConstants.STYLE_STARTSIZE, this.startSize);
- this.endSize = mxUtils.getNumber(style, mxConstants.STYLE_ENDSIZE, this.endSize);
- this.isRounded = mxUtils.getValue(style, mxConstants.STYLE_ROUNDED, this.isRounded);
- this.startArrow = mxUtils.getValue(style, mxConstants.STYLE_STARTARROW, this.startArrow);
- this.endArrow = mxUtils.getValue(style, mxConstants.STYLE_ENDARROW, this.endArrow);
- this.rotation = mxUtils.getValue(style, mxConstants.STYLE_ROTATION, this.rotation);
- this.direction = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, this.direction);
-
- if (this.fill == 'none')
- {
- this.fill = null;
- }
-
- if (this.gradient == 'none')
- {
- this.gradient = null;
- }
-
- if (this.stroke == 'none')
- {
- this.stroke = null;
- }
- }
-};
-
-/**
- * Function: createSvgGroup
- *
- * Creates a SVG group element and adds the given shape as a child of the
- * element. The child is stored in <innerNode> for later access.
- */
-mxShape.prototype.createSvgGroup = function(shape)
-{
- var g = document.createElementNS(mxConstants.NS_SVG, 'g');
-
- // Creates the shape inside an svg group
- this.innerNode = document.createElementNS(mxConstants.NS_SVG, shape);
- this.configureSvgShape(this.innerNode);
-
- // Avoids anti-aliasing for non-rounded rectangles with a
- // strokewidth of 1 or more pixels
- if (shape == 'rect' && this.strokewidth * this.scale >= 1 && !this.isRounded)
- {
- this.innerNode.setAttribute('shape-rendering', 'optimizeSpeed');
- }
-
- // Creates the shadow
- this.shadowNode = this.createSvgShadow(this.innerNode);
-
- if (this.shadowNode != null)
- {
- g.appendChild(this.shadowNode);
- }
-
- // Appends the main shape after the shadow
- g.appendChild(this.innerNode);
-
- return g;
-};
-
-/**
- * Function: createSvgShadow
- *
- * Creates a clone of the given node and configures the node's color
- * to use <mxConstants.SHADOWCOLOR>.
- */
-mxShape.prototype.createSvgShadow = function(node)
-{
- if (this.isShadow)
- {
- var shadow = node.cloneNode(true);
- shadow.setAttribute('opacity', mxConstants.SHADOW_OPACITY);
-
- if (this.fill != null && this.fill != mxConstants.NONE)
- {
- shadow.setAttribute('fill', mxConstants.SHADOWCOLOR);
- }
-
- if (this.stroke != null && this.stroke != mxConstants.NONE)
- {
- shadow.setAttribute('stroke', mxConstants.SHADOWCOLOR);
- }
-
- return shadow;
- }
-
- return null;
-};
-
-/**
- * Function: configureHtmlShape
- *
- * Configures the specified HTML node by applying the current color,
- * bounds, shadow, opacity etc.
- */
-mxShape.prototype.configureHtmlShape = function(node)
-{
- if (mxUtils.isVml(node))
- {
- this.configureVmlShape(node);
- }
- else
- {
- node.style.position = 'absolute';
- node.style.overflow = 'hidden';
- var color = this.stroke;
-
- if (color != null && color != mxConstants.NONE)
- {
- node.style.borderColor = color;
-
- if (this.isDashed)
- {
- node.style.borderStyle = 'dashed';
- }
- else if (this.strokewidth > 0)
- {
- node.style.borderStyle = 'solid';
- }
-
- node.style.borderWidth = Math.ceil(this.strokewidth * this.scale) + 'px';
- }
- else
- {
- node.style.borderWidth = '0px';
- }
-
- color = this.fill;
- node.style.background = '';
-
- if (color != null && color != mxConstants.NONE)
- {
- node.style.backgroundColor = color;
- }
- else if (this.points == null)
- {
- this.configureTransparentBackground(node);
- }
-
- if (this.opacity != null)
- {
- mxUtils.setOpacity(node, this.opacity);
- }
- }
-};
-
-/**
- * Function: updateVmlFill
- *
- * Updates the given VML fill node.
- */
-mxShape.prototype.updateVmlFill = function(node, c1, c2, dir, alpha)
-{
- node.color = c1;
-
- if (alpha != null && alpha != 100)
- {
- node.opacity = alpha + '%';
-
- if (c2 != null)
- {
- // LATER: Set namespaced attribute without using setAttribute
- // which is required for updating the value in IE8 standards.
- node.setAttribute('o:opacity2', alpha + '%');
- }
- }
-
- if (c2 != null)
- {
- node.type = 'gradient';
- node.color2 = c2;
- var angle = '180';
-
- if (this.gradientDirection == mxConstants.DIRECTION_EAST)
- {
- angle = '270';
- }
- else if (this.gradientDirection == mxConstants.DIRECTION_WEST)
- {
- angle = '90';
- }
- else if (this.gradientDirection == mxConstants.DIRECTION_NORTH)
- {
- angle = '0';
- }
-
- node.angle = angle;
- }
-};
-
-/**
- * Function: updateVmlStrokeNode
- *
- * Creates the stroke node for VML.
- */
-mxShape.prototype.updateVmlStrokeNode = function(parent)
-{
- // Stroke node is always needed to specify defaults that match SVG output
- if (this.strokeNode == null)
- {
- this.strokeNode = document.createElement('v:stroke');
-
- // To math SVG defaults jointsyle miter and miterlimit 4
- this.strokeNode.joinstyle = 'miter';
- this.strokeNode.miterlimit = 4;
-
- parent.appendChild(this.strokeNode);
- }
-
- if (this.opacity != null)
- {
- this.strokeNode.opacity = this.opacity + '%';
- }
-
- this.updateVmlDashStyle();
-};
-
-/**
- * Function: updateVmlStrokeColor
- *
- * Updates the VML stroke color for the given node.
- */
-mxShape.prototype.updateVmlStrokeColor = function(node)
-{
- var color = this.stroke;
-
- if (color != null && color != mxConstants.NONE)
- {
- node.stroked = 'true';
- node.strokecolor = color;
- }
- else
- {
- node.stroked = 'false';
- }
-};
-
-/**
- * Function: configureVmlShape
- *
- * Configures the specified VML node by applying the current color,
- * bounds, shadow, opacity etc.
- */
-mxShape.prototype.configureVmlShape = function(node)
-{
- node.style.position = 'absolute';
- this.updateVmlStrokeColor(node);
- node.style.background = '';
- var color = this.fill;
-
- if (color != null && color != mxConstants.NONE)
- {
- if (this.fillNode == null)
- {
- this.fillNode = document.createElement('v:fill');
- node.appendChild(this.fillNode);
- }
-
- this.updateVmlFill(this.fillNode, color, this.gradient, this.gradientDirection, this.opacity);
- }
- else
- {
- node.filled = 'false';
-
- if (this.points == null)
- {
- this.configureTransparentBackground(node);
- }
- }
-
- this.updateVmlStrokeNode(node);
-
- if (this.isShadow)
- {
- this.createVmlShadow(node);
- }
-
- // Fixes possible hang in IE when arcsize is set on non-rects
- if (node.nodeName == 'roundrect')
- {
- // Workaround for occasional "member not found" error
- try
- {
- var f = mxConstants.RECTANGLE_ROUNDING_FACTOR * 100;
-
- if (this.style != null)
- {
- f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, f);
- }
-
- node.setAttribute('arcsize', String(f) + '%');
- }
- catch (e)
- {
- // ignore
- }
- }
-};
-
-/**
- * Function: createVmlShadow
- *
- * Creates the VML shadow node.
- */
-mxShape.prototype.createVmlShadow = function(node)
-{
- // Adds a shadow only once per shape
- if (this.shadowNode == null)
- {
- this.shadowNode = document.createElement('v:shadow');
- this.shadowNode.on = 'true';
- this.shadowNode.color = mxConstants.SHADOWCOLOR;
- this.shadowNode.opacity = (mxConstants.SHADOW_OPACITY * 100) + '%';
-
- this.shadowStrokeNode = document.createElement('v:stroke');
- this.shadowNode.appendChild(this.shadowStrokeNode);
-
- node.appendChild(this.shadowNode);
- }
-};
-
-/**
- * Function: configureTransparentBackground
- *
- * Hook to make the background of a shape transparent. This hook was added as
- * a workaround for the "display non secure items" warning dialog in IE which
- * appears if the background:url(transparent.gif) is used in the overlay pane
- * of a diagram. Since only mxImageShapes currently exist in the overlay pane
- * this function is only overridden in mxImageShape.
- */
-mxShape.prototype.configureTransparentBackground = function(node)
-{
- node.style.background = 'url(\'' + mxClient.imageBasePath + '/transparent.gif\')';
-};
-
-/**
- * Function: configureSvgShape
- *
- * Configures the specified SVG node by applying the current color,
- * bounds, shadow, opacity etc.
- */
-mxShape.prototype.configureSvgShape = function(node)
-{
- var color = this.stroke;
-
- if (color != null && color != mxConstants.NONE)
- {
- node.setAttribute('stroke', color);
- }
- else
- {
- node.setAttribute('stroke', 'none');
- }
-
- color = this.fill;
-
- if (color != null && color != mxConstants.NONE)
- {
- // Fetches a reference to a shared gradient
- if (this.gradient != null)
- {
- var id = this.getGradientId(color, this.gradient);
-
- if (this.gradientNode != null && this.gradientNode.getAttribute('id') != id)
- {
- this.gradientNode = null;
- node.setAttribute('fill', '');
- }
-
- if (this.gradientNode == null)
- {
- this.gradientNode = this.createSvgGradient(id,
- color, this.gradient, node);
- node.setAttribute('fill', 'url(#'+id+')');
- }
- }
- else
- {
- // TODO: Remove gradient from document if no longer shared
- this.gradientNode = null;
- node.setAttribute('fill', color);
- }
- }
- else
- {
- node.setAttribute('fill', 'none');
- }
-
- if (this.opacity != null)
- {
- // Improves opacity performance in Firefox
- node.setAttribute('fill-opacity', this.opacity / 100);
- node.setAttribute('stroke-opacity', this.opacity / 100);
- }
-};
-
-/**
- * Function: getGradientId
- *
- * Creates a unique ID for the gradient of this shape.
- */
-mxShape.prototype.getGradientId = function(start, end)
-{
- // Removes illegal characters from gradient ID
- if (start.charAt(0) == '#')
- {
- start = start.substring(1);
- }
-
- if (end.charAt(0) == '#')
- {
- end = end.substring(1);
- }
-
- // Workaround for gradient IDs not working in Safari 5 / Chrome 6
- // if they contain uppercase characters
- start = start.toLowerCase();
- end = end.toLowerCase();
-
- var dir = null;
-
- if (this.gradientDirection == null ||
- this.gradientDirection == mxConstants.DIRECTION_SOUTH)
- {
- dir = 'south';
- }
- else if (this.gradientDirection == mxConstants.DIRECTION_EAST)
- {
- dir = 'east';
- }
- else
- {
- var tmp = start;
- start = end;
- end = tmp;
-
- if (this.gradientDirection == mxConstants.DIRECTION_NORTH)
- {
- dir = 'south';
- }
- else if (this.gradientDirection == mxConstants.DIRECTION_WEST)
- {
- dir = 'east';
- }
- }
-
- return 'mx-gradient-'+start+'-'+end+'-'+dir;
-};
-
-/**
- * Function: createSvgPipe
- *
- * Creates an invisible path which is used to increase the hit detection for
- * edges in SVG.
- */
-mxShape.prototype.createSvgPipe = function(id, start, end, node)
-{
- var pipe = document.createElementNS(mxConstants.NS_SVG, 'path');
- pipe.setAttribute('pointer-events', 'stroke');
- pipe.setAttribute('fill', 'none');
- pipe.setAttribute('visibility', 'hidden');
- // Workaround for Opera ignoring the visiblity attribute above while
- // other browsers need a stroke color to perform the hit-detection but
- // do not ignore the visibility attribute. Side-effect is that Opera's
- // hit detection for horizontal/vertical edges seems to ignore the pipe.
- pipe.setAttribute('stroke', (mxClient.IS_OP) ? 'none' : 'white');
-
- return pipe;
-};
-
-/**
- * Function: createSvgGradient
- *
- * Creates a gradient object for SVG using the specified startcolor,
- * endcolor and opacity.
- */
-mxShape.prototype.createSvgGradient = function(id, start, end, node)
-{
- var gradient = this.insertGradientNode;
-
- if (gradient == null)
- {
- gradient = document.createElementNS(mxConstants.NS_SVG, 'linearGradient');
- gradient.setAttribute('id', id);
- gradient.setAttribute('x1', '0%');
- gradient.setAttribute('y1', '0%');
- gradient.setAttribute('x2', '0%');
- gradient.setAttribute('y2', '0%');
-
- if (this.gradientDirection == null ||
- this.gradientDirection == mxConstants.DIRECTION_SOUTH)
- {
- gradient.setAttribute('y2', '100%');
- }
- else if (this.gradientDirection == mxConstants.DIRECTION_EAST)
- {
- gradient.setAttribute('x2', '100%');
- }
- else if (this.gradientDirection == mxConstants.DIRECTION_NORTH)
- {
- gradient.setAttribute('y1', '100%');
- }
- else if (this.gradientDirection == mxConstants.DIRECTION_WEST)
- {
- gradient.setAttribute('x1', '100%');
- }
-
- var stop = document.createElementNS(mxConstants.NS_SVG, 'stop');
- stop.setAttribute('offset', '0%');
- stop.setAttribute('style', 'stop-color:'+start);
- gradient.appendChild(stop);
-
- stop = document.createElementNS(mxConstants.NS_SVG, 'stop');
- stop.setAttribute('offset', '100%');
- stop.setAttribute('style', 'stop-color:'+end);
- gradient.appendChild(stop);
- }
-
- // Inserted later when the owner SVG element is known
- this.insertGradientNode = gradient;
-
- return gradient;
-};
-
-/**
- * Function: createPoints
- *
- * Creates a path expression using the specified commands for this.points.
- * If <isRounded> is true, then the path contains curves for the corners.
- */
-mxShape.prototype.createPoints = function(moveCmd, lineCmd, curveCmd, isRelative)
-{
- var offsetX = (isRelative) ? this.bounds.x : 0;
- var offsetY = (isRelative) ? this.bounds.y : 0;
-
- // Workaround for crisp shape-rendering in IE9
- var crisp = (this.crisp && this.dialect == mxConstants.DIALECT_SVG && mxClient.IS_IE) ? 0.5 : 0;
-
- if (isNaN(this.points[0].x) || isNaN(this.points[0].y))
- {
- return null;
- }
-
- var size = mxConstants.LINE_ARCSIZE * this.scale;
- var p0 = this.points[0];
-
- if (this.startOffset != null)
- {
- p0 = p0.clone();
- p0.x += this.startOffset.x;
- p0.y += this.startOffset.y;
- }
-
- var points = moveCmd + ' ' + (Math.round(p0.x - offsetX) + crisp) + ' ' +
- (Math.round(p0.y - offsetY) + crisp) + ' ';
-
- for (var i = 1; i < this.points.length; i++)
- {
- p0 = this.points[i - 1];
- var pt = this.points[i];
-
- if (isNaN(pt.x) || isNaN(pt.y))
- {
- return null;
- }
-
- if (i == this.points.length - 1 && this.endOffset != null)
- {
- pt = pt.clone();
- pt.x += this.endOffset.x;
- pt.y += this.endOffset.y;
- }
-
- var dx = p0.x - pt.x;
- var dy = p0.y - pt.y;
-
- if ((this.isRounded && i < this.points.length - 1) &&
- (dx != 0 || dy != 0) && this.scale > 0.3)
- {
- // Draws a line from the last point to the current point with a spacing
- // of size off the current point into direction of the last point
- var dist = Math.sqrt(dx * dx + dy * dy);
- var nx1 = dx * Math.min(size, dist / 2) / dist;
- var ny1 = dy * Math.min(size, dist / 2) / dist;
- points += lineCmd + ' ' + (Math.round(pt.x + nx1 - offsetX) + crisp) + ' ' +
- (Math.round(pt.y + ny1 - offsetY) + crisp) + ' ';
-
- // Draws a curve from the last point to the current point with a spacing
- // of size off the current point into direction of the next point
- var pe = this.points[i+1];
- dx = pe.x - pt.x;
- dy = pe.y - pt.y;
-
- dist = Math.max(1, Math.sqrt(dx * dx + dy * dy));
-
- if (dist != 0)
- {
- var nx2 = dx * Math.min(size, dist / 2) / dist;
- var ny2 = dy * Math.min(size, dist / 2) / dist;
-
- points += curveCmd + ' ' + Math.round(pt.x - offsetX) + ' '+
- Math.round(pt.y - offsetY) + ' ' + Math.round(pt.x - offsetX) + ',' +
- Math.round(pt.y - offsetY) + ' ' + (Math.round(pt.x + nx2 - offsetX) + crisp) + ' ' +
- (Math.round(pt.y + ny2 - offsetY) + crisp) + ' ';
- }
- }
- else
- {
- points += lineCmd + ' ' + (Math.round(pt.x - offsetX) + crisp) + ' ' + (Math.round(pt.y - offsetY) + crisp) + ' ';
- }
- }
-
- return points;
-};
-
-/**
- * Function: updateHtmlShape
- *
- * Updates the bounds or points of the specified HTML node and
- * updates the inner children to reflect the changes.
- */
-mxShape.prototype.updateHtmlShape = function(node)
-{
- if (node != null)
- {
- if (mxUtils.isVml(node))
- {
- this.updateVmlShape(node);
- }
- else
- {
- var sw = Math.ceil(this.strokewidth * this.scale);
- node.style.borderWidth = Math.max(1, sw) + 'px';
-
- if (this.bounds != null && !isNaN(this.bounds.x) && !isNaN(this.bounds.y) &&
- !isNaN(this.bounds.width) && !isNaN(this.bounds.height))
- {
- node.style.left = Math.round(this.bounds.x - sw / 2) + 'px';
- node.style.top = Math.round(this.bounds.y - sw / 2) + 'px';
-
- if (document.compatMode == 'CSS1Compat')
- {
- sw = -sw;
- }
-
- node.style.width = Math.round(Math.max(0, this.bounds.width + sw)) + 'px';
- node.style.height = Math.round(Math.max(0, this.bounds.height + sw)) + 'px';
-
- if (this.bounds.width == 0 || this.bounds.height == 0)
- {
- node.style.visibility = 'hidden';
- }
- else
- {
- node.style.visibility = 'visible';
- }
- }
- }
-
- if (this.points != null && this.bounds != null && !mxUtils.isVml(node))
- {
- if (this.divContainer == null)
- {
- this.divContainer = node;
- }
-
- while (this.divContainer.firstChild != null)
- {
- mxEvent.release(this.divContainer.firstChild);
- this.divContainer.removeChild(this.divContainer.firstChild);
- }
-
- node.style.borderStyle = '';
- node.style.background = '';
-
- if (this.points.length == 2)
- {
- var p0 = this.points[0];
- var pe = this.points[1];
-
- var dx = pe.x - p0.x;
- var dy = pe.y - p0.y;
-
- if (dx == 0 || dy == 0)
- {
- node.style.borderStyle = 'solid';
- }
- else
- {
- node.style.width = Math.round(this.bounds.width + 1) + 'px';
- node.style.height = Math.round(this.bounds.height + 1) + 'px';
-
- var length = Math.sqrt(dx * dx + dy * dy);
- var dotCount = 1 + (length / (8 * this.scale));
-
- var nx = dx / dotCount;
- var ny = dy / dotCount;
- var x = p0.x - this.bounds.x;
- var y = p0.y - this.bounds.y;
-
- for (var i = 0; i < dotCount; i++)
- {
- var tmp = document.createElement('DIV');
-
- tmp.style.position = 'absolute';
- tmp.style.overflow = 'hidden';
-
- tmp.style.left = Math.round(x) + 'px';
- tmp.style.top = Math.round(y) + 'px';
- tmp.style.width = Math.max(1, 2 * this.scale) + 'px';
- tmp.style.height = Math.max(1, 2 * this.scale) + 'px';
-
- tmp.style.backgroundColor = this.stroke;
- this.divContainer.appendChild(tmp);
-
- x += nx;
- y += ny;
- }
- }
- }
- else if (this.points.length == 3)
- {
- var mid = this.points[1];
-
- var n = '0';
- var s = '1';
- var w = '0';
- var e = '1';
-
- if (mid.x == this.bounds.x)
- {
- e = '0';
- w = '1';
- }
-
- if (mid.y == this.bounds.y)
- {
- n = '1';
- s = '0';
- }
-
- node.style.borderStyle = 'solid';
- node.style.borderWidth = n + ' ' + e + ' ' + s + ' ' + w + 'px';
- }
- else
- {
- node.style.width = Math.round(this.bounds.width + 1) + 'px';
- node.style.height = Math.round(this.bounds.height + 1) + 'px';
- var last = this.points[0];
-
- for (var i = 1; i < this.points.length; i++)
- {
- var next = this.points[i];
-
- // TODO: Use one div for multiple lines
- var tmp = document.createElement('DIV');
-
- tmp.style.position = 'absolute';
- tmp.style.overflow = 'hidden';
-
- tmp.style.borderColor = this.stroke;
- tmp.style.borderStyle = 'solid';
- tmp.style.borderWidth = '1 0 0 1px';
-
- var x = Math.min(next.x, last.x) - this.bounds.x;
- var y = Math.min(next.y, last.y) - this.bounds.y;
- var w = Math.max(1, Math.abs(next.x - last.x));
- var h = Math.max(1, Math.abs(next.y - last.y));
-
- tmp.style.left = x + 'px';
- tmp.style.top = y + 'px';
- tmp.style.width = w + 'px';
- tmp.style.height = h + 'px';
-
- this.divContainer.appendChild(tmp);
- last = next;
- }
- }
- }
- }
-};
-
-/**
- * Function: updateVmlDashStyle
- *
- * Updates the dashstyle in the stroke node.
- */
-mxShape.prototype.updateVmlDashStyle = function()
-{
- if (this.isDashed)
- {
- if (this.strokeNode.dashstyle != 'dash')
- {
- this.strokeNode.dashstyle = 'dash';
- }
- }
- else if (this.strokeNode.dashstyle != 'solid')
- {
- this.strokeNode.dashstyle = 'solid';
- }
-};
-
-/**
- * Function: updateVmlShape
- *
- * Updates the bounds or points of the specified VML node and
- * updates the inner children to reflect the changes.
- */
-mxShape.prototype.updateVmlShape = function(node)
-{
- node.strokeweight = (this.strokewidth * this.scale) + 'px';
-
- // Dash pattern needs updating as it depends on strokeweight in VML
- if (this.strokeNode != null)
- {
- this.updateVmlDashStyle();
- }
-
- // Updates the offset of the shadow
- if (this.shadowNode != null)
- {
- var dx = Math.round(mxConstants.SHADOW_OFFSET_X * this.scale);
- var dy = Math.round(mxConstants.SHADOW_OFFSET_Y * this.scale);
- this.shadowNode.offset = dx + 'px,' + dy + 'px';
- }
-
- if (this.bounds != null && !isNaN(this.bounds.x) && !isNaN(this.bounds.y) &&
- !isNaN(this.bounds.width) && !isNaN(this.bounds.height))
- {
- var f = 1;
-
- var w = Math.max(0, Math.round(this.bounds.width));
- var h = Math.max(0, Math.round(this.bounds.height));
-
- // Groups and shapes need a coordsize
- if (this.points != null || node.nodeName == 'shape' || node.nodeName == 'group')
- {
- var tmp = (node.parentNode.nodeName == 'group') ? 1 : this.vmlScale;
- node.coordsize = (w * tmp) + ',' + (h * tmp);
- }
- else if (node.parentNode.nodeName == 'group')
- {
- f = this.vmlScale;
- }
-
- // Only top-level nodes are non-relative and rotated
- if (node.parentNode != this.node)
- {
- node.style.left = Math.round(this.bounds.x * f) + 'px';
- node.style.top = Math.round(this.bounds.y * f) + 'px';
-
- if (this.points == null)
- {
- if (this.rotation != null && this.rotation != 0)
- {
- node.style.rotation = this.rotation;
- }
- else if (node.style.rotation != null)
- {
- node.style.rotation = '';
- }
- }
- }
-
- node.style.width = (w * f) + 'px';
- node.style.height = (h * f) + 'px';
- }
-
- if (this.points != null && node.nodeName != 'group')
- {
- if (node.nodeName == 'polyline' && node.points != null)
- {
- var points = '';
-
- for (var i = 0; i < this.points.length; i++)
- {
- points += this.points[i].x + ',' + this.points[i].y + ' ';
- }
-
- node.points.value = points;
-
- node.style.left = null;
- node.style.top = null;
- node.style.width = null;
- node.style.height = null;
- }
- else if (this.bounds != null)
- {
- var points = this.createPoints('m', 'l', 'c', true);
-
- // Smooth style for VML (experimental)
- if (this.style != null && this.style[mxConstants.STYLE_SMOOTH])
- {
- var pts = this.points;
- var n = pts.length;
-
- if (n > 3)
- {
- var x0 = this.bounds.x;
- var y0 = this.bounds.y;
- points = 'm ' + Math.round(pts[0].x - x0) + ' ' + Math.round(pts[0].y - y0) + ' qb';
-
- for (var i = 1; i < n - 1; i++)
- {
- points += ' ' + Math.round(pts[i].x - x0) + ' ' + Math.round(pts[i].y - y0);
- }
-
- points += ' nf l ' + Math.round(pts[n - 1].x - x0) + ' ' + Math.round(pts[n - 1].y - y0);
- }
- }
-
- node.path = points + ' e';
- }
- }
-};
-
-/**
- * Function: updateSvgBounds
- *
- * Updates the bounds of the given node using <bounds>.
- */
-mxShape.prototype.updateSvgBounds = function(node)
-{
- var w = this.bounds.width;
- var h = this.bounds.height;
-
- if (this.isRounded && !(this.crisp && mxClient.IS_IE))
- {
- node.setAttribute('x', this.bounds.x);
- node.setAttribute('y', this.bounds.y);
- node.setAttribute('width', w);
- node.setAttribute('height', h);
- }
- else
- {
- // Workaround for crisp shape-rendering in IE9
- var dd = (this.crisp && mxClient.IS_IE) ? 0.5 : 0;
- node.setAttribute('x', Math.round(this.bounds.x) + dd);
- node.setAttribute('y', Math.round(this.bounds.y) + dd);
-
- w = Math.round(w);
- h = Math.round(h);
-
- node.setAttribute('width', w);
- node.setAttribute('height', h);
- }
-
- if (this.isRounded)
- {
- var f = mxConstants.RECTANGLE_ROUNDING_FACTOR * 100;
-
- if (this.style != null)
- {
- f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, f) / 100;
- }
-
- var r = Math.min(w * f, h * f);
- node.setAttribute('rx', r);
- node.setAttribute('ry', r);
- }
-
- this.updateSvgTransform(node, node == this.shadowNode);
-};
-
-/**
- * Function: updateSvgPath
- *
- * Updates the path of the given node using <points>.
- */
-mxShape.prototype.updateSvgPath = function(node)
-{
- var d = this.createPoints('M', 'L', 'C', false);
-
- if (d != null)
- {
- node.setAttribute('d', d);
-
- // Smooth style for SVG (experimental)
- if (this.style != null && this.style[mxConstants.STYLE_SMOOTH])
- {
- var pts = this.points;
- var n = pts.length;
-
- if (n > 3)
- {
- var points = 'M '+pts[0].x+' '+pts[0].y+' ';
- points += ' Q '+pts[1].x + ' ' + pts[1].y + ' ' +
- ' '+pts[2].x + ' ' + pts[2].y;
-
- for (var i = 3; i < n; i++)
- {
- points += ' T ' + pts[i].x + ' ' + pts[i].y;
- }
-
- node.setAttribute('d', points);
- }
- }
-
- node.removeAttribute('x');
- node.removeAttribute('y');
- node.removeAttribute('width');
- node.removeAttribute('height');
- }
-};
-
-/**
- * Function: updateSvgScale
- *
- * Updates the properties of the given node that depend on the scale and checks
- * the crisp rendering attribute.
- */
-mxShape.prototype.updateSvgScale = function(node)
-{
- node.setAttribute('stroke-width', Math.round(Math.max(1, this.strokewidth * this.scale)));
-
- if (this.isDashed)
- {
- var phase = Math.max(1, Math.round(3 * this.scale * this.strokewidth));
- node.setAttribute('stroke-dasharray', phase + ' ' + phase);
- }
-
- if (this.crisp && (this.roundedCrispSvg || this.isRounded != true) &&
- (this.rotation == null || this.rotation == 0))
- {
- node.setAttribute('shape-rendering', 'crispEdges');
- }
- else
- {
- node.removeAttribute('shape-rendering');
- }
-};
-
-/**
- * Function: updateSvgShape
- *
- * Updates the bounds or points of the specified SVG node and
- * updates the inner children to reflect the changes.
- */
-mxShape.prototype.updateSvgShape = function(node)
-{
- if (this.points != null && this.points[0] != null)
- {
- this.updateSvgPath(node);
- }
- else if (this.bounds != null)
- {
- this.updateSvgBounds(node);
- }
-
- this.updateSvgScale(node);
-};
-
-/**
- * Function: getSvgShadowTransform
- *
- * Returns the current transformation for SVG shadows.
- */
-mxShape.prototype.getSvgShadowTransform = function(node, shadow)
-{
- var dx = mxConstants.SHADOW_OFFSET_X * this.scale;
- var dy = mxConstants.SHADOW_OFFSET_Y * this.scale;
-
- return 'translate(' + dx + ' ' + dy + ')';
-};
-
-/**
- * Function: updateSvgTransform
- *
- * Updates the tranform of the given node.
- */
-mxShape.prototype.updateSvgTransform = function(node, shadow)
-{
- var st = (shadow) ? this.getSvgShadowTransform() : '';
-
- if (this.rotation != null && this.rotation != 0)
- {
- var cx = this.bounds.x + this.bounds.width / 2;
- var cy = this.bounds.y + this.bounds.height / 2;
- node.setAttribute('transform', 'rotate(' + this.rotation + ',' + cx + ',' + cy + ') ' + st);
- }
- else
- {
- if (shadow)
- {
- node.setAttribute('transform', st);
- }
- else
- {
- node.removeAttribute('transform');
- }
- }
-};
-
-/**
- * Function: reconfigure
- *
- * Reconfigures this shape. This will update the colors etc in
- * addition to the bounds or points.
- */
-mxShape.prototype.reconfigure = function()
-{
- if (this.dialect == mxConstants.DIALECT_SVG)
- {
- if (this.innerNode != null)
- {
- this.configureSvgShape(this.innerNode);
- }
- else
- {
- this.configureSvgShape(this.node);
- }
-
- if (this.insertGradientNode != null)
- {
- this.insertGradient(this.insertGradientNode);
- this.insertGradientNode = null;
- }
- }
- else if (mxUtils.isVml(this.node))
- {
- this.node.style.visibility = 'hidden';
- this.configureVmlShape(this.node);
- this.node.style.visibility = 'visible';
- }
- else
- {
- this.node.style.visibility = 'hidden';
- this.configureHtmlShape(this.node);
- this.node.style.visibility = 'visible';
- }
-};
-
-/**
- * Function: redraw
- *
- * Invokes <redrawSvg>, <redrawVml> or <redrawHtml> depending on the
- * dialect of the shape.
- */
-mxShape.prototype.redraw = function()
-{
- this.updateBoundingBox();
-
- if (this.dialect == mxConstants.DIALECT_SVG)
- {
- this.redrawSvg();
- }
- else if (mxUtils.isVml(this.node))
- {
- this.node.style.visibility = 'hidden';
- this.redrawVml();
- this.node.style.visibility = 'visible';
- }
- else
- {
- this.redrawHtml();
- }
-};
-
-/**
- * Function: updateBoundingBox
- *
- * Updates the <boundingBox> for this shape using <createBoundingBox> and
- * <augmentBoundingBox> and stores the result in <boundingBox>.
- */
-mxShape.prototype.updateBoundingBox = function()
-{
- if (this.bounds != null)
- {
- var bbox = this.createBoundingBox();
- this.augmentBoundingBox(bbox);
-
- var rot = Number(mxUtils.getValue(this.style, mxConstants.STYLE_ROTATION, 0));
-
- if (rot != 0)
- {
- bbox = mxUtils.getBoundingBox(bbox, rot);
- }
-
- bbox.x = Math.floor(bbox.x);
- bbox.y = Math.floor(bbox.y);
- // TODO: Fix rounding errors
- bbox.width = Math.ceil(bbox.width);
- bbox.height = Math.ceil(bbox.height);
-
- this.boundingBox = bbox;
- }
-};
-
-/**
- * Function: createBoundingBox
- *
- * Returns a new rectangle that represents the bounding box of the bare shape
- * with no shadows or strokewidths.
- */
-mxShape.prototype.createBoundingBox = function()
-{
- return this.bounds.clone();
-};
-
-/**
- * Function: augmentBoundingBox
- *
- * Augments the bounding box with the strokewidth and shadow offsets.
- */
-mxShape.prototype.augmentBoundingBox = function(bbox)
-{
- if (this.isShadow)
- {
- bbox.width += Math.ceil(mxConstants.SHADOW_OFFSET_X * this.scale);
- bbox.height += Math.ceil(mxConstants.SHADOW_OFFSET_Y * this.scale);
- }
-
- // Adds strokeWidth
- var sw = Math.ceil(this.strokewidth * this.scale);
- bbox.grow(Math.ceil(sw / 2));
-};
-
-/**
- * Function: redrawSvg
- *
- * Redraws this SVG shape by invoking <updateSvgShape> on this.node,
- * this.innerNode and this.shadowNode.
- */
-mxShape.prototype.redrawSvg = function()
-{
- if (this.innerNode != null)
- {
- this.updateSvgShape(this.innerNode);
-
- if (this.shadowNode != null)
- {
- this.updateSvgShape(this.shadowNode);
- }
- }
- else
- {
- this.updateSvgShape(this.node);
-
- // Updates the transform of the shadow
- if (this.shadowNode != null)
- {
- this.shadowNode.setAttribute('transform', this.getSvgShadowTransform());
- }
- }
-
- this.updateSvgGlassPane();
-};
-
-/**
- * Function: updateVmlGlassPane
- *
- * Draws the glass overlay if mxConstants.STYLE_GLASS is 1.
- */
-mxShape.prototype.updateVmlGlassPane = function()
-{
- // Currently only used in mxLabel. Most shapes would have to be changed to use
- // a group node in VML which might affect performance for glass-less cells.
- if (this.bounds != null && this.node.nodeName == 'group' && this.style != null &&
- mxUtils.getValue(this.style, mxConstants.STYLE_GLASS, 0) == 1)
- {
- // Glass overlay
- if (this.node.glassOverlay == null)
- {
- // Creates glass overlay
- this.node.glassOverlay = document.createElement('v:shape');
- this.node.glassOverlay.setAttribute('filled', 'true');
- this.node.glassOverlay.setAttribute('fillcolor', 'white');
- this.node.glassOverlay.setAttribute('stroked', 'false');
-
- var fillNode = document.createElement('v:fill');
- fillNode.setAttribute('type', 'gradient');
- fillNode.setAttribute('color', 'white');
- fillNode.setAttribute('color2', 'white');
- fillNode.setAttribute('opacity', '90%');
- fillNode.setAttribute('o:opacity2', '15%');
- fillNode.setAttribute('angle', '180');
-
- this.node.glassOverlay.appendChild(fillNode);
- this.node.appendChild(this.node.glassOverlay);
- }
-
- var size = 0.4;
-
- // TODO: Mask with rectangle or rounded rectangle of label
- var b = this.bounds;
- var sw = Math.ceil(this.strokewidth * this.scale / 2 + 1);
- var d = 'm ' + (-sw) + ' ' + (-sw) + ' l ' + (-sw) + ' ' + Math.round(b.height * size) +
- ' c ' + Math.round(b.width * 0.3) + ' ' + Math.round(b.height * 0.6) +
- ' ' + Math.round(b.width * 0.7) + ' ' + Math.round(b.height * 0.6) +
- ' ' + Math.round(b.width + sw) + ' ' + Math.round(b.height * size) +
- ' l '+Math.round(b.width + sw)+' ' + (-sw) + ' x e';
- this.node.glassOverlay.style.position = 'absolute';
- this.node.glassOverlay.style.width = b.width + 'px';
- this.node.glassOverlay.style.height = b.height + 'px';
- this.node.glassOverlay.setAttribute('coordsize',
- Math.round(this.bounds.width) + ',' +
- Math.round(this.bounds.height));
- this.node.glassOverlay.setAttribute('path', d);
- }
- else if (this.node.glassOverlay != null)
- {
- this.node.glassOverlay.parentNode.removeChild(this.node.glassOverlay);
- this.node.glassOverlay = null;
- }
-};
-
-/**
- * Function: updateSvgGlassPane
- *
- * Draws the glass overlay if mxConstants.STYLE_GLASS is 1.
- */
-mxShape.prototype.updateSvgGlassPane = function()
-{
- if (this.node.nodeName == 'g' && this.style != null &&
- mxUtils.getValue(this.style, mxConstants.STYLE_GLASS, 0) == 1)
- {
- // Glass overlay
- if (this.node.glassOverlay == null)
- {
- // Glass overlay gradient
- if (this.node.ownerSVGElement.glassGradient == null)
- {
- // Creates glass overlay gradient
- var glassGradient = document.createElementNS(mxConstants.NS_SVG, 'linearGradient');
- glassGradient.setAttribute('x1', '0%');
- glassGradient.setAttribute('y1', '0%');
- glassGradient.setAttribute('x2', '0%');
- glassGradient.setAttribute('y2', '100%');
-
- var stop1 = document.createElementNS(mxConstants.NS_SVG, 'stop');
- stop1.setAttribute('offset', '0%');
- stop1.setAttribute('style', 'stop-color:#ffffff;stop-opacity:0.9');
- glassGradient.appendChild(stop1);
-
- var stop2 = document.createElementNS(mxConstants.NS_SVG, 'stop');
- stop2.setAttribute('offset', '100%');
- stop2.setAttribute('style', 'stop-color:#ffffff;stop-opacity:0.1');
- glassGradient.appendChild(stop2);
-
- // Finds a unique ID for the gradient
- var prefix = 'mx-glass-gradient-';
- var counter = 0;
-
- while (document.getElementById(prefix+counter) != null)
- {
- counter++;
- }
-
- glassGradient.setAttribute('id', prefix+counter);
- this.node.ownerSVGElement.appendChild(glassGradient);
- this.node.ownerSVGElement.glassGradient = glassGradient;
- }
-
- // Creates glass overlay
- this.node.glassOverlay = document.createElementNS(mxConstants.NS_SVG, 'path');
- // LATER: Not sure what the behaviour is for mutiple SVG elements in page.
- // Probably its possible that this points to an element in another SVG
- // node which when removed will result in an undefined background.
- var id = this.node.ownerSVGElement.glassGradient.getAttribute('id');
- this.node.glassOverlay.setAttribute('style', 'fill:url(#'+id+');');
- this.node.appendChild(this.node.glassOverlay);
- }
-
- var size = 0.4;
-
- // TODO: Mask with rectangle or rounded rectangle of label
- var b = this.bounds;
- var sw = Math.ceil(this.strokewidth * this.scale / 2);
- var d = 'm ' + (b.x - sw) + ',' + (b.y - sw) +
- ' L ' + (b.x - sw) + ',' + (b.y + b.height * size) +
- ' Q '+ (b.x + b.width * 0.5) + ',' + (b.y + b.height * 0.7) + ' '+
- (b.x + b.width + sw) + ',' + (b.y + b.height * size) +
- ' L ' + (b.x + b.width + sw) + ',' + (b.y - sw) + ' z';
- this.node.glassOverlay.setAttribute('d', d);
- }
- else if (this.node.glassOverlay != null)
- {
- this.node.glassOverlay.parentNode.removeChild(this.node.glassOverlay);
- this.node.glassOverlay = null;
- }
-};
-
-/**
- * Function: redrawVml
- *
- * Redraws this VML shape by invoking <updateVmlShape> on this.node.
- */
-mxShape.prototype.redrawVml = function()
-{
- this.node.style.visibility = 'hidden';
- this.updateVmlShape(this.node);
- this.updateVmlGlassPane();
- this.node.style.visibility = 'visible';
-};
-
-/**
- * Function: redrawHtml
- *
- * Redraws this HTML shape by invoking <updateHtmlShape> on this.node.
- */
-mxShape.prototype.redrawHtml = function()
-{
- this.updateHtmlShape(this.node);
-};
-
-/**
- * Function: getRotation
- *
- * Returns the current rotation including direction.
- */
-mxShape.prototype.getRotation = function()
-{
- var rot = this.rotation || 0;
-
- // Default direction is east (ignored if rotation exists)
- if (this.direction != null)
- {
- if (this.direction == 'north')
- {
- rot += 270;
- }
- else if (this.direction == 'west')
- {
- rot += 180;
- }
- else if (this.direction == 'south')
- {
- rot += 90;
- }
- }
-
- return rot;
-};
-
-/**
- * Function: createPath
- *
- * Creates an <mxPath> for the specified format and origin. The path object is
- * then passed to <redrawPath> and <mxPath.getPath> is returned.
- */
-mxShape.prototype.createPath = function(arg)
-{
- var x = this.bounds.x;
- var y = this.bounds.y;
- var w = this.bounds.width;
- var h = this.bounds.height;
- var dx = 0;
- var dy = 0;
-
- // Inverts bounds for stencils which are rotated 90 or 270 degrees
- if (this.direction == 'north' || this.direction == 'south')
- {
- dx = (w - h) / 2;
- dy = (h - w) / 2;
- x += dx;
- y += dy;
- var tmp = w;
- w = h;
- h = tmp;
- }
-
- var rotation = this.getRotation();
- var path = null;
-
- if (this.dialect == mxConstants.DIALECT_SVG)
- {
- path = new mxPath('svg');
- path.setTranslate(x, y);
-
- // Adds rotation as a separate transform
- if (rotation != 0)
- {
- var cx = this.bounds.getCenterX();
- var cy = this.bounds.getCenterY();
- var transform = 'rotate(' + rotation + ' ' + cx + ' ' + cy + ')';
-
- if (this.innerNode != null)
- {
- this.innerNode.setAttribute('transform', transform);
- }
-
- if (this.foreground != null)
- {
- this.foreground.setAttribute('transform', transform);
- }
-
- // Shadow needs different transform so that it ends up on the correct side
- if (this.shadowNode != null)
- {
- this.shadowNode.setAttribute('transform', this.getSvgShadowTransform() + ' ' + transform);
- }
- }
- }
- else
- {
- path = new mxPath('vml');
- path.setTranslate(dx, -dx);
- path.scale = this.vmlScale;
-
- if (rotation != 0)
- {
- this.node.style.rotation = rotation;
- }
- }
-
- this.redrawPath(path, x, y, w, h, arg);
-
- return path.getPath();
-};
-
-/**
- * Function: redrawPath
- *
- * Draws the path for this shape. This implementation is empty. See
- * <mxActor> and <mxCylinder> for implementations.
- */
-mxShape.prototype.redrawPath = function(path, x, y, w, h)
-{
- // do nothing
-};