oh boy what have I done :O

This commit is contained in:
Dylan Vorster
2017-11-23 23:43:03 +02:00
parent f7aa626783
commit 23b5689ef4
25 changed files with 6455 additions and 6421 deletions

View File

@ -1,12 +1,24 @@
import { Toolkit } from "./Toolkit";
/**
* @author Dylan Vorster
*/
export class BaseListener {
lockChanged?(entity: BaseEntity<BaseListener>, locked: boolean): void;
export interface BaseEvent<T extends BaseEntity = any> {
entity: BaseEntity<BaseListener>;
stopPropagation: () => any;
firing: boolean;
id: string;
}
export class BaseEntity<T extends BaseListener> {
export interface BaseListener<T extends BaseEntity = any> {
lockChanged?(event: BaseEvent<T> & {locked: boolean} ): void;
}
export class BaseEntity<T extends BaseListener = {}> {
public listeners: { [s: string]: T };
public id: string;
public locked: boolean;
@ -35,9 +47,21 @@ export class BaseEntity<T extends BaseListener> {
};
}
public iterateListeners(cb: (t: T) => any) {
public iterateListeners(cb: (t: T, event: BaseEvent) => any) {
let event: BaseEvent = {
id: Toolkit.UID(),
firing: true,
entity: this,
stopPropagation: () => {
event.firing = false;
}
};
for (var i in this.listeners) {
cb(this.listeners[i]);
// propagation stopped
if(!event.firing){
return;
}
cb(this.listeners[i], event);
}
}
@ -61,9 +85,9 @@ export class BaseEntity<T extends BaseListener> {
public setLocked(locked: boolean = true) {
this.locked = locked;
this.iterateListeners(listener => {
this.iterateListeners((listener, event) => {
if (listener.lockChanged) {
listener.lockChanged(this, locked);
listener.lockChanged({...event, locked: locked});
}
});
}

View File

@ -1,7 +1,8 @@
import { DiagramModel } from "./DiagramModel";
import { DiagramModel } from "./models/DiagramModel";
import { DiagramEngine } from "./DiagramEngine";
import { NodeModel, PointModel } from "./Common";
import { SelectionModel } from "./widgets/DiagramWidget";
import {PointModel} from "./models/PointModel";
import {NodeModel} from "./models/NodeModel";
export class BaseAction {
mouseX: number;

View File

@ -1,441 +0,0 @@
import { BaseEntity, BaseListener } from "./BaseEntity";
import * as _ from "lodash";
import { port } from "_debugger";
export interface BaseModelListener extends BaseListener {
selectionChanged?(item: BaseModel<BaseModelListener>, isSelected: boolean): void;
entityRemoved?(item: any): void;
}
/**
* @author Dylan Vorster
*/
export class BaseModel<T extends BaseModelListener> extends BaseEntity<BaseModelListener> {
selected: boolean;
constructor(id?: string) {
super(id);
this.selected = false;
}
getSelectedEntities(): BaseModel<T>[] {
if (this.isSelected()) {
return [this];
}
return [];
}
deSerialize(ob) {
super.deSerialize(ob);
this.selected = ob.selected;
}
serialize() {
return _.merge(super.serialize(), {
_class: this.constructor.name,
selected: this.selected
});
}
public getID(): string {
return this.id;
}
public isSelected(): boolean {
return this.selected;
}
public setSelected(selected: boolean = true) {
this.selected = selected;
this.iterateListeners(listener => {
if (listener.selectionChanged) {
listener.selectionChanged(this, selected);
}
});
}
remove() {
this.iterateListeners(listener => {
if (listener.entityRemoved) {
listener.entityRemoved(this);
}
});
}
}
export class PointModel extends BaseModel<BaseModelListener> {
x: number;
y: number;
link: LinkModel;
constructor(link: LinkModel, points: { x: number; y: number }) {
super();
this.x = points.x;
this.y = points.y;
this.link = link;
}
getSelectedEntities() {
if (super.isSelected() && !this.isConnectedToPort()) {
return [this];
}
return [];
}
isConnectedToPort(): boolean {
return this.link.getPortForPoint(this) !== null;
}
deSerialize(ob) {
super.deSerialize(ob);
this.x = ob.x;
this.y = ob.y;
}
serialize() {
return _.merge(super.serialize(), {
x: this.x,
y: this.y
});
}
remove() {
//clear references
if (this.link) {
this.link.removePoint(this);
}
super.remove();
}
updateLocation(points: { x: number; y: number }) {
this.x = points.x;
this.y = points.y;
}
getX(): number {
return this.x;
}
getY(): number {
return this.y;
}
getLink(): LinkModel {
return this.link;
}
}
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;
targetPort: PortModel | null;
points: PointModel[];
extras: {};
constructor() {
super();
this.linkType = "default";
this.points = [new PointModel(this, { x: 0, y: 0 }), new PointModel(this, { x: 0, y: 0 })];
this.extras = {};
this.sourcePort = null;
this.targetPort = null;
}
deSerialize(ob) {
super.deSerialize(ob);
this.linkType = ob.type;
this.extras = ob.extras;
this.points = _.map(ob.points, (point: { x; y }) => {
var p = new PointModel(this, { x: point.x, y: point.y });
p.deSerialize(point);
return p;
});
}
serialize() {
return _.merge(super.serialize(), {
type: this.linkType,
source: this.sourcePort ? this.sourcePort.getParent().id : null,
sourcePort: this.sourcePort ? this.sourcePort.id : null,
target: this.targetPort ? this.targetPort.getParent().id : null,
targetPort: this.targetPort ? this.targetPort.id : null,
points: _.map(this.points, point => {
return point.serialize();
}),
extras: this.extras
});
}
remove() {
if (this.sourcePort) {
this.sourcePort.removeLink(this);
}
if (this.targetPort) {
this.targetPort.removeLink(this);
}
super.remove();
}
isLastPoint(point: PointModel) {
var index = this.getPointIndex(point);
return index === this.points.length - 1;
}
getPointIndex(point: PointModel) {
return this.points.indexOf(point);
}
getPointModel(id: string): PointModel | null {
for (var i = 0; i < this.points.length; i++) {
if (this.points[i].id === id) {
return this.points[i];
}
}
return null;
}
getPortForPoint(point: PointModel): PortModel {
if (this.sourcePort !== null && this.getFirstPoint().getID() === point.getID()) {
return this.sourcePort;
}
if (this.targetPort !== null && this.getLastPoint().getID() === point.getID()) {
return this.targetPort;
}
return null;
}
getPointForPort(port: PortModel): PointModel {
if (this.sourcePort !== null && this.sourcePort.getID() === port.getID()) {
return this.getFirstPoint();
}
if (this.targetPort !== null && this.targetPort.getID() === port.getID()) {
return this.getLastPoint();
}
return null;
}
getFirstPoint(): PointModel {
return this.points[0];
}
getLastPoint(): PointModel {
return this.points[this.points.length - 1];
}
setSourcePort(port: PortModel) {
port.addLink(this);
this.sourcePort = port;
this.iterateListeners((listener: LinkModelListener) => {
listener.sourcePortChanged && listener.sourcePortChanged(this, port);
});
}
getSourcePort(): PortModel {
return this.sourcePort;
}
getTargetPort(): PortModel {
return this.targetPort;
}
setTargetPort(port: PortModel) {
port.addLink(this);
this.targetPort = port;
this.iterateListeners((listener: LinkModelListener) => {
listener.targetPortChanged && listener.targetPortChanged(this, port);
});
}
getPoints(): PointModel[] {
return this.points;
}
setPoints(points: PointModel[]) {
this.points = points;
}
removePoint(pointModel: PointModel) {
this.points.splice(this.getPointIndex(pointModel), 1);
}
addPoint(pointModel: PointModel, index = 1) {
this.points.splice(index, 0, pointModel);
}
getType(): string {
return this.linkType;
}
}
export class PortModel extends BaseModel<BaseModelListener> {
name: string;
parentNode: NodeModel;
links: { [id: string]: LinkModel };
deSerialize(ob) {
super.deSerialize(ob);
this.name = ob.name;
}
serialize() {
return _.merge(super.serialize(), {
name: this.name,
parentNode: this.parentNode.id,
links: _.map(this.links, link => {
return link.id;
})
});
}
constructor(name: string, id?: string) {
super(id);
this.name = name;
this.links = {};
this.parentNode = null;
}
getName(): string {
return this.name;
}
getParent(): NodeModel {
return this.parentNode;
}
setParentNode(node: NodeModel) {
this.parentNode = node;
}
removeLink(link: LinkModel) {
delete this.links[link.getID()];
}
addLink(link: LinkModel) {
this.links[link.getID()] = link;
}
getLinks(): { [id: string]: LinkModel } {
return this.links;
}
}
export class NodeModel extends BaseModel<BaseModelListener> {
nodeType: string;
x: number;
y: number;
extras: {};
ports: { [s: string]: PortModel };
constructor(nodeType: string = "default", id?: string) {
super(id);
this.nodeType = nodeType;
this.x = 0;
this.y = 0;
this.extras = {};
this.ports = {};
}
setPosition(x, y){
//store position
let oldX = this.x;
let oldY = this.y;
for(let port in this.ports){
_.forEach(this.ports[port].getLinks(), (link) => {
let point = link.getPointForPort(this.ports[port]);
point.x = point.x + x - oldX;
point.y = point.y + y - oldY;
})
}
this.x = x;
this.y = y;
}
getSelectedEntities() {
let entities = super.getSelectedEntities();
// add the points of each link that are selected here
if (this.isSelected()) {
for (let portName in this.ports) {
entities = entities.concat(
_.map(this.ports[portName].getLinks(), link => {
return link.getPointForPort(this.ports[portName]);
})
);
}
}
return entities;
}
deSerialize(ob) {
super.deSerialize(ob);
this.nodeType = ob.type;
this.x = ob.x;
this.y = ob.y;
this.extras = ob.extras;
}
serialize() {
return _.merge(super.serialize(), {
type: this.nodeType,
x: this.x,
y: this.y,
extras: this.extras,
ports: _.map(this.ports, port => {
return port.serialize();
})
});
}
remove() {
super.remove();
for (var i in this.ports) {
_.forEach(this.ports[i].getLinks(), link => {
link.remove();
});
}
}
getPortFromID(id): PortModel | null {
for (var i in this.ports) {
if (this.ports[i].id === id) {
return this.ports[i];
}
}
return null;
}
getPort(name: string): PortModel | null {
return this.ports[name];
}
getPorts(): { [s: string]: PortModel } {
return this.ports;
}
removePort(port: PortModel) {
//clear the parent node reference
if (this.ports[port.name]) {
this.ports[port.name].setParentNode(null);
delete this.ports[port.name];
}
}
addPort(port: PortModel): PortModel {
port.setParentNode(this);
this.ports[port.name] = port;
return port;
}
getType(): string {
return this.nodeType;
}
}

View File

@ -1,9 +1,13 @@
import { NodeWidgetFactory, LinkWidgetFactory } from "./WidgetFactories";
import { LinkModel, NodeModel, BaseModel, BaseModelListener, PortModel, PointModel } from "./Common";
import { BaseEntity, BaseListener } from "./BaseEntity";
import { DiagramModel } from "./DiagramModel";
import { DiagramModel } from "./models/DiagramModel";
import { AbstractInstanceFactory } from "./AbstractInstanceFactory";
import * as _ from "lodash";
import {BaseModel, BaseModelListener} from "./models/BaseModel";
import {NodeModel} from "./models/NodeModel";
import {PointModel} from "./models/PointModel";
import {PortModel} from "./models/PortModel";
import {LinkModel} from "./models/LinkModel";
/**
* @author Dylan Vorster
*/

3
src/Function.d.ts vendored
View File

@ -1,3 +0,0 @@
interface Function {
name: string;
}

View File

@ -1,6 +1,5 @@
import { LinkModel } from "./Common";
import * as _ from "lodash";
import { AbstractInstanceFactory } from "./AbstractInstanceFactory";
import {LinkModel} from "./models/LinkModel";
/**
* @author Dylan Vorster
*/

View File

@ -1,5 +1,6 @@
import { NodeModel, LinkModel } from "./Common";
import { DiagramEngine } from "./DiagramEngine";
import {NodeModel} from "./models/NodeModel";
import {LinkModel} from "./models/LinkModel";
/**
* @author Dylan Vorster
*/

View File

@ -1,8 +1,8 @@
import { LinkWidgetFactory } from "../WidgetFactories";
import { LinkModel } from "../Common";
import * as React from "react";
import { DefaultLinkWidget } from "./DefaultLinkWidget";
import { DiagramEngine } from "../DiagramEngine";
import {LinkModel} from "../models/LinkModel";
/**
* @author Dylan Vorster
*/

View File

@ -1,7 +1,7 @@
import * as React from "react";
import { LinkModel, PointModel } from "../Common";
import * as _ from "lodash";
import { DiagramEngine } from "../DiagramEngine";
import {LinkModel} from "../models/LinkModel";
import {PointModel} from "../models/PointModel";
export interface DefaultLinkProps {
color?: string;

View File

@ -1,8 +1,8 @@
import { NodeModel } from "../Common";
import { DefaultPortModel } from "./DefaultPortModel";
import * as _ from "lodash";
import { AbstractInstanceFactory } from "../AbstractInstanceFactory";
import {NodeModel} from "../models/NodeModel";
export class DefaultNodeInstanceFactory extends AbstractInstanceFactory<DefaultNodeModel> {
constructor() {

View File

@ -1,6 +1,6 @@
import { PortModel } from "../Common";
import * as _ from "lodash";
import { AbstractInstanceFactory } from "../AbstractInstanceFactory";
import {PortModel} from "../models/PortModel";
export class DefaultPortInstanceFactory extends AbstractInstanceFactory<DefaultPortModel> {
constructor() {

View File

@ -15,13 +15,19 @@ export * from "./WidgetFactories";
export * from "./Toolkit";
export * from "./DiagramEngine";
export * from "./DiagramModel";
export * from "./models/DiagramModel";
export * from "./BaseEntity";
export * from "./CanvasActions";
export * from "./Common";
export * from "./AbstractInstanceFactory";
export * from "./LinkInstanceFactory";
export * from "./models/BaseModel";
export * from "./models/DiagramModel";
export * from "./models/LinkModel";
export * from "./models/NodeModel";
export * from "./models/PointModel";
export * from "./models/PortModel";
export * from "./widgets/DiagramWidget";
export * from "./widgets/LinkLayerWidget";
export * from "./widgets/LinkWidget";

69
src/models/BaseModel.ts Normal file
View File

@ -0,0 +1,69 @@
import { BaseEntity, BaseListener } from "../BaseEntity";
import * as _ from "lodash";
import {BaseEvent} from "../BaseEntity";
export interface BaseModelListener extends BaseListener {
selectionChanged?(event: BaseEvent<BaseModel> & {isSelected: boolean}): void;
entityRemoved?(event: BaseEvent<BaseModel>): void;
}
/**
* @author Dylan Vorster
*/
export class BaseModel<T extends BaseModelListener = BaseModelListener> extends BaseEntity<BaseModelListener> {
selected: boolean;
class: string;
constructor(id?: string) {
super(id);
this.selected = false;
this.class = this.constructor.name;
}
public getSelectedEntities(): BaseModel<T>[] {
if (this.isSelected()) {
return [this];
}
return [];
}
public deSerialize(ob) {
super.deSerialize(ob);
this.selected = ob.selected;
}
public serialize() {
return _.merge(super.serialize(), {
_class: this.class,
selected: this.selected
});
}
public getID(): string {
return this.id;
}
public isSelected(): boolean {
return this.selected;
}
public setSelected(selected: boolean = true) {
this.selected = selected;
this.iterateListeners((listener, event) => {
if (listener.selectionChanged) {
listener.selectionChanged({...event, isSelected: selected});
}
});
}
public remove() {
this.iterateListeners((listener, event) => {
if (listener.entityRemoved) {
listener.entityRemoved(event);
}
});
}
}

View File

@ -1,26 +1,27 @@
import { LinkModel, NodeModel, BaseModel, BaseModelListener, PortModel } from "./Common";
import { BaseListener, BaseEntity } from "./BaseEntity";
import {BaseListener, BaseEntity, BaseEvent} from "../BaseEntity";
import * as _ from "lodash";
import { DiagramEngine } from "./DiagramEngine";
import { DiagramEngine } from "../DiagramEngine";
import {LinkModel} from "./LinkModel";
import {NodeModel} from "./NodeModel";
import {PortModel} from "./PortModel";
import {BaseModel, BaseModelListener} from "./BaseModel";
/**
* @author Dylan Vorster
*
*/
export interface DiagramListener extends BaseListener {
nodesUpdated?(node: any, isCreated: boolean): void;
linksUpdated?(link: any, isCreated: boolean): void;
nodesUpdated?(event: BaseEvent & { node: NodeModel, isCreated: boolean }): void;
/**
* @deprecated
*/
controlsUpdated?(): void;
linksUpdated?(event: BaseEvent & { link: LinkModel, isCreated: boolean }): void;
offsetUpdated?(model: DiagramModel, offsetX: number, offsetY: number): void;
offsetUpdated?(event: BaseEvent<DiagramModel> & { offsetX: number, offsetY: number}): void;
zoomUpdated?(event: BaseEvent<DiagramModel> & { zoom: number }): void;
gridUpdated?(event: BaseEvent<DiagramModel> & { size: number }): void;
zoomUpdated?(model: DiagramModel, zoom: number): void;
gridUpdated?(model: DiagramModel, size: number): void;
}
/**
*
@ -52,8 +53,8 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
setGridSize(size: number = 0) {
this.gridSize = size;
this.iterateListeners(listener => {
listener.gridUpdated && listener.gridUpdated(this, size);
this.iterateListeners((listener, event) => {
listener.gridUpdated && listener.gridUpdated({...event, size: size});
});
}
@ -157,41 +158,31 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
setZoomLevel(zoom: number) {
this.zoom = zoom;
this.iterateListeners(listener => {
if (listener.controlsUpdated) listener.controlsUpdated();
});
this.iterateListeners(listener => {
listener.zoomUpdated && listener.zoomUpdated(this, this.zoom);
this.iterateListeners((listener, event) => {
listener.zoomUpdated && listener.zoomUpdated({...event, zoom: zoom});
});
}
setOffset(offsetX: number, offsetY: number) {
this.offsetX = offsetX;
this.offsetY = offsetY;
this.iterateListeners(listener => {
if (listener.controlsUpdated) listener.controlsUpdated();
});
this.iterateListeners(listener => {
listener.offsetUpdated && listener.offsetUpdated(this, this.offsetX, this.offsetY);
this.iterateListeners((listener, event) => {
listener.offsetUpdated && listener.offsetUpdated({...event, offsetX: offsetX, offsetY: offsetY});
});
}
setOffsetX(offsetX: number) {
this.offsetX = offsetX;
this.iterateListeners(listener => {
if (listener.controlsUpdated) listener.controlsUpdated();
});
this.iterateListeners(listener => {
listener.offsetUpdated && listener.offsetUpdated(this, this.offsetX, this.offsetY);
this.iterateListeners((listener, event) => {
listener.offsetUpdated && listener.offsetUpdated({...event, offsetX: offsetX, offsetY: this.offsetY});
});
}
setOffsetY(offsetY: number) {
this.offsetY = offsetY;
this.iterateListeners(listener => {
if (listener.controlsUpdated) listener.controlsUpdated();
});
this.iterateListeners(listener => {
listener.offsetUpdated && listener.offsetUpdated(this, this.offsetX, this.offsetY);
this.iterateListeners((listener, event) => {
listener.offsetUpdated && listener.offsetUpdated({...event, offsetX: this.offsetX, offsetY: this.offsetY});
});
}
@ -234,8 +225,8 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
}
});
this.links[link.getID()] = link;
this.iterateListeners(listener => {
if (listener.linksUpdated) listener.linksUpdated(link, true);
this.iterateListeners((listener, event) => {
listener.linksUpdated && listener.linksUpdated({...event,link: link, isCreated: true});
});
return link;
}
@ -247,37 +238,25 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
}
});
this.nodes[node.getID()] = node;
this.iterateListeners(listener => {
if (listener.nodesUpdated) listener.nodesUpdated(node, true);
this.iterateListeners((listener, event) => {
listener.nodesUpdated && listener.nodesUpdated({...event,node: node, isCreated: true});
});
return node;
}
removeLink(link: LinkModel | string) {
if (link instanceof LinkModel) {
delete this.links[link.getID()];
this.iterateListeners(listener => {
if (listener.linksUpdated) listener.linksUpdated(link, false);
});
return;
}
delete this.links["" + link];
this.iterateListeners(listener => {
if (listener.linksUpdated) listener.linksUpdated(link, false);
link = this.getLink(link);
delete this.links[link.getID()];
this.iterateListeners((listener, event) => {
listener.linksUpdated && listener.linksUpdated({...event, link: link as LinkModel, isCreated: false});
});
}
removeNode(node: NodeModel | string) {
if (node instanceof NodeModel) {
delete this.nodes[node.getID()];
this.iterateListeners(listener => {
if (listener.nodesUpdated) listener.nodesUpdated(node, false);
});
return;
}
delete this.nodes["" + node];
this.iterateListeners(listener => {
if (listener.nodesUpdated) listener.nodesUpdated(node, false);
removeNode(node: NodeModel | string) {
node = this.getNode(node);
delete this.nodes[node.getID()];
this.iterateListeners((listener, event) => {
listener.nodesUpdated && listener.nodesUpdated({...event, node: node as NodeModel, isCreated: false});
});
}

154
src/models/LinkModel.ts Normal file
View File

@ -0,0 +1,154 @@
import {BaseModel, BaseModelListener} from "./BaseModel";
import {PortModel} from "./PortModel";
import {PointModel} from "./PointModel";
import * as _ from "lodash";
import {BaseEvent} from "../BaseEntity";
export interface LinkModelListener extends BaseModelListener {
sourcePortChanged?(event: BaseEvent<LinkModel> & {port: null | PortModel}): void;
targetPortChanged?(event: BaseEvent<LinkModel> & {port: null | PortModel}): void;
}
export class LinkModel extends BaseModel<LinkModelListener> {
linkType: string;
sourcePort: PortModel | null;
targetPort: PortModel | null;
points: PointModel[];
extras: {};
constructor() {
super();
this.linkType = "default";
this.points = [new PointModel(this, { x: 0, y: 0 }), new PointModel(this, { x: 0, y: 0 })];
this.extras = {};
this.sourcePort = null;
this.targetPort = null;
}
deSerialize(ob) {
super.deSerialize(ob);
this.linkType = ob.type;
this.extras = ob.extras;
this.points = _.map(ob.points, (point: { x; y }) => {
var p = new PointModel(this, { x: point.x, y: point.y });
p.deSerialize(point);
return p;
});
}
serialize() {
return _.merge(super.serialize(), {
type: this.linkType,
source: this.sourcePort ? this.sourcePort.getParent().id : null,
sourcePort: this.sourcePort ? this.sourcePort.id : null,
target: this.targetPort ? this.targetPort.getParent().id : null,
targetPort: this.targetPort ? this.targetPort.id : null,
points: _.map(this.points, point => {
return point.serialize();
}),
extras: this.extras
});
}
remove() {
if (this.sourcePort) {
this.sourcePort.removeLink(this);
}
if (this.targetPort) {
this.targetPort.removeLink(this);
}
super.remove();
}
isLastPoint(point: PointModel) {
var index = this.getPointIndex(point);
return index === this.points.length - 1;
}
getPointIndex(point: PointModel) {
return this.points.indexOf(point);
}
getPointModel(id: string): PointModel | null {
for (var i = 0; i < this.points.length; i++) {
if (this.points[i].id === id) {
return this.points[i];
}
}
return null;
}
getPortForPoint(point: PointModel): PortModel {
if (this.sourcePort !== null && this.getFirstPoint().getID() === point.getID()) {
return this.sourcePort;
}
if (this.targetPort !== null && this.getLastPoint().getID() === point.getID()) {
return this.targetPort;
}
return null;
}
getPointForPort(port: PortModel): PointModel {
if (this.sourcePort !== null && this.sourcePort.getID() === port.getID()) {
return this.getFirstPoint();
}
if (this.targetPort !== null && this.targetPort.getID() === port.getID()) {
return this.getLastPoint();
}
return null;
}
getFirstPoint(): PointModel {
return this.points[0];
}
getLastPoint(): PointModel {
return this.points[this.points.length - 1];
}
setSourcePort(port: PortModel) {
port.addLink(this);
this.sourcePort = port;
this.iterateListeners((listener: LinkModelListener, event) => {
listener.sourcePortChanged && listener.sourcePortChanged({...event, port: port});
});
}
getSourcePort(): PortModel {
return this.sourcePort;
}
getTargetPort(): PortModel {
return this.targetPort;
}
setTargetPort(port: PortModel) {
port.addLink(this);
this.targetPort = port;
this.iterateListeners((listener: LinkModelListener, event) => {
listener.targetPortChanged && listener.targetPortChanged({...event, port: port});
});
}
getPoints(): PointModel[] {
return this.points;
}
setPoints(points: PointModel[]) {
this.points = points;
}
removePoint(pointModel: PointModel) {
this.points.splice(this.getPointIndex(pointModel), 1);
}
addPoint(pointModel: PointModel, index = 1) {
this.points.splice(index, 0, pointModel);
}
getType(): string {
return this.linkType;
}
}

117
src/models/NodeModel.ts Normal file
View File

@ -0,0 +1,117 @@
import {BaseModel, BaseModelListener} from "./BaseModel";
import {PortModel} from "./PortModel";
import * as _ from "lodash";
export class NodeModel extends BaseModel<BaseModelListener> {
nodeType: string;
x: number;
y: number;
extras: {};
ports: { [s: string]: PortModel };
constructor(nodeType: string = "default", id?: string) {
super(id);
this.nodeType = nodeType;
this.x = 0;
this.y = 0;
this.extras = {};
this.ports = {};
}
setPosition(x, y){
//store position
let oldX = this.x;
let oldY = this.y;
for(let port in this.ports){
_.forEach(this.ports[port].getLinks(), (link) => {
let point = link.getPointForPort(this.ports[port]);
point.x = point.x + x - oldX;
point.y = point.y + y - oldY;
})
}
this.x = x;
this.y = y;
}
getSelectedEntities() {
let entities = super.getSelectedEntities();
// add the points of each link that are selected here
if (this.isSelected()) {
for (let portName in this.ports) {
entities = entities.concat(
_.map(this.ports[portName].getLinks(), link => {
return link.getPointForPort(this.ports[portName]);
})
);
}
}
return entities;
}
deSerialize(ob) {
super.deSerialize(ob);
this.nodeType = ob.type;
this.x = ob.x;
this.y = ob.y;
this.extras = ob.extras;
}
serialize() {
return _.merge(super.serialize(), {
type: this.nodeType,
x: this.x,
y: this.y,
extras: this.extras,
ports: _.map(this.ports, port => {
return port.serialize();
})
});
}
remove() {
super.remove();
for (var i in this.ports) {
_.forEach(this.ports[i].getLinks(), link => {
link.remove();
});
}
}
getPortFromID(id): PortModel | null {
for (var i in this.ports) {
if (this.ports[i].id === id) {
return this.ports[i];
}
}
return null;
}
getPort(name: string): PortModel | null {
return this.ports[name];
}
getPorts(): { [s: string]: PortModel } {
return this.ports;
}
removePort(port: PortModel) {
//clear the parent node reference
if (this.ports[port.name]) {
this.ports[port.name].setParentNode(null);
delete this.ports[port.name];
}
}
addPort(port: PortModel): PortModel {
port.setParentNode(this);
this.ports[port.name] = port;
return port;
}
getType(): string {
return this.nodeType;
}
}

65
src/models/PointModel.ts Normal file
View File

@ -0,0 +1,65 @@
import {BaseModel, BaseModelListener} from "./BaseModel";
import {LinkModel} from "./LinkModel";
import * as _ from "lodash";
export class PointModel extends BaseModel<BaseModelListener> {
x: number;
y: number;
link: LinkModel;
constructor(link: LinkModel, points: { x: number; y: number }) {
super();
this.x = points.x;
this.y = points.y;
this.link = link;
}
getSelectedEntities() {
if (super.isSelected() && !this.isConnectedToPort()) {
return [this];
}
return [];
}
isConnectedToPort(): boolean {
return this.link.getPortForPoint(this) !== null;
}
deSerialize(ob) {
super.deSerialize(ob);
this.x = ob.x;
this.y = ob.y;
}
serialize() {
return _.merge(super.serialize(), {
x: this.x,
y: this.y
});
}
remove() {
//clear references
if (this.link) {
this.link.removePoint(this);
}
super.remove();
}
updateLocation(points: { x: number; y: number }) {
this.x = points.x;
this.y = points.y;
}
getX(): number {
return this.x;
}
getY(): number {
return this.y;
}
getLink(): LinkModel {
return this.link;
}
}

56
src/models/PortModel.ts Normal file
View File

@ -0,0 +1,56 @@
import {BaseModel, BaseModelListener} from "./BaseModel";
import {NodeModel} from "./NodeModel";
import {LinkModel} from "./LinkModel";
import * as _ from "lodash";
export class PortModel extends BaseModel<BaseModelListener> {
name: string;
parentNode: NodeModel;
links: { [id: string]: LinkModel };
deSerialize(ob) {
super.deSerialize(ob);
this.name = ob.name;
}
serialize() {
return _.merge(super.serialize(), {
name: this.name,
parentNode: this.parentNode.id,
links: _.map(this.links, link => {
return link.id;
})
});
}
constructor(name: string, id?: string) {
super(id);
this.name = name;
this.links = {};
this.parentNode = null;
}
getName(): string {
return this.name;
}
getParent(): NodeModel {
return this.parentNode;
}
setParentNode(node: NodeModel) {
this.parentNode = node;
}
removeLink(link: LinkModel) {
delete this.links[link.getID()];
}
addLink(link: LinkModel) {
this.links[link.getID()] = link;
}
getLinks(): { [id: string]: LinkModel } {
return this.links;
}
}

View File

@ -1,11 +1,15 @@
import * as React from "react";
import { DiagramEngine } from "../DiagramEngine";
import * as _ from "lodash";
import { PointModel, NodeModel, BaseModel, BaseModelListener, LinkModel, PortModel } from "../Common";
import { LinkLayerWidget } from "./LinkLayerWidget";
import { NodeLayerWidget } from "./NodeLayerWidget";
import { Toolkit } from "../Toolkit";
import { BaseAction, MoveCanvasAction, MoveItemsAction, SelectingAction } from "../CanvasActions";
import {NodeModel} from "../models/NodeModel";
import {PointModel} from "../models/PointModel";
import {PortModel} from "../models/PortModel";
import {LinkModel} from "../models/LinkModel";
import {BaseModel, BaseModelListener} from "../models/BaseModel";
export interface SelectionModel {
model: BaseModel<BaseModelListener>;

View File

@ -1,9 +1,8 @@
import * as React from "react";
import { DiagramModel } from "../DiagramModel";
import { DiagramEngine } from "../DiagramEngine";
import { PointModel } from "../Common";
import { LinkWidget } from "./LinkWidget";
import * as _ from "lodash";
import {PointModel} from "../models/PointModel";
export interface LinkLayerProps {
diagramEngine: DiagramEngine;

View File

@ -1,6 +1,6 @@
import * as React from "react";
import { LinkModel } from "../Common";
import { DiagramEngine } from "../DiagramEngine";
import {LinkModel} from "../models/LinkModel";
export interface LinkProps {
link: LinkModel;

View File

@ -1,5 +1,5 @@
import * as React from "react";
import { DiagramModel } from "../DiagramModel";
import { DiagramModel } from "../models/DiagramModel";
import { DiagramEngine } from "../DiagramEngine";
import * as _ from "lodash";
import { NodeWidget } from "./NodeWidget";

View File

@ -1,6 +1,6 @@
import * as React from "react";
import { NodeModel } from "../Common";
import { DiagramEngine } from "../DiagramEngine";
import {NodeModel} from "../models/NodeModel";
export interface NodeProps {
node: NodeModel;

View File

@ -1,5 +1,5 @@
import * as React from "react";
import { NodeModel } from "../Common";
import {NodeModel} from "../models/NodeModel";
export interface PortProps {
name: string;

File diff suppressed because it is too large Load Diff