diff --git a/packages/html/stories/Stencils.stories.js b/packages/html/stories/Stencils.stories.ts
similarity index 74%
rename from packages/html/stories/Stencils.stories.js
rename to packages/html/stories/Stencils.stories.ts
index 1be86264a1..9a8ff8b91c 100644
--- a/packages/html/stories/Stencils.stories.js
+++ b/packages/html/stories/Stencils.stories.ts
@@ -16,22 +16,24 @@ limitations under the License.
*/
import {
- Graph,
+ type AbstractCanvas2D,
+ CellHighlight,
+ CellRenderer,
+ type CellState,
ConnectionHandler,
+ constants,
DomHelpers,
EdgeHandler,
+ Graph,
InternalEvent,
+ load,
Point,
- CellHighlight,
- constants,
- VertexHandler,
+ type Rectangle,
RubberBandHandler,
Shape,
StencilShape,
StencilShapeRegistry,
- CellRenderer,
- utils,
- load,
+ VertexHandler,
} from '@maxgraph/core';
import {
contextMenuTypes,
@@ -42,8 +44,7 @@ import {
rubberBandValues,
} from './shared/args.js';
import { createGraphContainer } from './shared/configure.js';
-// style required by RubberBand
-import '@maxgraph/core/css/common.css';
+import '@maxgraph/core/css/common.css'; // style required by RubberBand
export default {
title: 'Shapes/Stencils',
@@ -59,12 +60,12 @@ export default {
},
};
-const Template = ({ label, ...args }) => {
+const Template = ({ label, ...args }: Record) => {
const div = document.createElement('div');
const container = createGraphContainer(args);
div.appendChild(container);
- // Allow overriding constants?
+ // Allow overriding constants. See https://github.com/maxGraph/maxGraph/issues/192
// Sets the global shadow color
// constants.SHADOWCOLOR = '#C0C0C0';
// constants.SHADOW_OPACITY = 0.5;
@@ -83,33 +84,42 @@ const Template = ({ label, ...args }) => {
// Enable rotation handle
VertexHandler.prototype.rotationEnabled = true;
- // Uses the shape for resize previews
- VertexHandler.prototype.createSelectionShape = function (bounds) {
- const key = this.state.style.shape;
- const stencil = StencilShapeRegistry.getStencil(key);
- let shape = null;
-
- if (stencil != null) {
- shape = new Shape(stencil);
- shape.apply(this.state);
- } else {
- shape = new this.state.shape.constructor();
- }
+ class CustomVertexHandler extends VertexHandler {
+ // Uses the shape for resize previews
+ createSelectionShape(bounds: Rectangle) {
+ const stencil = StencilShapeRegistry.getStencil(this.state.style.shape ?? '');
+ let shape = null;
+
+ if (stencil != null) {
+ shape = new Shape(stencil);
+ shape.apply(this.state);
+ } else {
+ // @ts-ignore known to work at runtime
+ shape = new this.state.shape.constructor();
+ }
- shape.outline = true;
- shape.bounds = bounds;
- shape.stroke = constants.HANDLE_STROKECOLOR;
- shape.strokewidth = this.getSelectionStrokeWidth();
- shape.isDashed = this.isSelectionDashed();
- shape.isShadow = false;
- return shape;
- };
+ shape.outline = true;
+ shape.bounds = bounds;
+ shape.stroke = constants.HANDLE_STROKECOLOR;
+ shape.strokewidth = this.getSelectionStrokeWidth();
+ shape.isDashed = this.isSelectionDashed();
+ shape.isShadow = false;
+ return shape;
+ }
+ }
- // Defines a custom stencil via the canvas API as defined here:
- // http://jgraph.github.io/mxgraph/docs/js-api/files/util/mxXmlCanvas2D-js.html
+ class CustomGraph extends Graph {
+ constructor(container: HTMLElement) {
+ super(container);
+ }
+ createVertexHandler(state: CellState) {
+ return new CustomVertexHandler(state);
+ }
+ }
+ // Defines a custom Shape via the canvas API
class CustomShape extends Shape {
- paintBackground(c, x, y, w, h) {
+ paintBackground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
c.translate(x, y);
// Head
@@ -143,12 +153,16 @@ const Template = ({ label, ...args }) => {
// Loads the stencils into the registry
const req = load('stencils.xml');
const root = req.getDocumentElement();
- let shape = root.firstChild;
+ let shape = root!.firstChild;
+
+ function isElement(node: ChildNode): node is Element {
+ return node.nodeType === constants.NODETYPE.ELEMENT;
+ }
while (shape != null) {
- if (shape.nodeType === constants.NODETYPE.ELEMENT) {
+ if (isElement(shape)) {
StencilShapeRegistry.addStencil(
- shape.getAttribute('name'),
+ shape.getAttribute('name')!, // the "name" attribute is always set
new StencilShape(shape)
);
}
@@ -159,26 +173,23 @@ const Template = ({ label, ...args }) => {
if (!args.contextMenu) InternalEvent.disableContextMenu(container);
// Creates the graph inside the given container
- const graph = new Graph(container);
+ // const graph = new Graph(container);
+ const graph = new CustomGraph(container);
graph.setConnectable(true);
graph.setTooltips(true);
graph.setPanning(true);
graph.getTooltipForCell = function (cell) {
- if (cell != null) {
- return cell.style;
- }
-
- return null;
+ return cell ? JSON.stringify(cell.style) : 'Cell without dedicated style';
};
// Changes default styles
let style = graph.getStylesheet().getDefaultEdgeStyle();
- style.edge = 'orthogonalEdgeStyle';
+ style.edgeStyle = 'orthogonalEdgeStyle';
style = graph.getStylesheet().getDefaultVertexStyle();
style.fillColor = '#adc5ff';
style.gradientColor = '#7d85df';
- style.shadow = '1';
+ style.shadow = true;
// Enables rubberband selection
if (args.rubberBand) new RubberBandHandler(graph);
@@ -193,9 +204,9 @@ const Template = ({ label, ...args }) => {
const v2 = graph.insertVertex(parent, null, 'A2', 20, 220, 40, 80, { shape: 'and' });
const v3 = graph.insertVertex(parent, null, 'X1', 160, 110, 80, 80, { shape: 'xor' });
const e1 = graph.insertEdge(parent, null, '', v1, v3);
- e1.geometry.points = [new Point(90, 60), new Point(90, 130)];
+ e1.geometry!.points = [new Point(90, 60), new Point(90, 130)];
const e2 = graph.insertEdge(parent, null, '', v2, v3);
- e2.geometry.points = [new Point(90, 260), new Point(90, 170)];
+ e2.geometry!.points = [new Point(90, 260), new Point(90, 170)];
const v4 = graph.insertVertex(parent, null, 'A3', 520, 20, 40, 80, {
shape: 'customShape',
@@ -210,21 +221,21 @@ const Template = ({ label, ...args }) => {
flipH: true,
});
const e3 = graph.insertEdge(parent, null, '', v4, v6);
- e3.geometry.points = [new Point(490, 60), new Point(130, 130)];
+ e3.geometry!.points = [new Point(490, 60), new Point(130, 130)];
const e4 = graph.insertEdge(parent, null, '', v5, v6);
- e4.geometry.points = [new Point(490, 260), new Point(130, 170)];
+ e4.geometry!.points = [new Point(490, 260), new Point(130, 170)];
const v7 = graph.insertVertex(parent, null, 'O1', 250, 260, 80, 60, {
shape: 'or',
direction: 'south',
});
const e5 = graph.insertEdge(parent, null, '', v6, v7);
- e5.geometry.points = [new Point(310, 150)];
+ e5.geometry!.points = [new Point(310, 150)];
const e6 = graph.insertEdge(parent, null, '', v3, v7);
- e6.geometry.points = [new Point(270, 150)];
+ e6.geometry!.points = [new Point(270, 150)];
const e7 = graph.insertEdge(parent, null, '', v7, v5);
- e7.geometry.points = [new Point(290, 370)];
+ e7.geometry!.points = [new Point(290, 370)];
});
const buttons = document.createElement('div');
@@ -257,7 +268,7 @@ const Template = ({ label, ...args }) => {
if (geo != null) {
graph.batchUpdate(() => {
// Rotates the size and position in the geometry
- geo = geo.clone();
+ geo = geo!.clone();
geo.x += geo.width / 2 - geo.height / 2;
geo.y += geo.height / 2 - geo.width / 2;
const tmp = geo.width;
@@ -318,17 +329,23 @@ const Template = ({ label, ...args }) => {
buttons.appendChild(
DomHelpers.button('Style', function () {
const cell = graph.getSelectionCell();
+ if (!cell) return;
- if (cell != null) {
- const style = utils.prompt('Style', cell.getStyle());
-
- if (style != null) {
- graph.getDataModel().setStyle(cell, style);
- }
+ const newStyle = window.prompt(
+ `Style Cell #${cell.getId()}`,
+ JSON.stringify(cell.getStyle())
+ );
+ if (newStyle) {
+ graph.getDataModel().setStyle(cell, JSON.parse(newStyle));
}
})
);
+ buttons.appendChild(document.createTextNode('\u00a0'));
+ buttons.appendChild(document.createTextNode('\u00a0'));
+ buttons.appendChild(document.createTextNode('\u00a0'));
+ buttons.appendChild(document.createTextNode('\u00a0'));
+
buttons.appendChild(
DomHelpers.button('+', function () {
graph.zoomIn();