+ Cleaned up documentation

+ Added new events to the LinkModel for when ports change
+ Added properties allowing the canvas to lock its zoom and panning
+ Added option for disabling loose links
+ depreciated but did not remove the controlsUpdated event
This commit is contained in:
Dylan Vorster
2017-03-23 11:43:03 +02:00
parent 27c0883dab
commit f36a8cf304
18 changed files with 361 additions and 114 deletions

2
.gitignore vendored
View File

@@ -4,6 +4,8 @@ demos/demo2/bundle.js
demos/demo2/bundle.js.map
demos/demo3/bundle.js
demos/demo3/bundle.js.map
demos/demo4/bundle.js
demos/demo4/bundle.js.map
dist/main.js
dist/main.js.map

View File

@@ -59,40 +59,7 @@ a link can be connected to it.
## Events
Each model (DiagramModel, NodeModel etc..) are all built ontop of an event system. You can listen for most of these events by registering
an event on the model itself. See below for some common events (I will add better documentation soon)
- entityRemoved (entity)
- selectionChanged (entity, isSelected:Boolean)
- nodeFactoriesUpdated
- linkFactoriesUpdated
- controlsUpdated
- linksUpdated (entity, isAdded:Boolean)
- nodesUpdated (entity, isAdded:Boolean)
### Example of usage
```javascript
let model = new SRD.DiagramModel();
let node1 = new SRD.DefaultNodeModel("default","rgb(0,192,255)");
node1.addListener({
entityRemoved: (node) => {
console.log('Removed', node.id)
},
selectionChanged: (node, isSelected) => {
console.log(isSelected?'Selected':'Unselected', node)
}
});
model.addListener({
linksUpdated:(entity, isAdded) => {
console.log(isAdded?'added':'removed', entity)
},
nodesUpdated: (entity, isAdded) => {
console.log(isAdded?'added':'removed', entity)
}
});
```
[Event System](docs/Events.md)
## DiagramWidget props

15
demos/demo4/index.html Normal file
View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>STORM React Diagrams Test 2</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/react/dist/react.min.js"></script>
<script src="https://unpkg.com/react-dom/dist/react-dom.min.js"></script>
<script src="https://unpkg.com/lodash@4.17.4/lodash.min.js"></script>
<script src="./bundle.js"></script>
</head>
<body>
</body>
</html>

63
demos/demo4/index.ts Normal file
View File

@@ -0,0 +1,63 @@
import * as SRD from "../../src/main";
import * as React from "react";
import * as ReactDOM from "react-dom";
declare var require: {
<T>(path: string): T;
(paths: string[], callback: (...modules: any[]) => void): void;
ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
};
require("../test.scss");
/**
*
* Shows how you can lock down the ystem so that the entire scene cant be interacted with.
*
* @Author Dylan Vorster
*/
window.onload = () => {
//1) setup the diagram engine
var engine = new SRD.DiagramEngine();
engine.registerNodeFactory(new SRD.DefaultNodeFactory());
engine.registerLinkFactory(new SRD.DefaultLinkFactory());
var model = new SRD.DiagramModel();
var node1 = new SRD.DefaultNodeModel("Node 1","rgb(0,192,255)");
var port1 = node1.addPort(new SRD.DefaultPortModel(false,"out-1","Out"));
node1.x = 100;
node1.y = 100;
var node2 = new SRD.DefaultNodeModel("Node 2","rgb(192,255,0)");
var port2 = node2.addPort(new SRD.DefaultPortModel(true,"in-1","IN"));
node2.x = 400;
node2.y = 100;
var link1 = new SRD.LinkModel();
link1.setSourcePort(port1);
link1.setTargetPort(port2);
model.addNode(node1);
model.addNode(node2);
model.addLink(link1);
engine.setDiagramModel(model);
//!========================================= <<<<<<<
model.setLocked(true);
var props = {
diagramEngine: engine,
allowLooseLinks: false,
allowCanvasTranslation: false,
allowCanvasZoom: false
} as SRD.DiagramProps;
//!========================================= <<<<<<<
ReactDOM.render(React.createElement(SRD.DiagramWidget,props), document.body);
}

0
dist/demos/demo4/index.d.ts vendored Normal file
View File

View File

