Merge branch 'development' into development
commit
ef76a1db87
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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') ||
|
||||||
|
|
|
@ -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/
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue