clean refactor / consistent TSLint / Prettier

This commit is contained in:
maxleiko
2018-03-02 16:31:50 +01:00
parent 2ee0211994
commit 1debc9c891
65 changed files with 798 additions and 723 deletions

View File

@ -50,7 +50,7 @@ export class CodePreview extends React.Component {
<SyntaxHighlighter
customStyle={{width: '100%', overflowX:'hidden', tabSize: 4}}
showLineNumbers={true}
language='typescript'
language='language-tsx'
style={github}
>
{this.state.code}

View File

@ -15,7 +15,7 @@ import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
* Tests cloning
*/
class CloneSelected extends React.Component<any, any> {
constructor(props) {
constructor(props: any) {
super(props);
this.cloneSelected = this.cloneSelected.bind(this);
}

View File

@ -11,7 +11,6 @@ import {
} from "../../src/main";
import { action } from "@storybook/addon-actions";
import * as React from "react";
import { LinkFactory } from "../../src/AbstractFactory";
import { DefaultLinkModel } from "../../src/defaults/models/DefaultLinkModel";
import { DefaultLinkFactory } from "../../src/defaults/factories/DefaultLinkFactory";

View File

@ -3,7 +3,7 @@ import { DiamonNodeWidget } from "./DiamondNodeWidget";
import { DiamondNodeModel } from "./DiamondNodeModel";
import * as React from "react";
export class DiamondNodeFactory extends SRD.NodeFactory {
export class DiamondNodeFactory extends SRD.AbstractNodeFactory {
constructor() {
super("diamond");
}

View File

@ -1,8 +1,5 @@
import * as _ from "lodash";
import { LinkModel } from "../../src/models/LinkModel";
import { DiagramEngine } from "../../src/DiagramEngine";
import { PortModel } from "../../src/models/PortModel";
import { DefaultLinkModel } from "../../src/defaults/models/DefaultLinkModel";
import { LinkModel, DiagramEngine, PortModel, DefaultLinkModel } from "../../src/main";
export class DiamondPortModel extends PortModel {
position: string | "top" | "bottom" | "left" | "right";

View File

@ -0,0 +1,14 @@
import { PortModel, AbstractPortFactory } from "../../src/main";
export class SimplePortFactory extends AbstractPortFactory {
cb: (initialConfig?: any) => PortModel;
constructor(type: string, cb: (initialConfig?: any) => PortModel) {
super(type);
this.cb = cb;
}
getNewInstance(initialConfig?: any): PortModel {
return this.cb(initialConfig);
}
}

View File

@ -11,7 +11,7 @@ import * as React from "react";
// import the custom models
import { DiamondNodeModel } from "./DiamondNodeModel";
import { DiamondNodeFactory } from "./DiamondNodeFactory";
import { SimplePortFactory } from "../../src/AbstractFactory";
import { SimplePortFactory } from "./SimplePortFactory";
import { DiamondPortModel } from "./DiamondPortModel";
/**

View File

@ -22,9 +22,7 @@ function distributeGraph(model) {
let edges = mapEdges(model);
let graph = new dagre.graphlib.Graph();
graph.setGraph({});
graph.setDefaultEdgeLabel(function() {
return {};
});
graph.setDefaultEdgeLabel(() => ({}));
//add elements to dagre graph
nodes.forEach(node => {
graph.setNode(node.id, node.metadata);

View File

@ -3,7 +3,7 @@ import * as React from "react";
import { BodyWidget } from "./components/BodyWidget";
import { Application } from "./Application";
require("./sass/main.scss");
import "./sass/main.scss";
export default () => {
var app = new Application();

View File

@ -13,6 +13,22 @@ export default () => {
var engine = new DiagramEngine();
engine.installDefaultFactories();
//2) setup the diagram model
var model = new DiagramModel();
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
generateNodes(model, i * 200, j * 100);
}
}
//5) load model into engine
engine.setDiagramModel(model);
//6) render the diagram!
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
};
function generateNodes(model: DiagramModel, offsetX: number, offsetY: number) {
//3-A) create a default node
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
@ -30,19 +46,3 @@ export default () => {
//4) add the models to the root graph
model.addAll(node1, node2, link1);
}
//2) setup the diagram model
var model = new DiagramModel();
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
generateNodes(model, i * 200, j * 100);
}
}
//5) load model into engine
engine.setDiagramModel(model);
//6) render the diagram!
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
};

View File

@ -2,7 +2,7 @@ import { DiagramEngine, DiagramModel, DefaultNodeModel, LinkModel, DiagramWidget
import * as React from "react";
import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
import { action } from "@storybook/addon-actions";
var beautify = require("json-beautify");
import * as beautify from "json-beautify";
export default () => {
//1) setup the diagram engine

View File

@ -20,24 +20,6 @@ export default () => {
var engine = new DiagramEngine();
engine.installDefaultFactories();
function generateNodes(model: DiagramModel, offsetX: number, offsetY: number) {
//3-A) create a default node
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
var port1 = node1.addOutPort("Out");
node1.setPosition(100 + offsetX, 100 + offsetY);
//3-B) create another default node
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
var port2 = node2.addInPort("In");
node2.setPosition(200 + offsetX, 100 + offsetY);
//3-C) link the 2 nodes together
var link1 = port1.link(port2);
//4) add the models to the root graph
model.addAll(node1, node2, link1);
}
//2) setup the diagram model
var model = new DiagramModel();
@ -57,3 +39,21 @@ export default () => {
</DemoWorkspaceWidget>
);
};
function generateNodes(model: DiagramModel, offsetX: number, offsetY: number) {
//3-A) create a default node
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
var port1 = node1.addOutPort("Out");
node1.setPosition(100 + offsetX, 100 + offsetY);
//3-B) create another default node
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
var port2 = node2.addInPort("In");
node2.setPosition(200 + offsetX, 100 + offsetY);
//3-C) link the 2 nodes together
var link1 = port1.link(port2);
//4) add the models to the root graph
model.addAll(node1, node2, link1);
}

View File

@ -6,7 +6,7 @@ import { Helper } from "./.helpers/Helper";
import { Toolkit } from "../src/Toolkit";
//include the SCSS for the demo
require("./.helpers/demo.scss");
import "./.helpers/demo.scss";
Toolkit.TESTING = true;

10
demos/tslint.json Normal file
View File

@ -0,0 +1,10 @@
{
"extends": [
"../tslint.json"
],
"rules": {
"no-console": false,
"max-classes-per-file": false,
"no-var-requires": false
}
}

View File

@ -20,13 +20,21 @@
"typings": "./dist/@types/src/main",
"author": "dylanvorster",
"scripts": {
"test:ci": "rm -rf ./dist && node ./tests/e2e/generate-e2e.js && jest --no-cache",
"test": "jest --no-cache",
"build:ts": "webpack",
"build:ts:prod": "cross-env NODE_ENV=production webpack",
"build:sass:prod": "node-sass --output-style compressed ./src/sass/main.scss > ./dist/style.min.css",
"storybook": "start-storybook -p 9001 -c .storybook",
"storybook:build": "build-storybook -c .storybook -o .out",
"storybook:github": "storybook-to-ghpages",
"prepublishOnly": "rm -rf ./dist && cross-env NODE_ENV=production webpack && ./node_modules/node-sass/bin/node-sass --output-style compressed ./src/sass/main.scss > ./dist/style.min.css",
"pretty": "prettier --use-tabs --write \"{src,demos}/**/*.{ts,tsx}\" --print-width 120"
"pretty": "prettier --use-tabs --write \"{src,demos,tests}/**/*.{ts,tsx}\" --print-width 120",
"lint": "tslint -p .",
"test:ci": "rm -rf ./dist && node ./tests/e2e/generate-e2e.js && jest --no-cache",
"test": "jest --no-cache",
"prepublishOnly": "yarn run build:ts:prod && yarn run build:sass:prod"
},
"dependencies": {
"closest": "^0.0.1",

View File

@ -1,48 +0,0 @@
import { BaseModel } from "./models/BaseModel";
import { NodeModel } from "./models/NodeModel";
import { LinkModel } from "./models/LinkModel";
import { DiagramEngine } from "./DiagramEngine";
import { PortModel } from "./models/PortModel";
import { PointModel } from "./models/PointModel";
import { LabelModel } from "./models/LabelModel";
export abstract class AbstractFactory<T extends BaseModel> {
type: string;
constructor(name: string) {
this.type = name;
}
getType(): string {
return this.type;
}
abstract getNewInstance(initialConfig?: any): T;
}
export abstract class NodeFactory<T extends NodeModel = NodeModel> extends AbstractFactory<T> {
abstract generateReactWidget(diagramEngine: DiagramEngine, node: T): JSX.Element;
}
export abstract class LinkFactory<T extends LinkModel = LinkModel> extends AbstractFactory<T> {
abstract generateReactWidget(diagramEngine: DiagramEngine, link: T): JSX.Element;
}
export abstract class LabelFactory<T extends LabelModel = LabelModel> extends AbstractFactory<T> {
abstract generateReactWidget(diagramEngine: DiagramEngine, label: T): JSX.Element;
}
export abstract class PortFactory<T extends PortModel = PortModel> extends AbstractFactory<T> {}
export class SimplePortFactory extends PortFactory {
cb: (initialConfig?: any) => PortModel;
constructor(type: string, cb: (initialConfig?: any) => PortModel) {
super(type);
this.cb = cb;
}
getNewInstance(initialConfig?: any): PortModel {
return this.cb(initialConfig);
}
}

View File

@ -33,9 +33,11 @@ export class BaseEntity<T extends BaseListener = BaseListener> {
return this.id;
}
doClone(lookupTable = {}, clone) {}
doClone(lookupTable: { [s: string]: any } = {}, clone: any) {
/*noop*/
}
clone(lookupTable = {}) {
clone(lookupTable: { [s: string]: any } = {}) {
// try and use an existing clone first
if (lookupTable[this.id]) {
return lookupTable[this.id];
@ -53,7 +55,7 @@ export class BaseEntity<T extends BaseListener = BaseListener> {
this.listeners = {};
}
public deSerialize(data, engine: DiagramEngine) {
public deSerialize(data: { [s: string]: any }, engine: DiagramEngine) {
this.id = data.id;
}
@ -72,7 +74,9 @@ export class BaseEntity<T extends BaseListener = BaseListener> {
event.firing = false;
}
};
for (var i in this.listeners) {
if (this.listeners.hasOwnProperty(i)) {
// propagation stopped
if (!event.firing) {
return;
@ -80,6 +84,7 @@ export class BaseEntity<T extends BaseListener = BaseListener> {
cb(this.listeners[i], event);
}
}
}
public removeListener(listener: string) {
if (this.listeners[listener]) {

View File

@ -1,87 +0,0 @@
import { DiagramModel } from "./models/DiagramModel";
import { DiagramEngine } from "./DiagramEngine";
import { SelectionModel } from "./widgets/DiagramWidget";
import { PointModel } from "./models/PointModel";
import { NodeModel } from "./models/NodeModel";
export class BaseAction {
mouseX: number;
mouseY: number;
ms: number;
constructor(mouseX: number, mouseY: number) {
this.mouseX = mouseX;
this.mouseY = mouseY;
this.ms = new Date().getTime();
}
}
export class SelectingAction extends BaseAction {
mouseX2: number;
mouseY2: number;
constructor(mouseX: number, mouseY: number) {
super(mouseX, mouseY);
this.mouseX2 = mouseX;
this.mouseY2 = mouseY;
}
getBoxDimensions() {
return {
left: this.mouseX2 > this.mouseX ? this.mouseX : this.mouseX2,
top: this.mouseY2 > this.mouseY ? this.mouseY : this.mouseY2,
width: Math.abs(this.mouseX2 - this.mouseX),
height: Math.abs(this.mouseY2 - this.mouseY),
right: this.mouseX2 < this.mouseX ? this.mouseX : this.mouseX2,
bottom: this.mouseY2 < this.mouseY ? this.mouseY : this.mouseY2
};
}
containsElement(x: number, y: number, diagramModel: DiagramModel): boolean {
var z = diagramModel.getZoomLevel() / 100.0;
let dimensions = this.getBoxDimensions();
return (
x * z + diagramModel.getOffsetX() > dimensions.left &&
x * z + diagramModel.getOffsetX() < dimensions.right &&
y * z + diagramModel.getOffsetY() > dimensions.top &&
y * z + diagramModel.getOffsetY() < dimensions.bottom
);
}
}
export class MoveCanvasAction extends BaseAction {
initialOffsetX: number;
initialOffsetY: number;
constructor(mouseX: number, mouseY: number, diagramModel: DiagramModel) {
super(mouseX, mouseY);
this.initialOffsetX = diagramModel.getOffsetX();
this.initialOffsetY = diagramModel.getOffsetY();
}
}
export class MoveItemsAction extends BaseAction {
selectionModels: SelectionModel[];
moved: boolean;
constructor(mouseX: number, mouseY: number, diagramEngine: DiagramEngine) {
super(mouseX, mouseY);
this.moved = false;
diagramEngine.enableRepaintEntities(diagramEngine.getDiagramModel().getSelectedItems());
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,
initialY: item.y
};
});
}
}

View File

@ -6,7 +6,10 @@ import { NodeModel } from "./models/NodeModel";
import { PointModel } from "./models/PointModel";
import { PortModel } from "./models/PortModel";
import { LinkModel } from "./models/LinkModel";
import { LabelFactory, LinkFactory, NodeFactory, PortFactory } from "./AbstractFactory";
import { AbstractLabelFactory } from "./factories/AbstractLabelFactory";
import { AbstractLinkFactory } from "./factories/AbstractLinkFactory";
import { AbstractNodeFactory } from "./factories/AbstractNodeFactory";
import { AbstractPortFactory } from "./factories/AbstractPortFactory";
import { DefaultLinkFactory, DefaultNodeFactory } from "./main";
import { ROUTING_SCALING_FACTOR } from "./routing/PathFinding";
import { DefaultPortFactory } from "./defaults/factories/DefaultPortFactory";
@ -32,10 +35,10 @@ export interface DiagramEngineListener extends BaseListener {
* Passed as a parameter to the DiagramWidget
*/
export class DiagramEngine extends BaseEntity<DiagramEngineListener> {
nodeFactories: { [s: string]: NodeFactory };
linkFactories: { [s: string]: LinkFactory };
portFactories: { [s: string]: PortFactory };
labelFactories: { [s: string]: LabelFactory };
nodeFactories: { [s: string]: AbstractNodeFactory };
linkFactories: { [s: string]: AbstractLinkFactory };
portFactories: { [s: string]: AbstractPortFactory };
labelFactories: { [s: string]: AbstractLabelFactory };
diagramModel: DiagramModel;
canvas: Element;
@ -82,7 +85,9 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener> {
repaintCanvas() {
this.iterateListeners(listener => {
listener.repaintCanvas && listener.repaintCanvas();
if (listener.repaintCanvas) {
listener.repaintCanvas();
}
});
}
@ -152,19 +157,19 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener> {
//!-------------- FACTORIES ------------
getNodeFactories(): { [s: string]: NodeFactory } {
getNodeFactories(): { [s: string]: AbstractNodeFactory } {
return this.nodeFactories;
}
getLinkFactories(): { [s: string]: LinkFactory } {
getLinkFactories(): { [s: string]: AbstractLinkFactory } {
return this.linkFactories;
}
getLabelFactories(): { [s: string]: LabelFactory } {
getLabelFactories(): { [s: string]: AbstractLabelFactory } {
return this.labelFactories;
}
registerLabelFactory(factory: LabelFactory) {
registerLabelFactory(factory: AbstractLabelFactory) {
this.labelFactories[factory.getType()] = factory;
this.iterateListeners(listener => {
if (listener.labelFactoriesUpdated) {
@ -173,7 +178,7 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener> {
});
}
registerPortFactory(factory: PortFactory) {
registerPortFactory(factory: AbstractPortFactory) {
this.portFactories[factory.getType()] = factory;
this.iterateListeners(listener => {
if (listener.portFactoriesUpdated) {
@ -182,7 +187,7 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener> {
});
}
registerNodeFactory(factory: NodeFactory) {
registerNodeFactory(factory: AbstractNodeFactory) {
this.nodeFactories[factory.getType()] = factory;
this.iterateListeners(listener => {
if (listener.nodeFactoriesUpdated) {
@ -191,7 +196,7 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener> {
});
}
registerLinkFactory(factory: LinkFactory) {
registerLinkFactory(factory: AbstractLinkFactory) {
this.linkFactories[factory.getType()] = factory;
this.iterateListeners(listener => {
if (listener.linkFactoriesUpdated) {
@ -200,47 +205,43 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener> {
});
}
getPortFactory(type: string): PortFactory {
getPortFactory(type: string): AbstractPortFactory {
if (this.portFactories[type]) {
return this.portFactories[type];
}
console.log("cannot find factory for port of type: [" + type + "]");
return null;
throw new Error(`cannot find factory for port of type: [${type}]`);
}
getNodeFactory(type: string): NodeFactory {
getNodeFactory(type: string): AbstractNodeFactory {
if (this.nodeFactories[type]) {
return this.nodeFactories[type];
}
console.log("cannot find factory for node of type: [" + type + "]");
return null;
throw new Error(`cannot find factory for node of type: [${type}]`);
}
getLinkFactory(type: string): LinkFactory {
getLinkFactory(type: string): AbstractLinkFactory {
if (this.linkFactories[type]) {
return this.linkFactories[type];
}
console.log("cannot find factory for link of type: [" + type + "]");
return null;
throw new Error(`cannot find factory for link of type: [${type}]`);
}
getLabelFactory(type: string): LabelFactory {
getLabelFactory(type: string): AbstractLabelFactory {
if (this.labelFactories[type]) {
return this.labelFactories[type];
}
console.log("cannot find factory for label of type: [" + type + "]");
return null;
throw new Error(`cannot find factory for label of type: [${type}]`);
}
getFactoryForNode(node: NodeModel): NodeFactory | null {
getFactoryForNode(node: NodeModel): AbstractNodeFactory | null {
return this.getNodeFactory(node.getType());
}
getFactoryForLink(link: LinkModel): LinkFactory | null {
getFactoryForLink(link: LinkModel): AbstractLinkFactory | null {
return this.getLinkFactory(link.getType());
}
getFactoryForLabel(label: LabelModel): LabelFactory | null {
getFactoryForLabel(label: LabelModel): AbstractLabelFactory | null {
return this.getLabelFactory(label.getType());
}
@ -274,7 +275,7 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener> {
}
getNodeElement(node: NodeModel): Element {
const selector = this.canvas.querySelector('.node[data-nodeid="' + node.getID() + '"]');
const selector = this.canvas.querySelector(`.node[data-nodeid="${node.getID()}"]`);
if (selector === null) {
throw new Error("Cannot find Node element with nodeID: [" + node.getID() + "]");
}
@ -283,7 +284,7 @@ export class DiagramEngine extends BaseEntity<DiagramEngineListener> {
getNodePortElement(port: PortModel): any {
var selector = this.canvas.querySelector(
'.port[data-name="' + port.getName() + '"][data-nodeid="' + port.getParent().getID() + '"]'
`.port[data-name="${port.getName()}"][data-nodeid="${port.getParent().getID()}"]`
);
if (selector === null) {
throw new Error(

View File

@ -1,3 +1,4 @@
// tslint:disable no-bitwise
import closest = require("closest");
import { PointModel } from "./models/PointModel";
import { ROUTING_SCALING_FACTOR } from "./routing/PathFinding";
@ -18,9 +19,9 @@ export class Toolkit {
Toolkit.TESTING_UID++;
return "" + Toolkit.TESTING_UID;
}
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
const r = (Math.random() * 16) | 0;
const v = c === "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}

11
src/actions/BaseAction.ts Normal file
View File

@ -0,0 +1,11 @@
export class BaseAction {
mouseX: number;
mouseY: number;
ms: number;
constructor(mouseX: number, mouseY: number) {
this.mouseX = mouseX;
this.mouseY = mouseY;
this.ms = new Date().getTime();
}
}

View File

@ -0,0 +1,13 @@
import { BaseAction } from "./BaseAction";
import { DiagramModel } from "../models/DiagramModel";
export class MoveCanvasAction extends BaseAction {
initialOffsetX: number;
initialOffsetY: number;
constructor(mouseX: number, mouseY: number, diagramModel: DiagramModel) {
super(mouseX, mouseY);
this.initialOffsetX = diagramModel.getOffsetX();
this.initialOffsetY = diagramModel.getOffsetY();
}
}

View File

@ -0,0 +1,30 @@
import { BaseAction } from "./BaseAction";
import { SelectionModel } from "../models/SelectionModel";
import { PointModel } from "../models/PointModel";
import { NodeModel } from "../models/NodeModel";
import { DiagramEngine } from "../DiagramEngine";
export class MoveItemsAction extends BaseAction {
selectionModels: SelectionModel[];
moved: boolean;
constructor(mouseX: number, mouseY: number, diagramEngine: DiagramEngine) {
super(mouseX, mouseY);
this.moved = false;
diagramEngine.enableRepaintEntities(diagramEngine.getDiagramModel().getSelectedItems());
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,
initialY: item.y
};
});
}
}

View File

@ -0,0 +1,36 @@
import { BaseAction } from "./BaseAction";
import { DiagramModel } from "../models/DiagramModel";
export class SelectingAction extends BaseAction {
mouseX2: number;
mouseY2: number;
constructor(mouseX: number, mouseY: number) {
super(mouseX, mouseY);
this.mouseX2 = mouseX;
this.mouseY2 = mouseY;
}
getBoxDimensions() {
return {
left: this.mouseX2 > this.mouseX ? this.mouseX : this.mouseX2,
top: this.mouseY2 > this.mouseY ? this.mouseY : this.mouseY2,
width: Math.abs(this.mouseX2 - this.mouseX),
height: Math.abs(this.mouseY2 - this.mouseY),
right: this.mouseX2 < this.mouseX ? this.mouseX : this.mouseX2,
bottom: this.mouseY2 < this.mouseY ? this.mouseY : this.mouseY2
};
}
containsElement(x: number, y: number, diagramModel: DiagramModel): boolean {
var z = diagramModel.getZoomLevel() / 100.0;
let dimensions = this.getBoxDimensions();
return (
x * z + diagramModel.getOffsetX() > dimensions.left &&
x * z + diagramModel.getOffsetX() < dimensions.right &&
y * z + diagramModel.getOffsetY() > dimensions.top &&
y * z + diagramModel.getOffsetY() < dimensions.bottom
);
}
}

View File

@ -1,13 +1,13 @@
import * as React from "react";
import { DiagramEngine } from "../../DiagramEngine";
import { LabelFactory } from "../../AbstractFactory";
import { AbstractLabelFactory } from "../../factories/AbstractLabelFactory";
import { DefaultLabelModel } from "../models/DefaultLabelModel";
import { DefaultLabelWidget } from "../widgets/DefaultLabelWidget";
/**
* @author Dylan Vorster
*/
export class DefaultLabelFactory extends LabelFactory<DefaultLabelModel> {
export class DefaultLabelFactory extends AbstractLabelFactory<DefaultLabelModel> {
constructor() {
super("default");
}

View File

@ -1,13 +1,13 @@
import * as React from "react";
import { DefaultLinkWidget } from "../widgets/DefaultLinkWidget";
import { DiagramEngine } from "../../DiagramEngine";
import { LinkFactory } from "../../AbstractFactory";
import { AbstractLinkFactory } from "../../factories/AbstractLinkFactory";
import { DefaultLinkModel } from "../models/DefaultLinkModel";
/**
* @author Dylan Vorster
*/
export class DefaultLinkFactory extends LinkFactory<DefaultLinkModel> {
export class DefaultLinkFactory extends AbstractLinkFactory<DefaultLinkModel> {
constructor() {
super("default");
}

View File

@ -2,11 +2,11 @@ import { DefaultNodeModel } from "../models/DefaultNodeModel";
import * as React from "react";
import { DefaultNodeWidget } from "../widgets/DefaultNodeWidget";
import { DiagramEngine } from "../../DiagramEngine";
import { NodeFactory } from "../../AbstractFactory";
import { AbstractNodeFactory } from "../../factories/AbstractNodeFactory";
/**
* @author Dylan Vorster
*/
export class DefaultNodeFactory extends NodeFactory<DefaultNodeModel> {
export class DefaultNodeFactory extends AbstractNodeFactory<DefaultNodeModel> {
constructor() {
super("default");
}

View File

@ -1,7 +1,7 @@
import { DefaultPortModel } from "../models/DefaultPortModel";
import { PortFactory } from "../../AbstractFactory";
import { AbstractPortFactory } from "../../factories/AbstractPortFactory";
export class DefaultPortFactory extends PortFactory<DefaultPortModel> {
export class DefaultPortFactory extends AbstractPortFactory<DefaultPortModel> {
constructor() {
super("default");
}

View File

@ -10,9 +10,9 @@ import { DefaultLabelModel } from "./DefaultLabelModel";
import { LabelModel } from "../../models/LabelModel";
export interface DefaultLinkModelListener extends LinkModelListener {
colorChanged?(event: BaseEvent<DefaultLinkModel> & { color: null | string });
colorChanged?(event: BaseEvent<DefaultLinkModel> & { color: null | string }): void;
widthChanged?(event: BaseEvent<DefaultLinkModel> & { width: 0 | number });
widthChanged?(event: BaseEvent<DefaultLinkModel> & { width: 0 | number }): void;
}
export class DefaultLinkModel extends LinkModel<DefaultLinkModelListener> {
@ -54,14 +54,18 @@ export class DefaultLinkModel extends LinkModel<DefaultLinkModelListener> {
setWidth(width: number) {
this.width = width;
this.iterateListeners((listener: DefaultLinkModelListener, event: BaseEvent) => {
listener.widthChanged && listener.widthChanged({ ...event, width: width });
if (listener.widthChanged) {
listener.widthChanged({ ...event, width: width });
}
});
}
setColor(color: string) {
this.color = color;
this.iterateListeners((listener: DefaultLinkModelListener, event: BaseEvent) => {
listener.colorChanged && listener.colorChanged({ ...event, color: color });
if (listener.colorChanged) {
listener.colorChanged({ ...event, color: color });
}
});
}
}

View File

@ -343,18 +343,18 @@ export class DefaultLinkWidget extends BaseWidget<DefaultLinkProps, DefaultLinkS
}
} else {
//draw the multiple anchors and complex line instead
for (let i = 0; i < points.length - 1; i++) {
for (let j = 0; j < points.length - 1; j++) {
paths.push(
this.generateLink(
Toolkit.generateLinePath(points[i], points[i + 1]),
Toolkit.generateLinePath(points[j], points[j + 1]),
{
"data-linkid": this.props.link.id,
"data-point": i,
"data-point": j,
onMouseDown: (event: MouseEvent) => {
this.addPointToLink(event, i + 1);
this.addPointToLink(event, j + 1);
}
},
i
j
)
);
}

View File

@ -0,0 +1,15 @@
import { BaseModel } from "../models/BaseModel";
export abstract class AbstractFactory<T extends BaseModel> {
type: string;
constructor(name: string) {
this.type = name;
}
getType(): string {
return this.type;
}
abstract getNewInstance(initialConfig?: any): T;
}

View File

@ -0,0 +1,7 @@
import { LabelModel } from "../models/LabelModel";
import { DiagramEngine } from "../DiagramEngine";
import { AbstractFactory } from "./AbstractFactory";
export abstract class AbstractLabelFactory<T extends LabelModel = LabelModel> extends AbstractFactory<T> {
abstract generateReactWidget(diagramEngine: DiagramEngine, link: T): JSX.Element;
}

View File

@ -0,0 +1,7 @@
import { LinkModel } from "../models/LinkModel";
import { DiagramEngine } from "../DiagramEngine";
import { AbstractFactory } from "./AbstractFactory";
export abstract class AbstractLinkFactory<T extends LinkModel = LinkModel> extends AbstractFactory<T> {
abstract generateReactWidget(diagramEngine: DiagramEngine, link: T): JSX.Element;
}

View File

@ -0,0 +1,7 @@
import { NodeModel } from "../models/NodeModel";
import { DiagramEngine } from "../DiagramEngine";
import { AbstractFactory } from "./AbstractFactory";
export abstract class AbstractNodeFactory<T extends NodeModel = NodeModel> extends AbstractFactory<T> {
abstract generateReactWidget(diagramEngine: DiagramEngine, node: T): JSX.Element;
}

View File

@ -0,0 +1,5 @@
import { PortModel } from "../models/PortModel";
import { DiagramEngine } from "../DiagramEngine";
import { AbstractFactory } from "./AbstractFactory";
export abstract class AbstractPortFactory<T extends PortModel = PortModel> extends AbstractFactory<T> {}

View File

@ -15,14 +15,24 @@ export * from "./defaults/widgets/DefaultLinkWidget";
export * from "./defaults/widgets/DefaultNodeWidget";
export * from "./defaults/widgets/DefaultPortLabelWidget";
export * from "./AbstractFactory";
export * from "./factories/AbstractFactory";
export * from "./factories/AbstractLabelFactory";
export * from "./factories/AbstractLinkFactory";
export * from "./factories/AbstractNodeFactory";
export * from "./factories/AbstractPortFactory";
export * from "./Toolkit";
export * from "./DiagramEngine";
export * from "./models/DiagramModel";
export * from "./BaseEntity";
export * from "./CanvasActions";
export * from "./actions/BaseAction";
export * from "./actions/MoveCanvasAction";
export * from "./actions/MoveItemsAction";
export * from "./actions/SelectingAction";
export * from "./models/SelectionModel";
export * from "./models/DiagramModel";
export * from "./models/BaseModel";
export * from "./models/DiagramModel";
export * from "./models/LinkModel";

View File

@ -53,7 +53,9 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
setGridSize(size: number = 0) {
this.gridSize = size;
this.iterateListeners((listener, event) => {
listener.gridUpdated && listener.gridUpdated({ ...event, size: size });
if (listener.gridUpdated) {
listener.gridUpdated({ ...event, size: size });
}
});
}
@ -169,7 +171,9 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
this.zoom = zoom;
this.iterateListeners((listener, event) => {
listener.zoomUpdated && listener.zoomUpdated({ ...event, zoom: zoom });
if (listener.zoomUpdated) {
listener.zoomUpdated({ ...event, zoom: zoom });
}
});
}
@ -177,22 +181,27 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
this.offsetX = offsetX;
this.offsetY = offsetY;
this.iterateListeners((listener, event) => {
listener.offsetUpdated && listener.offsetUpdated({ ...event, offsetX: offsetX, offsetY: offsetY });
if (listener.offsetUpdated) {
listener.offsetUpdated({ ...event, offsetX: offsetX, offsetY: offsetY });
}
});
}
setOffsetX(offsetX: number) {
this.offsetX = offsetX;
this.iterateListeners((listener, event) => {
listener.offsetUpdated && listener.offsetUpdated({ ...event, offsetX: offsetX, offsetY: this.offsetY });
if (listener.offsetUpdated) {
listener.offsetUpdated({ ...event, offsetX: offsetX, offsetY: this.offsetY });
}
});
}
setOffsetY(offsetY: number) {
this.offsetY = offsetY;
this.iterateListeners((listener, event) => {
listener.offsetUpdated &&
if (listener.offsetUpdated) {
listener.offsetUpdated({ ...event, offsetX: this.offsetX, offsetY: this.offsetY });
}
});
}
@ -247,7 +256,9 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
});
this.links[link.getID()] = link;
this.iterateListeners((listener, event) => {
listener.linksUpdated && listener.linksUpdated({ ...event, link: link, isCreated: true });
if (listener.linksUpdated) {
listener.linksUpdated({ ...event, link: link, isCreated: true });
}
});
return link;
}
@ -260,7 +271,9 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
});
this.nodes[node.getID()] = node;
this.iterateListeners((listener, event) => {
listener.nodesUpdated && listener.nodesUpdated({ ...event, node: node, isCreated: true });
if (listener.nodesUpdated) {
listener.nodesUpdated({ ...event, node: node, isCreated: true });
}
});
return node;
}
@ -269,7 +282,9 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
link = this.getLink(link);
delete this.links[link.getID()];
this.iterateListeners((listener, event) => {
listener.linksUpdated && listener.linksUpdated({ ...event, link: link as LinkModel, isCreated: false });
if (listener.linksUpdated) {
listener.linksUpdated({ ...event, link: link as LinkModel, isCreated: false });
}
});
}
@ -277,7 +292,9 @@ export class DiagramModel extends BaseEntity<DiagramListener> {
node = this.getNode(node);
delete this.nodes[node.getID()];
this.iterateListeners((listener, event) => {
listener.nodesUpdated && listener.nodesUpdated({ ...event, node: node as NodeModel, isCreated: false });
if (listener.nodesUpdated) {
listener.nodesUpdated({ ...event, node: node as NodeModel, isCreated: false });
}
});
}

View File

@ -158,7 +158,9 @@ export class LinkModel<T extends LinkModelListener = LinkModelListener> extends
}
this.sourcePort = port;
this.iterateListeners((listener: LinkModelListener, event) => {
listener.sourcePortChanged && listener.sourcePortChanged({ ...event, port: port });
if (listener.sourcePortChanged) {
listener.sourcePortChanged({ ...event, port: port });
}
});
}
@ -180,7 +182,9 @@ export class LinkModel<T extends LinkModelListener = LinkModelListener> extends
}
this.targetPort = port;
this.iterateListeners((listener: LinkModelListener, event) => {
listener.targetPortChanged && listener.targetPortChanged({ ...event, port: port });
if (listener.targetPortChanged) {
listener.targetPortChanged({ ...event, port: port });
}
});
}
@ -222,7 +226,7 @@ export class LinkModel<T extends LinkModelListener = LinkModelListener> extends
}
}
addPoint<T extends PointModel>(pointModel: T, index = 1): T {
addPoint<P extends PointModel>(pointModel: P, index = 1): P {
pointModel.setParent(this);
this.points.splice(index, 0, pointModel);
return pointModel;

View File

@ -26,14 +26,13 @@ export class NodeModel extends BaseModel<DiagramModel, BaseModelListener> {
//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]);
_.forEach(this.ports, port => {
_.forEach(port.getLinks(), link => {
let point = link.getPointForPort(port);
point.x = point.x + x - oldX;
point.y = point.y + y - oldY;
});
}
});
this.x = x;
this.y = y;
}
@ -43,13 +42,13 @@ export class NodeModel extends BaseModel<DiagramModel, BaseModelListener> {
// add the points of each link that are selected here
if (this.isSelected()) {
for (let portName in this.ports) {
_.forEach(this.ports, port => {
entities = entities.concat(
_.map(this.ports[portName].getLinks(), link => {
return link.getPointForPort(this.ports[portName]);
_.map(port.getLinks(), link => {
return link.getPointForPort(port);
})
);
}
});
}
return entities;
}
@ -82,18 +81,18 @@ export class NodeModel extends BaseModel<DiagramModel, BaseModelListener> {
doClone(lookupTable = {}, clone) {
// also clone the ports
clone.ports = {};
_.values(this.ports).forEach(port => {
_.forEach(this.ports, port => {
clone.addPort(port.clone(lookupTable));
});
}
remove() {
super.remove();
for (var i in this.ports) {
_.forEach(this.ports[i].getLinks(), link => {
_.forEach(this.ports, port => {
_.forEach(port.getLinks(), link => {
link.remove();
});
}
});
}
getPortFromID(id): PortModel | null {

View File

@ -0,0 +1,8 @@
import { BaseModel, BaseModelListener } from "./BaseModel";
import { BaseEntity } from "../BaseEntity";
export interface SelectionModel {
model: BaseModel<BaseEntity, BaseModelListener>;
initialX: number;
initialY: number;
}

View File

@ -4,21 +4,19 @@ import * as _ from "lodash";
import { LinkLayerWidget } from "./layers/LinkLayerWidget";
import { NodeLayerWidget } from "./layers/NodeLayerWidget";
import { Toolkit } from "../Toolkit";
import { BaseAction, MoveCanvasAction, MoveItemsAction, SelectingAction } from "../CanvasActions";
import { BaseAction } from "../actions/BaseAction";
import { MoveCanvasAction } from "../actions/MoveCanvasAction";
import { MoveItemsAction } from "../actions/MoveItemsAction";
import { SelectingAction } from "../actions/SelectingAction";
import { NodeModel } from "../models/NodeModel";
import { PointModel } from "../models/PointModel";
import { PortModel } from "../models/PortModel";
import { LinkModel } from "../models/LinkModel";
import { SelectionModel } from "../models/SelectionModel";
import { BaseModel, BaseModelListener } from "../models/BaseModel";
import { BaseEntity } from "../BaseEntity";
import { BaseWidget, BaseWidgetProps } from "./BaseWidget";
export interface SelectionModel {
model: BaseModel<BaseEntity, BaseModelListener>;
initialX: number;
initialY: number;
}
export interface DiagramProps extends BaseWidgetProps {
diagramEngine: DiagramEngine;
@ -60,6 +58,8 @@ export class DiagramWidget extends BaseWidget<DiagramProps, DiagramState> {
deleteKeys: [46, 8]
};
onKeyUpPointer: (this: Window, ev: KeyboardEvent) => void = null;
constructor(props: DiagramProps) {
super("srd-diagram", props);
this.onMouseMove = this.onMouseMove.bind(this);
@ -74,8 +74,6 @@ export class DiagramWidget extends BaseWidget<DiagramProps, DiagramState> {
};
}
onKeyUpPointer: null;
componentWillUnmount() {
this.props.diagramEngine.removeListener(this.state.diagramEngineListener);
this.props.diagramEngine.setCanvas(null);

View File

@ -53,7 +53,9 @@ export class LinkLayerWidget extends BaseWidget<LinkLayerProps, LinkLayerState>
link.sourcePort.updateCoords(portCoords);
this.props.diagramEngine.linksThatHaveInitiallyRendered[link.id] = true;
} catch (ex) {}
} catch (ignore) {
/*noop*/
}
}
if (link.targetPort !== null) {
try {
@ -64,15 +66,16 @@ export class LinkLayerWidget extends BaseWidget<LinkLayerProps, LinkLayerState>
link.targetPort.updateCoords(portCoords);
this.props.diagramEngine.linksThatHaveInitiallyRendered[link.id] = true;
} catch (ex) {}
} catch (ignore) {
/*noop*/
}
}
}
//generate links
var generatedLink = this.props.diagramEngine.generateWidgetForLink(link);
if (!generatedLink) {
console.log("no link generated for type: " + link.getType());
return null;
throw new Error(`no link generated for type: ${link.getType()}`);
}
return (

109
tests/e2e/E2EHelper.ts Normal file
View File

@ -0,0 +1,109 @@
import { ElementHandle, Page } from "puppeteer";
import { NodeModel } from "../../src/models/NodeModel";
import { LinkModel } from "../../src/models/LinkModel";
import * as _ from "lodash";
export class E2EElement {
helper: E2EHelper;
page: Page;
element: ElementHandle;
id: string;
constructor(helper: E2EHelper, page: Page, element: ElementHandle, id: string) {
this.page = page;
this.element = element;
this.id = id;
this.helper = helper;
}
}
export class E2ENode extends E2EElement {
async port(id: string): Promise<E2EPort> {
return new E2EPort(this.helper, this.page, await this.element.$(`div[data-name="${id}"]`), id, this);
}
async model(): Promise<any> {
return await this.page.evaluate(id => {
return window["diagram_instance"]
.getDiagramModel()
.getNode(id)
.serialize();
}, this.id);
}
}
export class E2EPort extends E2EElement {
parent: E2ENode;
constructor(helper: E2EHelper, page: Page, element: ElementHandle, id: string, parent: E2ENode) {
super(helper, page, element, id);
this.parent = parent;
}
async link(port: E2EPort): Promise<E2ELink> {
let currentLinks = _.flatMap((await this.parent.model()).ports, "links");
let bounds = await this.element.boundingBox();
// click on this port
this.page.mouse.move(bounds.x, bounds.y);
this.page.mouse.down();
let bounds2 = await port.element.boundingBox();
// drag to other port
this.page.mouse.move(bounds2.x, bounds2.y);
this.page.mouse.up();
// get the parent to get the link
return await this.helper.link(
_.difference(_.flatMap((await this.parent.model()).ports, "links"), currentLinks)[0]
);
}
}
export class E2ELink extends E2EElement {
async model(): Promise<any> {
return await this.page.evaluate(id => {
return window["diagram_instance"]
.getDiagramModel()
.getLink(id)
.serialize();
}, this.id);
}
async exists(): Promise<boolean> {
return await this.page.evaluate(id => {
return !!document.querySelector(`path[data-linkid="${id}"]`);
}, this.id);
}
async select(): Promise<any> {
const point = await this.page.evaluate(id => {
const path = document.querySelector(`path[data-linkid="${id}"]`) as SVGPathElement;
return path.getPointAtLength(path.getTotalLength() / 2);
}, this.id);
await this.page.keyboard.down("Shift");
await this.page.mouse.move(point.x, point.y);
await this.page.mouse.down();
await this.page.keyboard.up("Shift");
}
}
export class E2EHelper {
page: Page;
constructor(page: Page) {
this.page = page;
}
async link(id): Promise<E2ELink> {
let selector = await this.page.waitForSelector(`path[data-linkid="${id}"]`);
return new E2ELink(this, this.page, selector, id);
}
async node(id): Promise<E2ENode> {
let selector = await this.page.waitForSelector(`div[data-nodeid="${id}"]`);
return new E2ENode(this, this.page, selector, id);
}
}

View File

@ -1,115 +0,0 @@
import {ElementHandle, Page} from "puppeteer";
import {NodeModel} from "../../src/models/NodeModel";
import {LinkModel} from "../../src/models/LinkModel";
import * as _ from "lodash";
export class E2EElement{
helper: E2EHelper;
page: Page;
element: ElementHandle;
id: string;
constructor(helper: E2EHelper,page: Page, element: ElementHandle, id: string) {
this.page = page;
this.element = element;
this.id = id;
this.helper = helper;
}
}
export class E2ENode extends E2EElement{
async port(id: string): Promise<E2EPort>{
return new E2EPort(this.helper,this.page, await this.element.$('div[data-name="'+id+'"]'), id, this);
}
async model(): Promise<any>{
return await this.page.evaluate((id) => {
return window['diagram_instance'].getDiagramModel().getNode(id).serialize();
}, this.id)
}
}
export class E2EPort extends E2EElement{
parent: E2ENode;
constructor(helper: E2EHelper,page: Page, element: ElementHandle, id: string, parent: E2ENode) {
super(helper,page, element, id);
this.parent = parent;
}
async link(port: E2EPort): Promise<E2ELink>{
let currentLinks = _.flatMap((await this.parent.model()).ports, 'links');
let bounds = await this.element.boundingBox();
// click on this port
this.page.mouse.move(bounds.x, bounds.y);
this.page.mouse.down();
let bounds2 = await port.element.boundingBox();
// drag to other port
this.page.mouse.move(bounds2.x, bounds2.y);
this.page.mouse.up();
// get the parent to get the link
return await this.helper.link(_.difference(_.flatMap((await this.parent.model()).ports, 'links'), currentLinks)[0]);
}
}
export class E2ELink extends E2EElement{
async model(): Promise<any>{
return await this.page.evaluate((id) => {
return window['diagram_instance'].getDiagramModel().getLink(id).serialize();
}, this.id)
}
async exists():Promise<boolean>{
return await this.page.evaluate((id) => {
return !!document.querySelector('path[data-linkid="' + id + '"]');
}, this.id);
}
async select(): Promise<any>{
let point = await this.page.evaluate((id) => {
let path = (document.querySelector('path[data-linkid="' + id + '"]') as SVGPathElement);
let point = path.getPointAtLength(path.getTotalLength()/2);
return {
x: point.x,
y: point.y
}
}, this.id);
await this.page.keyboard.down('Shift');
await this.page.mouse.move(point.x, point.y);
await this.page.mouse.down();
await this.page.keyboard.up('Shift');
}
}
export class E2EHelper {
page: Page;
constructor(page: Page) {
this.page = page;
}
async link(id): Promise<E2ELink> {
let selector = await this.page.waitForSelector('path[data-linkid="' + id + '"]');
return new E2ELink(this,this.page, selector, id);
}
async node(id): Promise<E2ENode> {
let selector = await this.page.waitForSelector('div[data-nodeid="' + id + '"]');
return new E2ENode(this,this.page, selector, id);
}
}

View File

@ -1,5 +1,5 @@
import "jest";
import * as puppeteer from "puppeteer"
import * as puppeteer from "puppeteer";
import { E2EHelper } from "./E2EHelper";
var browser;
@ -7,7 +7,7 @@ var browser;
async function itShould(demo: string, directive, test: (page: puppeteer.Page, helper: E2EHelper) => any) {
it(directive, async () => {
let page = await browser.newPage();
await page.goto('file://' + __dirname + '/../../dist/e2e/' + demo + "/index.html");
await page.goto("file://" + __dirname + "/../../dist/e2e/" + demo + "/index.html");
let helper = new E2EHelper(page);
await test(page, helper);
await page.close();
@ -19,7 +19,7 @@ beforeAll(async () => {
console.log("using CircleCI");
browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox']
args: ["--no-sandbox", "--disable-setuid-sandbox"]
});
} else {
browser = await puppeteer.launch({
@ -32,31 +32,26 @@ afterAll(() => {
browser.close();
});
describe("simple test", async () => {
itShould("demo-simple", 'should delete a link and create a new one', async (page, helper) => {
itShould("demo-simple", "should delete a link and create a new one", async (page, helper) => {
// get the existing link
let link = await helper.link('12');
let link = await helper.link("12");
await expect(await link.exists()).toBeTruthy();
// remove it
await link.select();
await page.keyboard.press('Backspace');
await page.keyboard.press("Del");
await expect(await link.exists()).toBeFalsy();
// create a new link
let node1 = await helper.node('6');
let node2 = await helper.node('9');
let node1 = await helper.node("6");
let node2 = await helper.node("9");
let port1 = await node1.port('7');
let port2 = await node2.port('10');
let port1 = await node1.port("7");
let port2 = await node2.port("10");
let newlink = await port1.link(port2);
await expect(await newlink.exists()).toBeTruthy();
});
})
});

View File

@ -1,19 +1,18 @@
import PathFinding from "../../src/routing/PathFinding";
describe('calculating start and end points', () => {
describe("calculating start and end points", () => {
beforeEach(() => {
this.pathFinding = new PathFinding(null);
});
test('return correct object for valid walkable input', () => {
test("return correct object for valid walkable input", () => {
const matrix = [
[0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0]
];
const path = [[0, 5], [1, 4], [2, 3], [3, 2], [4, 1], [5, 0]];
@ -21,23 +20,18 @@ describe('calculating start and end points', () => {
expect(result.start).toEqual({
x: 2,
y: 3,
y: 3
});
expect(result.end).toEqual({
x: 3,
y: 2,
y: 2
});
expect(result.pathToStart).toEqual([[0, 5], [1, 4]]);
expect(result.pathToEnd).toEqual([[3, 2], [4, 1], [5, 0]]);
});
test('undefined is returned when no walkable path exists', () => {
const matrix = [
[0, 0, 1, 1],
[0, 0, 1, 1],
[1, 1, 0, 0],
[1, 1, 0, 0],
];
test("undefined is returned when no walkable path exists", () => {
const matrix = [[0, 0, 1, 1], [0, 0, 1, 1], [1, 1, 0, 0], [1, 1, 0, 0]];
const path = [[0, 3], [1, 2], [2, 1], [3, 0]];
const result = this.pathFinding.calculateLinkStartEndCoords(matrix, path);

View File

@ -1,4 +1,4 @@
import initStoryshots from '@storybook/addon-storyshots';
import 'raf/polyfill';
import initStoryshots from "@storybook/addon-storyshots";
import "raf/polyfill";
initStoryshots({ configPath: __dirname });

9
tests/tslint.json Normal file
View File

@ -0,0 +1,9 @@
{
"extends": [
"../tslint.json"
],
"rules": {
"no-console": false,
"max-classes-per-file": false
}
}

View File

@ -9,7 +9,11 @@
"comment-format": false,
"max-line-length": false,
"object-literal-sort-keys": false,
"quotemark": false,
"quotemark": [true, "double", "jsx-double"],
"arrow-parens": false,
"indent": [true, "tabs", 2],
"semicolon": false,
"object-literal-key-quotes": [true, "as-needed"],
"no-var-keyword": false,
"jsdoc-format": false,
"prefer-const": false,

View File

@ -14,7 +14,7 @@ if(process.env.NODE_ENV === 'production'){
}
}));
plugins.push(new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'process.env.NODE_ENV': 'production',
}));
}

View File

@ -2328,6 +2328,13 @@ create-react-class@^15.5.2, create-react-class@^15.6.2:
loose-envify "^1.3.1"
object-assign "^4.1.1"
cross-env@^5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.1.3.tgz#f8ae18faac87692b0a8b4d2f7000d4ec3a85dfd7"
dependencies:
cross-spawn "^5.1.0"
is-windows "^1.0.0"
cross-spawn@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
@ -2335,7 +2342,7 @@ cross-spawn@^3.0.0:
lru-cache "^4.0.1"
which "^1.2.9"
cross-spawn@^5.0.1:
cross-spawn@^5.0.1, cross-spawn@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
dependencies:
@ -4306,7 +4313,7 @@ is-utf8@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
is-windows@^1.0.2:
is-windows@^1.0.0, is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"