mirror of
https://github.com/projectstorm/react-diagrams.git
synced 2025-08-15 09:19:05 +08:00
add a few small fixes and improvements
This commit is contained in:
@ -3,14 +3,14 @@ import createEngine, {
|
|||||||
DefaultNodeModel,
|
DefaultNodeModel,
|
||||||
DefaultPortModel,
|
DefaultPortModel,
|
||||||
DefaultLinkFactory,
|
DefaultLinkFactory,
|
||||||
DefaultLinkPointWidget,
|
|
||||||
DefaultLinkModel,
|
DefaultLinkModel,
|
||||||
DefaultLinkWidget
|
DefaultLinkWidget
|
||||||
} from '@projectstorm/react-diagrams';
|
} 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 * as React from 'react';
|
||||||
import {CanvasWidget} from '@projectstorm/react-canvas-core';
|
import {CanvasWidget} from '@projectstorm/react-canvas-core';
|
||||||
import {DemoCanvasWidget} from '../helpers/DemoCanvasWidget';
|
import {DemoCanvasWidget} from '../helpers/DemoCanvasWidget';
|
||||||
|
import {MouseEvent} from "react";
|
||||||
|
|
||||||
export class AdvancedLinkModel extends DefaultLinkModel {
|
export class AdvancedLinkModel extends DefaultLinkModel {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -47,14 +47,8 @@ const CustomLinkArrowWidget = (props) => {
|
|||||||
<polygon
|
<polygon
|
||||||
points="0,10 8,30 -8,30"
|
points="0,10 8,30 -8,30"
|
||||||
fill={props.color}
|
fill={props.color}
|
||||||
onMouseLeave={() => {
|
|
||||||
this.setState({ selected: false });
|
|
||||||
}}
|
|
||||||
onMouseEnter={() => {
|
|
||||||
this.setState({ selected: true });
|
|
||||||
}}
|
|
||||||
data-id={point.getID()}
|
data-id={point.getID()}
|
||||||
data-linkid={point.getLink().getID()}></polygon>
|
data-linkid={point.getLink().getID()}/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
@ -125,6 +119,7 @@ export class AdvancedLinkFactory extends DefaultLinkFactory {
|
|||||||
return <AdvancedLinkWidget link={event.model} diagramEngine={this.engine}/>;
|
return <AdvancedLinkWidget link={event.model} diagramEngine={this.engine}/>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Simple link styling demo
|
* Simple link styling demo
|
||||||
|
@ -233,27 +233,32 @@ export class DiagramEngine extends CanvasEngine<CanvasEngineListener, DiagramMod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomToFitNodes(margin?: number) {
|
zoomToFitSelectedNodes(margin: number) {
|
||||||
let nodesRect; // nodes bounding rectangle
|
const nodes: NodeModel[] = this.model
|
||||||
let selectedNodes = this.model
|
|
||||||
.getSelectedEntities()
|
.getSelectedEntities()
|
||||||
.filter((entity) => entity instanceof NodeModel)
|
.filter((entity) => entity instanceof NodeModel) as NodeModel[];
|
||||||
.map((node) => node) as NodeModel[];
|
|
||||||
|
|
||||||
// no node selected
|
this.zoomToFitNodes({
|
||||||
if (selectedNodes.length == 0) {
|
margin: margin,
|
||||||
let allNodes = this.model
|
nodes: nodes.length > 0 ? nodes : null
|
||||||
.getSelectionEntities()
|
});
|
||||||
.filter((entity) => entity instanceof NodeModel)
|
|
||||||
.map((node) => node) as NodeModel[];
|
|
||||||
|
|
||||||
// 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) {
|
if (nodesRect) {
|
||||||
// there is something we should zoom on
|
// there is something we should zoom on
|
||||||
let canvasRect = this.canvas.getBoundingClientRect();
|
let canvasRect = this.canvas.getBoundingClientRect();
|
||||||
|
@ -224,6 +224,9 @@ export class LinkModel<G extends LinkModelGenerics = LinkModelGenerics>
|
|||||||
}
|
}
|
||||||
this.sourcePort = port;
|
this.sourcePort = port;
|
||||||
this.fireEvent({ port }, 'sourcePortChanged');
|
this.fireEvent({ port }, 'sourcePortChanged');
|
||||||
|
if (port.reportedPosition) {
|
||||||
|
this.getPointForPort(port).setPosition(port.getCenter());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSourcePort(): PortModel {
|
getSourcePort(): PortModel {
|
||||||
@ -243,6 +246,9 @@ export class LinkModel<G extends LinkModelGenerics = LinkModelGenerics>
|
|||||||
}
|
}
|
||||||
this.targetPort = port;
|
this.targetPort = port;
|
||||||
this.fireEvent({ port }, 'targetPortChanged');
|
this.fireEvent({ port }, 'targetPortChanged');
|
||||||
|
if (port.reportedPosition) {
|
||||||
|
this.getPointForPort(port).setPosition(port.getCenter());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
point(x: number, y: number, index: number = 1): PointModel {
|
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.disconnect();
|
||||||
this.ob = null;
|
this.ob = null;
|
||||||
|
|
||||||
this.listener.deregister();
|
this.listener?.deregister();
|
||||||
this.listener = null;
|
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 {
|
componentDidMount(): void {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.ob = new ResizeObserver((entities) => {
|
this.ob = new ResizeObserver((entities) => {
|
||||||
const bounds = entities[0].contentRect;
|
const bounds = entities[0].contentRect;
|
||||||
this.props.node.updateDimensions({ width: bounds.width, height: bounds.height });
|
this.updateSize(bounds.width, bounds.height);
|
||||||
|
});
|
||||||
|
|
||||||
//now mark the links as dirty
|
const b = this.ref.current.getBoundingClientRect();
|
||||||
_.forEach(this.props.node.getPorts(), (port) => {
|
this.updateSize(b.width, b.height);
|
||||||
port.updateCoords(this.props.diagramEngine.getPortCoords(port));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.ob.observe(this.ref.current);
|
this.ob.observe(this.ref.current);
|
||||||
this.installSelectionListener();
|
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);
|
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) {
|
updateCoords(coords: Rectangle) {
|
||||||
this.width = coords.getWidth();
|
this.width = coords.getWidth();
|
||||||
this.height = coords.getHeight();
|
this.height = coords.getHeight();
|
||||||
|
@ -9,6 +9,8 @@ export interface DefaultLinkProps {
|
|||||||
link: DefaultLinkModel;
|
link: DefaultLinkModel;
|
||||||
diagramEngine: DiagramEngine;
|
diagramEngine: DiagramEngine;
|
||||||
pointAdded?: (point: PointModel, event: MouseEvent) => any;
|
pointAdded?: (point: PointModel, event: MouseEvent) => any;
|
||||||
|
renderPoints?: boolean;
|
||||||
|
selected?: (event: MouseEvent) => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DefaultLinkState {
|
export interface DefaultLinkState {
|
||||||
@ -26,6 +28,10 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderPoints() {
|
||||||
|
return this.props.renderPoints ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(): void {
|
componentDidUpdate(): void {
|
||||||
this.props.link.setRenderedPaths(
|
this.props.link.setRenderedPaths(
|
||||||
this.refPaths.map((ref) => {
|
this.refPaths.map((ref) => {
|
||||||
@ -111,6 +117,7 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
|
|||||||
this.props.link.getSVGPath(),
|
this.props.link.getSVGPath(),
|
||||||
{
|
{
|
||||||
onMouseDown: (event) => {
|
onMouseDown: (event) => {
|
||||||
|
this.props.selected?.(event);
|
||||||
this.addPointToLink(event, 1);
|
this.addPointToLink(event, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -132,6 +139,7 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
|
|||||||
'data-linkid': this.props.link.getID(),
|
'data-linkid': this.props.link.getID(),
|
||||||
'data-point': j,
|
'data-point': j,
|
||||||
onMouseDown: (event: MouseEvent) => {
|
onMouseDown: (event: MouseEvent) => {
|
||||||
|
this.props.selected?.(event);
|
||||||
this.addPointToLink(event, j + 1);
|
this.addPointToLink(event, j + 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -140,6 +148,7 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.renderPoints()) {
|
||||||
//render the circles
|
//render the circles
|
||||||
for (let i = 1; i < points.length - 1; i++) {
|
for (let i = 1; i < points.length - 1; i++) {
|
||||||
paths.push(this.generatePoint(points[i]));
|
paths.push(this.generatePoint(points[i]));
|
||||||
@ -149,6 +158,7 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
|
|||||||
paths.push(this.generatePoint(points[points.length - 1]));
|
paths.push(this.generatePoint(points[points.length - 1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return <g data-default-link-test={this.props.link.getOptions().testName}>{paths}</g>;
|
return <g data-default-link-test={this.props.link.getOptions().testName}>{paths}</g>;
|
||||||
}
|
}
|
||||||
|
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) {
|
redistribute(model: DiagramModel) {
|
||||||
// Create a new directed graph
|
// Create a new directed graph
|
||||||
var g = new dagre.graphlib.Graph({
|
var g = new dagre.graphlib.Graph({
|
||||||
multigraph: true
|
multigraph: true,
|
||||||
|
compound: true
|
||||||
});
|
});
|
||||||
g.setGraph(this.options.graph || {});
|
g.setGraph(this.options.graph || {});
|
||||||
g.setDefaultEdgeLabel(function () {
|
g.setDefaultEdgeLabel(function () {
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
|
|
||||||
const processedlinks: { [id: string]: boolean } = {};
|
|
||||||
|
|
||||||
// set nodes
|
// set nodes
|
||||||
_.forEach(model.getNodes(), (node) => {
|
_.forEach(model.getNodes(), (node) => {
|
||||||
g.setNode(node.getID(), { width: node.width, height: node.height });
|
g.setNode(node.getID(), { width: node.width, height: node.height });
|
||||||
@ -39,7 +38,6 @@ export class DagreEngine {
|
|||||||
_.forEach(model.getLinks(), (link) => {
|
_.forEach(model.getLinks(), (link) => {
|
||||||
// set edges
|
// set edges
|
||||||
if (link.getSourcePort() && link.getTargetPort()) {
|
if (link.getSourcePort() && link.getTargetPort()) {
|
||||||
processedlinks[link.getID()] = true;
|
|
||||||
g.setEdge({
|
g.setEdge({
|
||||||
v: link.getSourcePort().getNode().getID(),
|
v: link.getSourcePort().getNode().getID(),
|
||||||
w: link.getTargetPort().getNode().getID(),
|
w: link.getTargetPort().getNode().getID(),
|
||||||
@ -63,7 +61,7 @@ export class DagreEngine {
|
|||||||
const link = model.getLink(e.name);
|
const link = model.getLink(e.name);
|
||||||
|
|
||||||
const points = [link.getFirstPoint()];
|
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) }));
|
points.push(new PointModel({ link: link, position: new Point(edge.points[i].x, edge.points[i].y) }));
|
||||||
}
|
}
|
||||||
link.setPoints(points.concat(link.getLastPoint()));
|
link.setPoints(points.concat(link.getLastPoint()));
|
||||||
|
Reference in New Issue
Block a user