Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
parent
fcc5e29216
commit
297a40d72e
401
js/ui/mxgraph/src/js/handler/mxEdgeSegmentHandler.js
Normal file
401
js/ui/mxgraph/src/js/handler/mxEdgeSegmentHandler.js
Normal file
|
@ -0,0 +1,401 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user