add a few small fixes and improvements

This commit is contained in:
Dylan Vorster
2021-03-20 22:20:24 +02:00
parent 53eee3f518
commit 8173b70834
8 changed files with 125 additions and 51 deletions

View File

@ -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 {MouseEvent} from "react";
export class AdvancedLinkModel extends DefaultLinkModel {
constructor() {
@ -47,14 +47,8 @@ const CustomLinkArrowWidget = (props) => {
<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>
@ -125,6 +119,7 @@ export class AdvancedLinkFactory extends DefaultLinkFactory {
return <AdvancedLinkWidget link={event.model} diagramEngine={this.engine}/>;
}
}
/**
*
* Simple link styling demo

View File

@ -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[];
// get nodes bounding box with margin
nodesRect = this.getBoundingNodesRect(allNodes, margin);
} else {
// get nodes bounding box with margin
nodesRect = this.getBoundingNodesRect(selectedNodes, margin);
this.zoomToFitNodes({
margin: margin,
nodes: nodes.length > 0 ? nodes : null
});
}
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();

View File

@ -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 {

View File

@ -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 });
this.updateSize(bounds.width, bounds.height);
});
//now mark the links as dirty
_.forEach(this.props.node.getPorts(), (port) => {
port.updateCoords(this.props.diagramEngine.getPortCoords(port));
});
});
const b = this.ref.current.getBoundingClientRect();
this.updateSize(b.width, b.height);
this.ob.observe(this.ref.current);
this.installSelectionListener();
}

View File

@ -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();

View File

@ -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,6 +148,7 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
);
}
if (this.renderPoints()) {
//render the circles
for (let i = 1; i < points.length - 1; 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]));
}
}
}
return <g data-default-link-test={this.props.link.getOptions().testName}>{paths}</g>;
}

View 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

View File

@ -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()));