123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- /**
- * Copyright (c) 2006-2015, JGraph Ltd
- * Copyright (c) 2006-2015, Gaudenz Alder
- */
- /**
- * Class: mxParallelEdgeLayout
- *
- * Extends <mxGraphLayout> for arranging parallel edges. This layout works
- * on edges for all pairs of vertices where there is more than one edge
- * connecting the latter.
- *
- * Example:
- *
- * (code)
- * var layout = new mxParallelEdgeLayout(graph);
- * layout.execute(graph.getDefaultParent());
- * (end)
- *
- * To run the layout for the parallel edges of a changed edge only, the
- * following code can be used.
- *
- * (code)
- * var layout = new mxParallelEdgeLayout(graph);
- *
- * graph.addListener(mxEvent.CELL_CONNECTED, function(sender, evt)
- * {
- * var model = graph.getModel();
- * var edge = evt.getProperty('edge');
- * var src = model.getTerminal(edge, true);
- * var trg = model.getTerminal(edge, false);
- *
- * layout.isEdgeIgnored = function(edge2)
- * {
- * var src2 = model.getTerminal(edge2, true);
- * var trg2 = model.getTerminal(edge2, false);
- *
- * return !(model.isEdge(edge2) && ((src == src2 && trg == trg2) || (src == trg2 && trg == src2)));
- * };
- *
- * layout.execute(graph.getDefaultParent());
- * });
- * (end)
- *
- * Constructor: mxParallelEdgeLayout
- *
- * Constructs a new parallel edge layout for the specified graph.
- */
- function mxParallelEdgeLayout(graph)
- {
- mxGraphLayout.call(this, graph);
- };
- /**
- * Extends mxGraphLayout.
- */
- mxParallelEdgeLayout.prototype = new mxGraphLayout();
- mxParallelEdgeLayout.prototype.constructor = mxParallelEdgeLayout;
- /**
- * Variable: spacing
- *
- * Defines the spacing between the parallels. Default is 20.
- */
- mxParallelEdgeLayout.prototype.spacing = 20;
- /**
- * Variable: checkOverlap
- *
- * Specifies if only overlapping edges should be considered
- * parallel. Default is false.
- */
- mxParallelEdgeLayout.prototype.checkOverlap = false;
- /**
- * Function: execute
- *
- * Implements <mxGraphLayout.execute>.
- */
- mxParallelEdgeLayout.prototype.execute = function(parent, cells)
- {
- var lookup = this.findParallels(parent, cells);
-
- this.graph.model.beginUpdate();
- try
- {
- for (var i in lookup)
- {
- var parallels = lookup[i];
- if (parallels.length > 1)
- {
- this.layout(parallels);
- }
- }
- }
- finally
- {
- this.graph.model.endUpdate();
- }
- };
- /**
- * Function: findParallels
- *
- * Finds the parallel edges in the given parent.
- */
- mxParallelEdgeLayout.prototype.findParallels = function(parent, cells)
- {
- var lookup = [];
-
- var addCell = mxUtils.bind(this, function(cell)
- {
- if (!this.isEdgeIgnored(cell))
- {
- var id = this.getEdgeId(cell);
-
- if (id != null)
- {
- if (lookup[id] == null)
- {
- lookup[id] = [];
- }
-
- lookup[id].push(cell);
- }
- }
- });
-
- if (cells != null)
- {
- for (var i = 0; i < cells.length; i++)
- {
- addCell(cells[i]);
- }
- }
- else
- {
- var model = this.graph.getModel();
- var childCount = model.getChildCount(parent);
-
- for (var i = 0; i < childCount; i++)
- {
- addCell(model.getChildAt(parent, i));
- }
- }
-
- return lookup;
- };
- /**
- * Function: getEdgeId
- *
- * Returns a unique ID for the given edge. The id is independent of the
- * edge direction and is built using the visible terminal of the given
- * edge.
- */
- mxParallelEdgeLayout.prototype.getEdgeId = function(edge)
- {
- var view = this.graph.getView();
-
- // Cannot used cached visible terminal because this could be triggered in BEFORE_UNDO
- var src = view.getVisibleTerminal(edge, true);
- var trg = view.getVisibleTerminal(edge, false);
- var pts = '';
- if (src != null && trg != null)
- {
- src = mxObjectIdentity.get(src);
- trg = mxObjectIdentity.get(trg);
-
- if (this.checkOverlap)
- {
- var state = this.graph.view.getState(edge);
-
- if (state != null && state.absolutePoints != null)
- {
- var tmp = [];
-
- for (var i = 0; i < state.absolutePoints.length; i++)
- {
- var pt = state.absolutePoints[i];
-
- if (pt != null)
- {
- tmp.push(pt.x, pt.y);
- }
- }
-
- pts = tmp.join(',');
- }
- };
-
- return ((src > trg) ? trg + '-' + src : src + '-' + trg) + pts;
- }
-
- return null;
- };
- /**
- * Function: layout
- *
- * Lays out the parallel edges in the given array.
- */
- mxParallelEdgeLayout.prototype.layout = function(parallels)
- {
- var edge = parallels[0];
- var view = this.graph.getView();
- var model = this.graph.getModel();
- var src = model.getGeometry(view.getVisibleTerminal(edge, true));
- var trg = model.getGeometry(view.getVisibleTerminal(edge, false));
-
- // Routes multiple loops
- if (src == trg)
- {
- var x0 = src.x + src.width + this.spacing;
- var y0 = src.y + src.height / 2;
- for (var i = 0; i < parallels.length; i++)
- {
- this.route(parallels[i], x0, y0);
- x0 += this.spacing;
- }
- }
- else if (src != null && trg != null)
- {
- // Routes parallel edges
- var scx = src.x + src.width / 2;
- var scy = src.y + src.height / 2;
-
- var tcx = trg.x + trg.width / 2;
- var tcy = trg.y + trg.height / 2;
-
- var dx = tcx - scx;
- var dy = tcy - scy;
- var len = Math.sqrt(dx * dx + dy * dy);
-
- if (len > 0)
- {
- var x0 = scx + dx / 2;
- var y0 = scy + dy / 2;
-
- var nx = dy * this.spacing / len;
- var ny = dx * this.spacing / len;
-
- x0 += nx * (parallels.length - 1) / 2;
- y0 -= ny * (parallels.length - 1) / 2;
-
- for (var i = 0; i < parallels.length; i++)
- {
- this.route(parallels[i], x0, y0);
- x0 -= nx;
- y0 += ny;
- }
- }
- }
- };
- /**
- * Function: route
- *
- * Routes the given edge via the given point.
- */
- mxParallelEdgeLayout.prototype.route = function(edge, x, y)
- {
- if (this.graph.isCellMovable(edge))
- {
- this.setEdgePoints(edge, [new mxPoint(x, y)]);
- }
- };
- __mxOutput.mxParallelEdgeLayout = typeof mxParallelEdgeLayout !== 'undefined' ? mxParallelEdgeLayout : undefined;
|