summaryrefslogtreecommitdiff
path: root/src/js/view/mxCellRenderer.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/view/mxCellRenderer.js')
-rw-r--r--src/js/view/mxCellRenderer.js1480
1 files changed, 0 insertions, 1480 deletions
diff --git a/src/js/view/mxCellRenderer.js b/src/js/view/mxCellRenderer.js
deleted file mode 100644
index 6b506ad..0000000
--- a/src/js/view/mxCellRenderer.js
+++ /dev/null
@@ -1,1480 +0,0 @@
-/**
- * $Id: mxCellRenderer.js,v 1.189 2012-11-20 09:06:07 gaudenz Exp $
- * Copyright (c) 2006-2010, JGraph Ltd
- */
-/**
- * Class: mxCellRenderer
- *
- * Renders cells into a document object model. The <defaultShapes> is a global
- * map of shapename, constructor pairs that is used in all instances. You can
- * get a list of all available shape names using the following code.
- *
- * In general the cell renderer is in charge of creating, redrawing and
- * destroying the shape and label associated with a cell state, as well as
- * some other graphical objects, namely controls and overlays. The shape
- * hieararchy in the display (ie. the hierarchy in which the DOM nodes
- * appear in the document) does not reflect the cell hierarchy. The shapes
- * are a (flat) sequence of shapes and labels inside the draw pane of the
- * graph view, with some exceptions, namely the HTML labels being placed
- * directly inside the graph container for certain browsers.
- *
- * (code)
- * mxLog.show();
- * for (var i in mxCellRenderer.prototype.defaultShapes)
- * {
- * mxLog.debug(i);
- * }
- * (end)
- *
- * Constructor: mxCellRenderer
- *
- * Constructs a new cell renderer with the following built-in shapes:
- * arrow, rectangle, ellipse, rhombus, image, line, label, cylinder,
- * swimlane, connector, actor and cloud.
- */
-function mxCellRenderer()
-{
- this.shapes = mxUtils.clone(this.defaultShapes);
-};
-
-/**
- * Variable: shapes
- *
- * Array that maps from shape names to shape constructors. All entries
- * in <defaultShapes> are added to this array.
- */
-mxCellRenderer.prototype.shapes = null;
-
-/**
- * Variable: defaultEdgeShape
- *
- * Defines the default shape for edges. Default is <mxConnector>.
- */
-mxCellRenderer.prototype.defaultEdgeShape = mxConnector;
-
-/**
- * Variable: defaultVertexShape
- *
- * Defines the default shape for vertices. Default is <mxRectangleShape>.
- */
-mxCellRenderer.prototype.defaultVertexShape = mxRectangleShape;
-
-/**
- * Variable: defaultShapes
- *
- * Static array that contains the globally registered shapes which are
- * known to all instances of this class. For adding instance-specific
- * shapes you should use <registerShape> on the instance. For adding
- * a shape to this array you can use the following code:
- *
- * (code)
- * mxCellRenderer.prototype.defaultShapes['myshape'] = myShape;
- * (end)
- *
- * Where 'myshape' is the key under which the shape is to be registered
- * and myShape is the name of the constructor function.
- */
-mxCellRenderer.prototype.defaultShapes = new Object();
-
-// Adds default shapes into the default shapes array
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_ARROW] = mxArrow;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_RECTANGLE] = mxRectangleShape;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_ELLIPSE] = mxEllipse;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_DOUBLE_ELLIPSE] = mxDoubleEllipse;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_RHOMBUS] = mxRhombus;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_IMAGE] = mxImageShape;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_LINE] = mxLine;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_LABEL] = mxLabel;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_CYLINDER] = mxCylinder;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_SWIMLANE] = mxSwimlane;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_CONNECTOR] = mxConnector;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_ACTOR] = mxActor;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_CLOUD] = mxCloud;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_TRIANGLE] = mxTriangle;
-mxCellRenderer.prototype.defaultShapes[mxConstants.SHAPE_HEXAGON] = mxHexagon;
-
-/**
- * Function: registerShape
- *
- * Registers the given constructor under the specified key in this instance
- * of the renderer.
- *
- * Example:
- *
- * (code)
- * this.registerShape(mxConstants.SHAPE_RECTANGLE, mxRectangleShape);
- * (end)
- *
- * Parameters:
- *
- * key - String representing the shape name.
- * shape - Constructor of the <mxShape> subclass.
- */
-mxCellRenderer.prototype.registerShape = function(key, shape)
-{
- this.shapes[key] = shape;
-};
-
-/**
- * Function: initialize
- *
- * Initializes the display for the given cell state. This is required once
- * after the cell state has been created. This is invoked in
- * mxGraphView.createState.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the display should be initialized.
- * rendering - Optional boolean that specifies if the cell should actually
- * be initialized for any given DOM node. If this is false then init
- * will not be called on the shape.
- */
-mxCellRenderer.prototype.initialize = function(state, rendering)
-{
- var model = state.view.graph.getModel();
-
- if (state.view.graph.container != null && state.shape == null &&
- state.cell != state.view.currentRoot &&
- (model.isVertex(state.cell) || model.isEdge(state.cell)))
- {
- this.createShape(state);
-
- if (state.shape != null && (rendering == null || rendering))
- {
- this.initializeShape(state);
-
- // Maintains the model order in the DOM
- if (state.view.graph.ordered || model.isEdge(state.cell))
- {
- //state.orderChanged = true;
- state.invalidOrder = true;
- }
- else if (state.view.graph.keepEdgesInForeground && this.firstEdge != null)
- {
- if (this.firstEdge.parentNode == state.shape.node.parentNode)
- {
- this.insertState(state, this.firstEdge);
- }
- else
- {
- this.firstEdge = null;
- }
- }
-
- state.shape.scale = state.view.scale;
-
- this.createCellOverlays(state);
- this.installListeners(state);
- }
- }
-};
-
-/**
- * Function: initializeShape
- *
- * Initializes the shape in the given state by calling its init method with
- * the correct container.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the shape should be initialized.
- */
-mxCellRenderer.prototype.initializeShape = function(state)
-{
- state.shape.init(state.view.getDrawPane());
-};
-
-/**
- * Returns the previous state that has a shape inside the given parent.
- */
-mxCellRenderer.prototype.getPreviousStateInContainer = function(state, container)
-{
- var result = null;
- var graph = state.view.graph;
- var model = graph.getModel();
- var child = state.cell;
- var p = model.getParent(child);
-
- while (p != null && result == null)
- {
- result = this.findPreviousStateInContainer(graph, p, child, container);
- child = p;
- p = model.getParent(child);
- }
-
- return result;
-};
-
-/**
- * Returns the previous state that has a shape inside the given parent.
- */
-mxCellRenderer.prototype.findPreviousStateInContainer = function(graph, cell, stop, container)
-{
- // Recurse first
- var result = null;
- var model = graph.getModel();
-
- if (stop != null)
- {
- var start = cell.getIndex(stop);
-
- for (var i = start - 1; i >= 0 && result == null; i--)
- {
- result = this.findPreviousStateInContainer(graph, model.getChildAt(cell, i), null, container);
- }
- }
- else
- {
- var childCount = model.getChildCount(cell);
-
- for (var i = childCount - 1; i >= 0 && result == null; i--)
- {
- result = this.findPreviousStateInContainer(graph, model.getChildAt(cell, i), null, container);
- }
- }
-
- if (result == null)
- {
- result = graph.view.getState(cell);
-
- if (result != null && (result.shape == null || result.shape.node == null ||
- result.shape.node.parentNode != container))
- {
- result = null;
- }
- }
-
- return result;
-};
-
-/**
- * Function: order
- *
- * Orders the DOM node of the shape for the given state according to the
- * position of the corresponding cell in the graph model.
- *
- * Parameters:
- *
- * state - <mxCellState> whose shape's DOM node should be ordered.
- */
-mxCellRenderer.prototype.order = function(state)
-{
- var container = state.shape.node.parentNode;
- var previous = this.getPreviousStateInContainer(state, container);
- var nextNode = container.firstChild;
-
- if (previous != null)
- {
- nextNode = previous.shape.node;
-
- if (previous.text != null && previous.text.node != null &&
- previous.text.node.parentNode == container)
- {
- nextNode = previous.text.node;
- }
-
- nextNode = nextNode.nextSibling;
- }
-
- this.insertState(state, nextNode);
-};
-
-/**
- * Function: orderEdge
- *
- * Orders the DOM node of the shape for the given edge's state according to
- * the <mxGraph.keepEdgesInBackground> and <mxGraph.keepEdgesInBackground>
- * rules.
- *
- * Parameters:
- *
- * state - <mxCellState> whose shape's DOM node should be ordered.
- */
-mxCellRenderer.prototype.orderEdge = function(state)
-{
- var view = state.view;
- var model = view.graph.getModel();
-
- // Moves edges to the foreground/background
- if (view.graph.keepEdgesInForeground)
- {
- if (this.firstEdge == null || this.firstEdge.parentNode == null ||
- this.firstEdge.parentNode != state.shape.node.parentNode)
- {
- this.firstEdge = state.shape.node;
- }
- }
- else if (view.graph.keepEdgesInBackground)
- {
- var node = state.shape.node;
- var parent = node.parentNode;
-
- // Keeps the DOM node in front of its parent
- var pcell = model.getParent(state.cell);
- var pstate = view.getState(pcell);
-
- if (pstate != null && pstate.shape != null && pstate.shape.node != null)
- {
- var child = pstate.shape.node.nextSibling;
-
- if (child != null && child != node)
- {
- this.insertState(state, child);
- }
- }
- else
- {
- var child = parent.firstChild;
-
- if (child != null && child != node)
- {
- this.insertState(state, child);
- }
- }
- }
-};
-
-/**
- * Function: insertState
- *
- * Inserts the given state before the given node into its parent.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the shape should be created.
- */
-mxCellRenderer.prototype.insertState = function(state, nextNode)
-{
- state.shape.node.parentNode.insertBefore(state.shape.node, nextNode);
-
- if (state.text != null && state.text.node != null &&
- state.text.node.parentNode == state.shape.node.parentNode)
- {
- state.shape.node.parentNode.insertBefore(state.text.node, state.shape.node.nextSibling);
- }
-};
-
-/**
- * Function: createShape
- *
- * Creates the shape for the given cell state. The shape is configured
- * using <configureShape>.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the shape should be created.
- */
-mxCellRenderer.prototype.createShape = function(state)
-{
- if (state.style != null)
- {
- // Checks if there is a stencil for the name and creates
- // a shape instance for the stencil if one exists
- var key = state.style[mxConstants.STYLE_SHAPE];
- var stencil = mxStencilRegistry.getStencil(key);
-
- if (stencil != null)
- {
- state.shape = new mxStencilShape(stencil);
- }
- else
- {
- var ctor = this.getShapeConstructor(state);
- state.shape = new ctor();
- }
-
- // Sets the initial bounds and points (will be updated in redraw)
- state.shape.points = state.absolutePoints;
- state.shape.bounds = new mxRectangle(
- state.x, state.y, state.width, state.height);
- state.shape.dialect = state.view.graph.dialect;
-
- this.configureShape(state);
- }
-};
-
-/**
- * Function: getShapeConstructor
- *
- * Returns the constructor to be used for creating the shape.
- */
-mxCellRenderer.prototype.getShapeConstructor = function(state)
-{
- var key = state.style[mxConstants.STYLE_SHAPE];
- var ctor = (key != null) ? this.shapes[key] : null;
-
- if (ctor == null)
- {
- ctor = (state.view.graph.getModel().isEdge(state.cell)) ?
- this.defaultEdgeShape : this.defaultVertexShape;
- }
-
- return ctor;
-};
-
-/**
- * Function: configureShape
- *
- * Configures the shape for the given cell state.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the shape should be configured.
- */
-mxCellRenderer.prototype.configureShape = function(state)
-{
- state.shape.apply(state);
- var image = state.view.graph.getImage(state);
-
- if (image != null)
- {
- state.shape.image = image;
- }
-
- var indicator = state.view.graph.getIndicatorColor(state);
- var key = state.view.graph.getIndicatorShape(state);
- var ctor = (key != null) ? this.shapes[key] : null;
-
- // Configures the indicator shape or image
- if (indicator != null)
- {
- state.shape.indicatorShape = ctor;
- state.shape.indicatorColor = indicator;
- state.shape.indicatorGradientColor =
- state.view.graph.getIndicatorGradientColor(state);
- state.shape.indicatorDirection =
- state.style[mxConstants.STYLE_INDICATOR_DIRECTION];
- }
- else
- {
- var indicator = state.view.graph.getIndicatorImage(state);
-
- if (indicator != null)
- {
- state.shape.indicatorImage = indicator;
- }
- }
-
- this.postConfigureShape(state);
-};
-
-/**
- * Function: postConfigureShape
- *
- * Replaces any reserved words used for attributes, eg. inherit,
- * indicated or swimlane for colors in the shape for the given state.
- * This implementation resolves these keywords on the fill, stroke
- * and gradient color keys.
- */
-mxCellRenderer.prototype.postConfigureShape = function(state)
-{
- if (state.shape != null)
- {
- this.resolveColor(state, 'indicatorColor', mxConstants.STYLE_FILLCOLOR);
- this.resolveColor(state, 'indicatorGradientColor', mxConstants.STYLE_GRADIENTCOLOR);
- this.resolveColor(state, 'fill', mxConstants.STYLE_FILLCOLOR);
- this.resolveColor(state, 'stroke', mxConstants.STYLE_STROKECOLOR);
- this.resolveColor(state, 'gradient', mxConstants.STYLE_GRADIENTCOLOR);
- }
-};
-
-/**
- * Function: resolveColor
- *
- * Resolves special keywords 'inherit', 'indicated' and 'swimlane' and sets
- * the respective color on the shape.
- */
-mxCellRenderer.prototype.resolveColor = function(state, field, key)
-{
- var value = state.shape[field];
- var graph = state.view.graph;
- var referenced = null;
-
- if (value == 'inherit')
- {
- referenced = graph.model.getParent(state.cell);
- }
- else if (value == 'swimlane')
- {
- if (graph.model.getTerminal(state.cell, false) != null)
- {
- referenced = graph.model.getTerminal(state.cell, false);
- }
- else
- {
- referenced = state.cell;
- }
-
- referenced = graph.getSwimlane(referenced);
- key = graph.swimlaneIndicatorColorAttribute;
- }
- else if (value == 'indicated')
- {
- state.shape[field] = state.shape.indicatorColor;
- }
-
- if (referenced != null)
- {
- var rstate = graph.getView().getState(referenced);
- state.shape[field] = null;
-
- if (rstate != null)
- {
- if (rstate.shape != null && field != 'indicatorColor')
- {
- state.shape[field] = rstate.shape[field];
- }
- else
- {
- state.shape[field] = rstate.style[key];
- }
- }
- }
-};
-
-/**
- * Function: getLabelValue
- *
- * Returns the value to be used for the label.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the label should be created.
- */
-mxCellRenderer.prototype.getLabelValue = function(state)
-{
- var graph = state.view.graph;
- var value = graph.getLabel(state.cell);
-
- if (!graph.isHtmlLabel(state.cell) && !mxUtils.isNode(value) &&
- graph.dialect != mxConstants.DIALECT_SVG && value != null)
- {
- value = mxUtils.htmlEntities(value, false);
- }
-
- return value;
-};
-
-/**
- * Function: createLabel
- *
- * Creates the label for the given cell state.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the label should be created.
- */
-mxCellRenderer.prototype.createLabel = function(state, value)
-{
- var graph = state.view.graph;
- var isEdge = graph.getModel().isEdge(state.cell);
-
- if (state.style[mxConstants.STYLE_FONTSIZE] > 0 ||
- state.style[mxConstants.STYLE_FONTSIZE] == null)
- {
- // Avoids using DOM node for empty labels
- var isForceHtml = (graph.isHtmlLabel(state.cell) ||
- (value != null && mxUtils.isNode(value))) &&
- graph.dialect == mxConstants.DIALECT_SVG;
-
- state.text = new mxText(value, new mxRectangle(),
- (state.style[mxConstants.STYLE_ALIGN] ||
- mxConstants.ALIGN_CENTER),
- graph.getVerticalAlign(state),
- state.style[mxConstants.STYLE_FONTCOLOR],
- state.style[mxConstants.STYLE_FONTFAMILY],
- state.style[mxConstants.STYLE_FONTSIZE],
- state.style[mxConstants.STYLE_FONTSTYLE],
- state.style[mxConstants.STYLE_SPACING],
- state.style[mxConstants.STYLE_SPACING_TOP],
- state.style[mxConstants.STYLE_SPACING_RIGHT],
- state.style[mxConstants.STYLE_SPACING_BOTTOM],
- state.style[mxConstants.STYLE_SPACING_LEFT],
- state.style[mxConstants.STYLE_HORIZONTAL],
- state.style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR],
- state.style[mxConstants.STYLE_LABEL_BORDERCOLOR],
- graph.isWrapping(state.cell) && graph.isHtmlLabel(state.cell),
- graph.isLabelClipped(state.cell),
- state.style[mxConstants.STYLE_OVERFLOW],
- state.style[mxConstants.STYLE_LABEL_PADDING]);
- state.text.opacity = state.style[mxConstants.STYLE_TEXT_OPACITY];
-
- state.text.dialect = (isForceHtml) ?
- mxConstants.DIALECT_STRICTHTML :
- state.view.graph.dialect;
- this.initializeLabel(state);
-
- // Workaround for touch devices routing all events for a mouse
- // gesture (down, move, up) via the initial DOM node. IE is even
- // worse in that it redirects the event via the initial DOM node
- // but the event source is the node under the mouse, so we need
- // to check if this is the case and force getCellAt for the
- // subsequent mouseMoves and the final mouseUp.
- var forceGetCell = false;
-
- var getState = function(evt)
- {
- var result = state;
-
- if (mxClient.IS_TOUCH || forceGetCell)
- {
- var x = mxEvent.getClientX(evt);
- var y = mxEvent.getClientY(evt);
-
- // Dispatches the drop event to the graph which
- // consumes and executes the source function
- var pt = mxUtils.convertPoint(graph.container, x, y);
- result = graph.view.getState(graph.getCellAt(pt.x, pt.y));
- }
-
- return result;
- };
-
- // TODO: Add handling for gestures
- var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown';
- var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove';
- var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup';
-
- mxEvent.addListener(state.text.node, md,
- mxUtils.bind(this, function(evt)
- {
- if (this.isLabelEvent(state, evt))
- {
- graph.fireMouseEvent(mxEvent.MOUSE_DOWN,
- new mxMouseEvent(evt, state));
- forceGetCell = graph.dialect != mxConstants.DIALECT_SVG && mxEvent.getSource(evt).nodeName == 'IMG';
- }
- })
- );
-
- mxEvent.addListener(state.text.node, mm,
- mxUtils.bind(this, function(evt)
- {
- if (this.isLabelEvent(state, evt))
- {
- graph.fireMouseEvent(mxEvent.MOUSE_MOVE,
- new mxMouseEvent(evt, getState(evt)));
- }
- })
- );
-
- mxEvent.addListener(state.text.node, mu,
- mxUtils.bind(this, function(evt)
- {
- if (this.isLabelEvent(state, evt))
- {
- graph.fireMouseEvent(mxEvent.MOUSE_UP,
- new mxMouseEvent(evt, getState(evt)));
- forceGetCell = false;
- }
- })
- );
-
- mxEvent.addListener(state.text.node, 'dblclick',
- mxUtils.bind(this, function(evt)
- {
- if (this.isLabelEvent(state, evt))
- {
- graph.dblClick(evt, state.cell);
- mxEvent.consume(evt);
- }
- })
- );
- }
-};
-
-/**
- * Function: initializeLabel
- *
- * Initiailzes the label with a suitable container.
- *
- * Parameters:
- *
- * state - <mxCellState> whose label should be initialized.
- */
-mxCellRenderer.prototype.initializeLabel = function(state)
-{
- var graph = state.view.graph;
-
- if (state.text.dialect != mxConstants.DIALECT_SVG)
- {
- // Adds the text to the container if the dialect is not SVG and we
- // have an SVG-based browser which doesn't support foreignObjects
- if (mxClient.IS_SVG && mxClient.NO_FO)
- {
- state.text.init(graph.container);
- }
- else if (mxUtils.isVml(state.view.getDrawPane()))
- {
- if (state.shape.label != null)
- {
- state.text.init(state.shape.label);
- }
- else
- {
- state.text.init(state.shape.node);
- }
- }
- }
-
- if (state.text.node == null)
- {
- state.text.init(state.view.getDrawPane());
-
- if (state.shape != null && state.text != null)
- {
- state.shape.node.parentNode.insertBefore(
- state.text.node, state.shape.node.nextSibling);
- }
- }
-};
-
-/**
- * Function: createCellOverlays
- *
- * Creates the actual shape for showing the overlay for the given cell state.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the overlay should be created.
- */
-mxCellRenderer.prototype.createCellOverlays = function(state)
-{
- var graph = state.view.graph;
- var overlays = graph.getCellOverlays(state.cell);
- var dict = null;
-
- if (overlays != null)
- {
- dict = new mxDictionary();
-
- for (var i = 0; i < overlays.length; i++)
- {
- var shape = (state.overlays != null) ? state.overlays.remove(overlays[i]) : null;
-
- if (shape == null)
- {
- var tmp = new mxImageShape(new mxRectangle(),
- overlays[i].image.src);
- tmp.dialect = state.view.graph.dialect;
- tmp.preserveImageAspect = false;
- tmp.overlay = overlays[i];
- this.initializeOverlay(state, tmp);
- this.installCellOverlayListeners(state, overlays[i], tmp);
-
- if (overlays[i].cursor != null)
- {
- tmp.node.style.cursor = overlays[i].cursor;
- }
-
- dict.put(overlays[i], tmp);
- }
- else
- {
- dict.put(overlays[i], shape);
- }
- }
- }
-
- // Removes unused
- if (state.overlays != null)
- {
- state.overlays.visit(function(id, shape)
- {
- shape.destroy();
- });
- }
-
- state.overlays = dict;
-};
-
-/**
- * Function: initializeOverlay
- *
- * Initializes the given overlay.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the overlay should be created.
- * overlay - <mxImageShape> that represents the overlay.
- */
-mxCellRenderer.prototype.initializeOverlay = function(state, overlay)
-{
- overlay.init(state.view.getOverlayPane());
-};
-
-/**
- * Function: installOverlayListeners
- *
- * Installs the listeners for the given <mxCellState>, <mxCellOverlay> and
- * <mxShape> that represents the overlay.
- */
-mxCellRenderer.prototype.installCellOverlayListeners = function(state, overlay, shape)
-{
- var graph = state.view.graph;
-
- mxEvent.addListener(shape.node, 'click', function (evt)
- {
- if (graph.isEditing())
- {
- graph.stopEditing(!graph.isInvokesStopCellEditing());
- }
-
- overlay.fireEvent(new mxEventObject(mxEvent.CLICK,
- 'event', evt, 'cell', state.cell));
- });
-
- var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown';
- var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove';
-
- mxEvent.addListener(shape.node, md, function (evt)
- {
- mxEvent.consume(evt);
- });
-
- mxEvent.addListener(shape.node, mm, function (evt)
- {
- graph.fireMouseEvent(mxEvent.MOUSE_MOVE,
- new mxMouseEvent(evt, state));
- });
-
- if (mxClient.IS_TOUCH)
- {
- mxEvent.addListener(shape.node, 'touchend', function (evt)
- {
- overlay.fireEvent(new mxEventObject(mxEvent.CLICK,
- 'event', evt, 'cell', state.cell));
- });
- }
-};
-
-/**
- * Function: createControl
- *
- * Creates the control for the given cell state.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the control should be created.
- */
-mxCellRenderer.prototype.createControl = function(state)
-{
- var graph = state.view.graph;
- var image = graph.getFoldingImage(state);
-
- if (graph.foldingEnabled && image != null)
- {
- if (state.control == null)
- {
- var b = new mxRectangle(0, 0, image.width, image.height);
- state.control = new mxImageShape(b, image.src);
- state.control.dialect = graph.dialect;
- state.control.preserveImageAspect = false;
-
- this.initControl(state, state.control, true, function (evt)
- {
- if (graph.isEnabled())
- {
- var collapse = !graph.isCellCollapsed(state.cell);
- graph.foldCells(collapse, false, [state.cell]);
- mxEvent.consume(evt);
- }
- });
- }
- }
- else if (state.control != null)
- {
- state.control.destroy();
- state.control = null;
- }
-};
-
-/**
- * Function: initControl
- *
- * Initializes the given control and returns the corresponding DOM node.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the control should be initialized.
- * control - <mxShape> to be initialized.
- * handleEvents - Boolean indicating if mousedown and mousemove should fire events via the graph.
- * clickHandler - Optional function to implement clicks on the control.
- */
-mxCellRenderer.prototype.initControl = function(state, control, handleEvents, clickHandler)
-{
- var graph = state.view.graph;
-
- // In the special case where the label is in HTML and the display is SVG the image
- // should go into the graph container directly in order to be clickable. Otherwise
- // it is obscured by the HTML label that overlaps the cell.
- var isForceHtml = graph.isHtmlLabel(state.cell) &&
- mxClient.NO_FO &&
- graph.dialect == mxConstants.DIALECT_SVG;
-
- if (isForceHtml)
- {
- control.dialect = mxConstants.DIALECT_PREFERHTML;
- control.init(graph.container);
- control.node.style.zIndex = 1;
- }
- else
- {
- control.init(state.view.getOverlayPane());
- }
-
- var node = control.innerNode || control.node;
-
- if (clickHandler)
- {
- if (graph.isEnabled())
- {
- node.style.cursor = 'pointer';
- }
-
- mxEvent.addListener(node, 'click', clickHandler);
- }
-
- if (handleEvents)
- {
- var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown';
- var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove';
-
- mxEvent.addListener(node, md, function (evt)
- {
- graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt, state));
- mxEvent.consume(evt);
- });
-
- mxEvent.addListener(node, mm, function (evt)
- {
- graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, state));
- });
- }
-
- return node;
-};
-
-/**
- * Function: isShapeEvent
- *
- * Returns true if the event is for the shape of the given state. This
- * implementation always returns true.
- *
- * Parameters:
- *
- * state - <mxCellState> whose shape fired the event.
- * evt - Mouse event which was fired.
- */
-mxCellRenderer.prototype.isShapeEvent = function(state, evt)
-{
- return true;
-};
-
-/**
- * Function: isLabelEvent
- *
- * Returns true if the event is for the label of the given state. This
- * implementation always returns true.
- *
- * Parameters:
- *
- * state - <mxCellState> whose label fired the event.
- * evt - Mouse event which was fired.
- */
-mxCellRenderer.prototype.isLabelEvent = function(state, evt)
-{
- return true;
-};
-
-/**
- * Function: installListeners
- *
- * Installs the event listeners for the given cell state.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the event listeners should be isntalled.
- */
-mxCellRenderer.prototype.installListeners = function(state)
-{
- var graph = state.view.graph;
-
- // Receives events from transparent backgrounds
- if (graph.dialect == mxConstants.DIALECT_SVG)
- {
- var events = 'all';
-
- // Disabled fill-events on non-filled edges
- if (graph.getModel().isEdge(state.cell) && state.shape.stroke != null &&
- (state.shape.fill == null || state.shape.fill == mxConstants.NONE))
- {
- events = 'visibleStroke';
- }
-
- // Specifies the event-processing on the shape
- if (state.shape.innerNode != null)
- {
- state.shape.innerNode.setAttribute('pointer-events', events);
- }
- else
- {
- state.shape.node.setAttribute('pointer-events', events);
- }
- }
-
- // Workaround for touch devices routing all events for a mouse
- // gesture (down, move, up) via the initial DOM node. Same for
- // HTML images in all IE versions (VML images are working).
- var getState = function(evt)
- {
- var result = state;
-
- if ((graph.dialect != mxConstants.DIALECT_SVG && mxEvent.getSource(evt).nodeName == 'IMG') || mxClient.IS_TOUCH)
- {
- var x = mxEvent.getClientX(evt);
- var y = mxEvent.getClientY(evt);
-
- // Dispatches the drop event to the graph which
- // consumes and executes the source function
- var pt = mxUtils.convertPoint(graph.container, x, y);
- result = graph.view.getState(graph.getCellAt(pt.x, pt.y));
- }
-
- return result;
- };
-
- // Experimental support for two-finger pinch to resize cells
- var gestureInProgress = false;
-
- mxEvent.addListener(state.shape.node, 'gesturestart',
- mxUtils.bind(this, function(evt)
- {
- // FIXME: Breaks encapsulation to reset the double
- // tap event handling when gestures take place
- graph.lastTouchTime = 0;
-
- gestureInProgress = true;
- mxEvent.consume(evt);
- })
- );
-
- var md = (mxClient.IS_TOUCH) ? 'touchstart' : 'mousedown';
- var mm = (mxClient.IS_TOUCH) ? 'touchmove' : 'mousemove';
- var mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup';
-
- mxEvent.addListener(state.shape.node, md,
- mxUtils.bind(this, function(evt)
- {
- if (this.isShapeEvent(state, evt) && !gestureInProgress)
- {
- // Redirects events from the "event-transparent" region of
- // a swimlane to the graph. This is only required in HTML,
- // SVG and VML do not fire mouse events on transparent
- // backgrounds.
- graph.fireMouseEvent(mxEvent.MOUSE_DOWN,
- new mxMouseEvent(evt, (state.shape != null &&
- mxEvent.getSource(evt) == state.shape.content) ?
- null : state));
- }
- else if (gestureInProgress)
- {
- mxEvent.consume(evt);
- }
- })
- );
-
- mxEvent.addListener(state.shape.node, mm,
- mxUtils.bind(this, function(evt)
- {
- if (this.isShapeEvent(state, evt) && !gestureInProgress)
- {
- graph.fireMouseEvent(mxEvent.MOUSE_MOVE,
- new mxMouseEvent(evt, (state.shape != null &&
- mxEvent.getSource(evt) == state.shape.content) ?
- null : getState(evt)));
- }
- else if (gestureInProgress)
- {
- mxEvent.consume(evt);
- }
- })
- );
-
- mxEvent.addListener(state.shape.node, mu,
- mxUtils.bind(this, function(evt)
- {
- if (this.isShapeEvent(state, evt) && !gestureInProgress)
- {
- graph.fireMouseEvent(mxEvent.MOUSE_UP,
- new mxMouseEvent(evt, (state.shape != null &&
- mxEvent.getSource(evt) == state.shape.content) ?
- null : getState(evt)));
- }
- else if (gestureInProgress)
- {
- mxEvent.consume(evt);
- }
- })
- );
-
- // Experimental handling for gestures. Double-tap handling is implemented
- // in mxGraph.fireMouseEvent.
- var dc = (mxClient.IS_TOUCH) ? 'gestureend' : 'dblclick';
-
- mxEvent.addListener(state.shape.node, dc,
- mxUtils.bind(this, function(evt)
- {
- gestureInProgress = false;
-
- if (dc == 'gestureend')
- {
- // FIXME: Breaks encapsulation to reset the double
- // tap event handling when gestures take place
- graph.lastTouchTime = 0;
-
- if (graph.gestureEnabled)
- {
- graph.handleGesture(state, evt);
- mxEvent.consume(evt);
- }
- }
- else if (this.isShapeEvent(state, evt))
- {
- graph.dblClick(evt, (state.shape != null &&
- mxEvent.getSource(evt) == state.shape.content) ?
- null : state.cell);
- mxEvent.consume(evt);
- }
- })
- );
-};
-
-/**
- * Function: redrawLabel
- *
- * Redraws the label for the given cell state.
- *
- * Parameters:
- *
- * state - <mxCellState> whose label should be redrawn.
- */
-mxCellRenderer.prototype.redrawLabel = function(state)
-{
- var value = this.getLabelValue(state);
-
- // FIXME: Add label always if HTML label and NO_FO
- if (state.text == null && value != null && (mxUtils.isNode(value) || value.length > 0))
- {
- this.createLabel(state, value);
- }
- else if (state.text != null && (value == null || value.length == 0))
- {
- state.text.destroy();
- state.text = null;
- }
-
- if (state.text != null)
- {
- var graph = state.view.graph;
- var wrapping = graph.isWrapping(state.cell);
- var clipping = graph.isLabelClipped(state.cell);
- var bounds = this.getLabelBounds(state);
-
- if (state.text.value != value || state.text.isWrapping != wrapping ||
- state.text.isClipping != clipping || state.text.scale != state.view.scale ||
- !state.text.bounds.equals(bounds))
- {
- state.text.value = value;
- state.text.bounds = bounds;
- state.text.scale = this.getTextScale(state);
- state.text.isWrapping = wrapping;
- state.text.isClipping = clipping;
-
- state.text.redraw();
- }
- }
-};
-
-/**
- * Function: getTextScale
- *
- * Returns the scaling used for the label of the given state
- *
- * Parameters:
- *
- * state - <mxCellState> whose label scale should be returned.
- */
-mxCellRenderer.prototype.getTextScale = function(state)
-{
- return state.view.scale;
-};
-
-/**
- * Function: getLabelBounds
- *
- * Returns the bounds to be used to draw the label of the given state.
- *
- * Parameters:
- *
- * state - <mxCellState> whose label bounds should be returned.
- */
-mxCellRenderer.prototype.getLabelBounds = function(state)
-{
- var graph = state.view.graph;
- var isEdge = graph.getModel().isEdge(state.cell);
- var bounds = new mxRectangle(state.absoluteOffset.x, state.absoluteOffset.y);
-
- if (!isEdge)
- {
- bounds.x += state.x;
- bounds.y += state.y;
-
- // Minimum of 1 fixes alignment bug in HTML labels
- bounds.width = Math.max(1, state.width);
- bounds.height = Math.max(1, state.height);
-
- if (graph.isSwimlane(state.cell))
- {
- var scale = graph.view.scale;
- var size = graph.getStartSize(state.cell);
-
- if (size.width > 0)
- {
- bounds.width = size.width * scale;
- }
- else if (size.height > 0)
- {
- bounds.height = size.height * scale;
- }
- }
- }
-
- return bounds;
-};
-
-/**
- * Function: redrawCellOverlays
- *
- * Redraws the overlays for the given cell state.
- *
- * Parameters:
- *
- * state - <mxCellState> whose overlays should be redrawn.
- */
-mxCellRenderer.prototype.redrawCellOverlays = function(state)
-{
- this.createCellOverlays(state);
-
- if (state.overlays != null)
- {
- state.overlays.visit(function(id, shape)
- {
- var bounds = shape.overlay.getBounds(state);
-
- if (shape.bounds == null || shape.scale != state.view.scale ||
- !shape.bounds.equals(bounds))
- {
- shape.bounds = bounds;
- shape.scale = state.view.scale;
- shape.redraw();
- }
- });
- }
-};
-
-/**
- * Function: redrawControl
- *
- * Redraws the control for the given cell state.
- *
- * Parameters:
- *
- * state - <mxCellState> whose control should be redrawn.
- */
-mxCellRenderer.prototype.redrawControl = function(state)
-{
- if (state.control != null)
- {
- var bounds = this.getControlBounds(state);
- var s = state.view.scale;
-
- if (state.control.scale != s || !state.control.bounds.equals(bounds))
- {
- state.control.bounds = bounds;
- state.control.scale = s;
- state.control.redraw();
- }
- }
-};
-
-/**
- * Function: getControlBounds
- *
- * Returns the bounds to be used to draw the control (folding icon) of the
- * given state.
- */
-mxCellRenderer.prototype.getControlBounds = function(state)
-{
- if (state.control != null)
- {
- var oldScale = state.control.scale;
- var w = state.control.bounds.width / oldScale;
- var h = state.control.bounds.height / oldScale;
- var s = state.view.scale;
-
- return (state.view.graph.getModel().isEdge(state.cell)) ?
- new mxRectangle(state.x + state.width / 2 - w / 2 * s,
- state.y + state.height / 2 - h / 2 * s, w * s, h * s)
- : new mxRectangle(state.x + w / 2 * s,
- state.y + h / 2 * s, w * s, h * s);
- }
-
- return null;
-};
-
-/**
- * Function: redraw
- *
- * Updates the bounds or points and scale of the shapes for the given cell
- * state. This is called in mxGraphView.validatePoints as the last step of
- * updating all cells.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the shapes should be updated.
- * force - Optional boolean that specifies if the cell should be reconfiured
- * and redrawn without any additional checks.
- * rendering - Optional boolean that specifies if the cell should actually
- * be drawn into the DOM. If this is false then redraw and/or reconfigure
- * will not be called on the shape.
- */
-mxCellRenderer.prototype.redraw = function(state, force, rendering)
-{
- if (state.shape != null)
- {
- var model = state.view.graph.getModel();
- var isEdge = model.isEdge(state.cell);
- reconfigure = (force != null) ? force : false;
-
- // Handles changes of the collapse icon
- this.createControl(state);
-
- // Handles changes to the order in the DOM
- if (state.orderChanged || state.invalidOrder)
- {
- if (state.view.graph.ordered)
- {
- this.order(state);
- }
- else
- {
- // Assert state.cell is edge
- this.orderEdge(state);
- }
-
- // Required to update inherited styles
- reconfigure = state.orderChanged;
- }
-
- delete state.invalidOrder;
- delete state.orderChanged;
-
- // Checks if the style in the state is different from the style
- // in the shape and re-applies the style if required
- if (!reconfigure && !mxUtils.equalEntries(state.shape.style, state.style))
- {
- reconfigure = true;
- }
-
- // Reconfiures the shape after an order or style change
- if (reconfigure)
- {
- this.configureShape(state);
- state.shape.reconfigure();
- }
-
- // Redraws the cell if required
- if (force || state.shape.bounds == null || state.shape.scale != state.view.scale ||
- !state.shape.bounds.equals(state) ||
- !mxUtils.equalPoints(state.shape.points, state.absolutePoints))
- {
- // FIXME: Move indicator color update into shape.redraw
-// var indicator = state.view.graph.getIndicatorColor(state);
-// if (indicator != null)
-// {
-// state.shape.indicatorColor = indicator;
-// }
-
- if (state.absolutePoints != null)
- {
- state.shape.points = state.absolutePoints.slice();
- }
- else
- {
- state.shape.points = null;
- }
-
- state.shape.bounds = new mxRectangle(
- state.x, state.y, state.width, state.height);
- state.shape.scale = state.view.scale;
-
- if (rendering == null || rendering)
- {
- state.shape.redraw();
- }
- else
- {
- state.shape.updateBoundingBox();
- }
- }
-
- // Updates the text label, overlays and control
- if (rendering == null || rendering)
- {
- this.redrawLabel(state);
- this.redrawCellOverlays(state);
- this.redrawControl(state);
- }
- }
-};
-
-/**
- * Function: destroy
- *
- * Destroys the shapes associated with the given cell state.
- *
- * Parameters:
- *
- * state - <mxCellState> for which the shapes should be destroyed.
- */
-mxCellRenderer.prototype.destroy = function(state)
-{
- if (state.shape != null)
- {
- if (state.text != null)
- {
- state.text.destroy();
- state.text = null;
- }
-
- if (state.overlays != null)
- {
- state.overlays.visit(function(id, shape)
- {
- shape.destroy();
- });
-
- state.overlays = null;
- }
-
- if (state.control != null)
- {
- state.control.destroy();
- state.control = null;
- }
-
- state.shape.destroy();
- state.shape = null;
- }
-};