From 1603729a9b03d4e817d5ac2473e6758842b3d0a8 Mon Sep 17 00:00:00 2001 From: Anatoliy Mayorov Date: Sat, 8 Oct 2022 21:43:35 +0300 Subject: [PATCH 1/4] fix: types of Hierarchical and Swimlane Layout #96 --- packages/core/src/types.ts | 25 ++++++ packages/core/src/view/layout/GraphLayout.ts | 19 ++--- .../src/view/layout/HierarchicalLayout.ts | 72 +++++++++-------- .../core/src/view/layout/SwimlaneLayout.ts | 80 ++++++++++--------- packages/ts-example/tsconfig.json | 4 +- 5 files changed, 115 insertions(+), 85 deletions(-) diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 4e3a4dfa3..9ece5e220 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -15,6 +15,7 @@ limitations under the License. */ import { DIRECTION } from './util/Constants'; +import Dictionary from './util/Dictionary'; import type Cell from './view/cell/Cell'; import type CellState from './view/cell/CellState'; import EventSource from './view/event/EventSource'; @@ -22,6 +23,7 @@ import type InternalMouseEvent from './view/event/InternalMouseEvent'; import type Shape from './view/geometry/Shape'; import type { Graph } from './view/Graph'; import type ImageBox from './view/image/ImageBox'; +import GraphHierarchyNode from './view/layout/datatypes/GraphHierarchyNode'; export type CellMap = { [id: string]: Cell; @@ -316,3 +318,26 @@ export interface PopupMenuItem extends HTMLElement { activeRow: PopupMenuItem | null; eventReceiver: HTMLElement | null; } + +// GraphLayout + +export interface GraphLayoutTraverseArgs { + vertex: Cell | null; + directed: boolean | null; + func: Function | null; + edge: Cell | null; + visited: Dictionary | null; +} + +export interface HierarchicalGraphLayoutTraverseArgs + extends GraphLayoutTraverseArgs{ + allVertices: { [key: string]: Cell } | null, + currentComp: { [key: string]: Cell | null }, + hierarchyVertices: GraphHierarchyNode[], + filledVertexSet: { [key: string]: Cell } | null +} + +export interface SwimlaneGraphLayoutTraverseArgs + extends HierarchicalGraphLayoutTraverseArgs{ + swimlaneIndex: number +} diff --git a/packages/core/src/view/layout/GraphLayout.ts b/packages/core/src/view/layout/GraphLayout.ts index aa177794e..e3b78975b 100644 --- a/packages/core/src/view/layout/GraphLayout.ts +++ b/packages/core/src/view/layout/GraphLayout.ts @@ -22,6 +22,7 @@ import Geometry from '../geometry/Geometry'; import Point from '../geometry/Point'; import { Graph } from '../Graph'; import Cell from '../cell/Cell'; +import { GraphLayoutTraverseArgs } from '../../types'; /** * @class GraphLayout @@ -141,13 +142,7 @@ class GraphLayout { * null for the first step of the traversal. * @param visited Optional {@link Dictionary} of cell paths for the visited cells. */ - traverse( - vertex: Cell, - directed?: boolean, - func?: Function, - edge?: Cell, - visited?: Dictionary - ): void { + traverse({vertex, directed, func, edge, visited}: GraphLayoutTraverseArgs): void { if (func != null && vertex != null) { directed = directed != null ? directed : true; visited = visited || new Dictionary(); @@ -161,12 +156,18 @@ class GraphLayout { if (edgeCount > 0) { for (let i = 0; i < edgeCount; i += 1) { - const e = vertex.getEdgeAt(i); + const e: Cell = vertex.getEdgeAt(i); const isSource = e.getTerminal(true) === vertex; if (!directed || isSource) { const next = this.graph.view.getVisibleTerminal(e, !isSource); - this.traverse(next, directed, func, e, visited); + this.traverse({ + vertex: next, + directed, + func, + edge: e, + visited + }); } } } diff --git a/packages/core/src/view/layout/HierarchicalLayout.ts b/packages/core/src/view/layout/HierarchicalLayout.ts index b084a8624..e52a86355 100644 --- a/packages/core/src/view/layout/HierarchicalLayout.ts +++ b/packages/core/src/view/layout/HierarchicalLayout.ts @@ -27,7 +27,7 @@ import MedianHybridCrossingReduction from './hierarchical/MedianHybridCrossingRe import CoordinateAssignment from './hierarchical/CoordinateAssignment'; import { Graph } from '../../view/Graph'; import Cell from '../../view/cell/Cell'; -import GraphHierarchyNode from './datatypes/GraphHierarchyNode'; +import { HierarchicalGraphLayoutTraverseArgs } from '../../types'; /** * A hierarchical layout algorithm. @@ -444,15 +444,17 @@ class HierarchicalLayout extends GraphLayout { const vertexSet = Object(); hierarchyVertices.push(vertexSet); - this.traverse( - candidateRoots[i], - true, - null, - allVertexSet, - vertexSet, - hierarchyVertices, - filledVertexSet - ); + this.traverse({ + vertex: candidateRoots[i], + directed: true, + edge: null, + allVertices: allVertexSet, + currentComp: vertexSet, + hierarchyVertices: hierarchyVertices, + filledVertexSet: filledVertexSet, + func: null, + visited: null + }); } for (let i = 0; i < candidateRoots.length; i += 1) { @@ -477,15 +479,17 @@ class HierarchicalLayout extends GraphLayout { const vertexSet = Object(); hierarchyVertices.push(vertexSet); - this.traverse( - roots[i], - true, - null, - allVertexSet, - vertexSet, - hierarchyVertices, - null - ); + this.traverse({ + vertex: roots[i], + directed: true, + edge: null, + allVertices: allVertexSet, + currentComp: vertexSet, + hierarchyVertices: hierarchyVertices, + filledVertexSet: null, + func: null, + visited: null + }); } } @@ -600,16 +604,14 @@ class HierarchicalLayout extends GraphLayout { * null for the first step of the traversal. * @param allVertices Array of cell paths for the visited cells. */ - // @ts-ignore - traverse( - vertex: Cell, - directed: boolean = false, - edge: Cell | null = null, - allVertices: { [key: string]: Cell } | null = null, - currentComp: { [key: string]: Cell | null }, - hierarchyVertices: GraphHierarchyNode[], - filledVertexSet: { [key: string]: Cell } | null = null - ) { + traverse({ + vertex, + directed, + allVertices, + currentComp, + hierarchyVertices, + filledVertexSet + }: HierarchicalGraphLayoutTraverseArgs) { if (vertex != null && allVertices != null) { // Has this vertex been seen before in any traversal // And if the filled vertex set is populated, only @@ -666,15 +668,17 @@ class HierarchicalLayout extends GraphLayout { } if (netCount >= 0) { - currentComp = this.traverse( - next, + currentComp = this.traverse({ + vertex: next, directed, - edges[i], + edge: edges[i], allVertices, currentComp, hierarchyVertices, - filledVertexSet - ); + filledVertexSet, + func: null, + visited: null + }); } } } diff --git a/packages/core/src/view/layout/SwimlaneLayout.ts b/packages/core/src/view/layout/SwimlaneLayout.ts index b29077c53..bf7b891ec 100644 --- a/packages/core/src/view/layout/SwimlaneLayout.ts +++ b/packages/core/src/view/layout/SwimlaneLayout.ts @@ -29,7 +29,7 @@ import CoordinateAssignment from './hierarchical/CoordinateAssignment'; import { Graph } from '../Graph'; import Cell from '../cell/Cell'; import Geometry from '../../view/geometry/Geometry'; -import GraphHierarchyNode from './datatypes/GraphHierarchyNode'; +import { SwimlaneGraphLayoutTraverseArgs } from '../../types'; /** * A hierarchical layout algorithm. @@ -579,16 +579,18 @@ class SwimlaneLayout extends GraphLayout { const vertexSet = Object(); hierarchyVertices.push(vertexSet); - this.traverse( - candidateRoots[i], - true, - null, - allVertexSet, - vertexSet, + this.traverse({ + vertex: candidateRoots[i], + directed: true, + edge: null, + allVertices: allVertexSet, + currentComp: vertexSet, hierarchyVertices, filledVertexSet, - laneCounter - ); + swimlaneIndex: laneCounter, + func: null, + visited: null + }); } for (let i = 0; i < candidateRoots.length; i += 1) { @@ -612,16 +614,18 @@ class SwimlaneLayout extends GraphLayout { for (let i = 0; i < roots.length; i += 1) { const vertexSet = Object(); hierarchyVertices.push(vertexSet); - this.traverse( - roots[i], - true, - null, - allVertexSet, - vertexSet, + this.traverse({ + vertex: roots[i], + directed: true, + edge: null, + allVertices: allVertexSet, + currentComp: vertexSet, hierarchyVertices, - null, - i - ); // CHECK THIS PARAM!! ==================== + filledVertexSet: null, + swimlaneIndex: i, + func: null, + visited: null + }); // CHECK THIS PARAM!! ==================== } } @@ -731,17 +735,15 @@ class SwimlaneLayout extends GraphLayout { * @param allVertices Array of cell paths for the visited cells. * @param swimlaneIndex the laid out order index of the swimlane vertex is contained in */ - // @ts-ignore - traverse( - vertex: Cell | null = null, - directed: boolean, - edge: Cell | null, - allVertices: { [key: string]: Cell } | null = null, - currentComp: { [key: string]: Cell }, - hierarchyVertices: GraphHierarchyNode[], - filledVertexSet: { [key: string]: Cell } | null = null, - swimlaneIndex: number - ) { + traverse({ + vertex, + directed, + allVertices, + currentComp, + hierarchyVertices, + filledVertexSet, + swimlaneIndex + }: SwimlaneGraphLayoutTraverseArgs) { if (vertex != null && allVertices != null) { // Has this vertex been seen before in any traversal // And if the filled vertex set is populated, only @@ -764,7 +766,6 @@ class SwimlaneLayout extends GraphLayout { } const edges = this.getEdges(vertex); - const { model } = this.graph; for (let i = 0; i < edges.length; i += 1) { let otherVertex = this.getVisibleTerminal(edges[i], true); @@ -775,16 +776,15 @@ class SwimlaneLayout extends GraphLayout { } let otherIndex = 0; - const swimlanes = this.swimlanes as Cell[]; // Get the swimlane index of the other terminal - for (otherIndex = 0; otherIndex < swimlanes.length; otherIndex++) { - if (swimlanes[otherIndex].isAncestor(otherVertex)) { + for (otherIndex = 0; otherIndex < this.swimlanes!.length; otherIndex++) { + if (this.swimlanes![otherIndex].isAncestor(otherVertex)) { break; } } - if (otherIndex >= swimlanes.length) { + if (otherIndex >= this.swimlanes!.length) { continue; } @@ -795,16 +795,18 @@ class SwimlaneLayout extends GraphLayout { otherIndex > swimlaneIndex || ((!directed || isSource) && otherIndex === swimlaneIndex) ) { - currentComp = this.traverse( - otherVertex, + currentComp = this.traverse({ + vertex: otherVertex, directed, - edges[i], + edge: edges[i], allVertices, currentComp, hierarchyVertices, filledVertexSet, - otherIndex - ); + swimlaneIndex: otherIndex, + func: null, + visited: null + }); } } } else if (currentComp[vertexID] == null) { diff --git a/packages/ts-example/tsconfig.json b/packages/ts-example/tsconfig.json index 2b114a62f..05f80b913 100644 --- a/packages/ts-example/tsconfig.json +++ b/packages/ts-example/tsconfig.json @@ -13,9 +13,7 @@ "noEmit": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noImplicitReturns": true, - // TODO required because some type definitions in the @maxgraph/core package generate errors: https://github.com/maxGraph/maxGraph/issues/96 - "skipLibCheck": true + "noImplicitReturns": true }, "include": ["src"] } From 133199bf478afbfe3580a7de46e42ab3154c91dd Mon Sep 17 00:00:00 2001 From: Thomas Bouffard <27200110+tbouffard@users.noreply.github.com> Date: Sun, 9 Oct 2022 18:56:53 +0200 Subject: [PATCH 2/4] docs: no more skipLibCheck needed for TS integration --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 754b3c766..818aa595b 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,6 @@ For more details, have a look at the [storybook stories](packages/html/stories). maxGraph is written in TypeScript and provides type definitions so maxGraph can be easily integrated into TypeScript projects. -**WARN**: some definitions are currently buggy, so please set `skipLibCheck` to `true` in the `tsconfig.json` file of your project. -For more details, see issues [#96](https://github.com/maxGraph/maxGraph/issues/96) and [#105](https://github.com/maxGraph/maxGraph/issues/105#issuecomment-1240640369). - ## Support From 7c4b1111eeaa7d40123997d3782cd4fefe8a7a8d Mon Sep 17 00:00:00 2001 From: Thomas Bouffard <27200110+tbouffard@users.noreply.github.com> Date: Sun, 9 Oct 2022 19:02:24 +0200 Subject: [PATCH 3/4] Apply prettier rules on layout types --- packages/core/src/types.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 9ece5e220..5ca9b5dcd 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -329,15 +329,13 @@ export interface GraphLayoutTraverseArgs { visited: Dictionary | null; } -export interface HierarchicalGraphLayoutTraverseArgs - extends GraphLayoutTraverseArgs{ - allVertices: { [key: string]: Cell } | null, - currentComp: { [key: string]: Cell | null }, - hierarchyVertices: GraphHierarchyNode[], - filledVertexSet: { [key: string]: Cell } | null +export interface HierarchicalGraphLayoutTraverseArgs extends GraphLayoutTraverseArgs { + allVertices: { [key: string]: Cell } | null; + currentComp: { [key: string]: Cell | null }; + hierarchyVertices: GraphHierarchyNode[]; + filledVertexSet: { [key: string]: Cell } | null; } -export interface SwimlaneGraphLayoutTraverseArgs - extends HierarchicalGraphLayoutTraverseArgs{ - swimlaneIndex: number +export interface SwimlaneGraphLayoutTraverseArgs extends HierarchicalGraphLayoutTraverseArgs { + swimlaneIndex: number; } From c4f537203b66c68e48d089f5afeb82e1a5a12097 Mon Sep 17 00:00:00 2001 From: Thomas Bouffard <27200110+tbouffard@users.noreply.github.com> Date: Sun, 9 Oct 2022 19:08:12 +0200 Subject: [PATCH 4/4] Move layout types to a dedicated types file These types are only used in the layout classes, so keep them located closed in the folder where they are used. --- packages/core/src/types.ts | 23 ----------- packages/core/src/view/layout/GraphLayout.ts | 8 ++-- .../src/view/layout/HierarchicalLayout.ts | 12 +++--- .../core/src/view/layout/SwimlaneLayout.ts | 4 +- packages/core/src/view/layout/types.ts | 38 +++++++++++++++++++ 5 files changed, 50 insertions(+), 35 deletions(-) create mode 100644 packages/core/src/view/layout/types.ts diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 5ca9b5dcd..4e3a4dfa3 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -15,7 +15,6 @@ limitations under the License. */ import { DIRECTION } from './util/Constants'; -import Dictionary from './util/Dictionary'; import type Cell from './view/cell/Cell'; import type CellState from './view/cell/CellState'; import EventSource from './view/event/EventSource'; @@ -23,7 +22,6 @@ import type InternalMouseEvent from './view/event/InternalMouseEvent'; import type Shape from './view/geometry/Shape'; import type { Graph } from './view/Graph'; import type ImageBox from './view/image/ImageBox'; -import GraphHierarchyNode from './view/layout/datatypes/GraphHierarchyNode'; export type CellMap = { [id: string]: Cell; @@ -318,24 +316,3 @@ export interface PopupMenuItem extends HTMLElement { activeRow: PopupMenuItem | null; eventReceiver: HTMLElement | null; } - -// GraphLayout - -export interface GraphLayoutTraverseArgs { - vertex: Cell | null; - directed: boolean | null; - func: Function | null; - edge: Cell | null; - visited: Dictionary | null; -} - -export interface HierarchicalGraphLayoutTraverseArgs extends GraphLayoutTraverseArgs { - allVertices: { [key: string]: Cell } | null; - currentComp: { [key: string]: Cell | null }; - hierarchyVertices: GraphHierarchyNode[]; - filledVertexSet: { [key: string]: Cell } | null; -} - -export interface SwimlaneGraphLayoutTraverseArgs extends HierarchicalGraphLayoutTraverseArgs { - swimlaneIndex: number; -} diff --git a/packages/core/src/view/layout/GraphLayout.ts b/packages/core/src/view/layout/GraphLayout.ts index e3b78975b..38005c61e 100644 --- a/packages/core/src/view/layout/GraphLayout.ts +++ b/packages/core/src/view/layout/GraphLayout.ts @@ -22,7 +22,7 @@ import Geometry from '../geometry/Geometry'; import Point from '../geometry/Point'; import { Graph } from '../Graph'; import Cell from '../cell/Cell'; -import { GraphLayoutTraverseArgs } from '../../types'; +import { GraphLayoutTraverseArgs } from './types'; /** * @class GraphLayout @@ -163,9 +163,9 @@ class GraphLayout { const next = this.graph.view.getVisibleTerminal(e, !isSource); this.traverse({ vertex: next, - directed, - func, - edge: e, + directed, + func, + edge: e, visited }); } diff --git a/packages/core/src/view/layout/HierarchicalLayout.ts b/packages/core/src/view/layout/HierarchicalLayout.ts index e52a86355..9d3c30e2d 100644 --- a/packages/core/src/view/layout/HierarchicalLayout.ts +++ b/packages/core/src/view/layout/HierarchicalLayout.ts @@ -27,7 +27,7 @@ import MedianHybridCrossingReduction from './hierarchical/MedianHybridCrossingRe import CoordinateAssignment from './hierarchical/CoordinateAssignment'; import { Graph } from '../../view/Graph'; import Cell from '../../view/cell/Cell'; -import { HierarchicalGraphLayoutTraverseArgs } from '../../types'; +import { HierarchicalGraphLayoutTraverseArgs } from './types'; /** * A hierarchical layout algorithm. @@ -605,11 +605,11 @@ class HierarchicalLayout extends GraphLayout { * @param allVertices Array of cell paths for the visited cells. */ traverse({ - vertex, - directed, - allVertices, - currentComp, - hierarchyVertices, + vertex, + directed, + allVertices, + currentComp, + hierarchyVertices, filledVertexSet }: HierarchicalGraphLayoutTraverseArgs) { if (vertex != null && allVertices != null) { diff --git a/packages/core/src/view/layout/SwimlaneLayout.ts b/packages/core/src/view/layout/SwimlaneLayout.ts index bf7b891ec..7e2666b9f 100644 --- a/packages/core/src/view/layout/SwimlaneLayout.ts +++ b/packages/core/src/view/layout/SwimlaneLayout.ts @@ -29,7 +29,7 @@ import CoordinateAssignment from './hierarchical/CoordinateAssignment'; import { Graph } from '../Graph'; import Cell from '../cell/Cell'; import Geometry from '../../view/geometry/Geometry'; -import { SwimlaneGraphLayoutTraverseArgs } from '../../types'; +import { SwimlaneGraphLayoutTraverseArgs } from './types'; /** * A hierarchical layout algorithm. @@ -806,7 +806,7 @@ class SwimlaneLayout extends GraphLayout { swimlaneIndex: otherIndex, func: null, visited: null - }); + }); } } } else if (currentComp[vertexID] == null) { diff --git a/packages/core/src/view/layout/types.ts b/packages/core/src/view/layout/types.ts new file mode 100644 index 000000000..da2da69b9 --- /dev/null +++ b/packages/core/src/view/layout/types.ts @@ -0,0 +1,38 @@ +/* +Copyright 2022-present The maxGraph project Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import type Cell from '../cell/Cell'; +import type Dictionary from '../../util/Dictionary'; +import type GraphHierarchyNode from './datatypes/GraphHierarchyNode'; + +export interface GraphLayoutTraverseArgs { + vertex: Cell | null; + directed: boolean | null; + func: Function | null; + edge: Cell | null; + visited: Dictionary | null; +} + +export interface HierarchicalGraphLayoutTraverseArgs extends GraphLayoutTraverseArgs { + allVertices: { [key: string]: Cell } | null; + currentComp: { [key: string]: Cell | null }; + hierarchyVertices: GraphHierarchyNode[]; + filledVertexSet: { [key: string]: Cell } | null; +} + +export interface SwimlaneGraphLayoutTraverseArgs extends HierarchicalGraphLayoutTraverseArgs { + swimlaneIndex: number; +}