@@ -2,12 +2,14 @@
* @author Dylan Vorster
*/
export declare class BaseListener {
lockChanged?(entity: BaseEntity<BaseListener>, locked: boolean): void;
}
export declare class BaseEntity<T extends BaseListener> {
listeners: {
[s: string]: T;
};
id: string;
locked: boolean;
constructor();
getID(): string;
clearListeners(): void;
@@ -18,4 +20,6 @@ export declare class BaseEntity<T extends BaseListener> {
itterateListeners(cb: (t: T) => any): void;
removeListener(listener: string): boolean;
addListener(listener: T): string;
isLocked(): boolean;
setLocked(locked?: boolean): void;
}

20
dist/src/Common.d.ts vendored
View File

@@ -1,12 +1,12 @@
import { BaseEntity, BaseListener } from "./BaseEntity";
export interface BaseModelListener extends BaseListener {
selectionChanged?(item: any, isSelected: boolean): any;
entityRemoved?(item: any): any;
selectionChanged?(item: BaseModel<BaseModelListener>, isSelected: boolean): void;
entityRemoved?(item: any): void;
}
/**
* @author Dylan Vorster
*/
export declare class BaseModel extends BaseEntity<BaseModelListener> {
export declare class BaseModel<T extends BaseModelListener> extends BaseEntity<BaseModelListener> {
selected: boolean;
constructor();
deSerialize(ob: any): void;
@@ -18,10 +18,10 @@ export declare class BaseModel extends BaseEntity<BaseModelListener> {
};
getID(): string;
isSelected(): boolean;
setSelected(selected: boolean): void;
setSelected(selected?: boolean): void;
remove(): void;
}
export declare class PointModel extends BaseModel {
export declare class PointModel extends BaseModel<BaseModelListener> {
x: number;
y: number;
link: LinkModel;
@@ -48,7 +48,11 @@ export declare class PointModel extends BaseModel {
getY(): number;
getLink(): LinkModel;
}
export declare class LinkModel extends BaseModel {
export interface LinkModelListener extends BaseModelListener {
sourcePortChanged?(item: LinkModel, target: null | PortModel): void;
targetPortChanged?(item: LinkModel, target: null | PortModel): void;
}
export declare class LinkModel extends BaseModel<LinkModelListener> {
linkType: string;
sourcePort: PortModel | null;
targetPort: PortModel | null;
@@ -94,7 +98,7 @@ export declare class LinkModel extends BaseModel {
addPoint(pointModel: PointModel, index?: number): void;
getType(): string;
}
export declare class PortModel extends BaseModel {
export declare class PortModel extends BaseModel<BaseModelListener> {
name: string;
parentNode: NodeModel;
links: {
@@ -121,7 +125,7 @@ export declare class PortModel extends BaseModel {
[id: string]: LinkModel;
};
}
export declare class NodeModel extends BaseModel {
export declare class NodeModel extends BaseModel<BaseModelListener> {
nodeType: string;
x: number;
y: number;

View File

@@ -1,6 +1,6 @@
/// <reference types="react" />
import { NodeWidgetFactory, LinkWidgetFactory } from "./WidgetFactories";
import { LinkModel, NodeModel, BaseModel, PortModel } from "./Common";
import { LinkModel, NodeModel, BaseModel, BaseModelListener, PortModel } from "./Common";
import { BaseEntity, BaseListener } from "./BaseEntity";
import { DiagramModel } from "./DiagramModel";
import { AbstractInstanceFactory } from "./AbstractInstanceFactory";
@@ -29,8 +29,13 @@ export declare class DiagramEngine extends BaseEntity<DiagramEngineListener> {
paintableWidgets: {};
constructor();
clearRepaintEntities(): void;
enableRepaintEntities(entities: BaseModel[]): void;
canEntityRepaint(baseModel: BaseModel): boolean;
enableRepaintEntities(entities: BaseModel<BaseModelListener>[]): void;
/**
* Checks to see if a model is locked by running through
* its parents to see if they are locked first
*/
isModelLocked(model: BaseEntity<BaseListener>): boolean;
canEntityRepaint(baseModel: BaseModel<BaseModelListener>): boolean;
setCanvas(canvas: Element | null): void;
setDiagramModel(model: DiagramModel): void;
getDiagramModel(): DiagramModel;

View File

@@ -1,4 +1,4 @@
import { LinkModel, NodeModel, BaseModel } from "./Common";
import { LinkModel, NodeModel, BaseModel, BaseModelListener } from "./Common";
import { BaseListener, BaseEntity } from "./BaseEntity";
import { DiagramEngine } from "./DiagramEngine";
/**
@@ -6,9 +6,14 @@ import { DiagramEngine } from "./DiagramEngine";
*
*/
export interface DiagramListener extends BaseListener {
nodesUpdated(node: any, isCreated: boolean): any;
linksUpdated(link: any, isCreated: boolean): any;
controlsUpdated(): any;
nodesUpdated(node: any, isCreated: boolean): void;
linksUpdated(link: any, isCreated: boolean): void;
/**
* @deprecated
*/
controlsUpdated(): void;
offsetUpdated(model: DiagramModel, offsetX: number, offsetY: number): void;
zoomUpdated(model: DiagramModel, zoom: number): void;
}
/**
*
@@ -76,8 +81,8 @@ export declare class DiagramModel extends BaseEntity<DiagramListener> {
})[];
})[];
};
clearSelection(ignore?: BaseModel | null): void;
getSelectedItems(): BaseModel[];
clearSelection(ignore?: BaseModel<BaseModelListener> | null): void;
getSelectedItems(): BaseModel<BaseModelListener>[];
setZoomLevel(zoom: number): void;
setOffset(offsetX: number, offsetY: number): void;
setOffsetX(offsetX: number): void;

View File

@@ -1,7 +1,7 @@
/// <reference types="react" />
import * as React from "react";
import { DiagramEngine } from "../DiagramEngine";
import { BaseModel } from "../Common";
import { BaseModel, BaseModelListener } from "../Common";
export declare class BaseAction {
mouseX: number;
mouseY: number;
@@ -10,7 +10,9 @@ export declare class BaseAction {
}
export interface DiagramProps {
diagramEngine: DiagramEngine;
onLinkStateChanged?: any;
allowLooseLinks?: boolean;
allowCanvasTranslation?: boolean;
allowCanvasZoom?: boolean;
}
export interface DiagramState {
action: BaseAction | null;
@@ -21,6 +23,7 @@ export interface DiagramState {
* @author Dylan Vorster
*/
export declare class DiagramWidget extends React.Component<DiagramProps, DiagramState> {
static defaultProps: DiagramProps;
constructor(props: DiagramProps);
componentWillUnmount(): void;
componentWillUpdate(nextProps: DiagramProps): void;
@@ -30,7 +33,7 @@ export declare class DiagramWidget extends React.Component<DiagramProps, Diagram
* Gets a model and element under the mouse cursor
*/
getMouseElement(event: any): {
model: BaseModel;
model: BaseModel<BaseModelListener>;
element: Element;
};
render(): React.DOMElement<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;

88
docs/Events.md Normal file
View File

@@ -0,0 +1,88 @@
# Events
Each model (DiagramModel, NodeModel etc..) are all built ontop of an event system. You can listen for most of these events by registering
an event on the model itself.
## All models
All models will fire these events:
#### lockChanged?(entity: BaseEntity,locked: boolean)
Fires when the lock state of the entity changes. If an element is locked, it cannot be moved or deletes.
## All Base models excluding DiagramModel
#### selectionChanged?(item: BaseModel, isSelected:boolean)
When the _selected_ property of a model changes
#### entityRemoved?(item:any)
When the entity is going to be deleted. The DiagramModel listenes for this event to when to remove the model from itself.
## DiagramModel
#### nodesUpdated(node: any, isCreated:boolean)
When nodes are added or removed
#### linksUpdated(link: any, isCreated:boolean)
when links are added or removed
#### controlsUpdated() [DEPRECIATED]
_depreciated, use offsetUpdated and zoomUpdated instead_
#### offsetUpdated(model: DiagramModel,offsetX: number, offsetY: number)
to know when the canvas was translated in any direction
#### zoomUpdated(model: DiagramModel,zoom: number)
to know when the zoom level of the canvas was updated
## DiagramEngine
The diagram engine
#### nodeFactoriesUpdated
When node factories have been added or removed from the engine
#### linkFactoriesUpdated
When link factories have been added or removed from the engine
## LinkModel
#### sourcePortChanged?(item:LinkModel,target: null|PortModel)
#### targetPortChanged?(item:LinkModel,target: null|PortModel)
# Example of usage
```javascript
let model = new SRD.DiagramModel();
let node1 = new SRD.DefaultNodeModel("default","rgb(0,192,255)");
node1.addListener({
entityRemoved: (node) => {
console.log('Removed', node.id)
},
selectionChanged: (node, isSelected) => {
console.log(isSelected?'Selected':'Unselected', node)
}
});
model.addListener({
linksUpdated:(entity, isAdded) => {
console.log(isAdded?'added':'removed', entity)
},
nodesUpdated: (entity, isAdded) => {
console.log(isAdded?'added':'removed', entity)
}
});
```

View File

@@ -1,20 +1,21 @@
import {Toolkit} from "./Toolkit";
import {AbstractInstanceFactory} from "./AbstractInstanceFactory";
/**
* @author Dylan Vorster
*/
export class BaseListener{
lockChanged?(entity: BaseEntity<BaseListener>,locked: boolean): void;
}
export class BaseEntity<T extends BaseListener>{
public listeners:{[s: string]: T};
public id: string;
public locked: boolean;
constructor(){
this.listeners = {};
this.id = Toolkit.UID();
this.locked = false;
}
getID(){
@@ -54,4 +55,17 @@ export class BaseEntity<T extends BaseListener>{
this.listeners[uid] = listener;
return uid;
}
public isLocked(): boolean{
return this.locked;
}
public setLocked(locked: boolean = true){
this.locked = locked;
this.itterateListeners((listener) => {
if (listener.lockChanged){
listener.lockChanged(this, locked);
}
});
}
}

View File

@@ -1,17 +1,17 @@
import {Toolkit} from "./Toolkit";
import {BaseEntity, BaseListener} from "./BaseEntity";
import * as _ from "lodash";
export interface BaseModelListener extends BaseListener{
selectionChanged?(item:any, isSelected:boolean);
entityRemoved?(item:any);
selectionChanged?(item: BaseModel<BaseModelListener>, isSelected:boolean): void;
entityRemoved?(item:any): void;
}
/**
* @author Dylan Vorster
*/
export class BaseModel extends BaseEntity<BaseModelListener>{
export class BaseModel<T extends BaseModelListener> extends BaseEntity<BaseModelListener>{
selected: boolean;
@@ -40,7 +40,7 @@ export class BaseModel extends BaseEntity<BaseModelListener>{
return this.selected;
}
public setSelected(selected: boolean){
public setSelected(selected: boolean = true){
this.selected = selected;
this.itterateListeners((listener) => {
if(listener.selectionChanged){
@@ -58,7 +58,7 @@ export class BaseModel extends BaseEntity<BaseModelListener>{
}
}
export class PointModel extends BaseModel{
export class PointModel extends BaseModel<BaseModelListener>{
x:number;
y:number;
@@ -111,7 +111,14 @@ export class PointModel extends BaseModel{
}
}
export class LinkModel extends BaseModel{
export interface LinkModelListener extends BaseModelListener{
sourcePortChanged?(item:LinkModel,target: null|PortModel): void;
targetPortChanged?(item:LinkModel,target: null|PortModel): void;
}
export class LinkModel extends BaseModel<LinkModelListener>{
linkType: string;
sourcePort: PortModel|null;
@@ -194,6 +201,9 @@ export class LinkModel extends BaseModel{
setSourcePort(port: PortModel){
port.addLink(this);
this.sourcePort = port;
this.itterateListeners((listener: LinkModelListener) => {
listener.sourcePortChanged && listener.sourcePortChanged(this, port);
});
}
getSourcePort(): PortModel{
@@ -207,6 +217,9 @@ export class LinkModel extends BaseModel{
setTargetPort(port: PortModel){
port.addLink(this);
this.targetPort = port;
this.itterateListeners((listener: LinkModelListener) => {
listener.targetPortChanged && listener.targetPortChanged(this, port);
});
}
getPoints(): PointModel[]{
@@ -230,7 +243,7 @@ export class LinkModel extends BaseModel{
}
}
export class PortModel extends BaseModel{
export class PortModel extends BaseModel<BaseModelListener>{
name: string;
parentNode: NodeModel;
links: {[id: string]: LinkModel};
@@ -282,7 +295,7 @@ export class PortModel extends BaseModel{
}
}
export class NodeModel extends BaseModel{
export class NodeModel extends BaseModel<BaseModelListener>{
nodeType: string;
x: number;

View File

@@ -1,5 +1,5 @@
import {NodeWidgetFactory, LinkWidgetFactory} from "./WidgetFactories";
import {LinkModel, NodeModel, BaseModel, PortModel, PointModel} from "./Common";
import {LinkModel, NodeModel, BaseModel,BaseModelListener, PortModel, PointModel} from "./Common";
import {BaseEntity, BaseListener} from "./BaseEntity";
import {DiagramModel} from "./DiagramModel";
import {AbstractInstanceFactory} from "./AbstractInstanceFactory";
@@ -41,7 +41,7 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener>{
this.paintableWidgets = null;
}
enableRepaintEntities(entities: BaseModel[]){
enableRepaintEntities(entities: BaseModel<BaseModelListener>[]){
this.paintableWidgets = {};
entities.forEach((entity) => {
@@ -62,7 +62,28 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener>{
});
}
canEntityRepaint(baseModel: BaseModel){
/**
* Checks to see if a model is locked by running through
* its parents to see if they are locked first
*/
isModelLocked(model: BaseEntity<BaseListener>){
//always check the diagram model
if (this.diagramModel.isLocked()){
return true;
}
//a point is locked, if its model is locked
if (model instanceof PointModel){
if (model.getLink().isLocked()){
return true;
}
}
return model.isLocked();
}
canEntityRepaint(baseModel: BaseModel<BaseModelListener>){
//no rules applied, allow repaint
if(this.paintableWidgets === null){
return true;

View File

@@ -1,4 +1,4 @@
import {LinkModel, NodeModel, BaseModel, PortModel} from "./Common";
import {LinkModel, NodeModel, BaseModel,BaseModelListener, PortModel} from "./Common";
import {BaseListener, BaseEntity} from "./BaseEntity";
import * as _ from "lodash";
import {DiagramEngine} from "./DiagramEngine";
@@ -8,11 +8,18 @@ import {DiagramEngine} from "./DiagramEngine";
*/
export interface DiagramListener extends BaseListener{
nodesUpdated(node: any, isCreated:boolean): any;
nodesUpdated(node: any, isCreated:boolean): void;
linksUpdated(link: any, isCreated:boolean): any;
linksUpdated(link: any, isCreated:boolean): void;
controlsUpdated(): any;
/**
* @deprecated
*/
controlsUpdated(): void;
offsetUpdated(model: DiagramModel,offsetX: number, offsetY: number): void;
zoomUpdated(model: DiagramModel,zoom: number): void;
}
/**
*
@@ -93,7 +100,7 @@ export class DiagramModel extends BaseEntity<DiagramListener>{
});
}
clearSelection(ignore: BaseModel|null = null){
clearSelection(ignore: BaseModel<BaseModelListener>|null = null){
_.forEach(this.getSelectedItems(),(element) => {
if (ignore && ignore.getID() === element.getID()){
return;
@@ -102,7 +109,7 @@ export class DiagramModel extends BaseEntity<DiagramListener>{
});
}
getSelectedItems(): BaseModel[]{
getSelectedItems(): BaseModel<BaseModelListener>[]{
var items = [];
//find all nodes
@@ -128,6 +135,9 @@ export class DiagramModel extends BaseEntity<DiagramListener>{
this.itterateListeners((listener) => {
if(listener.controlsUpdated) listener.controlsUpdated();
});
this.itterateListeners((listener) => {
listener.zoomUpdated && listener.zoomUpdated(this,this.zoom);
});
}
setOffset(offsetX: number, offsetY: number){
@@ -136,6 +146,9 @@ export class DiagramModel extends BaseEntity<DiagramListener>{
this.itterateListeners((listener) => {
if(listener.controlsUpdated) listener.controlsUpdated();
});
this.itterateListeners((listener) => {
listener.offsetUpdated && listener.offsetUpdated(this,this.offsetX, this.offsetY)
});
}
setOffsetX(offsetX: number){
@@ -143,12 +156,18 @@ export class DiagramModel extends BaseEntity<DiagramListener>{
this.itterateListeners((listener) => {
if(listener.controlsUpdated) listener.controlsUpdated();
});
this.itterateListeners((listener) => {
listener.offsetUpdated && listener.offsetUpdated(this,this.offsetX, this.offsetY)
});
}
setOffsetY(offsetY: number){
this.offsetX = offsetY;
this.itterateListeners((listener) => {
if(listener.controlsUpdated) listener.controlsUpdated();
});
this.itterateListeners((listener) => {
listener.offsetUpdated && listener.offsetUpdated(this,this.offsetX, this.offsetY)
});
}
getOffsetY(){

View File

@@ -55,11 +55,9 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
opacity: 0,
onMouseLeave:() => {
this.setState({selected: false});
// this.props.link.setSelected(false);
},
onMouseEnter:() => {
this.setState({selected: true});
// this.props.link.setSelected(true);
},
})
);
@@ -122,7 +120,7 @@ export class DefaultLinkWidget extends React.Component<DefaultLinkProps, Default
paths.push(this.generateLink({
id: 0,
onMouseDown: (event) =>{
if (!event.shiftKey){
if (!event.shiftKey && !this.props.diagramEngine.isModelLocked(this.props.link)){
var point = new PointModel(this.props.link,this.props.diagramEngine.getRelativeMousePoint(event));
point.setSelected(true);
this.forceUpdate();

View File

@@ -2,12 +2,12 @@ import * as React from "react";
import {DiagramEngine} from "../DiagramEngine";
import {DiagramModel} from "../DiagramModel";
import * as _ from "lodash";
import {PointModel, NodeModel, BaseModel, LinkModel,PortModel} from "../Common";
import {PointModel, NodeModel, BaseModel, BaseModelListener, LinkModel,PortModel} from "../Common";
import {LinkLayerWidget} from "./LinkLayerWidget";
import {NodeLayerWidget} from "./NodeLayerWidget";
interface SelectionModel{
model: BaseModel;
model: BaseModel<BaseModelListener>;
initialX: number;
initialY: number;
}
@@ -63,7 +63,14 @@ class MoveItemsAction extends BaseAction{
super(mouseX, mouseY);
this.moved = false;
diagramEngine.enableRepaintEntities(diagramEngine.getDiagramModel().getSelectedItems());
this.selectionModels = diagramEngine.getDiagramModel().getSelectedItems().map((item: PointModel | NodeModel) => {
var selectedItems = diagramEngine.getDiagramModel().getSelectedItems();
//dont allow items which are locked to move
selectedItems = selectedItems.filter((item) => {
return !diagramEngine.isModelLocked(item);
})
this.selectionModels = selectedItems.map((item: PointModel | NodeModel) => {
return {
model: item,
initialX: item.x,
@@ -75,7 +82,9 @@ class MoveItemsAction extends BaseAction{
export interface DiagramProps {
diagramEngine:DiagramEngine;
onLinkStateChanged?: any;
allowLooseLinks?: boolean;
allowCanvasTranslation?: boolean;
allowCanvasZoom?: boolean;
}
export interface DiagramState {
@@ -88,6 +97,13 @@ export interface DiagramState {
* @author Dylan Vorster
*/
export class DiagramWidget extends React.Component<DiagramProps, DiagramState> {
public static defaultProps: DiagramProps = {
diagramEngine:null,
allowLooseLinks: true,
allowCanvasTranslations: true,
allowCanvasZoom: true
};
constructor(props: DiagramProps) {
super(props);
@@ -133,7 +149,11 @@ export class DiagramWidget extends React.Component<DiagramProps, DiagramState> {
//delete all selected
if(event.keyCode === 46 || event.keyCode === 8){
_.forEach(this.props.diagramEngine.getDiagramModel().getSelectedItems(),(element) => {
element.remove();
//only delete items which are not locked
if (!this.props.diagramEngine.isModelLocked(element)){
element.remove();
}
});
this.forceUpdate();
}
@@ -145,7 +165,7 @@ export class DiagramWidget extends React.Component<DiagramProps, DiagramState> {
/**
* Gets a model and element under the mouse cursor
*/
getMouseElement(event): {model: BaseModel, element: Element}{
getMouseElement(event): {model: BaseModel<BaseModelListener>, element: Element}{
var target = event.target as Element;
var diagramModel = this.props.diagramEngine.diagramModel;
@@ -199,11 +219,13 @@ export class DiagramWidget extends React.Component<DiagramProps, DiagramState> {
ref:'canvas',
className:'storm-diagrams-canvas',
onWheel: (event) => {
event.preventDefault();
event.stopPropagation();
diagramModel.setZoomLevel(diagramModel.getZoomLevel()+(event.deltaY/60));
diagramEngine.enableRepaintEntities([]);
this.forceUpdate();
if (this.props.allowCanvasZoom){
event.preventDefault();
event.stopPropagation();
diagramModel.setZoomLevel(diagramModel.getZoomLevel()+(event.deltaY/60));
diagramEngine.enableRepaintEntities([]);
this.forceUpdate();
}
},
onMouseMove: (event) => {
@@ -252,18 +274,21 @@ export class DiagramWidget extends React.Component<DiagramProps, DiagramState> {
//translate the actual canvas
else if (this.state.action instanceof MoveCanvasAction){
diagramModel.setOffset(
this.state.action.initialOffsetX + ((event.pageX - this.state.action.mouseX) / (diagramModel.getZoomLevel()/100)),
this.state.action.initialOffsetY+((event.pageY-this.state.action.mouseY)/(diagramModel.getZoomLevel()/100))
);
this.forceUpdate();
if (this.props.allowCanvasTranslation){
diagramModel.setOffset(
this.state.action.initialOffsetX + ((event.pageX - this.state.action.mouseX) / (diagramModel.getZoomLevel()/100)),
this.state.action.initialOffsetY+((event.pageY-this.state.action.mouseY)/(diagramModel.getZoomLevel()/100))
);
this.forceUpdate();
}
}
},
onMouseDown: (event) =>{
diagramEngine.clearRepaintEntities();
var model = this.getMouseElement(event);
//its the canvas
//the canvas was selected
if(model === null){
//is it a multiple selection
if (event.shiftKey){
@@ -320,7 +345,23 @@ export class DiagramWidget extends React.Component<DiagramProps, DiagramState> {
//are we going to connect a link to something?
if (this.state.action instanceof MoveItemsAction){
var element = this.getMouseElement(event);
if(element){
var linkConnected = false;
_.forEach(this.state.action.selectionModels,(model) => {
//only care about points connecting to things
if (!(model.model instanceof PointModel)){
return;
}
if (element.model instanceof PortModel){
linkConnected = true;
let link = model.model.getLink();
link.setTargetPort(element.model);
}
});
//do we want to allow loose links on the diagram model or not
if (!linkConnected && !this.props.allowLooseLinks){
_.forEach(this.state.action.selectionModels,(model) => {
//only care about points connecting to things
@@ -328,27 +369,11 @@ export class DiagramWidget extends React.Component<DiagramProps, DiagramState> {
return;
}
if (element.model instanceof PortModel){
let link = model.model.getLink();
link.setTargetPort(element.model);
if(this.props.onLinkStateChanged && typeof this.props.onLinkStateChanged === 'function'){
this.props.onLinkStateChanged(link, true);
}
var link = model.model.getLink();
if(link.isLastPoint(model.model)){
link.remove();
}
});
} else {
console.log('unwired');
// it does not work :(
// _.forEach(this.state.action.selectionModels,(model) => {
// //only care about points connecting to things
// if (!(model.model instanceof PointModel)){
// return;
// }
// let link = model.model.getLink();
// if (this.props.onLinkStateChanged && typeof this.props.onLinkStateChanged === 'function') {
// this.props.onLinkStateChanged(link, false);
// }
// })
}
}

View File

@@ -57,6 +57,7 @@ module.exports = [
'demo1/bundle.js': './demos/demo1/index.ts',
'demo2/bundle.js': './demos/demo2/index.ts',
'demo3/bundle.js': './demos/demo3/index.ts',
'demo4/bundle.js': './demos/demo4/index.ts',
},
output: {
filename: '[name]',