From 8fe52f410698e5bbea995c5141d28dd245f57454 Mon Sep 17 00:00:00 2001 From: mcyph <20507948+mcyph@users.noreply.github.com> Date: Fri, 26 Mar 2021 13:26:24 +1100 Subject: [PATCH] cleanups and bugfixes --- src/mxgraph/handler/mxGraphHandler.js | 6 +- .../stage/mxMedianHybridCrossingReduction.js | 14 - src/mxgraph/util/mxGuide.js | 2 + src/pages/ContextIcons.js | 267 ++++++++---------- src/pages/Control.js | 24 +- src/pages/DragSource.js | 82 ++++-- src/pages/Overlays.js | 40 +-- src/pages/examplesListing.json | 138 ++++----- 8 files changed, 293 insertions(+), 280 deletions(-) diff --git a/src/mxgraph/handler/mxGraphHandler.js b/src/mxgraph/handler/mxGraphHandler.js index 89cdd1361..5e3aca31c 100644 --- a/src/mxgraph/handler/mxGraphHandler.js +++ b/src/mxgraph/handler/mxGraphHandler.js @@ -789,6 +789,10 @@ class mxGraphHandler { return shape; } + createGuide() { + return new mxGuide(this.graph, this.getGuideStates()); + } + /** * Function: start * @@ -809,7 +813,7 @@ class mxGraphHandler { } if (this.guidesEnabled) { - this.guide = new mxGuide(this.graph, this.getGuideStates()); + this.guide = this.createGuide(); const parent = this.graph.model.getParent(cell); const ignore = this.graph.model.getChildCount(parent) < 2; diff --git a/src/mxgraph/layout/hierarchical/stage/mxMedianHybridCrossingReduction.js b/src/mxgraph/layout/hierarchical/stage/mxMedianHybridCrossingReduction.js index bc15cac4d..d80ea5b3e 100644 --- a/src/mxgraph/layout/hierarchical/stage/mxMedianHybridCrossingReduction.js +++ b/src/mxgraph/layout/hierarchical/stage/mxMedianHybridCrossingReduction.js @@ -63,20 +63,6 @@ class mxMedianHybridCrossingReduction extends mxHierarchicalLayoutStage { */ function; - /** - * Variable: medianValue - * - * The weighted value of the cell stored. - */ - medianValue = 0; - - /** - * Variable: cell - * - * The cell whose median value is being calculated - */ - cell = false; - /** * Class: mxMedianHybridCrossingReduction * diff --git a/src/mxgraph/util/mxGuide.js b/src/mxgraph/util/mxGuide.js index c754be7c6..e5ba1074f 100644 --- a/src/mxgraph/util/mxGuide.js +++ b/src/mxgraph/util/mxGuide.js @@ -4,6 +4,8 @@ * Updated to ES9 syntax by David Morrissey 2021 */ import mxConstants from './mxConstants'; +import mxPoint from "./mxPoint"; +import mxPolyline from "../shape/mxPolyline"; /** * Class: mxGuide diff --git a/src/pages/ContextIcons.js b/src/pages/ContextIcons.js index da8280275..66447e610 100644 --- a/src/pages/ContextIcons.js +++ b/src/pages/ContextIcons.js @@ -39,82 +39,67 @@ class ContextIcons extends React.Component { }; componentDidMount = () => { - // Defines a subclass for mxVertexHandler that adds a set of clickable - // icons to every selected vertex. - function mxVertexToolHandler(state) { - mxVertexHandler.apply(this, arguments); - } + class mxVertexToolHandler extends mxVertexHandler { + // Defines a subclass for mxVertexHandler that adds a set of clickable + // icons to every selected vertex. - mxVertexToolHandler.prototype = new mxVertexHandler(); - mxVertexToolHandler.prototype.constructor = mxVertexToolHandler; + domNode = null; - mxVertexToolHandler.prototype.domNode = null; + init() { + super.init(); - mxVertexToolHandler.prototype.init = function() { - mxVertexHandler.prototype.init.apply(this, arguments); + // In this example we force the use of DIVs for images in IE. This + // handles transparency in PNG images properly in IE and fixes the + // problem that IE routes all mouse events for a gesture via the + // initial IMG node, which means the target vertices + this.domNode = document.createElement('div'); + this.domNode.style.position = 'absolute'; + this.domNode.style.whiteSpace = 'nowrap'; - // In this example we force the use of DIVs for images in IE. This - // handles transparency in PNG images properly in IE and fixes the - // problem that IE routes all mouse events for a gesture via the - // initial IMG node, which means the target vertices - this.domNode = document.createElement('div'); - this.domNode.style.position = 'absolute'; - this.domNode.style.whiteSpace = 'nowrap'; + // Workaround for event redirection via image tag in quirks and IE8 + const createImage = src => { + return mxUtils.createImage(src); + }; - // Workaround for event redirection via image tag in quirks and IE8 - function createImage(src) { - return mxUtils.createImage(src); - } - - // Delete - let img = createImage('images/delete2.png'); - img.setAttribute('title', 'Delete'); - img.style.cursor = 'pointer'; - img.style.width = '16px'; - img.style.height = '16px'; - mxEvent.addGestureListeners( - img, - mxUtils.bind(this, function(evt) { + // Delete + let img = createImage('images/delete2.png'); + img.setAttribute('title', 'Delete'); + img.style.cursor = 'pointer'; + img.style.width = '16px'; + img.style.height = '16px'; + mxEvent.addGestureListeners(img, evt => { // Disables dragging the image mxEvent.consume(evt); - }) - ); - mxEvent.addListener( - img, - 'click', - mxUtils.bind(this, function(evt) { + }); + mxEvent.addListener(img, 'click', evt => { this.graph.removeCells([this.state.cell]); mxEvent.consume(evt); - }) - ); - this.domNode.appendChild(img); + }); + this.domNode.appendChild(img); - // Size - img = createImage('images/fit_to_size.png'); - img.setAttribute('title', 'Resize'); - img.style.cursor = 'se-resize'; - img.style.width = '16px'; - img.style.height = '16px'; - mxEvent.addGestureListeners( - img, - mxUtils.bind(this, function(evt) { + // Size + img = createImage('images/fit_to_size.png'); + img.setAttribute('title', 'Resize'); + img.style.cursor = 'se-resize'; + img.style.width = '16px'; + img.style.height = '16px'; + + mxEvent.addGestureListeners(img, evt => { this.start(mxEvent.getClientX(evt), mxEvent.getClientY(evt), 7); this.graph.isMouseDown = true; this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt); mxEvent.consume(evt); - }) - ); - this.domNode.appendChild(img); + }); + this.domNode.appendChild(img); - // Move - img = createImage('images/plus.png'); - img.setAttribute('title', 'Move'); - img.style.cursor = 'move'; - img.style.width = '16px'; - img.style.height = '16px'; - mxEvent.addGestureListeners( - img, - mxUtils.bind(this, function(evt) { + // Move + img = createImage('images/plus.png'); + img.setAttribute('title', 'Move'); + img.style.cursor = 'move'; + img.style.width = '16px'; + img.style.height = '16px'; + + mxEvent.addGestureListeners(img, evt => { this.graph.graphHandler.start( this.state.cell, mxEvent.getClientX(evt), @@ -124,19 +109,17 @@ class ContextIcons extends React.Component { this.graph.isMouseDown = true; this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt); mxEvent.consume(evt); - }) - ); - this.domNode.appendChild(img); + }); + this.domNode.appendChild(img); - // Connect - img = createImage('images/check.png'); - img.setAttribute('title', 'Connect'); - img.style.cursor = 'pointer'; - img.style.width = '16px'; - img.style.height = '16px'; - mxEvent.addGestureListeners( - img, - mxUtils.bind(this, function(evt) { + // Connect + img = createImage('images/check.png'); + img.setAttribute('title', 'Connect'); + img.style.cursor = 'pointer'; + img.style.width = '16px'; + img.style.height = '16px'; + + mxEvent.addGestureListeners(img, evt => { const pt = mxUtils.convertPoint( this.graph.container, mxEvent.getClientX(evt), @@ -146,89 +129,81 @@ class ContextIcons extends React.Component { this.graph.isMouseDown = true; this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt); mxEvent.consume(evt); - }) - ); - this.domNode.appendChild(img); + }); + this.domNode.appendChild(img); - this.graph.container.appendChild(this.domNode); - this.redrawTools(); - }; - - mxVertexToolHandler.prototype.redraw = function() { - mxVertexHandler.prototype.redraw.apply(this); - this.redrawTools(); - }; - - mxVertexToolHandler.prototype.redrawTools = function() { - if (this.state != null && this.domNode != null) { - const dy = 4; - this.domNode.style.left = `${this.state.x + this.state.width - 56}px`; - this.domNode.style.top = `${this.state.y + this.state.height + dy}px`; + this.graph.container.appendChild(this.domNode); + this.redrawTools(); } - }; - mxVertexToolHandler.prototype.destroy = function(sender, me) { - mxVertexHandler.prototype.destroy.apply(this, arguments); - - if (this.domNode != null) { - this.domNode.parentNode.removeChild(this.domNode); - this.domNode = null; + redraw() { + super.redraw(); + this.redrawTools(); } - }; - // Program starts here. Creates a sample graph in the - // DOM node with the specified ID. This function is invoked - // from the onLoad event handler of the document (see below). - function main(container) { - // Checks if the browser is supported - if (!mxClient.isBrowserSupported()) { - // Displays an error message if the browser is not supported. - mxUtils.error('Browser is not supported!', 200, false); - } else { - // Creates the graph inside the given container - const graph = new mxGraph(container); - graph.setConnectable(true); - graph.connectionHandler.createTarget = true; + redrawTools() { + if (this.state != null && this.domNode != null) { + const dy = 4; + this.domNode.style.left = `${this.state.x + this.state.width - 56}px`; + this.domNode.style.top = `${this.state.y + this.state.height + dy}px`; + } + } - graph.createHandler = function(state) { - if (state != null && this.model.isVertex(state.cell)) { - return new mxVertexToolHandler(state); - } + destroy(sender, me) { + super.destroy(sender, me); - return mxGraph.prototype.createHandler.apply(this, arguments); - }; - - // Uncomment the following if you want the container - // to fit the size of the graph - // graph.setResizeContainer(true); - - // Enables rubberband selection - new mxRubberband(graph); - - // Gets the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - const parent = graph.getDefaultParent(); - - // Adds cells to the model in a single step - graph.getModel().beginUpdate(); - try { - const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30); - const v2 = graph.insertVertex( - parent, - null, - 'World!', - 200, - 150, - 80, - 30 - ); - const e1 = graph.insertEdge(parent, null, '', v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); + if (this.domNode != null) { + this.domNode.parentNode.removeChild(this.domNode); + this.domNode = null; } } } + + class MyCustomGraph extends mxGraph { + createHandler(state) { + if (state != null && this.model.isVertex(state.cell)) { + return new mxVertexToolHandler(state); + } + return super.createHandler(state); + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(this.el); + graph.setConnectable(true); + graph.connectionHandler.createTarget = true; + + // Uncomment the following if you want the container + // to fit the size of the graph + // graph.setResizeContainer(true); + + // Enables rubberband selection + new mxRubberband(graph); + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + // Adds cells to the model in a single step + graph.batchUpdate(() => { + const v1 = graph.insertVertex({ + parent, + value: 'Hello,', + position: [20, 20], + size: [80, 30], + }); + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [200, 150], + size: [80, 30], + }); + const e1 = graph.insertEdge({ + parent, + source: v1, + target: v2, + }); + }); }; } diff --git a/src/pages/Control.js b/src/pages/Control.js index 9389bd712..9968422f1 100644 --- a/src/pages/Control.js +++ b/src/pages/Control.js @@ -162,9 +162,23 @@ class Control extends React.Component { // Adds cells to the model in a single step graph.getModel().beginUpdate(); try { - const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30); - const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); - const e1 = graph.insertEdge(parent, null, '', v1, v2); + const v1 = graph.insertVertex({ + parent, + value: 'Hello,', + position: [20, 20], + size: [80, 30], + }); + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [200, 150], + size: [80, 30], + }); + const e1 = graph.insertEdge({ + parent, + source: v1, + target: v2, + }); } finally { // Updates the display graph.getModel().endUpdate(); @@ -173,13 +187,13 @@ class Control extends React.Component { graph.centerZoom = false; this.el2.appendChild( - mxUtils.button('Zoom In', function() { + mxUtils.button('Zoom In', () => { graph.zoomIn(); }) ); this.el2.appendChild( - mxUtils.button('Zoom Out', function() { + mxUtils.button('Zoom Out', () => { graph.zoomOut(); }) ); diff --git a/src/pages/DragSource.js b/src/pages/DragSource.js index f3f655311..871622820 100644 --- a/src/pages/DragSource.js +++ b/src/pages/DragSource.js @@ -38,16 +38,36 @@ class DragSource extends React.Component { }; componentDidMount = () => { - // Enables guides - mxGraphHandler.prototype.guidesEnabled = true; + class MyCustomGuide extends mxGuide { + isEnabledForEvent(evt) { + // Alt disables guides + return !mxEvent.isAltDown(evt); + } + } - // Alt disables guides - mxGuide.prototype.isEnabledForEvent = function(evt) { - return !mxEvent.isAltDown(evt); - }; + class MyCustomGraphHandler extends mxGraphHandler { + // Enables guides + guidesEnabled = true; - // Enables snapping waypoints to terminals - mxEdgeHandler.prototype.snapToTerminals = true; + createGuide() { + return new MyCustomGuide(this.graph, this.getGuideStates()); + } + } + + class MyCustomEdgeHandler extends mxEdgeHandler { + // Enables snapping waypoints to terminals + snapToTerminals = true; + } + + class MyCustomGraph extends mxGraph { + createGraphHandler() { + return new MyCustomGraphHandler(this); + } + + createEdgeHandler(state, edgeStyle) { + return new MyCustomEdgeHandler(state, edgeStyle); + } + } const graphs = []; @@ -63,7 +83,7 @@ class DragSource extends React.Component { this.el.appendChild(container); - var graph = new mxGraph(container); + const graph = new MyCustomGraph(container); graph.gridSize = 30; // Uncomment the following if you want the container @@ -78,28 +98,38 @@ class DragSource extends React.Component { const parent = graph.getDefaultParent(); // Adds cells to the model in a single step - graph.getModel().beginUpdate(); - try { - const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30); - const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); - const e1 = graph.insertEdge(parent, null, '', v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } + graph.batchUpdate(() => { + const v1 = graph.insertVertex({ + parent, + value: 'Hello,', + position: [20, 20], + size: [80, 30], + }); + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [200, 150], + size: [80, 30], + }); + const e1 = graph.insertEdge({ + parent, + source: v1, + target: v2, + }); + }); graphs.push(graph); } // Returns the graph under the mouse - const graphF = function(evt) { + const graphF = evt => { const x = mxEvent.getClientX(evt); const y = mxEvent.getClientY(evt); const elt = document.elementFromPoint(x, y); - for (let i = 0; i < graphs.length; i++) { - if (mxUtils.isAncestorNode(graphs[i].container, elt)) { - return graphs[i]; + for (const graph of graphs) { + if (mxUtils.isAncestorNode(graph.container, elt)) { + return graph; } } @@ -107,7 +137,7 @@ class DragSource extends React.Component { }; // Inserts a cell at the given location - const funct = function(graph, evt, target, x, y) { + const funct = (graph, evt, target, x, y) => { const cell = new mxCell('Test', new mxGeometry(0, 0, 120, 40)); cell.vertex = true; const cells = graph.importCells([cell], x, y, target); @@ -141,14 +171,14 @@ class DragSource extends React.Component { dragElt, null, null, - graph.autoscroll, + graphs[0].autoscroll, true ); // Redirects feature to global switch. Note that this feature should only be used // if the the x and y arguments are used in funct to insert the cell. - ds.isGuidesEnabled = function() { - return graph.graphHandler.guidesEnabled; + ds.isGuidesEnabled = () => { + return graphs[0].graphHandler.guidesEnabled; }; // Restores original drag icon while outside of graph diff --git a/src/pages/Overlays.js b/src/pages/Overlays.js index c14008bb5..d5ed6618c 100644 --- a/src/pages/Overlays.js +++ b/src/pages/Overlays.js @@ -53,7 +53,7 @@ class Overlays extends React.Component { // Installs a handler for click events in the graph // that toggles the overlay for the respective cell - graph.addListener(mxEvent.CLICK, function(sender, evt) { + graph.addListener(mxEvent.CLICK, (sender, evt) => { const cell = evt.getProperty('cell'); if (cell != null) { @@ -67,7 +67,7 @@ class Overlays extends React.Component { ); // Installs a handler for clicks on the overlay - overlay.addListener(mxEvent.CLICK, function(sender, evt2) { + overlay.addListener(mxEvent.CLICK, (sender, evt2) => { mxUtils.alert('Overlay clicked'); }); @@ -81,7 +81,7 @@ class Overlays extends React.Component { // Installs a handler for double click events in the graph // that shows an alert box - graph.addListener(mxEvent.DOUBLE_CLICK, function(sender, evt) { + graph.addListener(mxEvent.DOUBLE_CLICK, (sender, evt) => { const cell = evt.getProperty('cell'); mxUtils.alert(`Doubleclick: ${cell != null ? 'Cell' : 'Graph'}`); evt.consume(); @@ -92,23 +92,25 @@ class Overlays extends React.Component { const parent = graph.getDefaultParent(); // Adds cells to the model in a single step - graph.getModel().beginUpdate(); - try { - const v1 = graph.insertVertex(parent, null, 'Click,', 20, 20, 60, 40); - const v2 = graph.insertVertex( + graph.batchUpdate(() => { + const v1 = graph.insertVertex({ parent, - null, - 'Doubleclick', - 200, - 150, - 100, - 40 - ); - const e1 = graph.insertEdge(parent, null, '', v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } + value: 'Click,', + position: [20, 20], + size: [60, 40], + }); + const v2 = graph.insertVertex({ + parent, + value: 'Doubleclick', + position: [200, 150], + size: [100, 40], + }); + const e1 = graph.insertEdge({ + parent, + source: v1, + target: v2, + }); + }); } } diff --git a/src/pages/examplesListing.json b/src/pages/examplesListing.json index edf8c359f..138c82a92 100644 --- a/src/pages/examplesListing.json +++ b/src/pages/examplesListing.json @@ -1,73 +1,73 @@ { - "Morph": "/**\n * Copyright (c) 2006-2013, JGraph Ltd\n * Converted to ES9 syntax/React by David Morrissey 2021\n */\n\nimport React from 'react';\nimport mxEvent from '../mxgraph/util/mxEvent';\nimport mxGraph from '../mxgraph/view/mxGraph';\nimport mxRubberband from '../mxgraph/handler/mxRubberband';\nimport mxMorphing from '../mxgraph/util/mxMorphing';\nimport mxUtils from '../mxgraph/util/mxUtils';\n\nclass Morph extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n
\n {\n this.el = el;\n }}\n className={`language-${this.props.language}`}\n >\n {(this.props.code || '').trim()}\n
\n
\n >\n );\n }\n\n componentDidMount() {\n if (this.el) {\n Prism.highlightElement(this.el);\n }\n }\n\n componentDidUpdate() {\n if (this.el) {\n Prism.highlightElement(this.el);\n }\n }\n}\n\nexport default SourceCodeDisplay;\n",
- "DynamicStyle": "/**\n * Copyright (c) 2006-2013, JGraph Ltd\n * Converted to ES9 syntax/React by David Morrissey 2021\n */\n\nimport React from 'react';\nimport mxGraph from '../mxgraph/view/mxGraph';\nimport mxRubberband from '../mxgraph/handler/mxRubberband';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxConstants from '../mxgraph/util/mxConstants';\n\nclass DynamicStyle extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render = () => {\n // A container for the graph\n return (\n <>\n \n {this.el = el;}}\n style={{\n border: 'solid 1px black',\n overflow: 'hidden',\n height: '241px',\n cursor: 'default'\n }}\n />\n | \n \n {this.propertiesEl = el;}}\n style={{\n border: 'solid 1px black',\n padding: '10px'\n }}\n />\n | \n
\n {\n this.el = el;\n }}\n style={{\n border: 'solid 1px black',\n overflow: 'hidden',\n height: '241px',\n cursor: 'default',\n }}\n />\n | \n \n {\n this.propertiesEl = el;\n }}\n style={{\n border: 'solid 1px black',\n padding: '10px',\n }}\n />\n | \n