Make custom state demo where linking is done by clicking ports

This commit is contained in:
David Sljukic
2019-09-03 22:55:53 +02:00
parent 326567c290
commit 8ded9cd30e
5 changed files with 187 additions and 3 deletions

View File

@@ -0,0 +1,87 @@
import {
Action,
ActionEvent,
InputType,
State
} from '@projectstorm/react-canvas-core';
import { PortModel, LinkModel, DiagramEngine } from '@projectstorm/react-diagrams-core';
import { MouseEvent, KeyboardEvent } from 'react';
/**
* This state is controlling the creation of a link.
*/
export class CreateLinkState extends State<DiagramEngine> {
sourcePort: PortModel;
link: LinkModel;
constructor() {
super({ name: 'create-new-link' });
this.registerAction(
new Action({
type: InputType.MOUSE_UP,
fire: (actionEvent: ActionEvent<MouseEvent>) => {
const element = this.engine.getActionEventBus().getModelForEvent(actionEvent);
const { event: { clientX, clientY } } = actionEvent;
const ox = this.engine.getModel().getOffsetX();
const oy = this.engine.getModel().getOffsetY();
if (element instanceof PortModel && !this.sourcePort) {
this.sourcePort = element;
/* would be cool if link creating could be done somewhat like
const link = createLink({
sourcePort: this.sourcePort,
points: [{ x: clientX, y: clientY }, { x: clientX, y: clientY }]
})
*/
const link = this.sourcePort.createLinkModel();
link.setSourcePort(this.sourcePort);
link.getFirstPoint().setPosition(clientX - ox, clientY - oy);
link.getLastPoint().setPosition(clientX - ox + 20, clientY - oy + 20);
this.link = this.engine.getModel().addLink(link);
} else if (element instanceof PortModel && this.sourcePort && element != this.sourcePort) {
if (this.sourcePort.canLinkToPort(element)) {
this.link.setTargetPort(element);
element.reportPosition();
this.eject();
}
} else if (element === this.link.getLastPoint()) {
this.link.point(clientX - ox, clientY - oy, -1);
}
this.engine.repaintCanvas();
}
})
);
this.registerAction(
new Action({
type: InputType.MOUSE_MOVE,
fire: (actionEvent: ActionEvent<React.MouseEvent>) => {
if (!this.link) return;
const { event } = actionEvent;
this.link.getLastPoint().setPosition(event.clientX, event.clientY);
this.engine.repaintCanvas();
}
})
);
this.registerAction(
new Action({
type: InputType.KEY_UP,
fire: (actionEvent: ActionEvent<KeyboardEvent>) => {
// on esc press remove any started link and pop back to default state
if (actionEvent.event.keyCode === 27) {
this.link.remove();
this.link = undefined;
this.sourcePort = undefined;
this.eject();
this.engine.repaintCanvas();
}
}
})
);
}
}

View File

@@ -0,0 +1,64 @@
import { MouseEvent } from 'react';
import {
SelectingState,
State,
Action,
InputType,
ActionEvent,
DragCanvasState
} from '@projectstorm/react-canvas-core';
import {
PortModel,
DiagramEngine,
DragDiagramItemsState
} from '@projectstorm/react-diagrams-core';
import { CreateLinkState } from './CreateLinkState';
export class DefaultState extends State<DiagramEngine> {
dragCanvas: DragCanvasState;
createLink: CreateLinkState;
dragItems: DragDiagramItemsState;
constructor() {
super({ name: 'starting-state' });
this.childStates = [new SelectingState()];
this.dragCanvas = new DragCanvasState();
this.createLink = new CreateLinkState();
this.dragItems = new DragDiagramItemsState();
// determine what was clicked on
this.registerAction(
new Action({
type: InputType.MOUSE_DOWN,
fire: (event: ActionEvent<MouseEvent>) => {
const element = this.engine.getActionEventBus().getModelForEvent(event);
// the canvas was clicked on, transition to the dragging canvas state
if (!element) {
this.transitionWithEvent(this.dragCanvas, event);
}
// initiate dragging a new link
else if (element instanceof PortModel) {
return;
}
// move the items (and potentially link points)
else {
this.transitionWithEvent(this.dragItems, event);
}
}
})
);
this.registerAction(
new Action({
type: InputType.MOUSE_UP,
fire: (event: ActionEvent<MouseEvent>) => {
const element = this.engine.getActionEventBus().getModelForEvent(event);
if (element instanceof PortModel)
this.transitionWithEvent(this.createLink, event);
}
})
);
}
}

View File

@@ -0,0 +1,31 @@
import * as React from 'react';
import createEngine, { DiagramModel, DefaultNodeModel } from '@projectstorm/react-diagrams';
import { CanvasWidget } from '@projectstorm/react-canvas-core';
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
import { DefaultState } from './DefaultState';
export default () => {
const engine = createEngine();
const model = new DiagramModel();
const node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
node1.addOutPort('Out');
node1.setPosition(100, 100);
const node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
node2.addInPort('In');
node2.setPosition(400, 100);
model.addAll(node1, node2);
engine.setModel(model);
// Use this custom "DefaultState" instead of the actual default state we get with the engine
engine.getStateMachine().pushState(new DefaultState());
return (
<DemoCanvasWidget>
<CanvasWidget engine={engine} />
</DemoCanvasWidget>
);
};

View File

@@ -33,6 +33,7 @@ import demo_listeners from './demos/demo-listeners';
import demo_zoom from './demos/demo-zoom-to-fit';
import demo_labels from './demos/demo-labelled-links';
import demo_dynamic_ports from './demos/demo-dynamic-ports';
import demo_alternative_linking from './demos/demo-alternative-linking';
storiesOf('Simple Usage', module)
.add('Simple example', demo_simple)
@@ -58,7 +59,8 @@ storiesOf('Advanced Techniques', module)
.add('Programatically modifying graph', demo_adv_prog)
.add('Drag and drop', demo_adv_dnd)
.add('Smart routing', demo_smart_routing)
.add('Right angles routing', demo_right_angles_routing);
.add('Right angles routing', demo_right_angles_routing)
.add('Create link by clicking instead of dragging', demo_alternative_linking);
import demo_cust_nodes from './demos/demo-custom-node1';
import demo_cust_links from './demos/demo-custom-link1';

View File

@@ -244,8 +244,8 @@ export class LinkModel<G extends LinkModelGenerics = LinkModelGenerics> extends
this.fireEvent({ port }, 'targetPortChanged');
}
point(x: number, y: number): PointModel {
return this.addPoint(this.generatePoint(x, y));
point(x: number, y: number, index: number = 1): PointModel {
return this.addPoint(this.generatePoint(x, y), index);
}
addLabel(label: LabelModel) {