mirror of
https://github.com/projectstorm/react-diagrams.git
synced 2025-08-14 16:51:29 +08:00
add a few small fixes and improvements
This commit is contained in:
@ -3,14 +3,14 @@ import createEngine, {
|
||||
DefaultNodeModel,
|
||||
DefaultPortModel,
|
||||
DefaultLinkFactory,
|
||||
DefaultLinkPointWidget,
|
||||
DefaultLinkModel,
|
||||
DefaultLinkWidget
|
||||
} from '@projectstorm/react-diagrams';
|
||||
import { DiagramEngine, LinkWidget, PointModel } from '@projectstorm/react-diagrams-core';
|
||||
import {LinkWidget, PointModel} from '@projectstorm/react-diagrams-core';
|
||||
import * as React from 'react';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
import {CanvasWidget} from '@projectstorm/react-canvas-core';
|
||||
import {DemoCanvasWidget} from '../helpers/DemoCanvasWidget';
|
||||
import {MouseEvent} from "react";
|
||||
|
||||
export class AdvancedLinkModel extends DefaultLinkModel {
|
||||
constructor() {
|
||||
@ -28,33 +28,27 @@ export class AdvancedPortModel extends DefaultPortModel {
|
||||
}
|
||||
|
||||
const CustomLinkArrowWidget = (props) => {
|
||||
const { point, previousPoint } = props;
|
||||
const {point, previousPoint} = props;
|
||||
|
||||
const angle =
|
||||
90 +
|
||||
(Math.atan2(
|
||||
point.getPosition().y - previousPoint.getPosition().y,
|
||||
point.getPosition().x - previousPoint.getPosition().x
|
||||
) *
|
||||
) *
|
||||
180) /
|
||||
Math.PI;
|
||||
Math.PI;
|
||||
|
||||
//translate(50, -10),
|
||||
return (
|
||||
<g className="arrow" transform={'translate(' + point.getPosition().x + ', ' + point.getPosition().y + ')'}>
|
||||
<g style={{ transform: 'rotate(' + angle + 'deg)' }}>
|
||||
<g style={{transform: 'rotate(' + angle + 'deg)'}}>
|
||||
<g transform={'translate(0, -3)'}>
|
||||
<polygon
|
||||
points="0,10 8,30 -8,30"
|
||||
fill={props.color}
|
||||
onMouseLeave={() => {
|
||||
this.setState({ selected: false });
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
this.setState({ selected: true });
|
||||
}}
|
||||
data-id={point.getID()}
|
||||
data-linkid={point.getLink().getID()}></polygon>
|
||||
data-linkid={point.getLink().getID()}/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
@ -122,9 +116,10 @@ export class AdvancedLinkFactory extends DefaultLinkFactory {
|
||||
}
|
||||
|
||||
generateReactWidget(event): JSX.Element {
|
||||
return <AdvancedLinkWidget link={event.model} diagramEngine={this.engine} />;
|
||||
return <AdvancedLinkWidget link={event.model} diagramEngine={this.engine}/>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Simple link styling demo
|
||||
@ -166,7 +161,7 @@ export default () => {
|
||||
// render the diagram!
|
||||
return (
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
<CanvasWidget engine={engine}/>
|
||||
</DemoCanvasWidget>
|
||||
);
|
||||
};
|
||||
|
@ -233,27 +233,32 @@ export class DiagramEngine extends CanvasEngine<CanvasEngineListener, DiagramMod
|
||||
}
|
||||
}
|
||||
|
||||
zoomToFitNodes(margin?: number) {
|
||||
let nodesRect; // nodes bounding rectangle
|
||||
let selectedNodes = this.model
|
||||
zoomToFitSelectedNodes(margin: number) {
|
||||
const nodes: NodeModel[] = this.model
|
||||
.getSelectedEntities()
|
||||
.filter((entity) => entity instanceof NodeModel)
|
||||
.map((node) => node) as NodeModel[];
|
||||
.filter((entity) => entity instanceof NodeModel) as NodeModel[];
|
||||
|
||||
// no node selected
|
||||
if (selectedNodes.length == 0) {
|
||||
let allNodes = this.model
|
||||
.getSelectionEntities()
|
||||
.filter((entity) => entity instanceof NodeModel)
|
||||
.map((node) => node) as NodeModel[];
|
||||
this.zoomToFitNodes({
|
||||
margin: margin,
|
||||
nodes: nodes.length > 0 ? nodes : null
|
||||
});
|
||||
}
|
||||
|
||||
// get nodes bounding box with margin
|
||||
nodesRect = this.getBoundingNodesRect(allNodes, margin);
|
||||
} else {
|
||||
// get nodes bounding box with margin
|
||||
nodesRect = this.getBoundingNodesRect(selectedNodes, margin);
|
||||
zoomToFitNodes(options: { margin?: number; nodes?: NodeModel[] });
|
||||
zoomToFitNodes(margin: number);
|
||||
zoomToFitNodes(options) {
|
||||
let margin = options || 0;
|
||||
let nodes: NodeModel[] = [];
|
||||
if (!!options && typeof options == 'object') {
|
||||
margin = options.margin || 0;
|
||||
nodes = options.nodes || [];
|
||||
}
|
||||
|
||||
// no node selected
|
||||
if (nodes.length === 0) {
|
||||
nodes = this.model.getNodes();
|
||||
}
|
||||
const nodesRect = this.getBoundingNodesRect(nodes, margin);
|
||||
if (nodesRect) {
|
||||
// there is something we should zoom on
|
||||
let canvasRect = this.canvas.getBoundingClientRect();
|
||||
|
@ -224,6 +224,9 @@ export class LinkModel<G extends LinkModelGenerics = LinkModelGenerics>
|
||||
}
|
||||
this.sourcePort = port;
|
||||
this.fireEvent({ port }, 'sourcePortChanged');
|
||||
if (port.reportedPosition) {
|
||||
this.getPointForPort(port).setPosition(port.getCenter());
|
||||
}
|
||||
}
|
||||
|
||||
getSourcePort(): PortModel {
|
||||
@ -243,6 +246,9 @@ export class LinkModel<G extends LinkModelGenerics = LinkModelGenerics>
|
||||
}
|
||||
this.targetPort = port;
|
||||
this.fireEvent({ port }, 'targetPortChanged');
|
||||
if (port.reportedPosition) {
|
||||
this.getPointForPort(port).setPosition(port.getCenter());
|
||||
}
|
||||
}
|
||||
|
||||
point(x: number, y: number, index: number = 1): PointModel {
|
||||
|
@ -37,7 +37,7 @@ export class NodeWidget extends React.Component<NodeProps> {
|
||||
this.ob.disconnect();
|
||||
this.ob = null;
|
||||
|
||||
this.listener.deregister();
|
||||
this.listener?.deregister();
|
||||
this.listener = null;
|
||||
}
|
||||
|
||||
@ -56,17 +56,26 @@ export class NodeWidget extends React.Component<NodeProps> {
|
||||
});
|
||||
}
|
||||
|
||||
updateSize(width: number, height: number) {
|
||||
this.props.node.updateDimensions({ width, height });
|
||||
|
||||
//now mark the links as dirty
|
||||
try {
|
||||
_.forEach(this.props.node.getPorts(), (port) => {
|
||||
port.updateCoords(this.props.diagramEngine.getPortCoords(port));
|
||||
});
|
||||
} catch (ex) {}
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
// @ts-ignore
|
||||
this.ob = new ResizeObserver((entities) => {
|
||||
const bounds = entities[0].contentRect;
|
||||
this.props.node.updateDimensions({ width: bounds.width, height: bounds.height });
|
||||
|
||||
//now mark the links as dirty
|
||||
_.forEach(this.props.node.getPorts(), (port) => {
|
||||
port.updateCoords(this.props.diagramEngine.getPortCoords(port));
|
||||
});
|
||||
this.updateSize(bounds.width, bounds.height);
|
||||
});
|
||||
|
||||
const b = this.ref.current.getBoundingClientRect();
|
||||
this.updateSize(b.width, b.height);
|
||||
this.ob.observe(this.ref.current);
|
||||
this.installSelectionListener();
|
||||
}
|
||||
|
@ -142,6 +142,10 @@ export class PortModel<G extends PortModelGenerics = PortModelGenerics> extends
|
||||
return new Point(this.getX() + this.width / 2, this.getY() + this.height / 2);
|
||||
}
|
||||
|
||||
getBoundingBox(): Rectangle {
|
||||
return new Rectangle(this.position, this.width, this.height);
|
||||
}
|
||||
|
||||
updateCoords(coords: Rectangle) {
|
||||
this.width = coords.getWidth();
|
||||
this.height = coords.getHeight();
|
||||
|
@ -9,6 +9,8 @@ export interface DefaultLinkProps {
|
||||
link: DefaultLinkModel;
|
||||
diagramEngine: DiagramEngine;
|
||||
pointAdded?: (point: PointModel, event: MouseEvent) => any;
|
||||
renderPoints?: boolean;
|
||||
selected?: (event: MouseEvent) => any;
|
||||
}
|
||||
|
||||
export interface DefaultLinkState {
|
||||
@ -26,6 +28,10 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
|
||||
};
|
||||
}
|
||||
|
||||
renderPoints() {
|
||||
return this.props.renderPoints ?? true;
|
||||
}
|
||||
|
||||
componentDidUpdate(): void {
|
||||
this.props.link.setRenderedPaths(
|
||||
this.refPaths.map((ref) => {
|
||||
@ -111,6 +117,7 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
|
||||
this.props.link.getSVGPath(),
|
||||
{
|
||||
onMouseDown: (event) => {
|
||||
this.props.selected?.(event);
|
||||
this.addPointToLink(event, 1);
|
||||
}
|
||||
},
|
||||
@ -132,6 +139,7 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
|
||||
'data-linkid': this.props.link.getID(),
|
||||
'data-point': j,
|
||||
onMouseDown: (event: MouseEvent) => {
|
||||
this.props.selected?.(event);
|
||||
this.addPointToLink(event, j + 1);
|
||||
}
|
||||
},
|
||||
@ -140,13 +148,15 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
|
||||
);
|
||||
}
|
||||
|
||||
//render the circles
|
||||
for (let i = 1; i < points.length - 1; i++) {
|
||||
paths.push(this.generatePoint(points[i]));
|
||||
}
|
||||
if (this.renderPoints()) {
|
||||
//render the circles
|
||||
for (let i = 1; i < points.length - 1; i++) {
|
||||
paths.push(this.generatePoint(points[i]));
|
||||
}
|
||||
|
||||
if (this.props.link.getTargetPort() == null) {
|
||||
paths.push(this.generatePoint(points[points.length - 1]));
|
||||
if (this.props.link.getTargetPort() == null) {
|
||||
paths.push(this.generatePoint(points[points.length - 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
47
packages/react-diagrams-routing/pnpm-lock.yaml
generated
Normal file
47
packages/react-diagrams-routing/pnpm-lock.yaml
generated
Normal file
@ -0,0 +1,47 @@
|
||||
dependencies:
|
||||
'@projectstorm/geometry': 6.4.2
|
||||
'@projectstorm/react-diagrams-core': 6.4.2
|
||||
'@projectstorm/react-diagrams-defaults': 6.4.2
|
||||
lockfileVersion: 5.2
|
||||
packages:
|
||||
/@projectstorm/geometry/6.4.2:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-9h2OKHYW79tUdRzZ0InJ5unZ57AC0PR7XLF3WXlPsomXoZAVzDcwBMqbUoQmnfXHN9hE6iGQhcYUxYcvFm3DgQ==
|
||||
/@projectstorm/react-canvas-core/6.4.2:
|
||||
dependencies:
|
||||
'@projectstorm/geometry': 6.4.2
|
||||
dev: false
|
||||
peerDependencies:
|
||||
closest: ^0.0.1
|
||||
lodash: 4.*
|
||||
react: 17.*
|
||||
resolution:
|
||||
integrity: sha512-e0rcBM3gWQg65PGF4AiRE/J5mk0vzHjIKPfA7HBX9wCUdOxSpHL9t1CVD+UZZog6UcZzm00wNH2SSLHxzuwkvg==
|
||||
/@projectstorm/react-diagrams-core/6.4.2:
|
||||
dependencies:
|
||||
'@projectstorm/geometry': 6.4.2
|
||||
'@projectstorm/react-canvas-core': 6.4.2
|
||||
dev: false
|
||||
peerDependencies:
|
||||
closest: ^0.0.1
|
||||
lodash: 4.*
|
||||
react: 17.*
|
||||
resize-observer-polyfill: ^1.5.1
|
||||
resolution:
|
||||
integrity: sha512-zcXcxW1WMiU3AvQwI4h2+rg6irk7uNl3ZGDr5VE9wEc9kRAuhLE8VIWgjW0y3x0M8zCtC7cM6+879f8hwWa2Pg==
|
||||
/@projectstorm/react-diagrams-defaults/6.4.2:
|
||||
dependencies:
|
||||
'@projectstorm/react-diagrams-core': 6.4.2
|
||||
dev: false
|
||||
peerDependencies:
|
||||
'@emotion/core': ^11.*
|
||||
'@emotion/styled': ^11.*
|
||||
lodash: 4.*
|
||||
react: 17.*
|
||||
resolution:
|
||||
integrity: sha512-O4zqfa6uG2Yd6EjWdDBcZuPgwBKUBw+jJLhmARAwAmQAbqIzSXhgvXCBac0zuLwkQSdf+i2zkk24+ENxRc29RQ==
|
||||
specifiers:
|
||||
'@projectstorm/geometry': ^6.4.2
|
||||
'@projectstorm/react-diagrams-core': ^6.4.2
|
||||
'@projectstorm/react-diagrams-defaults': ^6.4.2
|
@ -22,15 +22,14 @@ export class DagreEngine {
|
||||
redistribute(model: DiagramModel) {
|
||||
// Create a new directed graph
|
||||
var g = new dagre.graphlib.Graph({
|
||||
multigraph: true
|
||||
multigraph: true,
|
||||
compound: true
|
||||
});
|
||||
g.setGraph(this.options.graph || {});
|
||||
g.setDefaultEdgeLabel(function () {
|
||||
return {};
|
||||
});
|
||||
|
||||
const processedlinks: { [id: string]: boolean } = {};
|
||||
|
||||
// set nodes
|
||||
_.forEach(model.getNodes(), (node) => {
|
||||
g.setNode(node.getID(), { width: node.width, height: node.height });
|
||||
@ -39,7 +38,6 @@ export class DagreEngine {
|
||||
_.forEach(model.getLinks(), (link) => {
|
||||
// set edges
|
||||
if (link.getSourcePort() && link.getTargetPort()) {
|
||||
processedlinks[link.getID()] = true;
|
||||
g.setEdge({
|
||||
v: link.getSourcePort().getNode().getID(),
|
||||
w: link.getTargetPort().getNode().getID(),
|
||||
@ -63,7 +61,7 @@ export class DagreEngine {
|
||||
const link = model.getLink(e.name);
|
||||
|
||||
const points = [link.getFirstPoint()];
|
||||
for (let i = 1; i < edge.points.length - 2; i++) {
|
||||
for (let i = 1; i < edge.points.length - 1; i++) {
|
||||
points.push(new PointModel({ link: link, position: new Point(edge.points[i].x, edge.points[i].y) }));
|
||||
}
|
||||
link.setPoints(points.concat(link.getLastPoint()));
|
||||
|
Reference in New Issue
Block a user