| /** |
| * Copyright (c) 2006-2015, JGraph Ltd |
| * Copyright (c) 2006-2015, Gaudenz Alder |
| */ |
| function mxEdgeSegmentHandler(state) |
| { |
| mxEdgeHandler.call(this, state); |
| }; |
| |
| /** |
| * Extends mxEdgeHandler. |
| */ |
| mxUtils.extend(mxEdgeSegmentHandler, mxElbowEdgeHandler); |
| |
| /** |
| * Function: getCurrentPoints |
| * |
| * Returns the current absolute points. |
| */ |
| mxEdgeSegmentHandler.prototype.getCurrentPoints = function() |
| { |
| var pts = this.state.absolutePoints; |
| |
| if (pts != null) |
| { |
| // Special case for straight edges where we add a virtual middle handle for moving the edge |
| if (pts.length == 2 || (pts.length == 3 && (pts[0].x == pts[1].x && pts[1].x == pts[2].x || |
| pts[0].y == pts[1].y && pts[1].y == pts[2].y))) |
| { |
| var cx = pts[0].x + (pts[pts.length - 1].x - pts[0].x) / 2; |
| var cy = pts[0].y + (pts[pts.length - 1].y - pts[0].y) / 2; |
| |
| pts = [pts[0], new mxPoint(cx, cy), new mxPoint(cx, cy), pts[pts.length - 1]]; |
| } |
| } |
| |
| return pts; |
| }; |
| |
| /** |
| * Function: getPreviewPoints |
| * |
| * Updates the given preview state taking into account the state of the constraint handler. |
| */ |
| mxEdgeSegmentHandler.prototype.getPreviewPoints = function(point) |
| { |
| if (this.isSource || this.isTarget) |
| { |
| return mxElbowEdgeHandler.prototype.getPreviewPoints.apply(this, arguments); |
| } |
| else |
| { |
| var pts = this.getCurrentPoints(); |
| var last = this.convertPoint(pts[0].clone(), false); |
| point = this.convertPoint(point.clone(), false); |
| var result = []; |
| |
| for (var i = 1; i < pts.length; i++) |
| { |
| var pt = this.convertPoint(pts[i].clone(), false); |
| |
| if (i == this.index) |
| { |
| if (Math.round(last.x - pt.x) == 0) |
| { |
| last.x = point.x; |
| pt.x = point.x; |
| } |
| |
| if (Math.round(last.y - pt.y) == 0) |
| { |
| last.y = point.y; |
| pt.y = point.y; |
| } |
| } |
| |
| if (i < pts.length - 1) |
| { |
| result.push(pt); |
| } |
| |
| last = pt; |
| } |
| |
| // Replaces single point that intersects with source or target |
| if (result.length == 1) |
| { |
| var source = this.state.getVisibleTerminalState(true); |
| var target = this.state.getVisibleTerminalState(false); |
| var scale = this.state.view.getScale(); |
| var tr = this.state.view.getTranslate(); |
| |
| var x = result[0].x * scale + tr.x; |
| var y = result[0].y * scale + tr.y; |
| |
| if ((source != null && mxUtils.contains(source, x, y)) || |
| (target != null && mxUtils.contains(target, x, y))) |
| { |
| result = [point, point]; |
| } |
| } |
| |
| return result; |
| } |
| }; |
| |
| /** |
| * Function: updatePreviewState |
| * |
| * Overridden to perform optimization of the edge style result. |
| */ |
| mxEdgeSegmentHandler.prototype.updatePreviewState = function(edge, point, terminalState, me) |
| { |
| mxEdgeHandler.prototype.updatePreviewState.apply(this, arguments); |
| |
| // Checks and corrects preview by running edge style again |
| if (!this.isSource && !this.isTarget) |
| { |
| point = this.convertPoint(point.clone(), false); |
| var pts = edge.absolutePoints; |
| var pt0 = pts[0]; |
| var pt1 = pts[1]; |
| |
| var result = []; |
| |
| for (var i = 2; i < pts.length; i++) |
| { |
| var pt2 = pts[i]; |
| |
| // Merges adjacent segments only if more than 2 to allow for straight edges |
| if ((Math.round(pt0.x - pt1.x) != 0 || Math.round(pt1.x - pt2.x) != 0) && |
| (Math.round(pt0.y - pt1.y) != 0 || Math.round(pt1.y - pt2.y) != 0)) |
| { |
| result.push(this.convertPoint(pt1.clone(), false)); |
| } |
| |
| pt0 = pt1; |
| pt1 = pt2; |
| } |
| |
| var source = this.state.getVisibleTerminalState(true); |
| var target = this.state.getVisibleTerminalState(false); |
| var rpts = this.state.absolutePoints; |
| |
| // A straight line is represented by 3 handles |
| if (result.length == 0 && (Math.round(pts[0].x - pts[pts.length - 1].x) == 0 || |
| Math.round(pts[0].y - pts[pts.length - 1].y) == 0)) |
| { |
| result = [point, point]; |
| } |
| // Handles special case of transitions from straight vertical to routed |
| else if (pts.length == 5 && result.length == 2 && source != null && target != null && |
| rpts != null && Math.round(rpts[0].x - rpts[rpts.length - 1].x) == 0) |
| { |
| var view = this.graph.getView(); |
| var scale = view.getScale(); |
| var tr = view.getTranslate(); |
| |
| var y0 = view.getRoutingCenterY(source) / scale - tr.y; |
| |
| // Use fixed connection point y-coordinate if one exists |
| var sc = this.graph.getConnectionConstraint(edge, source, true); |
| |
| if (sc != null) |
| { |
| var pt = this.graph.getConnectionPoint(source, sc); |
| |
| if (pt != null) |
| { |
| this.convertPoint(pt, false); |
| y0 = pt.y; |
| } |
| } |
| |
| var ye = view.getRoutingCenterY(target) / scale - tr.y; |
| |
| // Use fixed connection point y-coordinate if one exists |
| var tc = this.graph.getConnectionConstraint(edge, target, false); |
| |
| if (tc) |
| { |
| var pt = this.graph.getConnectionPoint(target, tc); |
| |
| if (pt != null) |
| { |
| this.convertPoint(pt, false); |
| ye = pt.y; |
| } |
| } |
| |
| result = [new mxPoint(point.x, y0), new mxPoint(point.x, ye)]; |
| } |
| |
| this.points = result; |
| |
| // LATER: Check if points and result are different |
| edge.view.updateFixedTerminalPoints(edge, source, target); |
| edge.view.updatePoints(edge, this.points, source, target); |
| edge.view.updateFloatingTerminalPoints(edge, source, target); |
| } |
| }; |
| |
| /** |
| * Overriden to merge edge segments. |
| */ |
| mxEdgeSegmentHandler.prototype.connect = function(edge, terminal, isSource, isClone, me) |
| { |
| // Merges adjacent edge segments |
| var pts = this.abspoints; |
| var pt0 = pts[0]; |
| var pt1 = pts[1]; |
| var result = []; |
| |
| for (var i = 2; i < pts.length; i++) |
| { |
| var pt2 = pts[i]; |
| |
| // Merges adjacent segments only if more than 2 to allow for straight edges |
| if ((Math.round(pt0.x - pt1.x) != 0 || Math.round(pt1.x - pt2.x) != 0) && |
| (Math.round(pt0.y - pt1.y) != 0 || Math.round(pt1.y - pt2.y) != 0)) |
| { |
| result.push(this.convertPoint(pt1.clone(), false)); |
| } |
| |
| pt0 = pt1; |
| pt1 = pt2; |
| } |
| |
| var model = this.graph.getModel(); |
| |
| model.beginUpdate(); |
| try |
| { |
| var geo = model.getGeometry(edge); |
| |
| if (geo != null) |
| { |
| geo = geo.clone(); |
| geo.points = result; |
| |
| model.setGeometry(edge, geo); |
| } |
| |
| edge = mxEdgeHandler.prototype.connect.apply(this, arguments); |
| } |
| finally |
| { |
| model.endUpdate(); |
| } |
| |
| return edge; |
| }; |
| |
| /** |
| * Function: getTooltipForNode |
| * |
| * Returns no tooltips. |
| */ |
| mxEdgeSegmentHandler.prototype.getTooltipForNode = function(node) |
| { |
| return null; |
| }; |
| |
| /** |
| * Function: createBends |
| * |
| * Adds custom bends for the center of each segment. |
| */ |
| mxEdgeSegmentHandler.prototype.start = function(x, y, index) |
| { |
| mxEdgeHandler.prototype.start.apply(this, arguments); |
| |
| if (this.bends[index] != null && !this.isSource && !this.isTarget) |
| { |
| mxUtils.setOpacity(this.bends[index].node, 100); |
| } |
| }; |
| |
| /** |
| * Function: createBends |
| * |
| * Adds custom bends for the center of each segment. |
| */ |
| mxEdgeSegmentHandler.prototype.createBends = function() |
| { |
| var bends = []; |
| |
| // Source |
| var bend = this.createHandleShape(0); |
| this.initBend(bend); |
| bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE); |
| bends.push(bend); |
| |
| var pts = this.getCurrentPoints(); |
| |
| // Waypoints (segment handles) |
| if (this.graph.isCellBendable(this.state.cell)) |
| { |
| if (this.points == null) |
| { |
| this.points = []; |
| } |
| |
| for (var i = 0; i < pts.length - 1; i++) |
| { |
| bend = this.createVirtualBend(); |
| bends.push(bend); |
| var horizontal = Math.round(pts[i].x - pts[i + 1].x) == 0; |
| |
| // Special case where dy is 0 as well |
| if (Math.round(pts[i].y - pts[i + 1].y) == 0 && i < pts.length - 2) |
| { |
| horizontal = Math.round(pts[i].x - pts[i + 2].x) == 0; |
| } |
| |
| bend.setCursor((horizontal) ? 'col-resize' : 'row-resize'); |
| this.points.push(new mxPoint(0,0)); |
| } |
| } |
| |
| // Target |
| var bend = this.createHandleShape(pts.length); |
| this.initBend(bend); |
| bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE); |
| bends.push(bend); |
| |
| return bends; |
| }; |
| |
| /** |
| * Function: redraw |
| * |
| * Overridden to invoke <refresh> before the redraw. |
| */ |
| mxEdgeSegmentHandler.prototype.redraw = function() |
| { |
| this.refresh(); |
| mxEdgeHandler.prototype.redraw.apply(this, arguments); |
| }; |
| |
| /** |
| * Function: redrawInnerBends |
| * |
| * Updates the position of the custom bends. |
| */ |
| mxEdgeSegmentHandler.prototype.redrawInnerBends = function(p0, pe) |
| { |
| if (this.graph.isCellBendable(this.state.cell)) |
| { |
| var pts = this.getCurrentPoints(); |
| |
| if (pts != null && pts.length > 1) |
| { |
| var straight = false; |
| |
| // Puts handle in the center of straight edges |
| if (pts.length == 4 && Math.round(pts[1].x - pts[2].x) == 0 && Math.round(pts[1].y - pts[2].y) == 0) |
| { |
| straight = true; |
| |
| if (Math.round(pts[0].y - pts[pts.length - 1].y) == 0) |
| { |
| var cx = pts[0].x + (pts[pts.length - 1].x - pts[0].x) / 2; |
| pts[1] = new mxPoint(cx, pts[1].y); |
| pts[2] = new mxPoint(cx, pts[2].y); |
| } |
| else |
| { |
| var cy = pts[0].y + (pts[pts.length - 1].y - pts[0].y) / 2; |
| pts[1] = new mxPoint(pts[1].x, cy); |
| pts[2] = new mxPoint(pts[2].x, cy); |
| } |
| } |
| |
| for (var i = 0; i < pts.length - 1; i++) |
| { |
| if (this.bends[i + 1] != null) |
| { |
| var p0 = pts[i]; |
| var pe = pts[i + 1]; |
| var pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2); |
| var b = this.bends[i + 1].bounds; |
| this.bends[i + 1].bounds = new mxRectangle(Math.floor(pt.x - b.width / 2), |
| Math.floor(pt.y - b.height / 2), b.width, b.height); |
| this.bends[i + 1].redraw(); |
| |
| if (this.manageLabelHandle) |
| { |
| this.checkLabelHandle(this.bends[i + 1].bounds); |
| } |
| } |
| } |
| |
| if (straight) |
| { |
| mxUtils.setOpacity(this.bends[1].node, this.virtualBendOpacity); |
| mxUtils.setOpacity(this.bends[3].node, this.virtualBendOpacity); |
| } |
| } |
| } |
| }; |