Merge branch 'development' into development

development
Thomas Bouffard 2022-10-22 10:41:32 +02:00 committed by GitHub
commit ef76a1db87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 175 additions and 155 deletions

View File

@ -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. 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 ## Support

View File

@ -508,7 +508,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
/** /**
* Private helper function to create SVG elements * Private helper function to create SVG elements
*/ */
// createGradientId(start: string, end: string, alpha1: string, alpha2: string, direction: string): string;
createGradientId( createGradientId(
start: string, start: string,
end: string, end: string,
@ -562,13 +561,11 @@ class SvgCanvas2D extends AbstractCanvas2D {
alpha2: number, alpha2: number,
direction: DirectionValue direction: DirectionValue
) { ) {
if (!this.root) return;
const id = this.createGradientId(start, end, alpha1, alpha2, direction); const id = this.createGradientId(start, end, alpha1, alpha2, direction);
let gradient: Gradient | null = this.gradients[id]; let gradient: Gradient | null = this.gradients[id];
if (!gradient) { if (!gradient) {
const svg = this.root.ownerSVGElement; const svg = this.root!.ownerSVGElement;
let counter = 0; let counter = 0;
let tmpId = `${id}-${counter}`; let tmpId = `${id}-${counter}`;
@ -649,8 +646,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
* Private helper function to create SVG elements * Private helper function to create SVG elements
*/ */
addNode(filled: boolean, stroked: boolean) { addNode(filled: boolean, stroked: boolean) {
if (!this.root) return;
const { node } = this; const { node } = this;
const s = this.state; const s = this.state;
@ -689,12 +684,12 @@ class SvgCanvas2D extends AbstractCanvas2D {
} }
if (s.shadow) { if (s.shadow) {
this.root.appendChild(this.createShadow(node)); this.root!.appendChild(this.createShadow(node));
} }
// Adds stroke tolerance // Adds stroke tolerance
if (this.strokeTolerance > 0 && !filled) { if (this.strokeTolerance > 0 && !filled) {
this.root.appendChild(this.createTolerance(node)); this.root!.appendChild(this.createTolerance(node));
} }
// Adds pointer events // Adds pointer events
@ -717,7 +712,7 @@ class SvgCanvas2D extends AbstractCanvas2D {
node.getAttribute('pointer-events') !== NONE node.getAttribute('pointer-events') !== NONE
) { ) {
// LATER: Update existing DOM for performance // LATER: Update existing DOM for performance
this.root.appendChild(node); this.root!.appendChild(node);
} }
this.node = null; this.node = null;
@ -728,12 +723,10 @@ class SvgCanvas2D extends AbstractCanvas2D {
* Transfers the stroke attributes from <state> to <node>. * Transfers the stroke attributes from <state> to <node>.
*/ */
updateFill() { updateFill() {
if (!this.node) return;
const s = this.state; const s = this.state;
if (s.alpha < 1 || s.fillAlpha < 1) { if (s.alpha < 1 || s.fillAlpha < 1) {
this.node.setAttribute('fill-opacity', String(s.alpha * s.fillAlpha)); this.node!.setAttribute('fill-opacity', String(s.alpha * s.fillAlpha));
} }
if (s.fillColor !== NONE) { if (s.fillColor !== NONE) {
@ -749,12 +742,12 @@ class SvgCanvas2D extends AbstractCanvas2D {
if (this.root?.ownerDocument === document && useAbsoluteIds) { if (this.root?.ownerDocument === document && useAbsoluteIds) {
// Workaround for no fill with base tag in page (escape brackets) // Workaround for no fill with base tag in page (escape brackets)
const base = this.getBaseUrl().replace(/([\(\)])/g, '\\$1'); const base = this.getBaseUrl().replace(/([\(\)])/g, '\\$1');
this.node.setAttribute('fill', `url(${base}#${id})`); this.node!.setAttribute('fill', `url(${base}#${id})`);
} else { } else {
this.node.setAttribute('fill', `url(#${id})`); this.node!.setAttribute('fill', `url(#${id})`);
} }
} else { } else {
this.node.setAttribute('fill', s.fillColor.toLowerCase()); this.node!.setAttribute('fill', s.fillColor.toLowerCase());
} }
} }
} }
@ -762,7 +755,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
/** /**
* Returns the current stroke width (>= 1), ie. max(1, this.format(this.state.strokeWidth * this.state.scale)). * Returns the current stroke width (>= 1), ie. max(1, this.format(this.state.strokeWidth * this.state.scale)).
*/ */
// getCurrentStrokeWidth(): number;
getCurrentStrokeWidth() { getCurrentStrokeWidth() {
return Math.max( return Math.max(
this.minStrokeWidth, this.minStrokeWidth,
@ -774,29 +766,27 @@ class SvgCanvas2D extends AbstractCanvas2D {
* Transfers the stroke attributes from {@link mxAbstractCanvas2D.state} to {@link node}. * Transfers the stroke attributes from {@link mxAbstractCanvas2D.state} to {@link node}.
*/ */
updateStroke() { updateStroke() {
if (!this.node) return;
const s = this.state; const s = this.state;
if (s.strokeColor && s.strokeColor !== NONE) { if (s.strokeColor && s.strokeColor !== NONE) {
this.node.setAttribute('stroke', s.strokeColor.toLowerCase()); this.node!.setAttribute('stroke', s.strokeColor.toLowerCase());
} }
if (s.alpha < 1 || s.strokeAlpha < 1) { if (s.alpha < 1 || s.strokeAlpha < 1) {
this.node.setAttribute('stroke-opacity', String(s.alpha * s.strokeAlpha)); this.node!.setAttribute('stroke-opacity', String(s.alpha * s.strokeAlpha));
} }
const sw = this.getCurrentStrokeWidth(); const sw = this.getCurrentStrokeWidth();
if (sw !== 1) { if (sw !== 1) {
this.node.setAttribute('stroke-width', String(sw)); this.node!.setAttribute('stroke-width', String(sw));
} }
if (this.node.nodeName === 'path') { if (this.node!.nodeName === 'path') {
this.updateStrokeAttributes(); this.updateStrokeAttributes();
} }
if (s.dashed) { if (s.dashed) {
this.node.setAttribute( this.node!.setAttribute(
'stroke-dasharray', 'stroke-dasharray',
this.createDashPattern((s.fixDash ? 1 : s.strokeWidth) * s.scale) this.createDashPattern((s.fixDash ? 1 : s.strokeWidth) * s.scale)
); );
@ -807,13 +797,11 @@ class SvgCanvas2D extends AbstractCanvas2D {
* Transfers the stroke attributes from {@link mxAbstractCanvas2D.state} to {@link node}. * Transfers the stroke attributes from {@link mxAbstractCanvas2D.state} to {@link node}.
*/ */
updateStrokeAttributes() { updateStrokeAttributes() {
if (!this.node) return;
const s = this.state; const s = this.state;
// Linejoin miter is default in SVG // Linejoin miter is default in SVG
if (s.lineJoin && s.lineJoin !== 'miter') { if (s.lineJoin && s.lineJoin !== 'miter') {
this.node.setAttribute('stroke-linejoin', s.lineJoin); this.node!.setAttribute('stroke-linejoin', s.lineJoin);
} }
if (s.lineCap) { if (s.lineCap) {
@ -826,13 +814,13 @@ class SvgCanvas2D extends AbstractCanvas2D {
// Linecap butt is default in SVG // Linecap butt is default in SVG
if (value !== 'butt') { if (value !== 'butt') {
this.node.setAttribute('stroke-linecap', value); this.node!.setAttribute('stroke-linecap', value);
} }
} }
// Miterlimit 10 is default in our document // Miterlimit 10 is default in our document
if (s.miterLimit != null && (!this.styleEnabled || s.miterLimit !== 10)) { if (s.miterLimit != null && (!this.styleEnabled || s.miterLimit !== 10)) {
this.node.setAttribute('stroke-miterlimit', String(s.miterLimit)); this.node!.setAttribute('stroke-miterlimit', String(s.miterLimit));
} }
} }
@ -858,7 +846,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
/** /**
* Creates a hit detection tolerance shape for the given node. * Creates a hit detection tolerance shape for the given node.
*/ */
// createTolerance(node: Element): Element;
createTolerance(node: SVGElement) { createTolerance(node: SVGElement) {
const tol = node.cloneNode(true) as SVGElement; const tol = node.cloneNode(true) as SVGElement;
const sw = parseFloat(tol.getAttribute('stroke-width') || '1') + this.strokeTolerance; const sw = parseFloat(tol.getAttribute('stroke-width') || '1') + this.strokeTolerance;
@ -909,8 +896,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
* Experimental implementation for hyperlinks. * Experimental implementation for hyperlinks.
*/ */
setLink(link: string) { setLink(link: string) {
if (!this.root) return;
if (!link) { if (!link) {
this.root = this.originalRoot; this.root = this.originalRoot;
} else { } else {
@ -920,13 +905,13 @@ class SvgCanvas2D extends AbstractCanvas2D {
// Workaround for implicit namespace handling in HTML5 export, IE adds NS1 namespace so use code below // Workaround for implicit namespace handling in HTML5 export, IE adds NS1 namespace so use code below
// in all IE versions except quirks mode. KNOWN: Adds xlink namespace to each image tag in output. // in all IE versions except quirks mode. KNOWN: Adds xlink namespace to each image tag in output.
if (node.setAttributeNS == null || this.root.ownerDocument !== document) { if (node.setAttributeNS == null || this.root!.ownerDocument !== document) {
node.setAttribute('xlink:href', link); node.setAttribute('xlink:href', link);
} else { } else {
node.setAttributeNS(NS_XLINK, 'xlink:href', link); node.setAttributeNS(NS_XLINK, 'xlink:href', link);
} }
this.root.appendChild(node); this.root!.appendChild(node);
this.root = node; this.root = node;
} }
} }
@ -981,7 +966,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
/** /**
* Extends superclass to create path. * Extends superclass to create path.
*/ */
// begin(): void;
begin() { begin() {
super.begin(); super.begin();
this.node = this.createElement('path'); this.node = this.createElement('path');
@ -1005,16 +989,14 @@ class SvgCanvas2D extends AbstractCanvas2D {
* Private helper function to create SVG elements * Private helper function to create SVG elements
*/ */
roundrect(x: number, y: number, w: number, h: number, dx: number, dy: number) { roundrect(x: number, y: number, w: number, h: number, dx: number, dy: number) {
if (!this.node) return;
this.rect(x, y, w, h); this.rect(x, y, w, h);
if (dx > 0) { if (dx > 0) {
this.node.setAttribute('rx', String(this.format(dx * this.state.scale))); this.node!.setAttribute('rx', String(this.format(dx * this.state.scale)));
} }
if (dy > 0) { if (dy > 0) {
this.node.setAttribute('ry', String(this.format(dy * this.state.scale))); this.node!.setAttribute('ry', String(this.format(dy * this.state.scale)));
} }
} }
@ -1045,8 +1027,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
flipH = false, flipH = false,
flipV = false flipV = false
) { ) {
if (!this.root) return;
src = this.converter.convert(src); src = this.converter.convert(src);
const s = this.state; const s = this.state;
@ -1092,7 +1072,7 @@ class SvgCanvas2D extends AbstractCanvas2D {
dy = -h - 2 * y; dy = -h - 2 * y;
} }
// Adds image tansformation to existing transform // Adds image transformation to existing transform
tr += `scale(${sx},${sy})translate(${dx * s.scale},${dy * s.scale})`; tr += `scale(${sx},${sy})translate(${dx * s.scale},${dy * s.scale})`;
} }
@ -1104,7 +1084,7 @@ class SvgCanvas2D extends AbstractCanvas2D {
node.setAttribute('pointer-events', 'none'); node.setAttribute('pointer-events', 'none');
} }
this.root.appendChild(node); this.root!.appendChild(node);
} }
/** /**
@ -1134,8 +1114,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
* Note: signature changed in mxgraph 4.1.0 * Note: signature changed in mxgraph 4.1.0
*/ */
createDiv(str: string | HTMLElement) { createDiv(str: string | HTMLElement) {
if (!this.root) return;
let val = str; let val = str;
if (!isNode(val)) { if (!isNode(val)) {
@ -1152,7 +1130,7 @@ class SvgCanvas2D extends AbstractCanvas2D {
const div3 = div2.cloneNode(false); const div3 = div2.cloneNode(false);
// Creates a copy for export // Creates a copy for export
if (this.root.ownerDocument !== document) { if (this.root!.ownerDocument !== document) {
div2.appendChild(n.cloneNode(true)); div2.appendChild(n.cloneNode(true));
} else { } else {
div2.appendChild(n); div2.appendChild(n);
@ -1390,7 +1368,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
/** /**
* Private helper function to create SVG elements * Private helper function to create SVG elements
*/ */
// getTextCss(): string;
getTextCss() { getTextCss() {
const s = this.state; const s = this.state;
const lh = ABSOLUTE_LINE_HEIGHT const lh = ABSOLUTE_LINE_HEIGHT
@ -1450,8 +1427,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
rotation = 0, rotation = 0,
dir: TextDirectionValue dir: TextDirectionValue
) { ) {
if (!this.root) return;
if (this.textEnabled && str != null) { if (this.textEnabled && str != null) {
rotation = rotation != null ? rotation : 0; rotation = rotation != null ? rotation : 0;
@ -1479,7 +1454,7 @@ class SvgCanvas2D extends AbstractCanvas2D {
rotation, rotation,
dir, dir,
div, div,
this.root this.root!
); );
} }
} else { } else {
@ -1552,8 +1527,6 @@ class SvgCanvas2D extends AbstractCanvas2D {
rotation = 0, rotation = 0,
dir: TextDirectionValue dir: TextDirectionValue
) { ) {
if (!this.root) return;
const s = this.state; const s = this.state;
const size = s.fontSize; const size = s.fontSize;
const node = this.createElement('g'); const node = this.createElement('g');
@ -1604,13 +1577,13 @@ class SvgCanvas2D extends AbstractCanvas2D {
this.defs.appendChild(c); this.defs.appendChild(c);
} else { } else {
// Makes sure clip is removed with referencing node // Makes sure clip is removed with referencing node
this.root.appendChild(c); this.root!.appendChild(c);
} }
if ( if (
!Client.IS_CHROMEAPP && !Client.IS_CHROMEAPP &&
!Client.IS_EDGE && !Client.IS_EDGE &&
this.root.ownerDocument === document this.root!.ownerDocument === document
) { ) {
// Workaround for potential base tag // Workaround for potential base tag
const base = this.getBaseUrl().replace(/([\(\)])/g, '\\$1'); const base = this.getBaseUrl().replace(/([\(\)])/g, '\\$1');
@ -1684,7 +1657,7 @@ class SvgCanvas2D extends AbstractCanvas2D {
cy += lh; cy += lh;
} }
this.root.appendChild(node); this.root!.appendChild(node);
this.addTextBackground( this.addTextBackground(
node, node,
str, str,

View File

@ -22,6 +22,7 @@ import Geometry from '../geometry/Geometry';
import Point from '../geometry/Point'; import Point from '../geometry/Point';
import { Graph } from '../Graph'; import { Graph } from '../Graph';
import Cell from '../cell/Cell'; import Cell from '../cell/Cell';
import { GraphLayoutTraverseArgs } from './types';
/** /**
* @class GraphLayout * @class GraphLayout
@ -141,13 +142,7 @@ class GraphLayout {
* null for the first step of the traversal. * null for the first step of the traversal.
* @param visited Optional {@link Dictionary} of cell paths for the visited cells. * @param visited Optional {@link Dictionary} of cell paths for the visited cells.
*/ */
traverse( traverse({vertex, directed, func, edge, visited}: GraphLayoutTraverseArgs): void {
vertex: Cell,
directed?: boolean,
func?: Function,
edge?: Cell,
visited?: Dictionary<Cell, boolean>
): void {
if (func != null && vertex != null) { if (func != null && vertex != null) {
directed = directed != null ? directed : true; directed = directed != null ? directed : true;
visited = visited || new Dictionary(); visited = visited || new Dictionary();
@ -161,12 +156,18 @@ class GraphLayout {
if (edgeCount > 0) { if (edgeCount > 0) {
for (let i = 0; i < edgeCount; i += 1) { 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; const isSource = e.getTerminal(true) === vertex;
if (!directed || isSource) { if (!directed || isSource) {
const next = this.graph.view.getVisibleTerminal(e, !isSource); const next = this.graph.view.getVisibleTerminal(e, !isSource);
this.traverse(<Cell>next, directed, func, e, visited); this.traverse({
vertex: next,
directed,
func,
edge: e,
visited
});
} }
} }
} }

View File

@ -27,7 +27,7 @@ import MedianHybridCrossingReduction from './hierarchical/MedianHybridCrossingRe
import CoordinateAssignment from './hierarchical/CoordinateAssignment'; import CoordinateAssignment from './hierarchical/CoordinateAssignment';
import { Graph } from '../../view/Graph'; import { Graph } from '../../view/Graph';
import Cell from '../../view/cell/Cell'; import Cell from '../../view/cell/Cell';
import GraphHierarchyNode from './datatypes/GraphHierarchyNode'; import { HierarchicalGraphLayoutTraverseArgs } from './types';
/** /**
* A hierarchical layout algorithm. * A hierarchical layout algorithm.
@ -444,15 +444,17 @@ class HierarchicalLayout extends GraphLayout {
const vertexSet = Object(); const vertexSet = Object();
hierarchyVertices.push(vertexSet); hierarchyVertices.push(vertexSet);
this.traverse( this.traverse({
candidateRoots[i], vertex: candidateRoots[i],
true, directed: true,
null, edge: null,
allVertexSet, allVertices: allVertexSet,
vertexSet, currentComp: vertexSet,
hierarchyVertices, hierarchyVertices: hierarchyVertices,
filledVertexSet filledVertexSet: filledVertexSet,
); func: null,
visited: null
});
} }
for (let i = 0; i < candidateRoots.length; i += 1) { for (let i = 0; i < candidateRoots.length; i += 1) {
@ -477,15 +479,17 @@ class HierarchicalLayout extends GraphLayout {
const vertexSet = Object(); const vertexSet = Object();
hierarchyVertices.push(vertexSet); hierarchyVertices.push(vertexSet);
this.traverse( this.traverse({
roots[i], vertex: roots[i],
true, directed: true,
null, edge: null,
allVertexSet, allVertices: allVertexSet,
vertexSet, currentComp: vertexSet,
hierarchyVertices, hierarchyVertices: hierarchyVertices,
null filledVertexSet: null,
); func: null,
visited: null
});
} }
} }
@ -600,16 +604,14 @@ class HierarchicalLayout extends GraphLayout {
* null for the first step of the traversal. * null for the first step of the traversal.
* @param allVertices Array of cell paths for the visited cells. * @param allVertices Array of cell paths for the visited cells.
*/ */
// @ts-ignore traverse({
traverse( vertex,
vertex: Cell, directed,
directed: boolean = false, allVertices,
edge: Cell | null = null, currentComp,
allVertices: { [key: string]: Cell } | null = null, hierarchyVertices,
currentComp: { [key: string]: Cell | null }, filledVertexSet
hierarchyVertices: GraphHierarchyNode[], }: HierarchicalGraphLayoutTraverseArgs) {
filledVertexSet: { [key: string]: Cell } | null = null
) {
if (vertex != null && allVertices != null) { if (vertex != null && allVertices != null) {
// Has this vertex been seen before in any traversal // Has this vertex been seen before in any traversal
// And if the filled vertex set is populated, only // And if the filled vertex set is populated, only
@ -666,15 +668,17 @@ class HierarchicalLayout extends GraphLayout {
} }
if (netCount >= 0) { if (netCount >= 0) {
currentComp = this.traverse( currentComp = this.traverse({
<Cell>next, vertex: next,
directed, directed,
edges[i], edge: edges[i],
allVertices, allVertices,
currentComp, currentComp,
hierarchyVertices, hierarchyVertices,
filledVertexSet filledVertexSet,
); func: null,
visited: null
});
} }
} }
} }

View File

@ -29,7 +29,7 @@ import CoordinateAssignment from './hierarchical/CoordinateAssignment';
import { Graph } from '../Graph'; import { Graph } from '../Graph';
import Cell from '../cell/Cell'; import Cell from '../cell/Cell';
import Geometry from '../../view/geometry/Geometry'; import Geometry from '../../view/geometry/Geometry';
import GraphHierarchyNode from './datatypes/GraphHierarchyNode'; import { SwimlaneGraphLayoutTraverseArgs } from './types';
/** /**
* A hierarchical layout algorithm. * A hierarchical layout algorithm.
@ -579,16 +579,18 @@ class SwimlaneLayout extends GraphLayout {
const vertexSet = Object(); const vertexSet = Object();
hierarchyVertices.push(vertexSet); hierarchyVertices.push(vertexSet);
this.traverse( this.traverse({
candidateRoots[i], vertex: candidateRoots[i],
true, directed: true,
null, edge: null,
allVertexSet, allVertices: allVertexSet,
vertexSet, currentComp: vertexSet,
hierarchyVertices, hierarchyVertices,
filledVertexSet, filledVertexSet,
laneCounter swimlaneIndex: laneCounter,
); func: null,
visited: null
});
} }
for (let i = 0; i < candidateRoots.length; i += 1) { 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) { for (let i = 0; i < roots.length; i += 1) {
const vertexSet = Object(); const vertexSet = Object();
hierarchyVertices.push(vertexSet); hierarchyVertices.push(vertexSet);
this.traverse( this.traverse({
roots[i], vertex: roots[i],
true, directed: true,
null, edge: null,
allVertexSet, allVertices: allVertexSet,
vertexSet, currentComp: vertexSet,
hierarchyVertices, hierarchyVertices,
null, filledVertexSet: null,
i swimlaneIndex: i,
); // CHECK THIS PARAM!! ==================== 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 allVertices Array of cell paths for the visited cells.
* @param swimlaneIndex the laid out order index of the swimlane vertex is contained in * @param swimlaneIndex the laid out order index of the swimlane vertex is contained in
*/ */
// @ts-ignore traverse({
traverse( vertex,
vertex: Cell | null = null, directed,
directed: boolean, allVertices,
edge: Cell | null, currentComp,
allVertices: { [key: string]: Cell } | null = null, hierarchyVertices,
currentComp: { [key: string]: Cell }, filledVertexSet,
hierarchyVertices: GraphHierarchyNode[], swimlaneIndex
filledVertexSet: { [key: string]: Cell } | null = null, }: SwimlaneGraphLayoutTraverseArgs) {
swimlaneIndex: number
) {
if (vertex != null && allVertices != null) { if (vertex != null && allVertices != null) {
// Has this vertex been seen before in any traversal // Has this vertex been seen before in any traversal
// And if the filled vertex set is populated, only // And if the filled vertex set is populated, only
@ -764,7 +766,6 @@ class SwimlaneLayout extends GraphLayout {
} }
const edges = this.getEdges(vertex); const edges = this.getEdges(vertex);
const { model } = this.graph;
for (let i = 0; i < edges.length; i += 1) { for (let i = 0; i < edges.length; i += 1) {
let otherVertex = this.getVisibleTerminal(edges[i], true); let otherVertex = this.getVisibleTerminal(edges[i], true);
@ -775,16 +776,15 @@ class SwimlaneLayout extends GraphLayout {
} }
let otherIndex = 0; let otherIndex = 0;
const swimlanes = this.swimlanes as Cell[];
// Get the swimlane index of the other terminal // Get the swimlane index of the other terminal
for (otherIndex = 0; otherIndex < swimlanes.length; otherIndex++) { for (otherIndex = 0; otherIndex < this.swimlanes!.length; otherIndex++) {
if (swimlanes[otherIndex].isAncestor(otherVertex)) { if (this.swimlanes![otherIndex].isAncestor(otherVertex)) {
break; break;
} }
} }
if (otherIndex >= swimlanes.length) { if (otherIndex >= this.swimlanes!.length) {
continue; continue;
} }
@ -795,16 +795,18 @@ class SwimlaneLayout extends GraphLayout {
otherIndex > swimlaneIndex || otherIndex > swimlaneIndex ||
((!directed || isSource) && otherIndex === swimlaneIndex) ((!directed || isSource) && otherIndex === swimlaneIndex)
) { ) {
currentComp = this.traverse( currentComp = this.traverse({
<Cell>otherVertex, vertex: otherVertex,
directed, directed,
edges[i], edge: edges[i],
allVertices, allVertices,
currentComp, currentComp,
hierarchyVertices, hierarchyVertices,
filledVertexSet, filledVertexSet,
otherIndex swimlaneIndex: otherIndex,
); func: null,
visited: null
});
} }
} }
} else if (currentComp[vertexID] == null) { } else if (currentComp[vertexID] == null) {

View File

@ -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<Cell, boolean> | 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;
}

View File

@ -29,7 +29,7 @@ import type { CellStyle } from '../../types';
declare module '../Graph' { declare module '../Graph' {
interface Graph { interface Graph {
resetEdgesOnResize: boolean; resetEdgesOnResize: boolean;
resetEdgesOnMove: false; resetEdgesOnMove: boolean;
resetEdgesOnConnect: boolean; resetEdgesOnConnect: boolean;
connectableEdges: boolean; connectableEdges: boolean;
allowDanglingEdges: boolean; allowDanglingEdges: boolean;

View File

@ -18,8 +18,7 @@ limitations under the License.
import { import {
Graph, Graph,
SelectionHandler, SelectionHandler,
InternalEvent, eventUtils,
constants,
EdgeHandler, EdgeHandler,
EdgeStyle, EdgeStyle,
RubberBandHandler, RubberBandHandler,
@ -47,12 +46,9 @@ const Template = ({ label, ...args }) => {
container.style.background = 'url(/images/grid.gif)'; container.style.background = 'url(/images/grid.gif)';
container.style.cursor = 'default'; container.style.cursor = 'default';
// Enables guides
SelectionHandler.prototype.guidesEnabled = true;
// Alt disables guides // Alt disables guides
SelectionHandler.prototype.useGuidesForEvent = function (me) { SelectionHandler.prototype.useGuidesForEvent = function (me) {
return !InternalEvent.isAltDown(me.getEvent()); return !eventUtils.isAltDown(me.getEvent());
}; };
// Defines the guides to be red (default) // Defines the guides to be red (default)
@ -69,6 +65,11 @@ const Template = ({ label, ...args }) => {
graph.setConnectable(true); graph.setConnectable(true);
graph.gridSize = 30; graph.gridSize = 30;
// Enables guides
const selectionHandler = graph.getPlugin('SelectionHandler');
if (selectionHandler)
selectionHandler.guidesEnabled = true;
// Changes the default style for edges "in-place" and assigns // Changes the default style for edges "in-place" and assigns
// an alternate edge style which is applied in Graph.flip // an alternate edge style which is applied in Graph.flip
// when the user double clicks on the adjustment control point // when the user double clicks on the adjustment control point

View File

@ -62,7 +62,7 @@ const Template = ({ label, ...args }) => {
if (cell != null) { if (cell != null) {
const overlays = graph.getCellOverlays(cell); const overlays = graph.getCellOverlays(cell);
if (overlays == null) { if (overlays.length == 0) {
// Creates a new overlay with an image and a tooltip // Creates a new overlay with an image and a tooltip
const overlay = new CellOverlay( const overlay = new CellOverlay(
new ImageBox('/images/check.png', 16, 16), new ImageBox('/images/check.png', 16, 16),

View File

@ -61,7 +61,7 @@ const Template = ({ label, ...args }) => {
const f = () => { const f = () => {
const overlays = graph.getCellOverlays(v1); const overlays = graph.getCellOverlays(v1);
if (overlays == null) { if (overlays.length == 0) {
graph.removeCellOverlays(v2); graph.removeCellOverlays(v2);
graph.setCellWarning(v1, 'Tooltip'); graph.setCellWarning(v1, 'Tooltip');
} else { } else {

View File

@ -60,7 +60,7 @@ const Template = ({ label, ...args }) => {
const isVisible = function () { const isVisible = function () {
// TODO super cannot be used here // TODO super cannot be used here
// let result = super.isVisible(); // let result = super.isVisible();
let result; let result = true;
if (result && this.value != null) { if (result && this.value != null) {
result = result =
(showOne && this.value == '1') || (showOne && this.value == '1') ||

View File

@ -2,8 +2,15 @@
Initialized from https://github.com/vitejs/vite/tree/v2.9.8/packages/create-vite/template-vanilla-ts Initialized from https://github.com/vitejs/vite/tree/v2.9.8/packages/create-vite/template-vanilla-ts
Do not forget to initialize all packages (you may also need to build the maxgraph@core package) ## Setup
Initialize all packages
> From the repository root, run `npm install`. > From the repository root, run `npm install`.
Build maxgraph@core
> From the `packages/core` directory, run `npm run generate-esm`.
## Run
Run `npm run dev` and go to http://localhost:5173/ Run `npm run dev` and go to http://localhost:5173/

View File

@ -29,8 +29,7 @@ class CustomRectangleShape extends RectangleShape {
constructor(bounds: Rectangle, fill: ColorValue, stroke: ColorValue) { constructor(bounds: Rectangle, fill: ColorValue, stroke: ColorValue) {
super(bounds, fill, stroke, 3); super(bounds, fill, stroke, 3);
// TODO if set, the shape is not painted this.isRounded = true; // force rounded shape
// this.isRounded = true; // force rounded shape
} }
paintBackground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number): void { paintBackground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number): void {

View File

@ -13,9 +13,7 @@
"noEmit": true, "noEmit": true,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"noImplicitReturns": 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
}, },
"include": ["src"] "include": ["src"]
} }