UNPKG

@projectstorm/react-diagrams-routing

Version:

This package adds dagre integration for laying out nodes and links

220 lines 10.5 kB
import * as React from 'react'; import { LinkWidget, PointModel } from '@projectstorm/react-diagrams-core'; import { DefaultLinkSegmentWidget } from '@projectstorm/react-diagrams-defaults'; import { Point } from '@projectstorm/geometry'; export class RightAngleLinkWidget extends React.Component { constructor(props) { super(props); this.handleMove = function (event) { this.draggingEvent(event, this.dragging_index); }.bind(this); this.handleUp = function (event) { // Unregister handlers to avoid multiple event handlers for other links this.setState({ canDrag: false, selected: false }); window.removeEventListener('mousemove', this.handleMove); window.removeEventListener('mouseup', this.handleUp); }.bind(this); this.refPaths = []; this.state = { selected: false, canDrag: false }; this.dragging_index = 0; } componentDidUpdate() { this.props.link.setRenderedPaths(this.refPaths.map((ref) => { return ref.current; })); } componentDidMount() { this.props.link.setRenderedPaths(this.refPaths.map((ref) => { return ref.current; })); } componentWillUnmount() { this.props.link.setRenderedPaths([]); } generateLink(path, extraProps, id) { const ref = React.createRef(); this.refPaths.push(ref); return (React.createElement(DefaultLinkSegmentWidget, { key: `link-${id}`, path: path, selected: this.state.selected, diagramEngine: this.props.diagramEngine, factory: this.props.diagramEngine.getFactoryForLink(this.props.link), link: this.props.link, forwardRef: ref, onSelection: (selected) => { this.setState({ selected: selected }); }, extras: extraProps })); } calculatePositions(points, event, index, coordinate) { // If path is first or last add another point to keep node port on its position if (index === 0) { let point = new PointModel({ link: this.props.link, position: new Point(points[index].getX(), points[index].getY()) }); this.props.link.addPoint(point, index); this.dragging_index++; return; } else if (index === points.length - 2) { let point = new PointModel({ link: this.props.link, position: new Point(points[index + 1].getX(), points[index + 1].getY()) }); this.props.link.addPoint(point, index + 1); return; } // Merge two points if it is not close to node port and close to each other if (index - 2 > 0) { let _points = { [index - 2]: points[index - 2].getPosition(), [index + 1]: points[index + 1].getPosition(), [index - 1]: points[index - 1].getPosition() }; if (Math.abs(_points[index - 1][coordinate] - _points[index + 1][coordinate]) < 5) { _points[index - 2][coordinate] = this.props.diagramEngine.getRelativeMousePoint(event)[coordinate]; _points[index + 1][coordinate] = this.props.diagramEngine.getRelativeMousePoint(event)[coordinate]; points[index - 2].setPosition(_points[index - 2]); points[index + 1].setPosition(_points[index + 1]); points[index - 1].remove(); points[index - 1].remove(); this.dragging_index--; this.dragging_index--; return; } } // Merge two points if it is not close to node port if (index + 2 < points.length - 2) { let _points = { [index + 3]: points[index + 3].getPosition(), [index + 2]: points[index + 2].getPosition(), [index + 1]: points[index + 1].getPosition(), [index]: points[index].getPosition() }; if (Math.abs(_points[index + 1][coordinate] - _points[index + 2][coordinate]) < 5) { _points[index][coordinate] = this.props.diagramEngine.getRelativeMousePoint(event)[coordinate]; _points[index + 3][coordinate] = this.props.diagramEngine.getRelativeMousePoint(event)[coordinate]; points[index].setPosition(_points[index]); points[index + 3].setPosition(_points[index + 3]); points[index + 1].remove(); points[index + 1].remove(); return; } } // If no condition above handled then just update path points position let _points = { [index]: points[index].getPosition(), [index + 1]: points[index + 1].getPosition() }; _points[index][coordinate] = this.props.diagramEngine.getRelativeMousePoint(event)[coordinate]; _points[index + 1][coordinate] = this.props.diagramEngine.getRelativeMousePoint(event)[coordinate]; points[index].setPosition(_points[index]); points[index + 1].setPosition(_points[index + 1]); } draggingEvent(event, index) { let points = this.props.link.getPoints(); // get moving difference. Index + 1 will work because links indexes has // length = points.lenght - 1 let dx = Math.abs(points[index].getX() - points[index + 1].getX()); let dy = Math.abs(points[index].getY() - points[index + 1].getY()); // moving with y direction if (dx === 0) { this.calculatePositions(points, event, index, 'x'); } else if (dy === 0) { this.calculatePositions(points, event, index, 'y'); } this.props.link.setFirstAndLastPathsDirection(); } render() { //ensure id is present for all points on the path let points = this.props.link.getPoints(); let paths = []; // Get points based on link orientation let pointLeft = points[0]; let pointRight = points[points.length - 1]; let hadToSwitch = false; if (pointLeft.getX() > pointRight.getX()) { pointLeft = points[points.length - 1]; pointRight = points[0]; hadToSwitch = true; } let dy = Math.abs(points[0].getY() - points[points.length - 1].getY()); // When new link add one middle point to get everywhere 90° angle if (this.props.link.getTargetPort() === null && points.length === 2) { [...Array(2)].forEach((item) => { this.props.link.addPoint(new PointModel({ link: this.props.link, position: new Point(pointLeft.getX(), pointRight.getY()) }), 1); }); this.props.link.setManuallyFirstAndLastPathsDirection(true, true); } // When new link is moving and not connected to target port move with middle point // TODO: @DanielLazarLDAPPS This will be better to update in DragNewLinkState // in function fireMouseMoved to avoid calling this unexpectedly e.g. after Deserialize else if (this.props.link.getTargetPort() === null && this.props.link.getSourcePort() !== null) { points[1].setPosition(pointRight.getX() + (pointLeft.getX() - pointRight.getX()) / 2, !hadToSwitch ? pointLeft.getY() : pointRight.getY()); points[2].setPosition(pointRight.getX() + (pointLeft.getX() - pointRight.getX()) / 2, !hadToSwitch ? pointRight.getY() : pointLeft.getY()); } // Render was called but link is not moved but user. // Node is moved and in this case fix coordinates to get 90° angle. // For loop just for first and last path else if (!this.state.canDrag && points.length > 2) { // Those points and its position only will be moved for (let i = 1; i < points.length; i += points.length - 2) { if (i - 1 === 0) { if (this.props.link.getFirstPathXdirection()) { points[i].setPosition(points[i].getX(), points[i - 1].getY()); } else { points[i].setPosition(points[i - 1].getX(), points[i].getY()); } } else { if (this.props.link.getLastPathXdirection()) { points[i - 1].setPosition(points[i - 1].getX(), points[i].getY()); } else { points[i - 1].setPosition(points[i].getX(), points[i - 1].getY()); } } } } // If there is existing link which has two points add one // NOTE: It doesn't matter if check is for dy or dx if (points.length === 2 && dy !== 0 && !this.state.canDrag) { this.props.link.addPoint(new PointModel({ link: this.props.link, position: new Point(pointLeft.getX(), pointRight.getY()) })); } for (let j = 0; j < points.length - 1; j++) { paths.push(this.generateLink(LinkWidget.generateLinePath(points[j], points[j + 1]), { 'data-linkid': this.props.link.getID(), 'data-point': j, onMouseDown: (event) => { if (event.button === 0) { this.setState({ canDrag: true }); this.dragging_index = j; // Register mouse move event to track mouse position // On mouse up these events are unregistered check "this.handleUp" window.addEventListener('mousemove', this.handleMove); window.addEventListener('mouseup', this.handleUp); } }, onMouseEnter: (event) => { this.setState({ selected: true }); this.props.link.lastHoverIndexOfPath = j; } }, j)); } this.refPaths = []; return React.createElement("g", { "data-default-link-test": this.props.link.getOptions().testName }, paths); } } RightAngleLinkWidget.defaultProps = { color: 'red', width: 3, link: null, smooth: false, diagramEngine: null, factory: null }; //# sourceMappingURL=RightAngleLinkWidget.js.map