diff --git a/package-lock.json b/package-lock.json index 7826818ac..8ec81d432 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4245,6 +4245,38 @@ "escape-string-regexp": "^1.0.5" } }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5368,12 +5400,6 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, - "klona": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", - "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", - "dev": true - }, "lerna": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/lerna/-/lerna-4.0.0.tgz", @@ -7270,16 +7296,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sass-loader": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-11.0.1.tgz", - "integrity": "sha512-Vp1LcP4slTsTNLEiDkTcm8zGN/XYYrZz2BZybQbliWA8eXveqA/AxsEjllQTpJbg2MzCsx/qNO48sHdZtOaxTw==", - "dev": true, - "requires": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" - } - }, "schema-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", @@ -8044,6 +8060,39 @@ "punycode": "^2.1.0" } }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index eb2e6f74a..482c8e645 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,9 @@ "lerna": "^4.0.0", "@lerna/filter-options": "4.0.0", "prettier": "^2.2.1", - "sass-loader": "^11.0.1", "style-loader": "^2.0.0", + "url-loader": "^4.1.1", + "file-loader": "^6.2.0", "webpack": "^5.32.0", "webpack-cli": "^4.6.0", "webpack-merge": "^5.7.3", diff --git a/src/public/css/common.css b/packages/core/css/common.css similarity index 100% rename from src/public/css/common.css rename to packages/core/css/common.css diff --git a/src/public/images/button.gif b/packages/core/images/button.gif similarity index 100% rename from src/public/images/button.gif rename to packages/core/images/button.gif diff --git a/src/public/images/close.gif b/packages/core/images/close.gif similarity index 100% rename from src/public/images/close.gif rename to packages/core/images/close.gif diff --git a/src/public/images/collapsed.gif b/packages/core/images/collapsed.gif similarity index 100% rename from src/public/images/collapsed.gif rename to packages/core/images/collapsed.gif diff --git a/src/public/images/error.gif b/packages/core/images/error.gif similarity index 100% rename from src/public/images/error.gif rename to packages/core/images/error.gif diff --git a/src/public/images/expanded.gif b/packages/core/images/expanded.gif similarity index 100% rename from src/public/images/expanded.gif rename to packages/core/images/expanded.gif diff --git a/src/public/images/maximize.gif b/packages/core/images/maximize.gif similarity index 100% rename from src/public/images/maximize.gif rename to packages/core/images/maximize.gif diff --git a/src/public/images/minimize.gif b/packages/core/images/minimize.gif similarity index 100% rename from src/public/images/minimize.gif rename to packages/core/images/minimize.gif diff --git a/src/public/images/normalize.gif b/packages/core/images/normalize.gif similarity index 100% rename from src/public/images/normalize.gif rename to packages/core/images/normalize.gif diff --git a/src/public/images/point.gif b/packages/core/images/point.gif similarity index 100% rename from src/public/images/point.gif rename to packages/core/images/point.gif diff --git a/src/public/images/resize.gif b/packages/core/images/resize.gif similarity index 100% rename from src/public/images/resize.gif rename to packages/core/images/resize.gif diff --git a/src/public/images/separator.gif b/packages/core/images/separator.gif similarity index 100% rename from src/public/images/separator.gif rename to packages/core/images/separator.gif diff --git a/src/public/images/submenu.gif b/packages/core/images/submenu.gif similarity index 100% rename from src/public/images/submenu.gif rename to packages/core/images/submenu.gif diff --git a/src/public/images/transparent.gif b/packages/core/images/transparent.gif similarity index 100% rename from src/public/images/transparent.gif rename to packages/core/images/transparent.gif diff --git a/src/public/images/warning.gif b/packages/core/images/warning.gif similarity index 100% rename from src/public/images/warning.gif rename to packages/core/images/warning.gif diff --git a/src/public/images/warning.png b/packages/core/images/warning.png similarity index 100% rename from src/public/images/warning.png rename to packages/core/images/warning.png diff --git a/src/public/images/window-title.gif b/packages/core/images/window-title.gif similarity index 100% rename from src/public/images/window-title.gif rename to packages/core/images/window-title.gif diff --git a/src/public/images/window.gif b/packages/core/images/window.gif similarity index 100% rename from src/public/images/window.gif rename to packages/core/images/window.gif diff --git a/packages/core/src/handler/mxGraphHandler.js b/packages/core/src/handler/mxGraphHandler.js index 0f0e31306..13dbbf2af 100644 --- a/packages/core/src/handler/mxGraphHandler.js +++ b/packages/core/src/handler/mxGraphHandler.js @@ -15,7 +15,7 @@ import mxConstants from '../util/mxConstants'; import mxDictionary from '../util/datatypes/mxDictionary'; import mxCellHighlight from './mxCellHighlight'; import mxRectangle from '../util/datatypes/mxRectangle'; -import { isAltDown, isMultiTouchEvent } from '../util/mxEventUtils'; +import { getClientX, getClientY, isAltDown, isMultiTouchEvent } from '../util/mxEventUtils'; /** * Class: mxGraphHandler @@ -1709,8 +1709,8 @@ class mxGraphHandler { if (pState != null) { let pt = mxUtils.convertPoint( this.graph.container, - mxEvent.getClientX(evt), - mxEvent.getClientY(evt) + getClientX(evt), + getClientY(evt) ); const alpha = mxUtils.toRadians( mxUtils.getValue(pState.style, mxConstants.STYLE_ROTATION) || 0 diff --git a/packages/core/src/handler/mxKeyHandler.js b/packages/core/src/handler/mxKeyHandler.js index 30efcb36a..f76129df5 100644 --- a/packages/core/src/handler/mxKeyHandler.js +++ b/packages/core/src/handler/mxKeyHandler.js @@ -7,7 +7,7 @@ import mxEvent from '../util/event/mxEvent'; import { isAncestorNode } from '../util/mxDomUtils'; -import { getSource, isAltDown, isConsumed, isShiftDown } from '../util/mxEventUtils'; +import { getSource, isAltDown, isConsumed, isControlDown as _isControlDown, isShiftDown } from '../util/mxEventUtils'; import mxUtils from '../util/mxUtils'; /** @@ -235,7 +235,7 @@ class mxKeyHandler { * evt - Key event whose control key pressed state should be returned. */ isControlDown(evt) { - return mxEvent.isControlDown(evt); + return _isControlDown(evt); } /** diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index d2c9c69c7..c31db2f2a 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,5 +1,17 @@ import mxClient from './mxClient'; +import mxCellAttributeChange from './atomic_changes/mxCellAttributeChange'; +import mxChildChange from './atomic_changes/mxChildChange'; +import mxCollapseChange from './atomic_changes/mxCollapseChange'; +import mxCurrentRootChange from './atomic_changes/mxCurrentRootChange'; +import mxGeometryChange from './atomic_changes/mxGeometryChange'; +import mxRootChange from './atomic_changes/mxRootChange'; +import mxSelectionChange from './atomic_changes/mxSelectionChange'; +import mxStyleChange from './atomic_changes/mxStyleChange'; +import mxTerminalChange from './atomic_changes/mxTerminalChange'; +import mxValueChange from './atomic_changes/mxValueChange'; +import mxVisibleChange from './atomic_changes/mxVisibleChange'; + import mxDefaultKeyHandler from './editor/mxDefaultKeyHandler'; import mxDefaultPopupMenu from './editor/mxDefaultPopupMenu'; import mxDefaultToolbar from './editor/mxDefaultToolbar'; @@ -173,6 +185,8 @@ import mxOutline from './view/graph/mxOutline'; import mxPrintPreview from './view/graph/mxPrintPreview'; import mxSwimlaneManager from './view/graph/mxSwimlaneManager'; +import '../css/common.css'; + export default { mxClient, mxLog, @@ -320,5 +334,16 @@ export default { mxGestureUtils, mxStringUtils, mxXmlUtils, - mxDomHelpers + mxDomHelpers, + mxCellAttributeChange, + mxChildChange, + mxCollapseChange, + mxCurrentRootChange, + mxGeometryChange, + mxRootChange, + mxSelectionChange, + mxStyleChange, + mxTerminalChange, + mxValueChange, + mxVisibleChange }; diff --git a/packages/core/src/layout/hierarchical/stage/mxCoordinateAssignment.js b/packages/core/src/layout/hierarchical/stage/mxCoordinateAssignment.js index 6bd091716..a30048b7f 100644 --- a/packages/core/src/layout/hierarchical/stage/mxCoordinateAssignment.js +++ b/packages/core/src/layout/hierarchical/stage/mxCoordinateAssignment.js @@ -990,10 +990,11 @@ class mxCoordinateAssignment extends mxHierarchicalLayoutStage { let downSegCount = 0; const upXPositions = []; const downXPositions = []; + let i = 0; let currentX = cell.getGeneralPurposeVariable(cell.minRank + 1); - for (let i = cell.minRank + 1; i < cell.maxRank - 1; i += 1) { + for (i = cell.minRank + 1; i < cell.maxRank - 1; i += 1) { // Attempt to straight out the control point on the // next segment up with the current control point. const nextX = cell.getX(i + 1); diff --git a/packages/core/src/layout/hierarchical/stage/mxMinimumCycleRemover.js b/packages/core/src/layout/hierarchical/stage/mxMinimumCycleRemover.js index 5e0c07822..8099c4251 100644 --- a/packages/core/src/layout/hierarchical/stage/mxMinimumCycleRemover.js +++ b/packages/core/src/layout/hierarchical/stage/mxMinimumCycleRemover.js @@ -6,6 +6,7 @@ */ import mxHierarchicalLayoutStage from './mxHierarchicalLayoutStage'; import mxUtils from '../../../util/mxUtils'; +import { clone } from '../../../util/mxCloneUtils'; /** * Class: mxMinimumCycleRemover @@ -85,7 +86,7 @@ class mxMinimumCycleRemover extends mxHierarchicalLayoutStage { // If there are any nodes that should be nodes that the dfs can miss // these need to be processed with the dfs and the roots assigned // correctly to form a correct internal model - const seenNodesCopy = mxUtils.clone(seenNodes, null, true); + const seenNodesCopy = clone(seenNodes, null, true); // Pick a random cell and dfs from it model.visit( diff --git a/packages/core/src/serialization/mxCodec.js b/packages/core/src/serialization/mxCodec.js index ffa961225..317b280a2 100644 --- a/packages/core/src/serialization/mxCodec.js +++ b/packages/core/src/serialization/mxCodec.js @@ -5,7 +5,6 @@ * Type definitions from the typed-mxgraph project */ -import mxUtils from '../util/mxUtils'; import mxCellPath from '../view/cell/mxCellPath'; import mxCodecRegistry from './mxCodecRegistry'; import mxConstants from '../util/mxConstants'; @@ -13,6 +12,7 @@ import mxCell from '../view/cell/mxCell'; import mxLog from '../util/gui/mxLog'; import { getFunctionName } from '../util/mxStringUtils'; import { importNode, isNode } from '../util/mxDomUtils'; +import { createXmlDocument } from '../util/mxXmlUtils'; /** * XML codec for JavaScript object graphs. See {@link mxObjectCodec} for a @@ -120,7 +120,7 @@ import { importNode, isNode } from '../util/mxDomUtils'; */ class mxCodec { constructor(document) { - this.document = document || mxUtils.createXmlDocument(); + this.document = document || createXmlDocument(); this.objects = []; } diff --git a/packages/core/src/shape/edge/mxArrow.js b/packages/core/src/shape/edge/mxArrow.js index e64a81c21..8ecc2c07b 100644 --- a/packages/core/src/shape/edge/mxArrow.js +++ b/packages/core/src/shape/edge/mxArrow.js @@ -29,7 +29,7 @@ class mxArrow extends mxShape { */ // augmentBoundingBox(bbox: mxRectangle): void; augmentBoundingBox(bbox) { - super.augmentBoundingBox.apply(bbox); + super.augmentBoundingBox(bbox); const w = Math.max(this.arrowWidth, this.endSize); bbox.grow((w / 2 + this.strokewidth) * this.scale); diff --git a/packages/core/src/util/datatypes/style/mxEdgeStyle.js b/packages/core/src/util/datatypes/style/mxEdgeStyle.js index 482c8d2b1..cb3912f56 100644 --- a/packages/core/src/util/datatypes/style/mxEdgeStyle.js +++ b/packages/core/src/util/datatypes/style/mxEdgeStyle.js @@ -601,6 +601,7 @@ class mxEdgeStyle { } const lastInx = pts.length - 1; + let pe = null; // Adds the waypoints if (controlHints != null && controlHints.length > 0) { @@ -634,7 +635,7 @@ class mxEdgeStyle { } } - const pe = pts[lastInx]; + pe = pts[lastInx]; if (pe != null && hints[hints.length - 1] != null) { if (Math.abs(hints[hints.length - 1].x - pe.x) < tol) { diff --git a/packages/core/src/util/datatypes/style/mxStylesheet.js b/packages/core/src/util/datatypes/style/mxStylesheet.js index d48a05e00..0be984d0e 100644 --- a/packages/core/src/util/datatypes/style/mxStylesheet.js +++ b/packages/core/src/util/datatypes/style/mxStylesheet.js @@ -7,6 +7,7 @@ import mxConstants from '../../mxConstants'; import mxPerimeter from './mxPerimeter'; import mxUtils from '../../mxUtils'; +import { clone } from '../../mxCloneUtils'; /** * @class mxStylesheet @@ -190,7 +191,7 @@ class mxStylesheet { const pairs = name.split(';'); if (style != null && name.charAt(0) !== ';') { - style = mxUtils.clone(style); + style = clone(style); } else { style = {}; } diff --git a/packages/core/src/util/mxGestureUtils.js b/packages/core/src/util/mxGestureUtils.js index 15e48d334..889d84acb 100644 --- a/packages/core/src/util/mxGestureUtils.js +++ b/packages/core/src/util/mxGestureUtils.js @@ -1,5 +1,6 @@ import mxDragSource from './drag_pan/mxDragSource'; import mxPoint from './datatypes/mxPoint'; +import mxConstants from './mxConstants'; /** * Function: makeDraggable diff --git a/packages/core/webpack.config.js b/packages/core/webpack.config.js index 9f45b6c05..3e9c2a737 100644 --- a/packages/core/webpack.config.js +++ b/packages/core/webpack.config.js @@ -17,6 +17,22 @@ module.exports = merge(base, { library: 'mxgraph', libraryTarget: 'umd' }, + module: { + rules: [ + { + test: /\.(sa|sc|c)ss$/, + use: ['style-loader', 'css-loader'] + }, + { + test: /\.(ico|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/, + loader: 'url-loader', + options: { + name: 'images/[hash].[ext]', + limit: 10000, + }, + } + ] + }, plugins: [ new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1, diff --git a/packages/html/.storybook/preview.js b/packages/html/.storybook/preview.js index 645f52de9..32d38e266 100644 --- a/packages/html/.storybook/preview.js +++ b/packages/html/.storybook/preview.js @@ -7,4 +7,15 @@ export const parameters = { date: /Date$/, }, }, -} \ No newline at end of file +} + +export const globalTypes = { + width: { + type: 'number', + defaultValue: 800 + }, + height: { + type: 'number', + defaultValue: 600 + } +}; diff --git a/packages/html/package.json b/packages/html/package.json index 349478b08..ae65a09c5 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "dev": "start-storybook -p 8901" + "dev": "start-storybook -p 8901 -s ./public" }, "author": "", "license": "ISC", diff --git a/src/pages/xml_json/fileio.txt b/packages/html/public/fileio.txt similarity index 100% rename from src/pages/xml_json/fileio.txt rename to packages/html/public/fileio.txt diff --git a/src/pages/xml_json/fileio.xml b/packages/html/public/fileio.xml similarity index 100% rename from src/pages/xml_json/fileio.xml rename to packages/html/public/fileio.xml diff --git a/src/public/editors/images/actor.gif b/packages/html/public/images/actor.gif similarity index 100% rename from src/public/editors/images/actor.gif rename to packages/html/public/images/actor.gif diff --git a/src/public/images/add.png b/packages/html/public/images/add.png similarity index 100% rename from src/public/images/add.png rename to packages/html/public/images/add.png diff --git a/src/public/editors/images/alignbottom.gif b/packages/html/public/images/alignbottom.gif similarity index 100% rename from src/public/editors/images/alignbottom.gif rename to packages/html/public/images/alignbottom.gif diff --git a/src/public/editors/images/aligncenter.gif b/packages/html/public/images/aligncenter.gif similarity index 100% rename from src/public/editors/images/aligncenter.gif rename to packages/html/public/images/aligncenter.gif diff --git a/src/public/editors/images/alignleft.gif b/packages/html/public/images/alignleft.gif similarity index 100% rename from src/public/editors/images/alignleft.gif rename to packages/html/public/images/alignleft.gif diff --git a/src/public/editors/images/alignmiddle.gif b/packages/html/public/images/alignmiddle.gif similarity index 100% rename from src/public/editors/images/alignmiddle.gif rename to packages/html/public/images/alignmiddle.gif diff --git a/src/public/editors/images/alignright.gif b/packages/html/public/images/alignright.gif similarity index 100% rename from src/public/editors/images/alignright.gif rename to packages/html/public/images/alignright.gif diff --git a/src/public/editors/images/aligntop.gif b/packages/html/public/images/aligntop.gif similarity index 100% rename from src/public/editors/images/aligntop.gif rename to packages/html/public/images/aligntop.gif diff --git a/src/public/editors/images/arrow.gif b/packages/html/public/images/arrow.gif similarity index 100% rename from src/public/editors/images/arrow.gif rename to packages/html/public/images/arrow.gif diff --git a/src/public/editors/images/bell.png b/packages/html/public/images/bell.png similarity index 100% rename from src/public/editors/images/bell.png rename to packages/html/public/images/bell.png diff --git a/src/public/editors/images/bg.gif b/packages/html/public/images/bg.gif similarity index 100% rename from src/public/editors/images/bg.gif rename to packages/html/public/images/bg.gif diff --git a/src/public/editors/images/block_end.gif b/packages/html/public/images/block_end.gif similarity index 100% rename from src/public/editors/images/block_end.gif rename to packages/html/public/images/block_end.gif diff --git a/src/public/editors/images/block_start.gif b/packages/html/public/images/block_start.gif similarity index 100% rename from src/public/editors/images/block_start.gif rename to packages/html/public/images/block_start.gif diff --git a/src/public/editors/images/bold.gif b/packages/html/public/images/bold.gif similarity index 100% rename from src/public/editors/images/bold.gif rename to packages/html/public/images/bold.gif diff --git a/src/public/editors/images/bottom.gif b/packages/html/public/images/bottom.gif similarity index 100% rename from src/public/editors/images/bottom.gif rename to packages/html/public/images/bottom.gif diff --git a/src/public/editors/images/box.png b/packages/html/public/images/box.png similarity index 100% rename from src/public/editors/images/box.png rename to packages/html/public/images/box.png diff --git a/packages/html/public/images/button.gif b/packages/html/public/images/button.gif new file mode 100644 index 000000000..ad55cab61 Binary files /dev/null and b/packages/html/public/images/button.gif differ diff --git a/src/public/editors/images/camera.gif b/packages/html/public/images/camera.gif similarity index 100% rename from src/public/editors/images/camera.gif rename to packages/html/public/images/camera.gif diff --git a/src/public/images/camera.png b/packages/html/public/images/camera.png similarity index 100% rename from src/public/images/camera.png rename to packages/html/public/images/camera.png diff --git a/src/public/editors/images/center.gif b/packages/html/public/images/center.gif similarity index 100% rename from src/public/editors/images/center.gif rename to packages/html/public/images/center.gif diff --git a/src/public/images/check.png b/packages/html/public/images/check.png similarity index 100% rename from src/public/images/check.png rename to packages/html/public/images/check.png diff --git a/src/public/editors/images/classic_end.gif b/packages/html/public/images/classic_end.gif similarity index 100% rename from src/public/editors/images/classic_end.gif rename to packages/html/public/images/classic_end.gif diff --git a/src/public/editors/images/classic_start.gif b/packages/html/public/images/classic_start.gif similarity index 100% rename from src/public/editors/images/classic_start.gif rename to packages/html/public/images/classic_start.gif diff --git a/packages/html/public/images/close.gif b/packages/html/public/images/close.gif new file mode 100644 index 000000000..1069e94bb Binary files /dev/null and b/packages/html/public/images/close.gif differ diff --git a/src/public/images/close.png b/packages/html/public/images/close.png similarity index 100% rename from src/public/images/close.png rename to packages/html/public/images/close.png diff --git a/src/public/editors/images/cloud.gif b/packages/html/public/images/cloud.gif similarity index 100% rename from src/public/editors/images/cloud.gif rename to packages/html/public/images/cloud.gif diff --git a/src/public/editors/images/cmp-bg.gif b/packages/html/public/images/cmp-bg.gif similarity index 100% rename from src/public/editors/images/cmp-bg.gif rename to packages/html/public/images/cmp-bg.gif diff --git a/src/public/editors/images/collapse.gif b/packages/html/public/images/collapse.gif similarity index 100% rename from src/public/editors/images/collapse.gif rename to packages/html/public/images/collapse.gif diff --git a/packages/html/public/images/collapsed.gif b/packages/html/public/images/collapsed.gif new file mode 100644 index 000000000..0276444a6 Binary files /dev/null and b/packages/html/public/images/collapsed.gif differ diff --git a/src/public/editors/images/connect.gif b/packages/html/public/images/connect.gif similarity index 100% rename from src/public/editors/images/connect.gif rename to packages/html/public/images/connect.gif diff --git a/src/public/editors/images/connector.gif b/packages/html/public/images/connector.gif similarity index 100% rename from src/public/editors/images/connector.gif rename to packages/html/public/images/connector.gif diff --git a/src/public/editors/images/console.gif b/packages/html/public/images/console.gif similarity index 100% rename from src/public/editors/images/console.gif rename to packages/html/public/images/console.gif diff --git a/src/public/editors/images/copy.gif b/packages/html/public/images/copy.gif similarity index 100% rename from src/public/editors/images/copy.gif rename to packages/html/public/images/copy.gif diff --git a/src/public/images/copy.png b/packages/html/public/images/copy.png similarity index 100% rename from src/public/images/copy.png rename to packages/html/public/images/copy.png diff --git a/src/public/editors/images/cube_green.png b/packages/html/public/images/cube_green.png similarity index 100% rename from src/public/editors/images/cube_green.png rename to packages/html/public/images/cube_green.png diff --git a/src/public/editors/images/cut.gif b/packages/html/public/images/cut.gif similarity index 100% rename from src/public/editors/images/cut.gif rename to packages/html/public/images/cut.gif diff --git a/src/public/images/cut.png b/packages/html/public/images/cut.png similarity index 100% rename from src/public/images/cut.png rename to packages/html/public/images/cut.png diff --git a/src/public/editors/images/cylinder.gif b/packages/html/public/images/cylinder.gif similarity index 100% rename from src/public/editors/images/cylinder.gif rename to packages/html/public/images/cylinder.gif diff --git a/src/public/editors/images/delete.gif b/packages/html/public/images/delete.gif similarity index 100% rename from src/public/editors/images/delete.gif rename to packages/html/public/images/delete.gif diff --git a/src/public/images/delete2.png b/packages/html/public/images/delete2.png similarity index 100% rename from src/public/images/delete2.png rename to packages/html/public/images/delete2.png diff --git a/src/public/editors/images/diagram.gif b/packages/html/public/images/diagram.gif similarity index 100% rename from src/public/editors/images/diagram.gif rename to packages/html/public/images/diagram.gif diff --git a/src/public/editors/images/diamond_end.gif b/packages/html/public/images/diamond_end.gif similarity index 100% rename from src/public/editors/images/diamond_end.gif rename to packages/html/public/images/diamond_end.gif diff --git a/src/public/editors/images/diamond_start.gif b/packages/html/public/images/diamond_start.gif similarity index 100% rename from src/public/editors/images/diamond_start.gif rename to packages/html/public/images/diamond_start.gif diff --git a/src/public/images/dot.gif b/packages/html/public/images/dot.gif similarity index 100% rename from src/public/images/dot.gif rename to packages/html/public/images/dot.gif diff --git a/src/public/editors/images/doubleellipse.gif b/packages/html/public/images/doubleellipse.gif similarity index 100% rename from src/public/editors/images/doubleellipse.gif rename to packages/html/public/images/doubleellipse.gif diff --git a/src/public/editors/images/down.gif b/packages/html/public/images/down.gif similarity index 100% rename from src/public/editors/images/down.gif rename to packages/html/public/images/down.gif diff --git a/src/public/editors/images/draw/drawbg.jpg b/packages/html/public/images/draw/drawbg.jpg similarity index 100% rename from src/public/editors/images/draw/drawbg.jpg rename to packages/html/public/images/draw/drawbg.jpg diff --git a/src/public/editors/images/draw/drawbgcolor.jpg b/packages/html/public/images/draw/drawbgcolor.jpg similarity index 100% rename from src/public/editors/images/draw/drawbgcolor.jpg rename to packages/html/public/images/draw/drawbgcolor.jpg diff --git a/src/public/editors/images/draw/drawfooter.jpg b/packages/html/public/images/draw/drawfooter.jpg similarity index 100% rename from src/public/editors/images/draw/drawfooter.jpg rename to packages/html/public/images/draw/drawfooter.jpg diff --git a/src/public/editors/images/draw/drawheader.jpg b/packages/html/public/images/draw/drawheader.jpg similarity index 100% rename from src/public/editors/images/draw/drawheader.jpg rename to packages/html/public/images/draw/drawheader.jpg diff --git a/src/public/editors/images/draw/mxlogo.jpg b/packages/html/public/images/draw/mxlogo.jpg similarity index 100% rename from src/public/editors/images/draw/mxlogo.jpg rename to packages/html/public/images/draw/mxlogo.jpg diff --git a/src/public/editors/images/dude3.png b/packages/html/public/images/dude3.png similarity index 100% rename from src/public/editors/images/dude3.png rename to packages/html/public/images/dude3.png diff --git a/src/public/editors/images/earth.png b/packages/html/public/images/earth.png similarity index 100% rename from src/public/editors/images/earth.png rename to packages/html/public/images/earth.png diff --git a/src/public/editors/images/ellipse.gif b/packages/html/public/images/ellipse.gif similarity index 100% rename from src/public/editors/images/ellipse.gif rename to packages/html/public/images/ellipse.gif diff --git a/src/public/editors/images/entity.gif b/packages/html/public/images/entity.gif similarity index 100% rename from src/public/editors/images/entity.gif rename to packages/html/public/images/entity.gif diff --git a/packages/html/public/images/error.gif b/packages/html/public/images/error.gif new file mode 100644 index 000000000..14e1aeefd Binary files /dev/null and b/packages/html/public/images/error.gif differ diff --git a/src/public/editors/images/expand.gif b/packages/html/public/images/expand.gif similarity index 100% rename from src/public/editors/images/expand.gif rename to packages/html/public/images/expand.gif diff --git a/packages/html/public/images/expanded.gif b/packages/html/public/images/expanded.gif new file mode 100644 index 000000000..3767b0baf Binary files /dev/null and b/packages/html/public/images/expanded.gif differ diff --git a/src/public/images/export1.png b/packages/html/public/images/export1.png similarity index 100% rename from src/public/images/export1.png rename to packages/html/public/images/export1.png diff --git a/src/public/editors/images/fillcolor.gif b/packages/html/public/images/fillcolor.gif similarity index 100% rename from src/public/editors/images/fillcolor.gif rename to packages/html/public/images/fillcolor.gif diff --git a/src/public/editors/images/fit.gif b/packages/html/public/images/fit.gif similarity index 100% rename from src/public/editors/images/fit.gif rename to packages/html/public/images/fit.gif diff --git a/src/public/images/fit_to_size.png b/packages/html/public/images/fit_to_size.png similarity index 100% rename from src/public/images/fit_to_size.png rename to packages/html/public/images/fit_to_size.png diff --git a/src/public/editors/images/font.gif b/packages/html/public/images/font.gif similarity index 100% rename from src/public/editors/images/font.gif rename to packages/html/public/images/font.gif diff --git a/src/public/editors/images/fontcolor.gif b/packages/html/public/images/fontcolor.gif similarity index 100% rename from src/public/editors/images/fontcolor.gif rename to packages/html/public/images/fontcolor.gif diff --git a/src/public/editors/images/gear.gif b/packages/html/public/images/gear.gif similarity index 100% rename from src/public/editors/images/gear.gif rename to packages/html/public/images/gear.gif diff --git a/src/public/editors/images/gear.png b/packages/html/public/images/gear.png similarity index 100% rename from src/public/editors/images/gear.png rename to packages/html/public/images/gear.png diff --git a/src/public/images/gradient_background.jpg b/packages/html/public/images/gradient_background.jpg similarity index 100% rename from src/public/images/gradient_background.jpg rename to packages/html/public/images/gradient_background.jpg diff --git a/src/public/images/green-dot.gif b/packages/html/public/images/green-dot.gif similarity index 100% rename from src/public/images/green-dot.gif rename to packages/html/public/images/green-dot.gif diff --git a/src/public/editors/images/grid.gif b/packages/html/public/images/grid.gif similarity index 100% rename from src/public/editors/images/grid.gif rename to packages/html/public/images/grid.gif diff --git a/src/public/editors/images/group.gif b/packages/html/public/images/group.gif similarity index 100% rename from src/public/editors/images/group.gif rename to packages/html/public/images/group.gif diff --git a/src/public/images/group.png b/packages/html/public/images/group.png similarity index 100% rename from src/public/images/group.png rename to packages/html/public/images/group.png diff --git a/src/public/images/handle-connect.png b/packages/html/public/images/handle-connect.png similarity index 100% rename from src/public/images/handle-connect.png rename to packages/html/public/images/handle-connect.png diff --git a/src/public/images/handle-main.png b/packages/html/public/images/handle-main.png similarity index 100% rename from src/public/images/handle-main.png rename to packages/html/public/images/handle-main.png diff --git a/src/public/editors/images/help.gif b/packages/html/public/images/help.gif similarity index 100% rename from src/public/editors/images/help.gif rename to packages/html/public/images/help.gif diff --git a/src/public/editors/images/hexagon.gif b/packages/html/public/images/hexagon.gif similarity index 100% rename from src/public/editors/images/hexagon.gif rename to packages/html/public/images/hexagon.gif diff --git a/src/public/editors/images/hline.gif b/packages/html/public/images/hline.gif similarity index 100% rename from src/public/editors/images/hline.gif rename to packages/html/public/images/hline.gif diff --git a/src/public/editors/images/house.gif b/packages/html/public/images/house.gif similarity index 100% rename from src/public/editors/images/house.gif rename to packages/html/public/images/house.gif diff --git a/src/public/editors/images/house.png b/packages/html/public/images/house.png similarity index 100% rename from src/public/editors/images/house.png rename to packages/html/public/images/house.png diff --git a/src/public/images/icons48/column.png b/packages/html/public/images/icons48/column.png similarity index 100% rename from src/public/images/icons48/column.png rename to packages/html/public/images/icons48/column.png diff --git a/src/public/images/icons48/earth.png b/packages/html/public/images/icons48/earth.png similarity index 100% rename from src/public/images/icons48/earth.png rename to packages/html/public/images/icons48/earth.png diff --git a/src/public/images/icons48/gear.png b/packages/html/public/images/icons48/gear.png similarity index 100% rename from src/public/images/icons48/gear.png rename to packages/html/public/images/icons48/gear.png diff --git a/src/public/images/icons48/keys.png b/packages/html/public/images/icons48/keys.png similarity index 100% rename from src/public/images/icons48/keys.png rename to packages/html/public/images/icons48/keys.png diff --git a/src/public/images/icons48/mail_new.png b/packages/html/public/images/icons48/mail_new.png similarity index 100% rename from src/public/images/icons48/mail_new.png rename to packages/html/public/images/icons48/mail_new.png diff --git a/src/public/editors/images/server.png b/packages/html/public/images/icons48/server.png similarity index 100% rename from src/public/editors/images/server.png rename to packages/html/public/images/icons48/server.png diff --git a/src/public/images/icons48/table.png b/packages/html/public/images/icons48/table.png similarity index 100% rename from src/public/images/icons48/table.png rename to packages/html/public/images/icons48/table.png diff --git a/src/public/editors/images/image.gif b/packages/html/public/images/image.gif similarity index 100% rename from src/public/editors/images/image.gif rename to packages/html/public/images/image.gif diff --git a/src/public/editors/images/italic.gif b/packages/html/public/images/italic.gif similarity index 100% rename from src/public/editors/images/italic.gif rename to packages/html/public/images/italic.gif diff --git a/src/public/images/key.png b/packages/html/public/images/key.png similarity index 100% rename from src/public/images/key.png rename to packages/html/public/images/key.png diff --git a/src/public/editors/images/left.gif b/packages/html/public/images/left.gif similarity index 100% rename from src/public/editors/images/left.gif rename to packages/html/public/images/left.gif diff --git a/src/public/editors/images/linecolor.gif b/packages/html/public/images/linecolor.gif similarity index 100% rename from src/public/editors/images/linecolor.gif rename to packages/html/public/images/linecolor.gif diff --git a/src/public/editors/images/link.gif b/packages/html/public/images/link.gif similarity index 100% rename from src/public/editors/images/link.gif rename to packages/html/public/images/link.gif diff --git a/src/public/editors/images/loading.gif b/packages/html/public/images/loading.gif similarity index 100% rename from src/public/editors/images/loading.gif rename to packages/html/public/images/loading.gif diff --git a/packages/html/public/images/maximize.gif b/packages/html/public/images/maximize.gif new file mode 100644 index 000000000..e27cf3e19 Binary files /dev/null and b/packages/html/public/images/maximize.gif differ diff --git a/src/public/editors/images/middle.gif b/packages/html/public/images/middle.gif similarity index 100% rename from src/public/editors/images/middle.gif rename to packages/html/public/images/middle.gif diff --git a/packages/html/public/images/minimize.gif b/packages/html/public/images/minimize.gif new file mode 100644 index 000000000..1e95e7cae Binary files /dev/null and b/packages/html/public/images/minimize.gif differ diff --git a/src/public/images/navigate_minus.png b/packages/html/public/images/navigate_minus.png similarity index 100% rename from src/public/images/navigate_minus.png rename to packages/html/public/images/navigate_minus.png diff --git a/src/public/images/navigate_plus.png b/packages/html/public/images/navigate_plus.png similarity index 100% rename from src/public/images/navigate_plus.png rename to packages/html/public/images/navigate_plus.png diff --git a/src/public/editors/images/new.gif b/packages/html/public/images/new.gif similarity index 100% rename from src/public/editors/images/new.gif rename to packages/html/public/images/new.gif diff --git a/packages/html/public/images/normalize.gif b/packages/html/public/images/normalize.gif new file mode 100644 index 000000000..34a8d302e Binary files /dev/null and b/packages/html/public/images/normalize.gif differ diff --git a/src/public/editors/images/open.gif b/packages/html/public/images/open.gif similarity index 100% rename from src/public/editors/images/open.gif rename to packages/html/public/images/open.gif diff --git a/src/public/editors/images/open_end.gif b/packages/html/public/images/open_end.gif similarity index 100% rename from src/public/editors/images/open_end.gif rename to packages/html/public/images/open_end.gif diff --git a/src/public/editors/images/open_start.gif b/packages/html/public/images/open_start.gif similarity index 100% rename from src/public/editors/images/open_start.gif rename to packages/html/public/images/open_start.gif diff --git a/src/public/editors/images/outline.gif b/packages/html/public/images/outline.gif similarity index 100% rename from src/public/editors/images/outline.gif rename to packages/html/public/images/outline.gif diff --git a/src/public/editors/images/oval_end.gif b/packages/html/public/images/oval_end.gif similarity index 100% rename from src/public/editors/images/oval_end.gif rename to packages/html/public/images/oval_end.gif diff --git a/src/public/editors/images/oval_start.gif b/packages/html/public/images/oval_start.gif similarity index 100% rename from src/public/editors/images/oval_start.gif rename to packages/html/public/images/oval_start.gif diff --git a/src/public/editors/images/overlays/check.png b/packages/html/public/images/overlays/check.png similarity index 100% rename from src/public/editors/images/overlays/check.png rename to packages/html/public/images/overlays/check.png diff --git a/src/public/editors/images/overlays/error.png b/packages/html/public/images/overlays/error.png similarity index 100% rename from src/public/editors/images/overlays/error.png rename to packages/html/public/images/overlays/error.png diff --git a/src/public/editors/images/overlays/flash.png b/packages/html/public/images/overlays/flash.png similarity index 100% rename from src/public/editors/images/overlays/flash.png rename to packages/html/public/images/overlays/flash.png diff --git a/src/public/editors/images/overlays/forbidden.png b/packages/html/public/images/overlays/forbidden.png similarity index 100% rename from src/public/editors/images/overlays/forbidden.png rename to packages/html/public/images/overlays/forbidden.png diff --git a/src/public/editors/images/overlays/help.png b/packages/html/public/images/overlays/help.png similarity index 100% rename from src/public/editors/images/overlays/help.png rename to packages/html/public/images/overlays/help.png diff --git a/src/public/editors/images/overlays/house.png b/packages/html/public/images/overlays/house.png similarity index 100% rename from src/public/editors/images/overlays/house.png rename to packages/html/public/images/overlays/house.png diff --git a/src/public/editors/images/overlays/information.png b/packages/html/public/images/overlays/information.png similarity index 100% rename from src/public/editors/images/overlays/information.png rename to packages/html/public/images/overlays/information.png diff --git a/src/public/editors/images/overlays/lightbulb_on.png b/packages/html/public/images/overlays/lightbulb_on.png similarity index 100% rename from src/public/editors/images/overlays/lightbulb_on.png rename to packages/html/public/images/overlays/lightbulb_on.png diff --git a/src/public/editors/images/overlays/pencil.png b/packages/html/public/images/overlays/pencil.png similarity index 100% rename from src/public/editors/images/overlays/pencil.png rename to packages/html/public/images/overlays/pencil.png diff --git a/src/public/editors/images/overlays/printer.png b/packages/html/public/images/overlays/printer.png similarity index 100% rename from src/public/editors/images/overlays/printer.png rename to packages/html/public/images/overlays/printer.png diff --git a/src/public/editors/images/overlays/user3.png b/packages/html/public/images/overlays/user3.png similarity index 100% rename from src/public/editors/images/overlays/user3.png rename to packages/html/public/images/overlays/user3.png diff --git a/src/public/editors/images/overlays/users3.png b/packages/html/public/images/overlays/users3.png similarity index 100% rename from src/public/editors/images/overlays/users3.png rename to packages/html/public/images/overlays/users3.png diff --git a/src/public/editors/images/overlays/workplace.png b/packages/html/public/images/overlays/workplace.png similarity index 100% rename from src/public/editors/images/overlays/workplace.png rename to packages/html/public/images/overlays/workplace.png diff --git a/src/public/editors/images/package.png b/packages/html/public/images/package.png similarity index 100% rename from src/public/editors/images/package.png rename to packages/html/public/images/package.png diff --git a/src/public/editors/images/pan.gif b/packages/html/public/images/pan.gif similarity index 100% rename from src/public/editors/images/pan.gif rename to packages/html/public/images/pan.gif diff --git a/src/public/editors/images/paste.gif b/packages/html/public/images/paste.gif similarity index 100% rename from src/public/editors/images/paste.gif rename to packages/html/public/images/paste.gif diff --git a/src/public/images/paste.png b/packages/html/public/images/paste.png similarity index 100% rename from src/public/images/paste.png rename to packages/html/public/images/paste.png diff --git a/src/public/editors/images/plain.gif b/packages/html/public/images/plain.gif similarity index 100% rename from src/public/editors/images/plain.gif rename to packages/html/public/images/plain.gif diff --git a/src/public/images/plus.png b/packages/html/public/images/plus.png similarity index 100% rename from src/public/images/plus.png rename to packages/html/public/images/plus.png diff --git a/packages/html/public/images/point.gif b/packages/html/public/images/point.gif new file mode 100644 index 000000000..9074c395f Binary files /dev/null and b/packages/html/public/images/point.gif differ diff --git a/src/public/editors/images/preferences.gif b/packages/html/public/images/preferences.gif similarity index 100% rename from src/public/editors/images/preferences.gif rename to packages/html/public/images/preferences.gif diff --git a/src/public/editors/images/press.gif b/packages/html/public/images/press.gif similarity index 100% rename from src/public/editors/images/press.gif rename to packages/html/public/images/press.gif diff --git a/src/public/images/press32.png b/packages/html/public/images/press32.png similarity index 100% rename from src/public/images/press32.png rename to packages/html/public/images/press32.png diff --git a/src/public/editors/images/preview.gif b/packages/html/public/images/preview.gif similarity index 100% rename from src/public/editors/images/preview.gif rename to packages/html/public/images/preview.gif diff --git a/src/public/editors/images/print.gif b/packages/html/public/images/print.gif similarity index 100% rename from src/public/editors/images/print.gif rename to packages/html/public/images/print.gif diff --git a/src/public/images/print32.png b/packages/html/public/images/print32.png similarity index 100% rename from src/public/images/print32.png rename to packages/html/public/images/print32.png diff --git a/src/public/editors/images/printer.png b/packages/html/public/images/printer.png similarity index 100% rename from src/public/editors/images/printer.png rename to packages/html/public/images/printer.png diff --git a/src/public/editors/images/properties.gif b/packages/html/public/images/properties.gif similarity index 100% rename from src/public/editors/images/properties.gif rename to packages/html/public/images/properties.gif diff --git a/src/public/editors/images/rectangle.gif b/packages/html/public/images/rectangle.gif similarity index 100% rename from src/public/editors/images/rectangle.gif rename to packages/html/public/images/rectangle.gif diff --git a/src/public/editors/images/redo.gif b/packages/html/public/images/redo.gif similarity index 100% rename from src/public/editors/images/redo.gif rename to packages/html/public/images/redo.gif diff --git a/src/public/images/redo.png b/packages/html/public/images/redo.png similarity index 100% rename from src/public/images/redo.png rename to packages/html/public/images/redo.png diff --git a/src/public/editors/images/refresh.gif b/packages/html/public/images/refresh.gif similarity index 100% rename from src/public/editors/images/refresh.gif rename to packages/html/public/images/refresh.gif diff --git a/packages/html/public/images/resize.gif b/packages/html/public/images/resize.gif new file mode 100644 index 000000000..ff558dba0 Binary files /dev/null and b/packages/html/public/images/resize.gif differ diff --git a/src/public/editors/images/rhombus.gif b/packages/html/public/images/rhombus.gif similarity index 100% rename from src/public/editors/images/rhombus.gif rename to packages/html/public/images/rhombus.gif diff --git a/src/public/editors/images/right.gif b/packages/html/public/images/right.gif similarity index 100% rename from src/public/editors/images/right.gif rename to packages/html/public/images/right.gif diff --git a/src/public/editors/images/rounded.gif b/packages/html/public/images/rounded.gif similarity index 100% rename from src/public/editors/images/rounded.gif rename to packages/html/public/images/rounded.gif diff --git a/src/public/editors/images/save.gif b/packages/html/public/images/save.gif similarity index 100% rename from src/public/editors/images/save.gif rename to packages/html/public/images/save.gif diff --git a/src/public/editors/images/saveas.gif b/packages/html/public/images/saveas.gif similarity index 100% rename from src/public/editors/images/saveas.gif rename to packages/html/public/images/saveas.gif diff --git a/src/public/editors/images/script.gif b/packages/html/public/images/script.gif similarity index 100% rename from src/public/editors/images/script.gif rename to packages/html/public/images/script.gif diff --git a/src/public/editors/images/select.gif b/packages/html/public/images/select.gif similarity index 100% rename from src/public/editors/images/select.gif rename to packages/html/public/images/select.gif diff --git a/packages/html/public/images/separator.gif b/packages/html/public/images/separator.gif new file mode 100644 index 000000000..5c1b89566 Binary files /dev/null and b/packages/html/public/images/separator.gif differ diff --git a/src/public/images/icons48/server.png b/packages/html/public/images/server.png similarity index 100% rename from src/public/images/icons48/server.png rename to packages/html/public/images/server.png diff --git a/src/public/images/sidebar_bg.gif b/packages/html/public/images/sidebar_bg.gif similarity index 100% rename from src/public/images/sidebar_bg.gif rename to packages/html/public/images/sidebar_bg.gif diff --git a/src/public/images/spacer.gif b/packages/html/public/images/spacer.gif similarity index 100% rename from src/public/images/spacer.gif rename to packages/html/public/images/spacer.gif diff --git a/src/public/editors/images/straight.gif b/packages/html/public/images/straight.gif similarity index 100% rename from src/public/editors/images/straight.gif rename to packages/html/public/images/straight.gif diff --git a/packages/html/public/images/submenu.gif b/packages/html/public/images/submenu.gif new file mode 100644 index 000000000..ffe76176d Binary files /dev/null and b/packages/html/public/images/submenu.gif differ diff --git a/src/public/editors/images/swimlane.gif b/packages/html/public/images/swimlane.gif similarity index 100% rename from src/public/editors/images/swimlane.gif rename to packages/html/public/images/swimlane.gif diff --git a/src/public/editors/images/symbols/cancel_end.png b/packages/html/public/images/symbols/cancel_end.png similarity index 100% rename from src/public/editors/images/symbols/cancel_end.png rename to packages/html/public/images/symbols/cancel_end.png diff --git a/src/public/editors/images/symbols/cancel_intermediate.png b/packages/html/public/images/symbols/cancel_intermediate.png similarity index 100% rename from src/public/editors/images/symbols/cancel_intermediate.png rename to packages/html/public/images/symbols/cancel_intermediate.png diff --git a/src/public/editors/images/symbols/error.png b/packages/html/public/images/symbols/error.png similarity index 100% rename from src/public/editors/images/symbols/error.png rename to packages/html/public/images/symbols/error.png diff --git a/src/public/editors/images/symbols/event.png b/packages/html/public/images/symbols/event.png similarity index 100% rename from src/public/editors/images/symbols/event.png rename to packages/html/public/images/symbols/event.png diff --git a/src/public/editors/images/symbols/event_end.png b/packages/html/public/images/symbols/event_end.png similarity index 100% rename from src/public/editors/images/symbols/event_end.png rename to packages/html/public/images/symbols/event_end.png diff --git a/src/public/editors/images/symbols/event_intermediate.png b/packages/html/public/images/symbols/event_intermediate.png similarity index 100% rename from src/public/editors/images/symbols/event_intermediate.png rename to packages/html/public/images/symbols/event_intermediate.png diff --git a/src/public/editors/images/symbols/fork.png b/packages/html/public/images/symbols/fork.png similarity index 100% rename from src/public/editors/images/symbols/fork.png rename to packages/html/public/images/symbols/fork.png diff --git a/src/public/editors/images/symbols/inclusive.png b/packages/html/public/images/symbols/inclusive.png similarity index 100% rename from src/public/editors/images/symbols/inclusive.png rename to packages/html/public/images/symbols/inclusive.png diff --git a/src/public/editors/images/symbols/link.png b/packages/html/public/images/symbols/link.png similarity index 100% rename from src/public/editors/images/symbols/link.png rename to packages/html/public/images/symbols/link.png diff --git a/src/public/editors/images/symbols/merge.png b/packages/html/public/images/symbols/merge.png similarity index 100% rename from src/public/editors/images/symbols/merge.png rename to packages/html/public/images/symbols/merge.png diff --git a/src/public/editors/images/symbols/message.png b/packages/html/public/images/symbols/message.png similarity index 100% rename from src/public/editors/images/symbols/message.png rename to packages/html/public/images/symbols/message.png diff --git a/src/public/editors/images/symbols/message_end.png b/packages/html/public/images/symbols/message_end.png similarity index 100% rename from src/public/editors/images/symbols/message_end.png rename to packages/html/public/images/symbols/message_end.png diff --git a/src/public/editors/images/symbols/message_intermediate.png b/packages/html/public/images/symbols/message_intermediate.png similarity index 100% rename from src/public/editors/images/symbols/message_intermediate.png rename to packages/html/public/images/symbols/message_intermediate.png diff --git a/src/public/editors/images/symbols/multiple.png b/packages/html/public/images/symbols/multiple.png similarity index 100% rename from src/public/editors/images/symbols/multiple.png rename to packages/html/public/images/symbols/multiple.png diff --git a/src/public/editors/images/symbols/rule.png b/packages/html/public/images/symbols/rule.png similarity index 100% rename from src/public/editors/images/symbols/rule.png rename to packages/html/public/images/symbols/rule.png diff --git a/src/public/editors/images/symbols/small_cancel_end.gif b/packages/html/public/images/symbols/small_cancel_end.gif similarity index 100% rename from src/public/editors/images/symbols/small_cancel_end.gif rename to packages/html/public/images/symbols/small_cancel_end.gif diff --git a/src/public/editors/images/symbols/small_cancel_intermediate.gif b/packages/html/public/images/symbols/small_cancel_intermediate.gif similarity index 100% rename from src/public/editors/images/symbols/small_cancel_intermediate.gif rename to packages/html/public/images/symbols/small_cancel_intermediate.gif diff --git a/src/public/editors/images/symbols/small_error.gif b/packages/html/public/images/symbols/small_error.gif similarity index 100% rename from src/public/editors/images/symbols/small_error.gif rename to packages/html/public/images/symbols/small_error.gif diff --git a/src/public/editors/images/symbols/small_event.gif b/packages/html/public/images/symbols/small_event.gif similarity index 100% rename from src/public/editors/images/symbols/small_event.gif rename to packages/html/public/images/symbols/small_event.gif diff --git a/src/public/editors/images/symbols/small_event_end.gif b/packages/html/public/images/symbols/small_event_end.gif similarity index 100% rename from src/public/editors/images/symbols/small_event_end.gif rename to packages/html/public/images/symbols/small_event_end.gif diff --git a/src/public/editors/images/symbols/small_event_intermediate.gif b/packages/html/public/images/symbols/small_event_intermediate.gif similarity index 100% rename from src/public/editors/images/symbols/small_event_intermediate.gif rename to packages/html/public/images/symbols/small_event_intermediate.gif diff --git a/src/public/editors/images/symbols/small_fork.gif b/packages/html/public/images/symbols/small_fork.gif similarity index 100% rename from src/public/editors/images/symbols/small_fork.gif rename to packages/html/public/images/symbols/small_fork.gif diff --git a/src/public/editors/images/symbols/small_inclusive.gif b/packages/html/public/images/symbols/small_inclusive.gif similarity index 100% rename from src/public/editors/images/symbols/small_inclusive.gif rename to packages/html/public/images/symbols/small_inclusive.gif diff --git a/src/public/editors/images/symbols/small_link.gif b/packages/html/public/images/symbols/small_link.gif similarity index 100% rename from src/public/editors/images/symbols/small_link.gif rename to packages/html/public/images/symbols/small_link.gif diff --git a/src/public/editors/images/symbols/small_merge.gif b/packages/html/public/images/symbols/small_merge.gif similarity index 100% rename from src/public/editors/images/symbols/small_merge.gif rename to packages/html/public/images/symbols/small_merge.gif diff --git a/src/public/editors/images/symbols/small_message.gif b/packages/html/public/images/symbols/small_message.gif similarity index 100% rename from src/public/editors/images/symbols/small_message.gif rename to packages/html/public/images/symbols/small_message.gif diff --git a/src/public/editors/images/symbols/small_message_end.gif b/packages/html/public/images/symbols/small_message_end.gif similarity index 100% rename from src/public/editors/images/symbols/small_message_end.gif rename to packages/html/public/images/symbols/small_message_end.gif diff --git a/src/public/editors/images/symbols/small_message_intermediate.gif b/packages/html/public/images/symbols/small_message_intermediate.gif similarity index 100% rename from src/public/editors/images/symbols/small_message_intermediate.gif rename to packages/html/public/images/symbols/small_message_intermediate.gif diff --git a/src/public/editors/images/symbols/small_multiple.gif b/packages/html/public/images/symbols/small_multiple.gif similarity index 100% rename from src/public/editors/images/symbols/small_multiple.gif rename to packages/html/public/images/symbols/small_multiple.gif diff --git a/src/public/editors/images/symbols/small_rule.gif b/packages/html/public/images/symbols/small_rule.gif similarity index 100% rename from src/public/editors/images/symbols/small_rule.gif rename to packages/html/public/images/symbols/small_rule.gif diff --git a/src/public/editors/images/symbols/small_terminate.gif b/packages/html/public/images/symbols/small_terminate.gif similarity index 100% rename from src/public/editors/images/symbols/small_terminate.gif rename to packages/html/public/images/symbols/small_terminate.gif diff --git a/src/public/editors/images/symbols/small_timer.gif b/packages/html/public/images/symbols/small_timer.gif similarity index 100% rename from src/public/editors/images/symbols/small_timer.gif rename to packages/html/public/images/symbols/small_timer.gif diff --git a/src/public/editors/images/symbols/terminate.png b/packages/html/public/images/symbols/terminate.png similarity index 100% rename from src/public/editors/images/symbols/terminate.png rename to packages/html/public/images/symbols/terminate.png diff --git a/src/public/editors/images/symbols/timer.png b/packages/html/public/images/symbols/timer.png similarity index 100% rename from src/public/editors/images/symbols/timer.png rename to packages/html/public/images/symbols/timer.png diff --git a/src/public/editors/images/tasks.gif b/packages/html/public/images/tasks.gif similarity index 100% rename from src/public/editors/images/tasks.gif rename to packages/html/public/images/tasks.gif diff --git a/src/public/editors/images/text.gif b/packages/html/public/images/text.gif similarity index 100% rename from src/public/editors/images/text.gif rename to packages/html/public/images/text.gif diff --git a/src/public/editors/images/toback.gif b/packages/html/public/images/toback.gif similarity index 100% rename from src/public/editors/images/toback.gif rename to packages/html/public/images/toback.gif diff --git a/src/public/editors/images/tofront.gif b/packages/html/public/images/tofront.gif similarity index 100% rename from src/public/editors/images/tofront.gif rename to packages/html/public/images/tofront.gif diff --git a/src/public/editors/images/toolbar.gif b/packages/html/public/images/toolbar.gif similarity index 100% rename from src/public/editors/images/toolbar.gif rename to packages/html/public/images/toolbar.gif diff --git a/src/public/images/toolbar_bg.gif b/packages/html/public/images/toolbar_bg.gif similarity index 100% rename from src/public/images/toolbar_bg.gif rename to packages/html/public/images/toolbar_bg.gif diff --git a/src/public/editors/images/top.gif b/packages/html/public/images/top.gif similarity index 100% rename from src/public/editors/images/top.gif rename to packages/html/public/images/top.gif diff --git a/packages/html/public/images/transparent.gif b/packages/html/public/images/transparent.gif new file mode 100644 index 000000000..76040f2b0 Binary files /dev/null and b/packages/html/public/images/transparent.gif differ diff --git a/src/public/editors/images/tree.gif b/packages/html/public/images/tree.gif similarity index 100% rename from src/public/editors/images/tree.gif rename to packages/html/public/images/tree.gif diff --git a/src/public/editors/images/triangle.gif b/packages/html/public/images/triangle.gif similarity index 100% rename from src/public/editors/images/triangle.gif rename to packages/html/public/images/triangle.gif diff --git a/src/public/editors/images/underline.gif b/packages/html/public/images/underline.gif similarity index 100% rename from src/public/editors/images/underline.gif rename to packages/html/public/images/underline.gif diff --git a/src/public/editors/images/undo.gif b/packages/html/public/images/undo.gif similarity index 100% rename from src/public/editors/images/undo.gif rename to packages/html/public/images/undo.gif diff --git a/src/public/images/undo.png b/packages/html/public/images/undo.png similarity index 100% rename from src/public/images/undo.png rename to packages/html/public/images/undo.png diff --git a/src/public/editors/images/ungroup.gif b/packages/html/public/images/ungroup.gif similarity index 100% rename from src/public/editors/images/ungroup.gif rename to packages/html/public/images/ungroup.gif diff --git a/src/public/editors/images/up.gif b/packages/html/public/images/up.gif similarity index 100% rename from src/public/editors/images/up.gif rename to packages/html/public/images/up.gif diff --git a/src/public/editors/images/vertical.gif b/packages/html/public/images/vertical.gif similarity index 100% rename from src/public/editors/images/vertical.gif rename to packages/html/public/images/vertical.gif diff --git a/src/public/images/view_1_1.png b/packages/html/public/images/view_1_1.png similarity index 100% rename from src/public/images/view_1_1.png rename to packages/html/public/images/view_1_1.png diff --git a/src/public/images/view_1_132.png b/packages/html/public/images/view_1_132.png similarity index 100% rename from src/public/images/view_1_132.png rename to packages/html/public/images/view_1_132.png diff --git a/src/public/images/view_next.png b/packages/html/public/images/view_next.png similarity index 100% rename from src/public/images/view_next.png rename to packages/html/public/images/view_next.png diff --git a/src/public/images/view_previous.png b/packages/html/public/images/view_previous.png similarity index 100% rename from src/public/images/view_previous.png rename to packages/html/public/images/view_previous.png diff --git a/packages/html/public/images/warning.gif b/packages/html/public/images/warning.gif new file mode 100644 index 000000000..705235f95 Binary files /dev/null and b/packages/html/public/images/warning.gif differ diff --git a/packages/html/public/images/warning.png b/packages/html/public/images/warning.png new file mode 100644 index 000000000..2f7878964 Binary files /dev/null and b/packages/html/public/images/warning.png differ diff --git a/packages/html/public/images/window-title.gif b/packages/html/public/images/window-title.gif new file mode 100644 index 000000000..231def8bb Binary files /dev/null and b/packages/html/public/images/window-title.gif differ diff --git a/packages/html/public/images/window.gif b/packages/html/public/images/window.gif new file mode 100644 index 000000000..6631c4f5f Binary files /dev/null and b/packages/html/public/images/window.gif differ diff --git a/src/public/images/wires-grid.gif b/packages/html/public/images/wires-grid.gif similarity index 100% rename from src/public/images/wires-grid.gif rename to packages/html/public/images/wires-grid.gif diff --git a/src/public/editors/images/workplace.png b/packages/html/public/images/workplace.png similarity index 100% rename from src/public/editors/images/workplace.png rename to packages/html/public/images/workplace.png diff --git a/src/public/editors/images/wrench.png b/packages/html/public/images/wrench.png similarity index 100% rename from src/public/editors/images/wrench.png rename to packages/html/public/images/wrench.png diff --git a/src/public/editors/images/zoom.gif b/packages/html/public/images/zoom.gif similarity index 100% rename from src/public/editors/images/zoom.gif rename to packages/html/public/images/zoom.gif diff --git a/src/public/images/zoom_in.png b/packages/html/public/images/zoom_in.png similarity index 100% rename from src/public/images/zoom_in.png rename to packages/html/public/images/zoom_in.png diff --git a/src/public/images/zoom_in32.png b/packages/html/public/images/zoom_in32.png similarity index 100% rename from src/public/images/zoom_in32.png rename to packages/html/public/images/zoom_in32.png diff --git a/src/public/images/zoom_out.png b/packages/html/public/images/zoom_out.png similarity index 100% rename from src/public/images/zoom_out.png rename to packages/html/public/images/zoom_out.png diff --git a/src/public/images/zoom_out32.png b/packages/html/public/images/zoom_out32.png similarity index 100% rename from src/public/images/zoom_out32.png rename to packages/html/public/images/zoom_out32.png diff --git a/src/public/editors/images/zoomactual.gif b/packages/html/public/images/zoomactual.gif similarity index 100% rename from src/public/editors/images/zoomactual.gif rename to packages/html/public/images/zoomactual.gif diff --git a/src/public/editors/images/zoomin.gif b/packages/html/public/images/zoomin.gif similarity index 100% rename from src/public/editors/images/zoomin.gif rename to packages/html/public/images/zoomin.gif diff --git a/src/public/editors/images/zoomout.gif b/packages/html/public/images/zoomout.gif similarity index 100% rename from src/public/editors/images/zoomout.gif rename to packages/html/public/images/zoomout.gif diff --git a/src/pages/shapes_stencils/stencils.xml b/packages/html/public/stencils.xml similarity index 100% rename from src/pages/shapes_stencils/stencils.xml rename to packages/html/public/stencils.xml diff --git a/packages/html/stories/Anchors.stories.js b/packages/html/stories/Anchors.stories.js new file mode 100644 index 000000000..5e2954a81 --- /dev/null +++ b/packages/html/stories/Anchors.stories.js @@ -0,0 +1,136 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Connections/Anchors', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxConnectionHandler, + mxConnectionConstraint, + mxGeometry, + mxPolyline, + mxPoint, + mxCellState + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + class MyCustomConnectionHandler extends mxConnectionHandler { + // Enables connect preview for the default edge style + createEdgeState(me) { + const edge = graph.createEdge(null, null, null, null, null); + return new mxCellState( + this.graph.view, + edge, + this.graph.getCellStyle(edge) + ); + } + } + + class MyCustomGraph extends mxGraph { + getAllConnectionConstraints(terminal, source) { + // Overridden to define per-shape connection points + if (terminal != null && terminal.shape != null) { + if (terminal.shape.stencil != null) { + if (terminal.shape.stencil.constraints != null) { + return terminal.shape.stencil.constraints; + } + } else if (terminal.shape.constraints != null) { + return terminal.shape.constraints; + } + } + return null; + } + + createConnectionHandler() { + return new MyCustomConnectionHandler(this); + } + } + + class MyCustomGeometryClass extends mxGeometry { + // Defines the default constraints for the vertices + constraints = [ + new mxConnectionConstraint(new mxPoint(0.25, 0), true), + new mxConnectionConstraint(new mxPoint(0.5, 0), true), + new mxConnectionConstraint(new mxPoint(0.75, 0), true), + new mxConnectionConstraint(new mxPoint(0, 0.25), true), + new mxConnectionConstraint(new mxPoint(0, 0.5), true), + new mxConnectionConstraint(new mxPoint(0, 0.75), true), + new mxConnectionConstraint(new mxPoint(1, 0.25), true), + new mxConnectionConstraint(new mxPoint(1, 0.5), true), + new mxConnectionConstraint(new mxPoint(1, 0.75), true), + new mxConnectionConstraint(new mxPoint(0.25, 1), true), + new mxConnectionConstraint(new mxPoint(0.5, 1), true), + new mxConnectionConstraint(new mxPoint(0.75, 1), true), + ]; + } + + // Edges have no connection points + mxPolyline.prototype.constraints = null; + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + graph.setConnectable(true); + + // Specifies the default edge style + graph.getStylesheet().getDefaultEdgeStyle().edgeStyle = + 'orthogonalEdgeStyle'; + + // Enables rubberband selection + if (args.rubberBand) + 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], + geometryClass: MyCustomGeometryClass, + }); + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [200, 150], + size: [80, 30], + geometryClass: MyCustomGeometryClass, + }); + const e1 = graph.insertEdge({ + parent, + value: '', + position: v1, + size: v2, + }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Animation.stories.js b/packages/html/stories/Animation.stories.js new file mode 100644 index 000000000..21f9102ce --- /dev/null +++ b/packages/html/stories/Animation.stories.js @@ -0,0 +1,84 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +import './css/animation.css'; + +export default { + title: 'Effects/Animation', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxPoint + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + const graph = new mxGraph(container); + graph.setEnabled(false); + const parent = graph.getDefaultParent(); + + const vertexStyle = + 'shape=cylinder;strokeWidth=2;fillColor=#ffffff;strokeColor=black;' + + 'gradientColor=#a0a0a0;fontColor=black;fontStyle=1;spacingTop=14;'; + + graph.getModel().beginUpdate(); + try { + const v1 = graph.insertVertex({ + parent, + value: 'Pump', + position: [20, 20], + size: [60, 60], + style: vertexStyle, + }); + const v2 = graph.insertVertex({ + parent, + value: 'Tank', + position: [200, 150], + size: [60, 60], + style: vertexStyle, + }); + var e1 = graph.insertEdge({ + parent, + source: v1, + target: v2, + style: + 'strokeWidth=3;endArrow=block;endSize=2;endFill=1;strokeColor=black;rounded=1;', + }); + e1.geometry.points = [new mxPoint(230, 50)]; + graph.orderCells(true, [e1]); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + // Adds animation to edge shape and makes "pipe" visible + const state = graph.view.getState(e1); + state.shape.node + .getElementsByTagName('path')[0] + .removeAttribute('visibility'); + state.shape.node + .getElementsByTagName('path')[0] + .setAttribute('stroke-width', '6'); + state.shape.node + .getElementsByTagName('path')[0] + .setAttribute('stroke', 'lightGray'); + state.shape.node + .getElementsByTagName('path')[1] + .setAttribute('class', 'flow'); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/AutoLayout.stories.js b/packages/html/stories/AutoLayout.stories.js new file mode 100644 index 000000000..cc0e57149 --- /dev/null +++ b/packages/html/stories/AutoLayout.stories.js @@ -0,0 +1,217 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/AutoLayout', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxEvent, + mxUtils, + mxCellRenderer, + mxEdgeHandler, + mxHierarchicalLayout, + mxConstants, + mxCellOverlay, + mxImage, + mxClient, + mxMorphing, + mxEventObject, + mxEventUtils + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + class MyCustomCellRenderer extends mxCellRenderer { + installCellOverlayListeners(state, overlay, shape) { + super.installCellOverlayListeners(state, overlay, shape); + + mxEvent.addListener( + shape.node, + mxClient.IS_POINTER ? 'pointerdown' : 'mousedown', + evt => { + overlay.fireEvent( + new mxEventObject('pointerdown', 'event', evt, 'state', state) + ); + } + ); + + if (!mxClient.IS_POINTER && mxClient.IS_TOUCH) { + mxEvent.addListener(shape.node, 'touchstart', evt => { + overlay.fireEvent( + new mxEventObject('pointerdown', 'event', evt, 'state', state) + ); + }); + } + } + } + + class MyCustomEdgeHandler extends mxEdgeHandler { + connect(edge, terminal, isSource, isClone, me) { + super.connect(edge, terminal, isSource, isClone, me); + executeLayout(); + } + } + + class MyCustomGraph extends mxGraph { + createEdgeHandler(state, edgeStyle) { + return new MyCustomEdgeHandler(state, edgeStyle); + } + + createCellRenderer() { + return new MyCustomCellRenderer(); + } + } + + // Creates the graph inside the given this.el + const graph = new MyCustomGraph(container); + graph.setPanning(true); + graph.panningHandler.useLeftButtonForPanning = true; + graph.setAllowDanglingEdges(false); + graph.connectionHandler.select = false; + graph.view.setTranslate(20, 20); + + // Enables rubberband selection + if (args.rubberBand) + 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(); + + const layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_WEST); + const executeLayout = (change, post) => { + graph.getModel().beginUpdate(); + try { + if (change != null) { + change(); + } + layout.execute(graph.getDefaultParent(), v1); + } catch (e) { + throw e; + } finally { + // New API for animating graph layout results asynchronously + const morph = new mxMorphing(graph); + morph.addListener(mxEvent.DONE, () => { + graph.getModel().endUpdate(); + if (post != null) { + post(); + } + }); + morph.startAnimation(); + } + }; + + const addOverlay = cell => { + // Creates a new overlay with an image and a tooltip + const overlay = new mxCellOverlay( + new mxImage('images/add.png', 24, 24), + 'Add outgoing' + ); + overlay.cursor = 'hand'; + + // Installs a handler for clicks on the overlay + overlay.addListener(mxEvent.CLICK, (sender, evt2) => { + graph.clearSelection(); + const geo = graph.getCellGeometry(cell); + + let v2; + + executeLayout( + () => { + v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [geo.x, geo.y], + size: [80, 30], + }); + addOverlay(v2); + graph.view.refresh(v2); + const e1 = graph.insertEdge({ + parent, + source: cell, + target: v2, + }); + }, + () => { + graph.scrollCellToVisible(v2); + } + ); + }); + + // Special CMS event + overlay.addListener('pointerdown', (sender, eo) => { + const evt2 = eo.getProperty('event'); + const state = eo.getProperty('state'); + + graph.popupMenuHandler.hideMenu(); + graph.stopEditing(false); + + const pt = mxUtils.convertPoint( + graph.container, + mxEventUtils.getClientX(evt2), + mxEventUtils.getClientY(evt2) + ); + graph.connectionHandler.start(state, pt.x, pt.y); + graph.isMouseDown = true; + graph.isMouseTrigger = mxEventUtils.isMouseEvent(evt2); + mxEvent.consume(evt2); + }); + + // Sets the overlay for the cell in the graph + graph.addCellOverlay(cell, overlay); + }; + + // Adds cells to the model in a single step + graph.getModel().beginUpdate(); + let v1; + try { + v1 = graph.insertVertex({ + parent, + value: 'Hello,', + position: [0, 0], + size: [80, 30], + }); + addOverlay(v1); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + graph.resizeCell = function() { + mxGraph.prototype.resizeCell.apply(this, arguments); + executeLayout(); + }; + + graph.connectionHandler.addListener(mxEvent.CONNECT, function() { + executeLayout(); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Boundary.stories.js b/packages/html/stories/Boundary.stories.js new file mode 100644 index 000000000..221cc8c54 --- /dev/null +++ b/packages/html/stories/Boundary.stories.js @@ -0,0 +1,238 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Events/Boundary', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxConnectionHandler, + mxConnectionConstraint, + mxGeometry, + mxPolyline, + mxPoint, + mxConstants + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Disables the built-in context menu + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + class MyCustomGraph extends mxGraph { + // Enables moving of relative children + isCellLocked(cell) { + return false; + } + + // Removes folding icon for relative children + isCellFoldable(cell, collapse) { + const childCount = cell.getChildCount(); + + for (let i = 0; i < childCount; i++) { + const child = cell.getChildAt(i); + const geo = this.getCellGeometry(child); + + if (geo != null && geo.relative) { + return false; + } + } + + return childCount > 0; + } + + // Returns the relative position of the given child + getRelativePosition(state, dx, dy) { + if (state != null) { + const model = graph.getModel(); + const geo = state.cell.getGeometry(); + + if (geo != null && geo.relative && !state.cell.isEdge()) { + const parent = state.cell.getParent(); + + if (parent.isVertex()) { + const pstate = graph.view.getState(parent); + + if (pstate != null) { + const { scale } = graph.view; + let x = state.x + dx; + let y = state.y + dy; + + if (geo.offset != null) { + x -= geo.offset.x * scale; + y -= geo.offset.y * scale; + } + + x = (x - pstate.x) / pstate.width; + y = (y - pstate.y) / pstate.height; + + if (Math.abs(y - 0.5) <= Math.abs((x - 0.5) / 2)) { + x = x > 0.5 ? 1 : 0; + y = Math.min(1, Math.max(0, y)); + } else { + x = Math.min(1, Math.max(0, x)); + y = y > 0.5 ? 1 : 0; + } + + return new mxPoint(x, y); + } + } + } + } + + return null; + } + + // Replaces translation for relative children + translateCell(cell, dx, dy) { + const rel = this.getRelativePosition( + this.view.getState(cell), + dx * graph.view.scale, + dy * graph.view.scale + ); + + if (rel != null) { + let geo = cell.getGeometry(); + + if (geo != null && geo.relative) { + geo = geo.clone(); + geo.x = rel.x; + geo.y = rel.y; + + this.model.setGeometry(cell, geo); + } + } else { + mxGraph.prototype.translateCell.apply(this, arguments); + } + } + } + + // Creates the graph inside the given this.el + const graph = new MyCustomGraph(container); + + // Sets the base style for all vertices + const style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_FILLCOLOR] = '#ffffff'; + style[mxConstants.STYLE_STROKECOLOR] = '#000000'; + style[mxConstants.STYLE_STROKEWIDTH] = '2'; + style[mxConstants.STYLE_FONTCOLOR] = '#000000'; + style[mxConstants.STYLE_FONTSIZE] = '12'; + style[mxConstants.STYLE_FONTSTYLE] = 1; + graph.getStylesheet().putDefaultVertexStyle(style); + + // Replaces move preview for relative children + graph.graphHandler.getDelta = function(me) { + const point = mxUtils.convertPoint( + this.graph.container, + me.getX(), + me.getY() + ); + let delta = new mxPoint(point.x - this.first.x, point.y - this.first.y); + + if ( + this.cells != null && + this.cells.length > 0 && + this.cells[0] != null + ) { + const state = this.graph.view.getState(this.cells[0]); + const rel = graph.getRelativePosition(state, delta.x, delta.y); + + if (rel != null) { + const pstate = this.graph.view.getState( + state.cell.getParent() + ); + + if (pstate != null) { + delta = new mxPoint( + pstate.x + pstate.width * rel.x - state.getCenterX(), + pstate.y + pstate.height * rel.y - state.getCenterY() + ); + } + } + } + + return delta; + }; + + // Relative children cannot be removed from parent + graph.graphHandler.shouldRemoveCellsFromParent = function( + parent, + cells, + evt + ) { + return ( + cells.length === 0 && + !cells[0].geometry.relative && + mxGraphHandler.prototype.shouldRemoveCellsFromParent.apply( + this, + arguments + ) + ); + }; + + // Enables rubberband selection + if (args.rubberBand) + 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: 'Process', + position: [60, 60], + size: [90, 40], + }); + + const v2 = graph.insertVertex({ + parent: v1, + value: 'in', + position: [0, 0.5], + size: [20, 20], + style: 'fontSize=9;shape=ellipse;resizable=0;', + }); + v2.geometry.offset = new mxPoint(-10, -10); + v2.geometry.relative = true; + + const v3 = graph.insertVertex({ + parent: v1, + value: 'out', + position: [1, 0.5], + size: [20, 20], + style: 'fontSize=9;shape=ellipse;resizable=0;', + }); + v3.geometry.offset = new mxPoint(-10, -10); + v3.geometry.relative = true; + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Clipboard.stories.js b/packages/html/stories/Clipboard.stories.js new file mode 100644 index 000000000..4e16a8fd1 --- /dev/null +++ b/packages/html/stories/Clipboard.stories.js @@ -0,0 +1,357 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'DnD_CopyPaste/Clipboard', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxClipboard, + mxUtils, + mxEventUtils, + mxClient, + mxCodec, + mxGraphModel, + mxStringUtils + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Disables the built-in context menu + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + // Creates the graph inside the given this.el + const graph = new mxGraph(container); + + // Public helper method for shared clipboard. + mxClipboard.cellsToString = function(cells) { + const codec = new mxCodec(); + const model = new mxGraphModel(); + const parent = model.getRoot().getChildAt(0); + + for (let i = 0; i < cells.length; i++) { + model.add(parent, cells[i]); + } + + return mxUtils.getXml(codec.encode(model)); + }; + + // Focused but invisible textarea during control or meta key events + const textInput = document.createElement('textarea'); + mxUtils.setOpacity(textInput, 0); + textInput.style.width = '1px'; + textInput.style.height = '1px'; + let restoreFocus = false; + const gs = graph.gridSize; + let lastPaste = null; + let dx = 0; + let dy = 0; + + // Workaround for no copy event in IE/FF if empty + textInput.value = ' '; + + // Shows a textare when control/cmd is pressed to handle native clipboard actions + mxEvent.addListener(document, 'keydown', function(evt) { + // No dialog visible + const source = mxEventUtils.getSource(evt); + + if ( + graph.isEnabled() && + !graph.isMouseDown && + !graph.isEditing() && + source.nodeName !== 'INPUT' + ) { + if ( + evt.keyCode === 224 /* FF */ || + (!mxClient.IS_MAC && evt.keyCode === 17) /* Control */ || + (mxClient.IS_MAC && + (evt.keyCode === 91 || evt.keyCode === 93)) /* Left/Right Meta */ + ) { + // Cannot use parentNode for check in IE + if (!restoreFocus) { + // Avoid autoscroll but allow handling of events + textInput.style.position = 'absolute'; + textInput.style.left = `${graph.container.scrollLeft + 10}px`; + textInput.style.top = `${graph.container.scrollTop + 10}px`; + graph.container.appendChild(textInput); + + restoreFocus = true; + textInput.focus(); + textInput.select(); + } + } + } + }); + + // Restores focus on graph this.el and removes text input from DOM + mxEvent.addListener(document, 'keyup', function(evt) { + if ( + restoreFocus && + (evt.keyCode === 224 /* FF */ || + evt.keyCode === 17 /* Control */ || + evt.keyCode === 91 || + evt.keyCode === 93) /* Meta */ + ) { + restoreFocus = false; + + if (!graph.isEditing()) { + graph.container.focus(); + } + + textInput.parentNode.removeChild(textInput); + } + }); + + // Inserts the XML for the given cells into the text input for copy + const copyCells = function(graph, cells) { + if (cells.length > 0) { + const clones = graph.cloneCells(cells); + + // Checks for orphaned relative children and makes absolute + for (let i = 0; i < clones.length; i++) { + const state = graph.view.getState(cells[i]); + + if (state != null) { + const geo = graph.getCellGeometry(clones[i]); + + if (geo != null && geo.relative) { + geo.relative = false; + geo.x = state.x / state.view.scale - state.view.translate.x; + geo.y = state.y / state.view.scale - state.view.translate.y; + } + } + } + + textInput.value = mxClipboard.cellsToString(clones); + } + + textInput.select(); + lastPaste = textInput.value; + }; + + // Handles copy event by putting XML for current selection into text input + mxEvent.addListener( + textInput, + 'copy', + mxUtils.bind(this, function(evt) { + if (graph.isEnabled() && !graph.isSelectionEmpty()) { + copyCells( + graph, + mxUtils.sortCells( + graph.model.getTopmostCells(graph.getSelectionCells()) + ) + ); + dx = 0; + dy = 0; + } + }) + ); + + // Handles cut event by removing cells putting XML into text input + mxEvent.addListener( + textInput, + 'cut', + mxUtils.bind(this, function(evt) { + if (graph.isEnabled() && !graph.isSelectionEmpty()) { + copyCells(graph, graph.removeCells()); + dx = -gs; + dy = -gs; + } + }) + ); + + // Merges XML into existing graph and layers + const importXml = function(xml, dx, dy) { + dx = dx != null ? dx : 0; + dy = dy != null ? dy : 0; + let cells = []; + + try { + const doc = mxUtils.parseXml(xml); + const node = doc.documentElement; + + if (node != null) { + const model = new mxGraphModel(); + const codec = new mxCodec(node.ownerDocument); + codec.decode(node, model); + + const childCount = model.getRoot().getChildCount(); + const targetChildCount = graph.model.getRoot().getChildCount(); + + // Merges existing layers and adds new layers + graph.model.beginUpdate(); + try { + for (let i = 0; i < childCount; i++) { + let parent = model.getRoot().getChildAt(i); + + // Adds cells to existing layers if not locked + if (targetChildCount > i) { + // Inserts into active layer if only one layer is being pasted + const target = + childCount === 1 + ? graph.getDefaultParent() + : graph.model.getRoot().getChildAt(i); + + if (!graph.isCellLocked(target)) { + const children = parent.getChildren(); + cells = cells.concat( + graph.importCells(children, dx, dy, target) + ); + } + } else { + // Delta is non cascading, needs separate move for layers + parent = graph.importCells( + [parent], + 0, + 0, + graph.model.getRoot() + )[0]; + const children = parent.getChildren(); + graph.moveCells(children, dx, dy); + cells = cells.concat(children); + } + } + } finally { + graph.model.endUpdate(); + } + } + } catch (e) { + alert(e); + throw e; + } + + return cells; + }; + + // Parses and inserts XML into graph + const pasteText = function(text) { + const xml = mxStringUtils.trim(text); + const x = + graph.container.scrollLeft / graph.view.scale - graph.view.translate.x; + const y = + graph.container.scrollTop / graph.view.scale - graph.view.translate.y; + + if (xml.length > 0) { + if (lastPaste !== xml) { + lastPaste = xml; + dx = 0; + dy = 0; + } else { + dx += gs; + dy += gs; + } + + // Standard paste via control-v + if (xml.substring(0, 14) === '') { + graph.setSelectionCells(importXml(xml, dx, dy)); + graph.scrollCellToVisible(graph.getSelectionCell()); + } + } + }; + + // Function to fetch text from paste events + const extractGraphModelFromEvent = function(evt) { + let data = null; + + if (evt != null) { + const provider = + evt.dataTransfer != null ? evt.dataTransfer : evt.clipboardData; + + if (provider != null) { + data = + mxUtils.indexOf(provider.types, 'text/html') >= 0 + ? provider.getData('text/html') + : null; + + if ( + mxUtils.indexOf( + provider.types, + 'text/plain' && (data == null || data.length === 0) + ) + ) { + data = provider.getData('text/plain'); + } + } + } + + return data; + }; + + // Handles paste event by parsing and inserting XML + mxEvent.addListener(textInput, 'paste', function(evt) { + // Clears existing contents before paste - should not be needed + // because all text is selected, but doesn't hurt since the + // actual pasting of the new text is delayed in all cases. + textInput.value = ''; + + if (graph.isEnabled()) { + const xml = extractGraphModelFromEvent(evt); + + if (xml != null && xml.length > 0) { + pasteText(xml); + } else { + // Timeout for new value to appear + window.setTimeout( + mxUtils.bind(this, function() { + pasteText(textInput.value); + }), + 0 + ); + } + } + + textInput.select(); + }); + + // Enables rubberband selection + if (args.rubberBand) + 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 }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Collapse.stories.js b/packages/html/stories/Collapse.stories.js new file mode 100644 index 000000000..4b5278202 --- /dev/null +++ b/packages/html/stories/Collapse.stories.js @@ -0,0 +1,66 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/Collapse', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxGraphModel, + mxRectangle + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + const graph = new mxGraph(container); + const parent = graph.getDefaultParent(); + + const getStyle = function() { + // Extends mxGraphModel.getStyle to show an image when collapsed + // TODO cannot use super without a parent class + // let style = super.getStyle(); + let style = ''; + if (this.isCollapsed()) { + style = + `${style};shape=image;image=http://www.jgraph.com/images/mxgraph.gif;` + + `noLabel=1;imageBackground=#C3D9FF;imageBorder=#6482B9`; + } + return style; + } + + graph.batchUpdate(() => { + const v1 = graph.insertVertex({ + parent, + value: 'Container', + position: [20, 20], + size: [200, 200], + style: 'shape=swimlane;startSize=20;', + }); + v1.geometry.alternateBounds = new mxRectangle(0, 0, 110, 70); + v1.getStyle = getStyle; + + const v11 = graph.insertVertex({ + parent: v1, + value: 'Hello,', + position: [10, 40], + size: [120, 80], + }); + v11.getStyle = getStyle; + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Constituent.stories.js b/packages/html/stories/Constituent.stories.js new file mode 100644 index 000000000..06bc306dd --- /dev/null +++ b/packages/html/stories/Constituent.stories.js @@ -0,0 +1,104 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/Constituent', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxGraphHandler, + mxRubberband + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Disables the built-in context menu + mxEvent.disableContextMenu(container); + + class MyCustomGraphHandler extends mxGraphHandler { + /** + * Redirects start drag to parent. + */ + getInitialCellForEvent(me) { + let cell = super.getInitialCellForEvent(me); + if (this.graph.isPart(cell)) { + cell = this.cell.getParent(); + } + return cell; + } + } + + class MyCustomGraph extends mxGraph { + foldingEnabled = false; + + recursiveResize = true; + + isPart(cell) { + // Helper method to mark parts with constituent=1 in the style + return this.getCurrentCellStyle(cell).constituent == '1'; + } + + selectCellForEvent(cell, evt) { + // Redirects selection to parent + if (this.isPart(cell)) { + cell = cell.getParent(); + } + super.selectCellForEvent(cell, evt); + } + + createGraphHandler() { + return new MyCustomGraphHandler(this); + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + + // 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, + position: [20, 20], + size: [120, 70], + }); + const v2 = graph.insertVertex({ + parent: v1, + value: 'Constituent', + position: [20, 20], + size: [80, 30], + style: 'constituent=1;', + }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/ContextIcons.stories.js b/packages/html/stories/ContextIcons.stories.js new file mode 100644 index 000000000..22f972d45 --- /dev/null +++ b/packages/html/stories/ContextIcons.stories.js @@ -0,0 +1,207 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Icon_Images/ContextIcons', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxConnectionHandler, + mxConnectionConstraint, + mxGeometry, + mxEventUtils, + mxUtils, + mxVertexHandler + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + class mxVertexToolHandler extends mxVertexHandler { + // Defines a subclass for mxVertexHandler that adds a set of clickable + // icons to every selected vertex. + + domNode = null; + + init() { + super.init(); + + // 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); + }; + + // 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', evt => { + this.graph.removeCells([this.state.cell]); + mxEvent.consume(evt); + }); + 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, evt => { + this.start(mxEventUtils.getClientX(evt), mxEventUtils.getClientY(evt), 7); + this.graph.isMouseDown = true; + this.graph.isMouseTrigger = mxEventUtils.isMouseEvent(evt); + mxEvent.consume(evt); + }); + 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, evt => { + this.graph.graphHandler.start( + this.state.cell, + mxEventUtils.getClientX(evt), + mxEventUtils.getClientY(evt) + ); + this.graph.graphHandler.cellWasClicked = true; + this.graph.isMouseDown = true; + this.graph.isMouseTrigger = mxEventUtils.isMouseEvent(evt); + mxEvent.consume(evt); + }); + 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, evt => { + const pt = mxUtils.convertPoint( + this.graph.container, + mxEventUtils.getClientX(evt), + mxEventUtils.getClientY(evt) + ); + this.graph.connectionHandler.start(this.state, pt.x, pt.y); + this.graph.isMouseDown = true; + this.graph.isMouseTrigger = mxEventUtils.isMouseEvent(evt); + mxEvent.consume(evt); + }); + this.domNode.appendChild(img); + + this.graph.container.appendChild(this.domNode); + this.redrawTools(); + } + + redraw() { + super.redraw(); + this.redrawTools(); + } + + 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`; + } + } + + destroy(sender, me) { + super.destroy(sender, me); + + if (this.domNode != null) { + this.domNode.parentNode.removeChild(this.domNode); + this.domNode = null; + } + } + } + + class MyCustomGraph extends mxGraph { + createHandler(state) { + if (state != null && state.cell.isVertex()) { + return new mxVertexToolHandler(state); + } + return super.createHandler(state); + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + 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 + if (args.rubberBand) + 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, + }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Control.stories.js b/packages/html/stories/Control.stories.js new file mode 100644 index 000000000..ef1af80bd --- /dev/null +++ b/packages/html/stories/Control.stories.js @@ -0,0 +1,200 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Icon_Images/Control', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxDomHelpers, + mxImageShape, + mxRectangle, + mxCellRenderer, + mxUtils, + mxImage + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Specifies the URL and size of the new control + const deleteImage = new mxImage( + '/images/forbidden.png', + 16, + 16 + ); + + class MyCustomCellRenderer extends mxCellRenderer { + createControl(state) { + super.createControl(state); + + const { graph } = state.view; + + if (state.cell.isVertex()) { + if (state.deleteControl == null) { + const b = new mxRectangle( + 0, + 0, + deleteImage.width, + deleteImage.height + ); + state.deleteControl = new mxImageShape(b, deleteImage.src); + state.deleteControl.dialect = graph.dialect; + state.deleteControl.preserveImageAspect = false; + + this.initControl(state, state.deleteControl, false, function(evt) { + if (graph.isEnabled()) { + graph.removeCells([state.cell]); + mxEvent.consume(evt); + } + }); + } + } else if (state.deleteControl != null) { + state.deleteControl.destroy(); + state.deleteControl = null; + } + } + + getDeleteControlBounds(state) { + // Helper function to compute the bounds of the control + if (state.deleteControl != null) { + const oldScale = state.deleteControl.scale; + const w = state.deleteControl.bounds.width / oldScale; + const h = state.deleteControl.bounds.height / oldScale; + const s = state.view.scale; + + return state.cell.isEdge() + ? new mxRectangle( + state.x + state.width / 2 - (w / 2) * s, + state.y + state.height / 2 - (h / 2) * s, + w * s, + h * s + ) + : new mxRectangle( + state.x + state.width - w * s, + state.y, + w * s, + h * s + ); + } + return null; + } + + redrawControl(state) { + // Overridden to update the scale and bounds of the control + super.redrawControl(state); + + if (state.deleteControl != null) { + const bounds = this.getDeleteControlBounds(state); + const s = state.view.scale; + + if ( + state.deleteControl.scale !== s || + !state.deleteControl.bounds.equals(bounds) + ) { + state.deleteControl.bounds = bounds; + state.deleteControl.scale = s; + state.deleteControl.redraw(); + } + } + } + + destroy(state) { + // Overridden to remove the control if the state is destroyed + super.destroy(state); + + if (state.deleteControl != null) { + state.deleteControl.destroy(); + state.deleteControl = null; + } + } + } + + class MyCustomGraph extends mxGraph { + createCellRenderer() { + return new MyCustomCellRenderer(); + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + graph.setPanning(true); + + // Uncomment the following if you want the container + // to fit the size of the graph + // graph.setResizeContainer(true); + + // Enables rubberband selection + if (args.rubberBand) + 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, + 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(); + } + + graph.centerZoom = false; + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + buttons.appendChild( + mxDomHelpers.button('Zoom In', () => { + graph.zoomIn(); + }) + ); + + buttons.appendChild( + mxDomHelpers.button('Zoom Out', () => { + graph.zoomOut(); + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/DragSource.stories.js b/packages/html/stories/DragSource.stories.js new file mode 100644 index 000000000..366569425 --- /dev/null +++ b/packages/html/stories/DragSource.stories.js @@ -0,0 +1,189 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'DnD_CopyPaste/DragSource', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxDomUtils, + mxRubberband, + mxDragSource, + mxUtils, + mxGestureUtils, + mxEdgeHandler, + mxGraphHandler, + mxGuide, + mxEventUtils, + mxCell, + mxGeometry + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.cursor = 'default'; + + class MyCustomGuide extends mxGuide { + isEnabledForEvent(evt) { + // Alt disables guides + return !mxEventUtils.isAltDown(evt); + } + } + + class MyCustomGraphHandler extends mxGraphHandler { + // Enables guides + guidesEnabled = 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 = []; + + // Creates the graph inside the given container + for (let i = 0; i < 2; i++) { + const subContainer = document.createElement('div'); + subContainer.style.overflow = 'hidden'; + subContainer.style.position = 'relative'; + subContainer.style.width = '321px'; + subContainer.style.height = '241px'; + subContainer.style.background = "url('/images/grid.gif')"; + subContainer.style.cursor = 'default'; + + container.appendChild(subContainer); + + const graph = new MyCustomGraph(subContainer); + graph.gridSize = 30; + + // Uncomment the following if you want the container + // to fit the size of the graph + // graph.setResizeContainer(true); + + // Enables rubberband selection + if (args.rubberBand) + 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, + }); + }); + + graphs.push(graph); + } + + // Returns the graph under the mouse + const graphF = evt => { + const x = mxEventUtils.getClientX(evt); + const y = mxEventUtils.getClientY(evt); + const elt = document.elementFromPoint(x, y); + + for (const graph of graphs) { + if (mxDomUtils.isAncestorNode(graph.container, elt)) { + return graph; + } + } + + return null; + }; + + // Inserts a cell at the given location + 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); + + if (cells != null && cells.length > 0) { + graph.scrollCellToVisible(cells[0]); + graph.setSelectionCells(cells); + } + }; + + // Creates a DOM node that acts as the drag source + const img = mxUtils.createImage('images/icons48/gear.png'); + img.style.width = '48px'; + img.style.height = '48px'; + container.appendChild(img); + + // Creates the element that is being for the actual preview. + const dragElt = document.createElement('div'); + dragElt.style.border = 'dashed black 1px'; + dragElt.style.width = '120px'; + dragElt.style.height = '40px'; + + // Drag source is configured to use dragElt for preview and as drag icon + // if scalePreview (last) argument is true. Dx and dy are null to force + // the use of the defaults. Note that dx and dy are only used for the + // drag icon but not for the preview. + const ds = mxGestureUtils.makeDraggable( + img, + graphF, + funct, + dragElt, + null, + null, + 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 = () => { + return graphs[0].graphHandler.guidesEnabled; + }; + + // Restores original drag icon while outside of graph + ds.createDragElement = mxDragSource.prototype.createDragElement; + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Drop.stories.js b/packages/html/stories/Drop.stories.js new file mode 100644 index 000000000..738646869 --- /dev/null +++ b/packages/html/stories/Drop.stories.js @@ -0,0 +1,193 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'DnD_CopyPaste/Drop', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxDomUtils, + mxRubberband, + mxDragSource, + mxUtils, + mxGestureUtils, + mxEdgeHandler, + mxGraphHandler, + mxGuide, + mxEventUtils, + mxEvent, + mxClient + } = mxgraph; + + const div = document.createElement('div'); + div.innerHTML = 'Drag & drop your images below:
'; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Checks if the browser is supported + const fileSupport = + window.File != null && + window.FileReader != null && + window.FileList != null; + + if (!fileSupport || !mxClient.isBrowserSupported()) { + // Displays an error message if the browser is not supported. + mxUtils.error('Browser is not supported!', 200, false); + } else { + // Disables the built-in context menu + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + // Creates the graph inside the given this.el + const graph = new mxGraph(container); + + // Enables rubberband selection + if (args.rubberBand) + new mxRubberband(graph); + + mxEvent.addListener(container, 'dragover', function(evt) { + if (graph.isEnabled()) { + evt.stopPropagation(); + evt.preventDefault(); + } + }); + + mxEvent.addListener(container, 'drop', evt => { + if (graph.isEnabled()) { + evt.stopPropagation(); + evt.preventDefault(); + + // Gets drop location point for vertex + const pt = mxUtils.convertPoint( + graph.container, + mxEventUtils.getClientX(evt), + mxEventUtils.getClientY(evt) + ); + const tr = graph.view.translate; + const { scale } = graph.view; + const x = pt.x / scale - tr.x; + const y = pt.y / scale - tr.y; + + // Converts local images to data urls + const filesArray = evt.dataTransfer.files; + + for (let i = 0; i < filesArray.length; i++) { + handleDrop(graph, filesArray[i], x + i * 10, y + i * 10); + } + } + }); + } + + return div; +} + +function handleDrop(graph, file, x, y) { + // Handles each file as a separate insert for simplicity. + // Use barrier to handle multiple files as a single insert. + + if (file.type.substring(0, 5) === 'image') { + const reader = new FileReader(); + + reader.onload = function(e) { + // Gets size of image for vertex + let data = e.target.result; + + // SVG needs special handling to add viewbox if missing and + // find initial size from SVG attributes (only for IE11) + if (file.type.substring(0, 9) === 'image/svg') { + const comma = data.indexOf(','); + const svgText = atob(data.substring(comma + 1)); + const root = mxUtils.parseXml(svgText); + + // Parses SVG to find width and height + if (root != null) { + const svgs = root.getElementsByTagName('svg'); + + if (svgs.length > 0) { + const svgRoot = svgs[0]; + let w = parseFloat(svgRoot.getAttribute('width')); + let h = parseFloat(svgRoot.getAttribute('height')); + + // Check if viewBox attribute already exists + const vb = svgRoot.getAttribute('viewBox'); + + if (vb == null || vb.length === 0) { + svgRoot.setAttribute('viewBox', `0 0 ${w} ${h}`); + } + // Uses width and height from viewbox for + // missing width and height attributes + else if (Number.isNaN(w) || Number.isNaN(h)) { + const tokens = vb.split(' '); + + if (tokens.length > 3) { + w = parseFloat(tokens[2]); + h = parseFloat(tokens[3]); + } + } + + w = Math.max(1, Math.round(w)); + h = Math.max(1, Math.round(h)); + + data = `data:image/svg+xml,${btoa( + mxUtils.getXml(svgs[0], '\n') + )}`; + graph.insertVertex({ + position: [x, y], + size: [w, h], + style: `shape=image;image=${data};`, + }); + } + } + } else { + const img = new Image(); + + img.onload = () => { + const w = Math.max(1, img.width); + const h = Math.max(1, img.height); + + // Converts format of data url to cell style value for use in vertex + const semi = data.indexOf(';'); + + if (semi > 0) { + data = + data.substring(0, semi) + + data.substring(data.indexOf(',', semi + 1)); + } + + graph.insertVertex({ + position: [x, y], + size: [w, h], + style: `shape=image;image=${data};`, + }); + }; + + img.src = data; + } + }; + + reader.readAsDataURL(file); + } +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/DynamicLoading.stories.js b/packages/html/stories/DynamicLoading.stories.js new file mode 100644 index 000000000..bd20e8631 --- /dev/null +++ b/packages/html/stories/DynamicLoading.stories.js @@ -0,0 +1,216 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Misc/DynamicLoading', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxText, + mxEvent, + mxConstants, + mxPerimeter, + mxCodec, + mxUtils, + mxXmlUtils + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + let requestId = 0; + + // Speedup the animation + mxText.prototype.enableBoundingBox = false; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Disables all built-in interactions + graph.setEnabled(false); + + // Handles clicks on cells + graph.addListener(mxEvent.CLICK, function(sender, evt) { + const cell = evt.getProperty('cell'); + + if (cell != null) { + load(graph, cell); + } + }); + + // Changes the default vertex style in-place + const style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + const cx = graph.container.clientWidth / 2; + const cy = graph.container.clientHeight / 2; + + const cell = graph.insertVertex( + parent, + '0-0', + '0-0', + cx - 20, + cy - 15, + 60, + 40 + ); + + // Animates the changes in the graph model + graph.getModel().addListener(mxEvent.CHANGE, function(sender, evt) { + const { changes } = evt.getProperty('edit'); + mxEffects.animateChanges(graph, changes); + }); + + // Loads the links for the given cell into the given graph + // by requesting the respective data in the server-side + // (implemented for this demo using the server-function) + function load(graph, cell) { + if (cell.isVertex()) { + const cx = graph.container.clientWidth / 2; + const cy = graph.container.clientHeight / 2; + + // 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 xml = server(cell.id); + const doc = mxXmlUtils.parseXml(xml); + const dec = new mxCodec(doc); + const model = dec.decode(doc.documentElement); + + // Removes all cells which are not in the response + for (var key in graph.getModel().cells) { + const tmp = graph.getModel().getCell(key); + + if (tmp != cell && tmp.isVertex()) { + graph.removeCells([tmp]); + } + } + + // Merges the response model with the client model + graph.getModel().mergeChildren(model.getRoot().getChildAt(0), parent); + + // Moves the given cell to the center + let geo = cell.getGeometry(); + + if (geo != null) { + geo = geo.clone(); + geo.x = cx - geo.width / 2; + geo.y = cy - geo.height / 2; + + graph.getModel().setGeometry(cell, geo); + } + + // Creates a list of the new vertices, if there is more + // than the center vertex which might have existed + // previously, then this needs to be changed to analyze + // the target model before calling mergeChildren above + const vertices = []; + + for (var key in graph.getModel().cells) { + const tmp = graph.getModel().getCell(key); + + if (tmp != cell && tmp.isVertex()) { + vertices.push(tmp); + + // Changes the initial location "in-place" + // to get a nice animation effect from the + // center to the radius of the circle + const geo = tmp.getGeometry(); + + if (geo != null) { + geo.x = cx - geo.width / 2; + geo.y = cy - geo.height / 2; + } + } + } + + // Arranges the response in a circle + const cellCount = vertices.length; + const phi = (2 * Math.PI) / cellCount; + const r = Math.min( + graph.container.clientWidth / 4, + graph.container.clientHeight / 4 + ); + + for (let i = 0; i < cellCount; i++) { + let geo = vertices[i].getGeometry(); + + if (geo != null) { + geo = geo.clone(); + geo.x += r * Math.sin(i * phi); + geo.y += r * Math.cos(i * phi); + + graph.getModel().setGeometry(vertices[i], geo); + } + } + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + } + } + + // Simulates the existence of a server that can crawl the + // big graph with a certain depth and create a graph model + // for the traversed cells, which is then sent to the client + function server(cellId) { + // Increments the request ID as a prefix for the cell IDs + requestId++; + + // Creates a local graph with no display + const graph = new mxGraph(); + + // 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 v0 = graph.insertVertex(parent, cellId, 'Dummy', 0, 0, 60, 40); + const cellCount = parseInt(Math.random() * 16) + 4; + + // Creates the random links and cells for the response + for (let i = 0; i < cellCount; i++) { + const id = `${requestId}-${i}`; + const v = graph.insertVertex(parent, id, id, 0, 0, 60, 40); + const e = graph.insertEdge(parent, null, `Link ${i}`, v0, v); + } + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + const enc = new mxCodec(); + const node = enc.encode(graph.getModel()); + + return mxUtils.getXml(node); + } + + load(graph, cell); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/DynamicStyle.stories.js b/packages/html/stories/DynamicStyle.stories.js new file mode 100644 index 000000000..e0eb7575c --- /dev/null +++ b/packages/html/stories/DynamicStyle.stories.js @@ -0,0 +1,126 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Styles/DynamicStyle', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxUtils, + mxConstants, + mxRubberband, + mxStencilRegistry + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Disables moving of edge labels in this examples + graph.edgeLabelsMovable = false; + + // Enables rubberband selection + if (args.rubberBand) + new mxRubberband(graph); + + // Needs to set a flag to check for dynamic style changes, + // that is, changes to styles on cells where the style was + // not explicitely changed using mxStyleChange + graph.getView().updateStyle = true; + + // Overrides mxCell.getStyle to return a specific style + // for edges that reflects their target terminal (in this case + // the strokeColor will be equal to the target's fillColor). + + const getStyle = function() { + // TODO super cannot be used here + // let style = super.getStyle(); + let style; + + if (this.isEdge()) { + const target = this.getTerminal(false); + + if (target != null) { + const targetStyle = graph.getCurrentCellStyle(target); + const fill = mxUtils.getValue( + targetStyle, + mxConstants.STYLE_FILLCOLOR + ); + + if (fill != null) { + style += `;strokeColor=${fill}`; + } + } + } else if (this.isVertex()) { + const geometry = this.getGeometry(); + if (geometry != null && geometry.width > 80) { + style += ';fillColor=green'; + } + } + return style; + }; + + // 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], + style: 'fillColor=green', + }); + v1.getStyle = getStyle; + + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [200, 150], + size: [80, 30], + style: 'fillColor=blue', + }); + v2.getStyle = getStyle; + + const v3 = graph.insertVertex({ + parent, + value: 'World!', + position: [20, 150], + size: [80, 30], + style: 'fillColor=red', + }); + v3.getStyle = getStyle; + + const e1 = graph.insertEdge({ + parent, + value: 'Connect', + source: v1, + target: v2, + style: 'perimeterSpacing=4;strokeWidth=4;labelBackgroundColor=white;fontStyle=1', + }); + e1.getStyle = getStyle; + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/DynamicToolbar.stories.js b/packages/html/stories/DynamicToolbar.stories.js new file mode 100644 index 000000000..b9b917e70 --- /dev/null +++ b/packages/html/stories/DynamicToolbar.stories.js @@ -0,0 +1,147 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Toolbars/DynamicToolbar', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxConnectionHandler, + mxImage, + mxToolbar, + mxGraphModel, + mxKeyHandler, + mxCell, + mxGeometry, + mxEvent, + mxUtils, + mxGestureUtils + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Defines an icon for creating new connections in the connection handler. + // This will automatically disable the highlighting of the source vertex. + mxConnectionHandler.prototype.connectImage = new mxImage( + '/images/connector.gif', + 16, + 16 + ); + + // Creates the div for the toolbar + const tbContainer = document.createElement('div'); + tbContainer.style.position = 'absolute'; + tbContainer.style.overflow = 'hidden'; + tbContainer.style.padding = '2px'; + tbContainer.style.left = '0px'; + tbContainer.style.top = '0px'; + tbContainer.style.width = '24px'; + tbContainer.style.bottom = '0px'; + + div.appendChild(tbContainer); + + // Creates new toolbar without event processing + const toolbar = new mxToolbar(tbContainer); + toolbar.enabled = false; + + // Creates the model and the graph inside the container + // using the fastest rendering available on the browser + const model = new mxGraphModel(); + const graph = new mxGraph(container, model); + + // Enables new connections in the graph + graph.setConnectable(true); + graph.setMultigraph(false); + + // Stops editing on enter or escape keypress + const keyHandler = new mxKeyHandler(graph); + + if (args.rubberBand) + new mxRubberband(graph); + + addVertex('/images/rectangle.gif', 100, 40, ''); + addVertex('/images/rounded.gif', 100, 40, 'shape=rounded'); + addVertex('/images/ellipse.gif', 40, 40, 'shape=ellipse'); + addVertex('/images/rhombus.gif', 40, 40, 'shape=rhombus'); + addVertex('/images/triangle.gif', 40, 40, 'shape=triangle'); + addVertex('/images/cylinder.gif', 40, 40, 'shape=cylinder'); + addVertex('/images/actor.gif', 30, 40, 'shape=actor'); + + function addVertex(icon, w, h, style) { + const vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style); + vertex.setVertex(true); + + const img = addToolbarItem(graph, toolbar, vertex, icon); + img.enabled = true; + + graph.getSelectionModel().addListener(mxEvent.CHANGE, () => { + const tmp = graph.isSelectionEmpty(); + mxUtils.setOpacity(img, tmp ? 100 : 20); + img.enabled = tmp; + }); + } + + function addToolbarItem(graph, toolbar, prototype, image) { + // Function that is executed when the image is dropped on + // the graph. The cell argument points to the cell under + // the mousepointer if there is one. + const funct = (graph, evt, cell, x, y) => { + graph.stopEditing(false); + + const vertex = graph.getModel().cloneCell(prototype); + vertex.geometry.x = x; + vertex.geometry.y = y; + + graph.addCell(vertex); + graph.setSelectionCell(vertex); + }; + + // Creates the image which is used as the drag icon (preview) + const img = toolbar.addMode(null, image, (evt, cell) => { + const pt = graph.getPointForEvent(evt); + funct(graph, evt, cell, pt.x, pt.y); + }); + + // Disables dragging if element is disabled. This is a workaround + // for wrong event order in IE. Following is a dummy listener that + // is invoked as the last listener in IE. + mxEvent.addListener(img, 'mousedown', evt => { + // do nothing + }); + + // This listener is always called first before any other listener + // in all browsers. + mxEvent.addListener(img, 'mousedown', evt => { + if (img.enabled == false) { + mxEvent.consume(evt); + } + }); + + mxGestureUtils.makeDraggable(img, graph, funct); + return img; + } + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/EdgeTolerance.stories.js b/packages/html/stories/EdgeTolerance.stories.js new file mode 100644 index 000000000..0946f3f93 --- /dev/null +++ b/packages/html/stories/EdgeTolerance.stories.js @@ -0,0 +1,116 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Connections/EdgeTolerance', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxUtils + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + class MyCustomGraph extends mxGraph { + fireMouseEvent(evtName, me, sender) { + // Overrides the mouse event dispatching mechanism to update the + // cell which is associated with the event in case the native hit + // detection did not return anything. + + // Checks if native hit detection did not return anything + if (me.getState() == null) { + // Updates the graph coordinates in the event since we need + // them here. Storing them in the event means the overridden + // method doesn't have to do this again. + if (me.graphX == null || me.graphY == null) { + const pt = mxUtils.convertPoint(container, me.getX(), me.getY()); + + me.graphX = pt.x; + me.graphY = pt.y; + } + + const cell = this.getCellAt(me.graphX, me.graphY); + + if (cell?.isEdge()) { + me.state = this.view.getState(cell); + + if (me.state != null && me.state.shape != null) { + this.container.style.cursor = me.state.shape.node.style.cursor; + } + } + } + + if (me.state == null) { + this.container.style.cursor = 'default'; + } + + super.fireMouseEvent(evtName, me, sender); + } + + dblClick(evt, cell) { + // Overrides double click handling to use the tolerance + if (cell == null) { + const pt = mxUtils.convertPoint( + el, + mxEventUtils.getClientX(evt), + mxEventUtils.getClientY(evt) + ); + cell = this.getCellAt(pt.x, pt.y); + } + super.dblClick(evt, cell); + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + graph.setTolerance(20); + + // 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: [120, 120], + size: [80, 30], + }); + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [400, 250], + size: [80, 30], + }); + const e1 = graph.insertEdge({ + parent, + source: v1, + target: v2, + style: 'edgeStyle=orthogonalEdgeStyle;', + }); + const e2 = graph.insertEdge({ + parent, + source: v2, + target: v1, + style: 'edgeStyle=orthogonalEdgeStyle;', + }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Editing.stories.js b/packages/html/stories/Editing.stories.js new file mode 100644 index 000000000..4bc29e703 --- /dev/null +++ b/packages/html/stories/Editing.stories.js @@ -0,0 +1,149 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Editing/Editing', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxKeyHandler, + mxUtils, + mxDomUtils, + mxCloneUtils, + mxEventUtils + } = mxgraph; + + const div = document.createElement('div'); + div.innerHTML = ` + Double-click the upper/lower half of the cell to edit different fields + of the user object. + `; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + class MyCustomGraph extends mxGraph { + getLabel(cell) { + // Returns a HTML representation of the cell where the + // upper half is the first value, lower half is second + // value + + const table = document.createElement('table'); + table.style.height = '100%'; + table.style.width = '100%'; + + const body = document.createElement('tbody'); + const tr1 = document.createElement('tr'); + const td1 = document.createElement('td'); + td1.style.textAlign = 'center'; + td1.style.fontSize = '12px'; + td1.style.color = '#774400'; + mxDomUtils.write(td1, cell.value.first); + + const tr2 = document.createElement('tr'); + const td2 = document.createElement('td'); + td2.style.textAlign = 'center'; + td2.style.fontSize = '12px'; + td2.style.color = '#774400'; + mxDomUtils.write(td2, cell.value.second); + + tr1.appendChild(td1); + tr2.appendChild(td2); + body.appendChild(tr1); + body.appendChild(tr2); + table.appendChild(body); + + return table; + } + + getEditingValue(cell, evt) { + // Returns the editing value for the given cell and event + evt.fieldname = this.__getFieldnameForEvent(cell, evt); + return cell.value[evt.fieldname] || ''; + } + + __getFieldnameForEvent(cell, evt) { + // Helper method that returns the fieldname to be used for + // a mouse event + if (evt != null) { + // Finds the relative coordinates inside the cell + const point = mxUtils.convertPoint( + this.container, + mxEventUtils.getClientX(evt), + mxEventUtils.getClientY(evt) + ); + const state = this.getView().getState(cell); + + if (state != null) { + point.x -= state.x; + point.y -= state.y; + + // Returns second if mouse in second half of cell + if (point.y > state.height / 2) { + return 'second'; + } + } + } + return 'first'; + } + + labelChanged(cell, newValue, trigger) { + // Sets the new value for the given cell and trigger + const name = trigger != null ? trigger.fieldname : null; + + if (name != null) { + // Clones the user object for correct undo and puts + // the new value in the correct field. + const value = mxCloneUtils.clone(cell.value); + value[name] = newValue; + newValue = value; + + super.labelChanged(cell, newValue, trigger); + } + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + graph.setHtmlLabels(true); + + // Adds handling of return and escape keystrokes for editing + const keyHandler = new mxKeyHandler(graph); + + // Sample user objects with 2 fields + const value = {}; + value.first = 'First value'; + value.second = 'Second value'; + + // 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, + position: [100, 60], + size: [120, 80], + style: 'overflow=fill;', + }); + }); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Events.stories.js b/packages/html/stories/Events.stories.js new file mode 100644 index 000000000..1d88bd71b --- /dev/null +++ b/packages/html/stories/Events.stories.js @@ -0,0 +1,174 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Events/Events', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxConnectionHandler, + mxLayoutManager, + mxParallelEdgeLayout, + mxImage, + mxKeyHandler, + mxConstants, + mxEdgeStyle + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + class MyCustomConnectionHandler extends mxConnectionHandler { + // Sets the image to be used for creating new connections + connectImage = new mxImage('/images/green-dot.gif', 14, 14); + } + + // Disables built-in context menu + mxEvent.disableContextMenu(container); + + class MyCustomGraph extends mxGraph { + alternateEdgeStyle = 'elbow=vertical'; + + getTooltipForCell(cell) { + // Installs a custom tooltip for cells + return 'Doubleclick and right- or shiftclick'; + } + + createConnectionHandler() { + return new MyCustomConnectionHandler(this); + } + } + + // Creates the graph inside the DOM node. + // Optionally you can enable panning, tooltips and connections + // using graph.setPanning(), setTooltips() & setConnectable(). + // To enable rubberband selection and basic keyboard events, + // use new mxRubberband(graph) and new mxKeyHandler(graph). + const graph = new MyCustomGraph(container); + + // Enables tooltips, new connections and panning + graph.setPanning(true); + graph.setTooltips(true); + graph.setConnectable(true); + + // Automatically handle parallel edges + const layout = new mxParallelEdgeLayout(graph); + const layoutMgr = new mxLayoutManager(graph); + + layoutMgr.getLayout = function(cell) { + if (cell.getChildCount() > 0) { + return layout; + } + }; + + // Enables rubberband (marquee) selection and a handler + // for basic keystrokes (eg. return, escape during editing). + const rubberband = new mxRubberband(graph); + const keyHandler = new mxKeyHandler(graph); + + // Changes the default style for edges "in-place" and assigns + // an alternate edge style which is applied in mxGraph.flip + // when the user double clicks on the adjustment control point + // of the edge. The ElbowConnector edge style switches to TopToBottom + // if the horizontal style is true. + const style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; + + // Installs a popupmenu handler using local function (see below). + graph.popupMenuHandler.factoryMethod = (menu, cell, evt) => { + return createPopupMenu(graph, menu, cell, evt); + }; + + // 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, + 'Doubleclick', + 20, + 20, + 80, + 30 + ); + const v2 = graph.insertVertex( + parent, + null, + 'Right-/Shiftclick', + 200, + 150, + 120, + 30 + ); + const v3 = graph.insertVertex( + parent, + null, + 'Connect/Reconnect', + 200, + 20, + 120, + 30 + ); + const v4 = graph.insertVertex( + parent, + null, + 'Control-Drag', + 20, + 150, + 100, + 30 + ); + const e1 = graph.insertEdge(parent, null, 'Tooltips', v1, v2); + const e2 = graph.insertEdge(parent, null, '', v2, v3); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +function createPopupMenu(graph, menu, cell, evt) { + // Function to create the entries in the popupmenu + if (cell != null) { + menu.addItem('Cell Item', '/images/image.gif', () => { + mxUtils.alert('MenuItem1'); + }); + } else { + menu.addItem('No-Cell Item', '/images/image.gif', () => { + mxUtils.alert('MenuItem2'); + }); + } + menu.addSeparator(); + menu.addItem('MenuItem3', '/images/warning.gif', () => { + mxUtils.alert(`MenuItem3: ${graph.getSelectionCount()} selected`); + }); +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/src/pages/backgrounds/ExtendCanvas.js b/packages/html/stories/ExtendCanvas.stories.js similarity index 84% rename from src/pages/backgrounds/ExtendCanvas.js rename to packages/html/stories/ExtendCanvas.stories.js index b937da038..040bc15d9 100644 --- a/src/pages/backgrounds/ExtendCanvas.js +++ b/packages/html/stories/ExtendCanvas.stories.js @@ -1,49 +1,44 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ +import mxgraph from '@mxgraph/core'; -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; +import { globalTypes } from '../.storybook/preview'; -class ExtendCanvas extends React.Component { - constructor(props) { - super(props); +export default { + title: 'Backgrounds/ExtendCanvas', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } } +}; - render() { - // A container for the graph - return ( - <> -

Extend canvas

- This example demonstrates implementing an infinite canvas with - scrollbars. -
{ - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'auto', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxRectangle, + mxPoint, + mxUtils + } = mxgraph; - componentDidMount() { - // Disables the built-in context menu - mxEvent.disableContextMenu(this.el); + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'auto'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.cursor = 'default'; + container.style.background = 'url(/images/grid.gif)'; - /** + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + /** * Specifies the size of the size for "tiles" to be used for a graph with * scrollbars but no visible background page. A good value is large * enough to reduce the number of repaints that is caused for auto- @@ -170,7 +165,7 @@ class ExtendCanvas extends React.Component { } // Creates the graph inside the given container - const graph = (this.graph = new MyCustomGraph(this.el)); + const graph = new MyCustomGraph(container); graph.panningHandler.ignoreCell = true; graph.setPanning(true); @@ -213,7 +208,8 @@ class ExtendCanvas extends React.Component { }; // Enables rubberband selection - new mxRubberband(graph); + if (args.rubberBand) + new mxRubberband(graph); // Gets the default parent for inserting new cells. This // is normally the first child of the root (ie. layer 0). @@ -264,7 +260,8 @@ class ExtendCanvas extends React.Component { ) ); }, 0); - } + + return container; } -export default ExtendCanvas; +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/FileIO.stories.js b/packages/html/stories/FileIO.stories.js new file mode 100644 index 000000000..86cde6b18 --- /dev/null +++ b/packages/html/stories/FileIO.stories.js @@ -0,0 +1,210 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Xml_Json/FileIO', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRectangleShape, + mxDomHelpers, + mxText, + mxPoint, + mxRectangle, + mxConstants + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // 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 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.setEnabled(false); + graph.setPanning(true); + graph.setTooltips(true); + graph.panningHandler.useLeftButtonForPanning = true; + + // Adds a highlight on the cell under the mousepointer + new mxCellTracker(graph); + + // Changes the default vertex style in-place + let style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ROUNDED; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_PERIMETER_SPACING] = 4; + style[mxConstants.STYLE_SHADOW] = true; + + style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white'; + + style = mxUtils.clone(style); + style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_CLASSIC; + graph.getStylesheet().putCellStyle('2way', style); + + graph.isHtmlLabel = function(cell) { + return true; + }; + + // Larger grid size yields cleaner layout result + graph.gridSize = 20; + + // Creates a layout algorithm to be used + // with the graph + const layout = new mxFastOrganicLayout(graph); + + // Moves stuff wider apart than usual + layout.forceConstant = 140; + + // Adds a button to execute the layout + this.el2.appendChild( + mxUtils.button('Arrange', function(evt) { + const parent = graph.getDefaultParent(); + layout.execute(parent); + }) + ); + + // Load cells and layouts the graph + graph.getModel().beginUpdate(); + try { + // Loads the custom file format (TXT file) + parse(graph, 'fileio.txt'); + + // Loads the mxGraph file format (XML file) + // read(graph, 'fileio.xml'); + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + // Executes the layout + layout.execute(parent); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + graph.dblClick = function(evt, cell) { + const mxe = new mxEventObject( + mxEvent.DOUBLE_CLICK, + 'event', + evt, + 'cell', + cell + ); + this.fireEvent(mxe); + + if ( + this.isEnabled() && + !mxEvent.isConsumed(evt) && + !mxe.isConsumed() && + cell != null + ) { + mxUtils.alert( + `Show properties for cell ${cell.customId || cell.getId()}` + ); + } + }; + } + } + + // Custom parser for simple file format + function parse(graph, filename) { + const model = graph.getModel(); + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + const req = mxUtils.load(filename); + const text = req.getText(); + + const lines = text.split('\n'); + + // Creates the lookup table for the vertices + const vertices = []; + + // Parses all lines (vertices must be first in the file) + graph.getModel().beginUpdate(); + try { + for (let i = 0; i < lines.length; i++) { + // Ignores comments (starting with #) + const colon = lines[i].indexOf(':'); + + if (lines[i].substring(0, 1) != '#' || colon == -1) { + const comma = lines[i].indexOf(','); + const value = lines[i].substring(colon + 2, lines[i].length); + + if (comma == -1 || comma > colon) { + const key = lines[i].substring(0, colon); + + if (key.length > 0) { + vertices[key] = graph.insertVertex( + parent, + null, + value, + 0, + 0, + 80, + 70 + ); + } + } else if (comma < colon) { + // Looks up the vertices in the lookup table + const source = vertices[lines[i].substring(0, comma)]; + const target = vertices[lines[i].substring(comma + 1, colon)]; + + if (source != null && target != null) { + const e = graph.insertEdge(parent, null, value, source, target); + + // Uses the special 2-way style for 2-way labels + if (value.indexOf('2-Way') >= 0) { + e.style = '2way'; + } + } + } + } + } + } finally { + graph.getModel().endUpdate(); + } + } + + // Parses the mxGraph XML file format + function read(graph, filename) { + const req = mxUtils.load(filename); + const root = req.getDocumentElement(); + const dec = new mxCodec(root.ownerDocument); + + dec.decode(root, graph.getModel()); + } + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/FixedIcons.stories.js b/packages/html/stories/FixedIcons.stories.js new file mode 100644 index 000000000..595a095d0 --- /dev/null +++ b/packages/html/stories/FixedIcons.stories.js @@ -0,0 +1,97 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Icon_Images/FixedIcons', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxDomHelpers, + mxImageShape, + mxRectangle, + mxConstants, + mxUtils, + mxLabel + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Overrides the image bounds code to change the position + mxLabel.prototype.getImageBounds = function(x, y, w, h) { + const iw = mxUtils.getValue( + this.style, + mxConstants.STYLE_IMAGE_WIDTH, + mxConstants.DEFAULT_IMAGESIZE + ); + const ih = mxUtils.getValue( + this.style, + mxConstants.STYLE_IMAGE_HEIGHT, + mxConstants.DEFAULT_IMAGESIZE + ); + + // Places the icon + const ix = (w - iw) / 2; + const iy = h - ih; + + return new mxRectangle(x + ix, y + iy, iw, ih); + }; + + // Makes the shadow brighter + mxConstants.SHADOWCOLOR = '#C0C0C0'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Uncomment the following if you want the container + // to fit the size of the graph + // graph.setResizeContainer(true); + + // Enables rubberband selection + if (args.rubberBand) + 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, + 'Fixed icon', + 20, + 20, + 80, + 50, + 'shape=label;image=images/plus.png;imageWidth=16;imageHeight=16;spacingBottom=10;' + + 'fillColor=#adc5ff;gradientColor=#7d85df;glass=1;rounded=1;shadow=1;' + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/FixedPoints.stories.js b/packages/html/stories/FixedPoints.stories.js new file mode 100644 index 000000000..e0e396735 --- /dev/null +++ b/packages/html/stories/FixedPoints.stories.js @@ -0,0 +1,266 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Connections/FixedPoints', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxConnectionHandler, + mxConnectionConstraint, + mxConstraintHandler, + mxPoint, + mxCellState, + mxEdgeHandler + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + class MyCustomConstraintHandler extends mxConstraintHandler { + // Snaps to fixed points + intersects(icon, point, source, existingEdge) { + return ( + !source || existingEdge || mxUtils.intersects(icon.bounds, point) + ); + } + } + + class MyCustomConnectionHandler extends mxConnectionHandler { + // connectImage = new mxImage('images/connector.gif', 16, 16); + + isConnectableCell(cell) { + return false; + } + + /* + * Special case: Snaps source of new connections to fixed points + * Without a connect preview in connectionHandler.createEdgeState mouseMove + * and getSourcePerimeterPoint should be overriden by setting sourceConstraint + * sourceConstraint to null in mouseMove and updating it and returning the + * nearest point (cp) in getSourcePerimeterPoint (see below) + */ + updateEdgeState(pt, constraint) { + if (pt != null && this.previous != null) { + const constraints = this.graph.getAllConnectionConstraints( + this.previous + ); + let nearestConstraint = null; + let dist = null; + + for (let i = 0; i < constraints.length; i++) { + const cp = this.graph.getConnectionPoint( + this.previous, + constraints[i] + ); + + if (cp != null) { + const tmp = + (cp.x - pt.x) * (cp.x - pt.x) + (cp.y - pt.y) * (cp.y - pt.y); + + if (dist == null || tmp < dist) { + nearestConstraint = constraints[i]; + dist = tmp; + } + } + } + + if (nearestConstraint != null) { + this.sourceConstraint = nearestConstraint; + } + + // In case the edge style must be changed during the preview: + // this.edgeState.style['edgeStyle'] = 'orthogonalEdgeStyle'; + // And to use the new edge style in the new edge inserted into the graph, + // update the cell style as follows: + // this.edgeState.cell.style = mxUtils.setStyle(this.edgeState.cell.style, 'edgeStyle', this.edgeState.style['edgeStyle']); + } + return super.updateEdgeState(pt, constraint); + } + + createEdgeState(me) { + // Connect preview + const edge = this.graph.createEdge( + null, + null, + null, + null, + null, + 'edgeStyle=orthogonalEdgeStyle' + ); + + return new mxCellState( + this.graph.view, + edge, + this.graph.getCellStyle(edge) + ); + } + } + + class MyCustomEdgeHandler extends mxEdgeHandler { + // Disables floating connections (only use with no connect image) + isConnectableCell(cell) { + return graph.connectionHandler.isConnectableCell(cell); + } + } + + class MyCustomGraph extends mxGraph { + createConnectionHandler() { + const r = new MyCustomConnectionHandler(); + r.constraintHandler = new MyCustomConstraintHandler(this); + return r; + } + + createEdgeHandler(state, edgeStyle) { + const r = new MyCustomEdgeHandler(state, edgeStyle); + r.constraintHandler = new MyCustomConstraintHandler(this); + return r; + } + + getAllConnectionConstraints(terminal) { + if (terminal != null && this.model.isVertex(terminal.cell)) { + return [ + new mxConnectionConstraint(new mxPoint(0, 0), true), + new mxConnectionConstraint(new mxPoint(0.5, 0), true), + new mxConnectionConstraint(new mxPoint(1, 0), true), + new mxConnectionConstraint(new mxPoint(0, 0.5), true), + new mxConnectionConstraint(new mxPoint(1, 0.5), true), + new mxConnectionConstraint(new mxPoint(0, 1), true), + new mxConnectionConstraint(new mxPoint(0.5, 1), true), + new mxConnectionConstraint(new mxPoint(1, 1), true), + ]; + } + return null; + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + graph.setConnectable(true); + + // Enables rubberband selection + if (args.rubberBand) + 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, 60], + style: 'shape=triangle;perimeter=trianglePerimeter', + }); + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [200, 150], + size: [80, 60], + style: 'shape=ellipse;perimeter=ellipsePerimeter', + }); + const v3 = graph.insertVertex({ + parent, + value: 'Hello,', + position: [200, 20], + size: [80, 30], + }); + const e1 = graph.insertEdge({ + parent, + value: '', + source: v1, + target: v2, + style: + 'edgeStyle=elbowEdgeStyle;elbow=horizontal;' + + 'exitX=0.5;exitY=1;exitPerimeter=1;entryX=0;entryY=0;entryPerimeter=1;', + }); + const e2 = graph.insertEdge({ + parent, + value: '', + source: v3, + target: v2, + style: + 'edgeStyle=elbowEdgeStyle;elbow=horizontal;orthogonal=0;' + + 'entryX=0;entryY=0;entryPerimeter=1;', + }); + }); + + // Use this code to snap the source point for new connections without a connect preview, + // ie. without an overridden graph.connectionHandler.createEdgeState + /* + let mxConnectionHandlerMouseMove = mxConnectionHandler.prototype.mouseMove; + mxConnectionHandler.prototype.mouseMove = function(sender, me) + { + this.sourceConstraint = null; + + mxConnectionHandlerMouseMove.apply(this, arguments); + }; + + let mxConnectionHandlerGetSourcePerimeterPoint = mxConnectionHandler.prototype.getSourcePerimeterPoint; + mxConnectionHandler.prototype.getSourcePerimeterPoint = function(state, pt, me) + { + let result = null; + + if (this.previous != null && pt != null) + { + let constraints = this.graph.getAllConnectionConstraints(this.previous); + let nearestConstraint = null; + let nearest = null; + let dist = null; + + for (let i = 0; i < constraints.length; i++) + { + let cp = this.graph.getConnectionPoint(this.previous, constraints[i]); + + if (cp != null) + { + let tmp = (cp.x - pt.x) * (cp.x - pt.x) + (cp.y - pt.y) * (cp.y - pt.y); + + if (dist == null || tmp < dist) + { + nearestConstraint = constraints[i]; + nearest = cp; + dist = tmp; + } + } + } + + if (nearestConstraint != null) + { + this.sourceConstraint = nearestConstraint; + result = nearest; + } + } + + if (result == null) + { + result = mxConnectionHandlerGetSourcePerimeterPoint.apply(this, arguments); + } + + return result; + }; + */ + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Folding.stories.js b/packages/html/stories/Folding.stories.js new file mode 100644 index 000000000..a89fd9527 --- /dev/null +++ b/packages/html/stories/Folding.stories.js @@ -0,0 +1,145 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/Folding', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxConstants, + mxEdgeStyle, + mxStackLayout, + mxLayoutManager + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Enables crisp rendering of rectangles in SVG + mxConstants.ENTITY_SEGMENT = 20; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setDropEnabled(true); + + // Disables global features + graph.collapseToPreferredSize = false; + graph.constrainChildren = false; + graph.cellsSelectable = false; + graph.extendParentsOnAdd = false; + graph.extendParents = false; + graph.border = 10; + + // Sets global styles + let style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.EntityRelation; + style[mxConstants.STYLE_ROUNDED] = true; + + style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_FILLCOLOR] = '#ffffff'; + style[mxConstants.STYLE_SHAPE] = 'swimlane'; + style[mxConstants.STYLE_STARTSIZE] = 30; + + style = []; + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; + style[mxConstants.STYLE_STROKECOLOR] = 'none'; + style[mxConstants.STYLE_FILLCOLOR] = 'none'; + style[mxConstants.STYLE_FOLDABLE] = false; + graph.getStylesheet().putCellStyle('column', style); + + // Installs auto layout for all levels + const layout = new mxStackLayout(graph, true); + layout.border = graph.border; + const layoutMgr = new mxLayoutManager(graph); + layoutMgr.getLayout = function(cell) { + if (!cell.collapsed) { + if (cell.parent !== graph.model.root) { + layout.resizeParent = true; + layout.horizontal = false; + layout.spacing = 10; + } else { + layout.resizeParent = true; + layout.horizontal = true; + layout.spacing = 40; + } + + return layout; + } + + return null; + }; + + // Resizes the container + graph.setResizeContainer(true); + + // 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 col1 = graph.insertVertex(parent, null, '', 0, 0, 120, 0, 'column'); + + const v1 = graph.insertVertex(col1, null, '1', 0, 0, 100, 30); + v1.collapsed = true; + + const v11 = graph.insertVertex(v1, null, '1.1', 0, 0, 80, 30); + v11.collapsed = true; + + const v111 = graph.insertVertex(v11, null, '1.1.1', 0, 0, 60, 30); + const v112 = graph.insertVertex(v11, null, '1.1.2', 0, 0, 60, 30); + + const v12 = graph.insertVertex(v1, null, '1.2', 0, 0, 80, 30); + + const col2 = graph.insertVertex(parent, null, '', 0, 0, 120, 0, 'column'); + + const v2 = graph.insertVertex(col2, null, '2', 0, 0, 100, 30); + v2.collapsed = true; + + const v21 = graph.insertVertex(v2, null, '2.1', 0, 0, 80, 30); + v21.collapsed = true; + + const v211 = graph.insertVertex(v21, null, '2.1.1', 0, 0, 60, 30); + const v212 = graph.insertVertex(v21, null, '2.1.2', 0, 0, 60, 30); + + const v22 = graph.insertVertex(v2, null, '2.2', 0, 0, 80, 30); + + const v3 = graph.insertVertex(col2, null, '3', 0, 0, 100, 30); + v3.collapsed = true; + + const v31 = graph.insertVertex(v3, null, '3.1', 0, 0, 80, 30); + v31.collapsed = true; + + const v311 = graph.insertVertex(v31, null, '3.1.1', 0, 0, 60, 30); + const v312 = graph.insertVertex(v31, null, '3.1.2', 0, 0, 60, 30); + + const v32 = graph.insertVertex(v3, null, '3.2', 0, 0, 80, 30); + + graph.insertEdge(parent, null, '', v111, v211); + graph.insertEdge(parent, null, '', v112, v212); + graph.insertEdge(parent, null, '', v112, v22); + + graph.insertEdge(parent, null, '', v12, v311); + graph.insertEdge(parent, null, '', v12, v312); + graph.insertEdge(parent, null, '', v12, v32); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Grid.stories.js b/packages/html/stories/Grid.stories.js index 141c5e255..2e46e511e 100644 --- a/packages/html/stories/Grid.stories.js +++ b/packages/html/stories/Grid.stories.js @@ -1,7 +1,20 @@ import mxgraph from '@mxgraph/core'; +import { globalTypes } from '../.storybook/preview'; + export default { - title: 'Backgrounds/Grid' + title: 'Backgrounds/Grid', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } }; const Template = ({ label, ...args }) => { @@ -21,11 +34,13 @@ const Template = ({ label, ...args }) => { const container = document.createElement('div'); container.style.position = 'relative'; container.style.overflow = 'hidden'; - container.style.height = '481px'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; container.style.cursor = 'default'; div.appendChild(container); - mxEvent.disableContextMenu(container); + if (!args.contextMenu) + mxEvent.disableContextMenu(container); // Creates the graph inside the given container var graph = new mxGraph(container); @@ -33,7 +48,8 @@ const Template = ({ label, ...args }) => { graph.setPanning(true); // Enables rubberband selection - new mxRubberband(graph); + if (args.rubberBand) + new mxRubberband(graph); let repaintGrid; diff --git a/packages/html/stories/Groups.stories.js b/packages/html/stories/Groups.stories.js new file mode 100644 index 000000000..8cadac301 --- /dev/null +++ b/packages/html/stories/Groups.stories.js @@ -0,0 +1,167 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/Groups', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxGraphHandler, + mxPopupMenuHandler + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Overrides check for valid roots + mxGraph.prototype.isValidRoot = function() { + return false; + }; + + // Don't clear selection if multiple cells selected + const graphHandlerMouseDown = mxGraphHandler.prototype.mouseDown; + mxGraphHandler.prototype.mouseDown = function(sender, me) { + graphHandlerMouseDown.apply(this, arguments); + + if ( + this.graph.isCellSelected(me.getCell()) && + this.graph.getSelectionCount() > 1 + ) { + this.delayedSelection = false; + } + }; + + // Selects descendants before children selection mode + const graphHandlerGetInitialCellForEvent = + mxGraphHandler.prototype.getInitialCellForEvent; + mxGraphHandler.prototype.getInitialCellForEvent = function(me) { + const model = this.graph.getModel(); + const psel = this.graph.getSelectionCell().getParent(); + let cell = graphHandlerGetInitialCellForEvent.apply(this, arguments); + let parent = cell.getParent(); + + if (psel == null || (psel != cell && psel != parent)) { + while ( + !this.graph.isCellSelected(cell) && + !this.graph.isCellSelected(parent) && + parent.isVertex() && + !this.graph.isValidRoot(parent) + ) { + cell = parent; + parent = this.cell.getParent(); + } + } + + return cell; + }; + + // Selection is delayed to mouseup if child selected + const graphHandlerIsDelayedSelection = + mxGraphHandler.prototype.isDelayedSelection; + mxGraphHandler.prototype.isDelayedSelection = function(cell) { + let result = graphHandlerIsDelayedSelection.apply(this, arguments); + const model = this.graph.getModel(); + const psel = this.graph.getSelectionCell().getParent(); + const parent = cell.getParent(); + + if (psel == null || (psel != cell && psel != parent)) { + if ( + !this.graph.isCellSelected(cell) && + parent.isVertex() && + !this.graph.isValidRoot(parent) + ) { + result = true; + } + } + + return result; + }; + + // Delayed selection of parent group + mxGraphHandler.prototype.selectDelayed = function(me) { + let cell = me.getCell(); + + if (cell == null) { + cell = this.cell; + } + + const model = this.graph.getModel(); + let parent = cell.getParent(); + + while ( + this.graph.isCellSelected(cell) && + parent.isVertex() && + !this.graph.isValidRoot(parent) + ) { + cell = parent; + parent = cell.getParent(); + } + + this.graph.selectCellForEvent(cell, me.getEvent()); + }; + + // Returns last selected ancestor + mxPopupMenuHandler.prototype.getCellForPopupEvent = function(me) { + let cell = me.getCell(); + const model = this.graph.getModel(); + let parent = cell.getParent(); + + while (parent.isVertex() && !this.graph.isValidRoot(parent)) { + if (this.graph.isCellSelected(parent)) { + cell = parent; + } + + parent = parent.getParent(); + } + + return cell; + }; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.constrainChildren = false; + graph.extendParents = false; + graph.extendParentsOnAdd = false; + + // Uncomment the following if you want the container + // to fit the size of the graph + // graph.setResizeContainer(true); + + // Enables rubberband selection + if (args.rubberBand) + 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, 120, 60); + const v2 = graph.insertVertex(v1, null, 'World!', 90, 20, 60, 20); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Guides.stories.js b/packages/html/stories/Guides.stories.js new file mode 100644 index 000000000..3df4c5eb8 --- /dev/null +++ b/packages/html/stories/Guides.stories.js @@ -0,0 +1,136 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Misc/Guides', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxGraphHandler, + mxEvent, + mxConstants, + mxEdgeHandler, + mxEdgeStyle, + mxRubberband + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Enables guides + mxGraphHandler.prototype.guidesEnabled = true; + + // Alt disables guides + mxGraphHandler.prototype.useGuidesForEvent = function(me) { + return !mxEvent.isAltDown(me.getEvent()); + }; + + // Defines the guides to be red (default) + mxConstants.GUIDE_COLOR = '#FF0000'; + + // Defines the guides to be 1 pixel (default) + mxConstants.GUIDE_STROKEWIDTH = 1; + + // Enables snapping waypoints to terminals + mxEdgeHandler.prototype.snapToTerminals = true; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setConnectable(true); + graph.gridSize = 30; + + // Changes the default style for edges "in-place" and assigns + // an alternate edge style which is applied in mxGraph.flip + // when the user double clicks on the adjustment control point + // of the edge. The ElbowConnector edge style switches to TopToBottom + // if the horizontal style is true. + const style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; + graph.alternateEdgeStyle = 'elbow=vertical'; + + // Enables rubberband selection + if (args.rubberBand) + 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(); + let v1; + try { + v1 = graph.insertVertex(parent, null, 'Hello,', 20, 40, 80, 70); + const v2 = graph.insertVertex(parent, null, 'World!', 200, 140, 80, 40); + const e1 = graph.insertEdge(parent, null, '', v1, v2); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + // Handles cursor keys + const nudge = function(keyCode) { + if (!graph.isSelectionEmpty()) { + let dx = 0; + let dy = 0; + + if (keyCode === 37) { + dx = -1; + } else if (keyCode === 38) { + dy = -1; + } else if (keyCode === 39) { + dx = 1; + } else if (keyCode === 40) { + dy = 1; + } + + graph.moveCells(graph.getSelectionCells(), dx, dy); + } + + // Transfer initial focus to graph container for keystroke handling + graph.container.focus(); + + // Handles keystroke events + const keyHandler = new mxKeyHandler(graph); + + // Ignores enter keystroke. Remove this line if you want the + // enter keystroke to stop editing + keyHandler.enter = function() {}; + + keyHandler.bindKey(37, function() { + nudge(37); + }); + + keyHandler.bindKey(38, function() { + nudge(38); + }); + + keyHandler.bindKey(39, function() { + nudge(39); + }); + + keyHandler.bindKey(40, function() { + nudge(40); + }); + }; + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Handles.stories.js b/packages/html/stories/Handles.stories.js new file mode 100644 index 000000000..4d24b31ba --- /dev/null +++ b/packages/html/stories/Handles.stories.js @@ -0,0 +1,279 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/Handles', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxCylinder, + mxDomHelpers, + mxCellRenderer, + mxPoint, + mxRectangle, + mxVertexHandler, + mxEvent, + mxRubberband, + mxUtils, + mxHandle + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + class MyShape extends mxCylinder { + defaultPos1 = 20; + + defaultPos2 = 60; + + getLabelBounds(rect) { + const pos1 = + mxUtils.getValue(this.style, 'pos1', this.defaultPos1) * this.scale; + const pos2 = + mxUtils.getValue(this.style, 'pos2', this.defaultPos2) * this.scale; + return new mxRectangle( + rect.x, + rect.y + pos1, + rect.width, + Math.min(rect.height, pos2) - Math.max(0, pos1) + ); + } + + redrawPath(path, x, y, w, h, isForeground) { + const pos1 = mxUtils.getValue(this.style, 'pos1', this.defaultPos1); + const pos2 = mxUtils.getValue(this.style, 'pos2', this.defaultPos2); + + if (isForeground) { + if (pos1 < h) { + path.moveTo(0, pos1); + path.lineTo(w, pos1); + } + + if (pos2 < h) { + path.moveTo(0, pos2); + path.lineTo(w, pos2); + } + } else { + path.rect(0, 0, w, h); + } + } + } + mxCellRenderer.registerShape('myShape', MyShape); + + class MyCustomVertexHandler extends mxVertexHandler { + livePreview = true; + + rotationEnabled = true; + + createCustomHandles() { + if (this.state.style.shape === 'myShape') { + // Implements the handle for the first divider + const firstHandle = new mxHandle(this.state); + + firstHandle.getPosition = function(bounds) { + const pos2 = Math.max( + 0, + Math.min( + bounds.height, + parseFloat( + mxUtils.getValue( + this.state.style, + 'pos2', + MyShape.prototype.defaultPos2 + ) + ) + ) + ); + const pos1 = Math.max( + 0, + Math.min( + pos2, + parseFloat( + mxUtils.getValue( + this.state.style, + 'pos1', + MyShape.prototype.defaultPos1 + ) + ) + ) + ); + + return new mxPoint(bounds.getCenterX(), bounds.y + pos1); + }; + + firstHandle.setPosition = function(bounds, pt) { + const pos2 = Math.max( + 0, + Math.min( + bounds.height, + parseFloat( + mxUtils.getValue( + this.state.style, + 'pos2', + MyShape.prototype.defaultPos2 + ) + ) + ) + ); + + this.state.style.pos1 = Math.round( + Math.max(0, Math.min(pos2, pt.y - bounds.y)) + ); + }; + + firstHandle.execute = function() { + this.copyStyle('pos1'); + }; + + firstHandle.ignoreGrid = true; + + // Implements the handle for the second divider + const secondHandle = new mxHandle(this.state); + + secondHandle.getPosition = function(bounds) { + const pos1 = Math.max( + 0, + Math.min( + bounds.height, + parseFloat( + mxUtils.getValue( + this.state.style, + 'pos1', + MyShape.prototype.defaultPos1 + ) + ) + ) + ); + const pos2 = Math.max( + pos1, + Math.min( + bounds.height, + parseFloat( + mxUtils.getValue( + this.state.style, + 'pos2', + MyShape.prototype.defaultPos2 + ) + ) + ) + ); + + return new mxPoint(bounds.getCenterX(), bounds.y + pos2); + }; + + secondHandle.setPosition = function(bounds, pt) { + const pos1 = Math.max( + 0, + Math.min( + bounds.height, + parseFloat( + mxUtils.getValue( + this.state.style, + 'pos1', + MyShape.prototype.defaultPos1 + ) + ) + ) + ); + + this.state.style.pos2 = Math.round( + Math.max(pos1, Math.min(bounds.height, pt.y - bounds.y)) + ); + }; + + secondHandle.execute = function() { + this.copyStyle('pos2'); + }; + + secondHandle.ignoreGrid = true; + + return [firstHandle, secondHandle]; + } + + return null; + } + } + + class MyCustomGraph extends mxGraph { + createVertexHandler(state) { + return new MyCustomVertexHandler(state); + } + } + + // Disables the built-in context menu + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + graph.setCellsCloneable(true); + graph.setHtmlLabels(true); + graph.setPanning(true); + graph.centerZoom = false; + + // Enables rubberband selection + if (args.rubberBand) + 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, + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + 20, + 20, + 240, + 120, + 'shape=myShape;whiteSpace=wrap;overflow=hidden;pos1=30;pos2=80;' + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + buttons.appendChild( + mxDomHelpers.button('+', function() { + graph.zoomIn(); + }) + ); + buttons.appendChild( + mxDomHelpers.button('-', function() { + graph.zoomOut(); + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/HelloPort.stories.js b/packages/html/stories/HelloPort.stories.js new file mode 100644 index 000000000..0f439122b --- /dev/null +++ b/packages/html/stories/HelloPort.stories.js @@ -0,0 +1,118 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Connections/HelloPort', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxEdgeStyle, + mxPoint, + mxConstants, + mxDomHelpers, + mxClient + } = mxgraph; + + mxClient.setImageBasePath('/images'); + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setConnectable(true); + graph.setTooltips(true); + + // Sets the default edge style + const style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; + + // Ports are not used as terminals for edges, they are + // only used to compute the graphical connection point + graph.isPort = function(cell) { + const geo = this.getCellGeometry(cell); + + return geo != null ? geo.relative : false; + }; + + // Implements a tooltip that shows the actual + // source and target of an edge + graph.getTooltipForCell = function(cell) { + if (cell.isEdge()) { + return `${this.convertValueToString( + cell.getTerminal(true) + )} => ${this.convertValueToString( + cell.getTerminal(false) + )}`; + } + + return mxGraph.prototype.getTooltipForCell.apply(this, arguments); + }; + + // Removes the folding icon and disables any folding + graph.isCellFoldable = function(cell) { + return false; + }; + + // Enables rubberband selection + if (args.rubberBand) + 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, 80, 80, 30); + v1.setConnectable(false); + const v11 = graph.insertVertex(v1, null, '', 1, 1, 10, 10); + v11.geometry.offset = new mxPoint(-5, -5); + v11.geometry.relative = true; + const v12 = graph.insertVertex(v1, null, '', 1, 0, 10, 10); + v12.geometry.offset = new mxPoint(-5, -5); + v12.geometry.relative = true; + const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); + const v3 = graph.insertVertex(parent, null, 'World2', 200, 20, 80, 30); + var e1 = graph.insertEdge(parent, null, '', v11, v2); + var e1 = graph.insertEdge(parent, null, '', v12, v3); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + const controller = document.createElement('div'); + div.appendChild(controller); + + const button = mxDomHelpers.button('View XML', function() { + const encoder = new mxCodec(); + const node = encoder.encode(graph.getModel()); + mxUtils.popup(mxUtils.getPrettyXml(node), true); + }); + + controller.appendChild(button); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/HelloWorld.stories.js b/packages/html/stories/HelloWorld.stories.js index aa88b570d..309c9df3e 100644 --- a/packages/html/stories/HelloWorld.stories.js +++ b/packages/html/stories/HelloWorld.stories.js @@ -1,7 +1,20 @@ import mxgraph from '@mxgraph/core'; +import { globalTypes } from '../.storybook/preview'; + export default { - title: 'Basic/HelloWorld' + title: 'Basic/HelloWorld', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } }; const Template = ({ label, ...args }) => { @@ -10,14 +23,18 @@ const Template = ({ label, ...args }) => { const container = document.createElement('div'); container.style.position = 'relative'; container.style.overflow = 'hidden'; - container.style.height = '241px'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; container.style.cursor = 'default'; - mxEvent.disableContextMenu(container); + if (!args.contextMenu) + mxEvent.disableContextMenu(container); const graph = new mxGraph(container); - new mxRubberband(graph); + if (args.rubberBand) + new mxRubberband(graph); const parent = graph.getDefaultParent(); @@ -30,6 +47,7 @@ const Template = ({ label, ...args }) => { size: [80, 30], relative: false, }); + const vertex2 = graph.insertVertex({ parent, value: 'World!', @@ -37,9 +55,9 @@ const Template = ({ label, ...args }) => { size: [80, 30], relative: false, }); + const edge = graph.insertEdge({ parent, - // value: 'to the', source: vertex1, target: vertex2, }); diff --git a/packages/html/stories/HierarchicalLayout.stories.js b/packages/html/stories/HierarchicalLayout.stories.js new file mode 100644 index 000000000..39e789ae4 --- /dev/null +++ b/packages/html/stories/HierarchicalLayout.stories.js @@ -0,0 +1,130 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/HierarchicalLayout', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxDomUtils, + mxDomHelpers, + mxCellRenderer, + mxFastOrganicLayout, + mxHierarchicalLayout, + mxPerimeter, + mxEvent, + mxRubberband, + mxUtils, + mxConstants + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Adds rubberband selection + if (args.rubberBand) + new mxRubberband(graph); + + // Changes the default vertex style in-place + let style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_PERIMETER_SPACING] = 6; + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_SHADOW] = true; + + style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_ROUNDED] = true; + + // Creates a layout algorithm to be used + // with the graph + const layout = new mxHierarchicalLayout(graph); + const organic = new mxFastOrganicLayout(graph); + organic.forceConstant = 120; + + const parent = graph.getDefaultParent(); + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + // Adds a button to execute the layout + let button = document.createElement('button'); + mxDomUtils.write(button, 'Hierarchical'); + mxEvent.addListener(button, 'click', function(evt) { + layout.execute(parent); + }); + buttons.appendChild(button); + + // Adds a button to execute the layout + button = document.createElement('button'); + mxDomUtils.write(button, 'Organic'); + + mxEvent.addListener(button, 'click', function(evt) { + organic.execute(parent); + }); + + buttons.appendChild(button); + + // Load cells and layouts the graph + graph.getModel().beginUpdate(); + try { + const v1 = graph.insertVertex(parent, null, '1', 0, 0, 80, 30); + const v2 = graph.insertVertex(parent, null, '2', 0, 0, 80, 30); + const v3 = graph.insertVertex(parent, null, '3', 0, 0, 80, 30); + const v4 = graph.insertVertex(parent, null, '4', 0, 0, 80, 30); + const v5 = graph.insertVertex(parent, null, '5', 0, 0, 80, 30); + const v6 = graph.insertVertex(parent, null, '6', 0, 0, 80, 30); + const v7 = graph.insertVertex(parent, null, '7', 0, 0, 80, 30); + const v8 = graph.insertVertex(parent, null, '8', 0, 0, 80, 30); + const v9 = graph.insertVertex(parent, null, '9', 0, 0, 80, 30); + + const e1 = graph.insertEdge(parent, null, '', v1, v2); + const e2 = graph.insertEdge(parent, null, '', v1, v3); + const e3 = graph.insertEdge(parent, null, '', v3, v4); + const e4 = graph.insertEdge(parent, null, '', v2, v5); + const e5 = graph.insertEdge(parent, null, '', v1, v6); + const e6 = graph.insertEdge(parent, null, '', v2, v3); + const e7 = graph.insertEdge(parent, null, '', v6, v4); + const e8 = graph.insertEdge(parent, null, '', v6, v1); + const e9 = graph.insertEdge(parent, null, '', v6, v7); + const e10 = graph.insertEdge(parent, null, '', v7, v8); + const e11 = graph.insertEdge(parent, null, '', v7, v9); + const e12 = graph.insertEdge(parent, null, '', v7, v6); + const e13 = graph.insertEdge(parent, null, '', v7, v5); + + // Executes the layout + layout.execute(parent); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/HoverIcons.stories.js b/packages/html/stories/HoverIcons.stories.js new file mode 100644 index 000000000..9881096e1 --- /dev/null +++ b/packages/html/stories/HoverIcons.stories.js @@ -0,0 +1,215 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Icon_Images/HoverIcons', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxImage, + mxRectangle, + mxUtils, + mxConnectionHandler + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Defines an icon for creating new connections in the connection handler. + // This will automatically disable the highlighting of the source vertex. + mxConnectionHandler.prototype.connectImage = new mxImage( + 'images/connector.gif', + 16, + 16 + ); + + // Defines a new class for all icons + class mxIconSet { + constructor(state) { + this.images = []; + const { graph } = state.view; + + // Icon1 + let img = mxUtils.createImage('images/copy.png'); + img.setAttribute('title', 'Duplicate'); + Object.assign(img.style, { + cursor: 'pointer', + width: '16px', + height: '16px', + position: 'absolute', + left: `${state.x + state.width}px`, + top: `${state.y + state.height}px`, + }); + + mxEvent.addGestureListeners(img, evt => { + const s = graph.gridSize; + graph.setSelectionCells(graph.moveCells([state.cell], s, s, true)); + mxEvent.consume(evt); + this.destroy(); + }); + + state.view.graph.container.appendChild(img); + this.images.push(img); + + // Delete + img = mxUtils.createImage('images/delete2.png'); + img.setAttribute('title', 'Delete'); + Object.assign(img.style, { + cursor: 'pointer', + width: '16px', + height: '16px', + position: 'absolute', + left: `${state.x + state.width}px`, + top: `${state.y - 16}px`, + }); + + mxEvent.addGestureListeners(img, evt => { + // Disables dragging the image + mxEvent.consume(evt); + }); + + mxEvent.addListener(img, 'click', evt => { + graph.removeCells([state.cell]); + mxEvent.consume(evt); + this.destroy(); + }); + + state.view.graph.container.appendChild(img); + this.images.push(img); + } + + destroy() { + if (this.images != null) { + for (const img of this.images) { + img.parentNode.removeChild(img); + } + } + this.images = null; + } + } + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setConnectable(true); + + // Enables rubberband selection + if (args.rubberBand) + new mxRubberband(graph); + + // Defines the tolerance before removing the icons + const ICON_TOLERANCE = 20; + + // Shows icons if the mouse is over a cell + graph.addMouseListener({ + currentState: null, + currentIconSet: null, + + mouseDown(sender, me) { + // Hides icons on mouse down + if (this.currentState != null) { + this.dragLeave(me.getEvent(), this.currentState); + this.currentState = null; + } + }, + + mouseMove(sender, me) { + if ( + this.currentState != null && + (me.getState() === this.currentState || me.getState() == null) + ) { + const tol = ICON_TOLERANCE; + const tmp = new mxRectangle( + me.getGraphX() - tol, + me.getGraphY() - tol, + 2 * tol, + 2 * tol + ); + if (mxUtils.intersects(tmp, this.currentState)) { + return; + } + } + + let tmp = graph.view.getState(me.getCell()); + + // Ignore everything but vertices + if ( + graph.isMouseDown || + (tmp != null && !tmp.cell.isVertex()) + ) { + tmp = null; + } + + if (tmp !== this.currentState) { + if (this.currentState != null) { + this.dragLeave(me.getEvent(), this.currentState); + } + + this.currentState = tmp; + if (this.currentState != null) { + this.dragEnter(me.getEvent(), this.currentState); + } + } + }, + + mouseUp(sender, me) {}, + + dragEnter(evt, state) { + if (this.currentIconSet == null) { + this.currentIconSet = new mxIconSet(state); + } + }, + + dragLeave(evt, state) { + if (this.currentIconSet != null) { + this.currentIconSet.destroy(); + this.currentIconSet = null; + } + }, + }); + + // 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, + }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/HoverStyle.stories.js b/packages/html/stories/HoverStyle.stories.js new file mode 100644 index 000000000..1ced88904 --- /dev/null +++ b/packages/html/stories/HoverStyle.stories.js @@ -0,0 +1,141 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Styles/HoverStyle', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxUtils, + mxConstants, + mxRubberband, + mxStencilRegistry, + mxCloneUtils + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + function updateStyle(state, hover) { + if (hover) { + state.style[mxConstants.STYLE_FILLCOLOR] = '#ff0000'; + } + + // Sets rounded style for both cases since the rounded style + // is not set in the default style and is therefore inherited + // once it is set, whereas the above overrides the default value + state.style[mxConstants.STYLE_ROUNDED] = hover ? '1' : '0'; + state.style[mxConstants.STYLE_STROKEWIDTH] = hover ? '4' : '1'; + state.style[mxConstants.STYLE_FONTSTYLE] = hover + ? mxConstants.FONT_BOLD + : '0'; + } + + // Changes fill color to red on mouseover + graph.addMouseListener({ + currentState: null, + previousStyle: null, + mouseDown(sender, me) { + if (this.currentState != null) { + this.dragLeave(me.getEvent(), this.currentState); + this.currentState = null; + } + }, + mouseMove(sender, me) { + if (this.currentState != null && me.getState() == this.currentState) { + return; + } + + let tmp = graph.view.getState(me.getCell()); + + // Ignores everything but vertices + if ( + graph.isMouseDown || + (tmp != null && !tmp.cell.isVertex()) + ) { + tmp = null; + } + + if (tmp != this.currentState) { + if (this.currentState != null) { + this.dragLeave(me.getEvent(), this.currentState); + } + + this.currentState = tmp; + + if (this.currentState != null) { + this.dragEnter(me.getEvent(), this.currentState); + } + } + }, + mouseUp(sender, me) {}, + dragEnter(evt, state) { + if (state != null) { + this.previousStyle = state.style; + state.style = mxCloneUtils.clone(state.style); + updateStyle(state, true); + state.shape.apply(state); + state.shape.redraw(); + + if (state.text != null) { + state.text.apply(state); + state.text.redraw(); + } + } + }, + dragLeave(evt, state) { + if (state != null) { + state.style = this.previousStyle; + updateStyle(state, false); + state.shape.apply(state); + state.shape.redraw(); + + if (state.text != null) { + state.text.apply(state); + state.text.redraw(); + } + } + }, + }); + + // Enables rubberband selection + if (args.rubberBand) + 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(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Images.stories.js b/packages/html/stories/Images.stories.js new file mode 100644 index 000000000..07600c2af --- /dev/null +++ b/packages/html/stories/Images.stories.js @@ -0,0 +1,152 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Icon_Images/Images', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxCloneUtils, + mxImage, + mxRectangle, + mxConstants, + mxUtils, + mxPerimeter + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Sets a background image and restricts child movement to its bounds + graph.setBackgroundImage( + new mxImage('images/gradient_background.jpg', 360, 200) + ); + graph.maximumGraphBounds = new mxRectangle(0, 0, 360, 200); + + // Resizes the container but never make it bigger than the background + graph.minimumContainerSize = new mxRectangle(0, 0, 360, 200); + graph.setResizeContainer(true); + + // Disables basic selection and cell handling + // graph.setEnabled(false); + configureStylesheet(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 { + var v1 = graph.insertVertex( + parent, + null, + 'First Line\nSecond Line', + 20, + 10, + 80, + 100, + 'bottom' + ); + var v1 = graph.insertVertex( + parent, + null, + 'First Line\nSecond Line', + 130, + 10, + 80, + 100, + 'top' + ); + var v1 = graph.insertVertex(parent, null, '', 230, 10, 100, 100, 'image'); + var v2 = graph.insertVertex( + parent, + null, + 'First Line\nSecond Line', + 20, + 130, + 140, + 60, + 'right' + ); + var v2 = graph.insertVertex( + parent, + null, + 'First Line\nSecond Line', + 180, + 130, + 140, + 60, + 'left' + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + function configureStylesheet(graph) { + let style = {}; + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_IMAGE; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; + style[mxConstants.STYLE_IMAGE] = 'images/icons48/keys.png'; + style[mxConstants.STYLE_FONTCOLOR] = '#FFFFFF'; + graph.getStylesheet().putCellStyle('image', style); + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_LABEL; + style[mxConstants.STYLE_STROKECOLOR] = '#000000'; + style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; + style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP; + style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_CENTER; + style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP; + style[mxConstants.STYLE_IMAGE] = 'images/icons48/gear.png'; + style[mxConstants.STYLE_IMAGE_WIDTH] = '48'; + style[mxConstants.STYLE_IMAGE_HEIGHT] = '48'; + style[mxConstants.STYLE_SPACING_TOP] = '56'; + style[mxConstants.STYLE_SPACING] = '8'; + graph.getStylesheet().putCellStyle('bottom', style); + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_BOTTOM; + style[mxConstants.STYLE_IMAGE] = 'images/icons48/server.png'; + delete style[mxConstants.STYLE_SPACING_TOP]; + graph.getStylesheet().putCellStyle('top', style); + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT; + style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_LEFT; + style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; + style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; + style[mxConstants.STYLE_IMAGE] = 'images/icons48/earth.png'; + style[mxConstants.STYLE_SPACING_LEFT] = '55'; + style[mxConstants.STYLE_SPACING] = '4'; + graph.getStylesheet().putCellStyle('right', style); + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_RIGHT; + style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_RIGHT; + delete style[mxConstants.STYLE_SPACING_LEFT]; + style[mxConstants.STYLE_SPACING_RIGHT] = '55'; + graph.getStylesheet().putCellStyle('left', style); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Indicators.stories.js b/packages/html/stories/Indicators.stories.js new file mode 100644 index 000000000..03bb607ef --- /dev/null +++ b/packages/html/stories/Indicators.stories.js @@ -0,0 +1,93 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Icon_Images/Indicators', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEdgeStyle, + mxConstants, + mxKeyHandler + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setConnectable(true); + new mxKeyHandler(graph); + + // Enables moving of vertex labels + graph.vertexLabelsMovable = true; + + // Creates a style with an indicator + let style = graph.getStylesheet().getDefaultVertexStyle(); + + style[mxConstants.STYLE_SHAPE] = 'label'; + style[mxConstants.STYLE_VERTICAL_ALIGN] = 'bottom'; + style[mxConstants.STYLE_INDICATOR_SHAPE] = 'ellipse'; + style[mxConstants.STYLE_INDICATOR_WIDTH] = 34; + style[mxConstants.STYLE_INDICATOR_HEIGHT] = 34; + style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = 'top'; // indicator v-alignment + style[mxConstants.STYLE_IMAGE_ALIGN] = 'center'; + style[mxConstants.STYLE_INDICATOR_COLOR] = 'green'; + delete style[mxConstants.STYLE_STROKECOLOR]; // transparent + delete style[mxConstants.STYLE_FILLCOLOR]; // transparent + + // Creates a style with an indicator + style = graph.getStylesheet().getDefaultEdgeStyle(); + + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; + style[mxConstants.STYLE_ELBOW] = mxConstants.ELBOW_VERTICAL; + style[mxConstants.STYLE_ROUNDED] = true; + + // 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 { + graph.insertVertex(parent, null, 'Bottom Label', 80, 80, 80, 60); + graph.insertVertex( + parent, + null, + 'Top Label', + 200, + 80, + 60, + 60, + 'indicatorShape=actor;indicatorWidth=28;indicatorColor=blue;imageVerticalAlign=bottom;verticalAlign=top' + ); + graph.insertVertex( + parent, + null, + 'Right Label', + 300, + 80, + 120, + 60, + 'indicatorShape=cloud;indicatorWidth=40;indicatorColor=#00FFFF;imageVerticalAlign=center;verticalAlign=middle;imageAlign=left;align=left;spacingLeft=44' + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/JsonData.stories.js b/packages/html/stories/JsonData.stories.js new file mode 100644 index 000000000..bea764e75 --- /dev/null +++ b/packages/html/stories/JsonData.stories.js @@ -0,0 +1,99 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Xml_Json/JsonData', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxObjectCodec, + mxDomHelpers, + mxCodecRegistry, + mxEvent, + mxWindow, + mxClient, + mxCodec, + mxDomUtils, + mxUtils + } = mxgraph; + + mxClient.setImageBasePath('/images'); + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Register a new codec + function CustomData(value) { + this.value = value; + } + const codec = new mxObjectCodec(new CustomData()); + codec.encode = function(enc, obj) { + const node = enc.document.createElement('CustomData'); + mxDomUtils.setTextContent(node, JSON.stringify(obj)); + return node; + }; + codec.decode = function(dec, node, into) { + const obj = JSON.parse(mxDomUtils.getTextContent(node)); + obj.constructor = CustomData; + + return obj; + }; + mxCodecRegistry.register(codec); + + // Disables the built-in context menu + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Enables rubberband selection + if (args.rubberBand) + 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); + v1.data = new CustomData('v1'); + const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); + v2.data = new CustomData('v2'); + const e1 = graph.insertEdge(parent, null, '', v1, v2); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + buttons.appendChild( + mxDomHelpers.button('Show JSON', function() { + const encoder = new mxCodec(); + const node = encoder.encode(graph.getModel()); + mxWindow.popup(mxUtils.getXml(node), true); + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/LabelPosition.stories.js b/packages/html/stories/LabelPosition.stories.js new file mode 100644 index 000000000..95ecb8d7b --- /dev/null +++ b/packages/html/stories/LabelPosition.stories.js @@ -0,0 +1,97 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Labels/LabelPosition', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEdgeHandler, + mxGraphHandler, + mxCellRenderer, + mxMarker, + mxCylinder, + mxArrow, + mxPoint + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + // Defines the common part of all cell styles as a string-prefix + const prefix = 'shape=image;image=images/icons48/keys.png;'; + + // Adds cells to the model in a single step and set the vertex + // label positions using the label position styles. Vertical + // and horizontal label position styles can be combined. + // Note: Alternatively, vertex labels can be set be overriding + // mxCellRenderer.getLabelBounds. + graph.getModel().beginUpdate(); + try { + graph.insertVertex( + parent, + null, + 'Bottom', + 60, + 60, + 60, + 60, + `${prefix}verticalLabelPosition=bottom;verticalAlign=top` + ); + graph.insertVertex( + parent, + null, + 'Top', + 140, + 60, + 60, + 60, + `${prefix}verticalLabelPosition=top;verticalAlign=bottom` + ); + graph.insertVertex( + parent, + null, + 'Left', + 60, + 160, + 60, + 60, + `${prefix}labelPosition=left;align=right` + ); + graph.insertVertex( + parent, + null, + 'Right', + 140, + 160, + 60, + 60, + `${prefix}labelPosition=right;align=left` + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Labels.stories.js b/packages/html/stories/Labels.stories.js new file mode 100644 index 000000000..bd94bea72 --- /dev/null +++ b/packages/html/stories/Labels.stories.js @@ -0,0 +1,188 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Labels/Labels', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxKeyHandler, + mxConstants, + mxRectangle + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setTooltips(true); + graph.htmlLabels = true; + graph.vertexLabelsMovable = true; + + if (args.rubberBand) + new mxRubberband(graph); + + new mxKeyHandler(graph); + + // Do not allow removing labels from parents + graph.graphHandler.removeCellsFromParent = false; + + // Autosize labels on insert where autosize=1 + graph.autoSizeCellsOnAdd = true; + + // Allows moving of relative cells + graph.isCellLocked = function(cell) { + return this.isCellsLocked(); + }; + + graph.isCellResizable = function(cell) { + const geo = cell.getGeometry(); + + return geo == null || !geo.relative; + }; + + // Truncates the label to the size of the vertex + graph.getLabel = function(cell) { + const label = this.labelsVisible ? this.convertValueToString(cell) : ''; + const geometry = cell.getGeometry(); + + if ( + !cell.isCollapsed() && + geometry != null && + (geometry.offset == null || + (geometry.offset.x == 0 && geometry.offset.y == 0)) && + cell.isVertex() && + geometry.width >= 2 + ) { + const style = this.getCellStyle(cell); + const fontSize = + style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE; + const max = geometry.width / (fontSize * 0.625); + + if (max < label.length) { + return `${label.substring(0, max)}...`; + } + } + + return label; + }; + + // Enables wrapping for vertex labels + graph.isWrapping = function(cell) { + return cell.isCollapsed(); + }; + + // Enables clipping of vertex labels if no offset is defined + graph.isLabelClipped = function(cell) { + const geometry = cell.getGeometry(); + + return ( + geometry != null && + !geometry.relative && + (geometry.offset == null || + (geometry.offset.x == 0 && geometry.offset.y == 0)) + ); + }; + + // 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, + 'vertexLabelsMovable', + 20, + 20, + 80, + 30 + ); + + // Places sublabels inside the vertex + const label11 = graph.insertVertex( + v1, + null, + 'Label1', + 0.5, + 1, + 0, + 0, + null, + true + ); + const label12 = graph.insertVertex( + v1, + null, + 'Label2', + 0.5, + 0, + 0, + 0, + null, + true + ); + + const v2 = graph.insertVertex( + parent, + null, + 'Wrapping and clipping is enabled only if the cell is collapsed, otherwise the label is truncated if there is no manual offset.', + 200, + 150, + 80, + 30 + ); + v2.geometry.alternateBounds = new mxRectangle(0, 0, 80, 30); + const e1 = graph.insertEdge(parent, null, 'edgeLabelsMovable', v1, v2); + + // Places sublabels inside the vertex + const label21 = graph.insertVertex( + v2, + null, + 'Label1', + 0.5, + 1, + 0, + 0, + null, + true + ); + const label22 = graph.insertVertex( + v2, + null, + 'Label2', + 0.5, + 0, + 0, + 0, + null, + true + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Layers.stories.js b/packages/html/stories/Layers.stories.js new file mode 100644 index 000000000..cc394e11c --- /dev/null +++ b/packages/html/stories/Layers.stories.js @@ -0,0 +1,125 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/Layers', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxDomHelpers, + mxCell, + mxGraphModel, + mxPoint + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Creates the graph inside the given container using a model + // with a custom root and two layers. Layers can also be added + // dynamically using let layer = model.add(root, new mxCell()). + const root = new mxCell(); + const layer0 = root.insert(new mxCell()); + const layer1 = root.insert(new mxCell()); + const model = new mxGraphModel(root); + + const graph = new mxGraph(container, model); + + // Disables basic selection and cell handling + graph.setEnabled(false); + + // 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 + model.beginUpdate(); + try { + const v1 = graph.insertVertex( + layer1, + null, + 'Hello,', + 20, + 20, + 80, + 30, + 'fillColor=#C0C0C0' + ); + const v2 = graph.insertVertex( + layer1, + null, + 'Hello,', + 200, + 20, + 80, + 30, + 'fillColor=#C0C0C0' + ); + const v3 = graph.insertVertex(layer0, null, 'World!', 110, 150, 80, 30); + const e1 = graph.insertEdge( + layer1, + null, + '', + v1, + v3, + 'strokeColor=#0C0C0C' + ); + e1.geometry.points = [new mxPoint(60, 165)]; + const e2 = graph.insertEdge(layer0, null, '', v2, v3); + e2.geometry.points = [new mxPoint(240, 165)]; + const e3 = graph.insertEdge( + layer0, + null, + '', + v1, + v2, + 'edgeStyle=topToBottomEdgeStyle' + ); + e3.geometry.points = [new mxPoint(150, 30)]; + const e4 = graph.insertEdge( + layer1, + null, + '', + v2, + v1, + 'strokeColor=#0C0C0C;edgeStyle=topToBottomEdgeStyle' + ); + e4.geometry.points = [new mxPoint(150, 40)]; + } finally { + // Updates the display + model.endUpdate(); + } + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + buttons.appendChild( + mxDomHelpers.button('Layer 0', function() { + model.setVisible(layer0, !layer0.isVisible()); + }) + ); + + buttons.appendChild( + mxDomHelpers.button('Layer 1', function() { + model.setVisible(layer1, !layer1.isVisible()); + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/LoD.stories.js b/packages/html/stories/LoD.stories.js new file mode 100644 index 000000000..b551d3a00 --- /dev/null +++ b/packages/html/stories/LoD.stories.js @@ -0,0 +1,91 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Zoom_OffPage/LoD', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxDomHelpers + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.centerZoom = false; + + // Links level of detail to zoom level but can be independent of zoom + const isVisible = function(cell) { + return cell.lod == null || cell.lod / 2 < this.view.scale; + }; + + // 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, null, '1', 20, 20, 80, 30); + v1.lod = 1; + v1.isVisible = isVisible; + + const v2 = graph.insertVertex(parent, null, '1', 200, 150, 80, 30); + v2.lod = 1; + v2.isVisible = isVisible; + + const v3 = graph.insertVertex(parent, null, '2', 20, 150, 40, 20); + v3.lod = 2; + v3.isVisible = isVisible; + + const v4 = graph.insertVertex(parent, null, '3', 200, 10, 20, 20); + v4.lod = 3; + v4.isVisible = isVisible; + + const e1 = graph.insertEdge(parent, null, '2', v1, v2, 'strokeWidth=2'); + e1.lod = 2; + e1.isVisible = isVisible; + + const e2 = graph.insertEdge(parent, null, '2', v3, v4, 'strokeWidth=2'); + e2.lod = 2; + e2.isVisible = isVisible; + + const e3 = graph.insertEdge(parent, null, '3', v1, v4, 'strokeWidth=1'); + e3.lod = 3; + e3.isVisible = isVisible; + }); + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + buttons.appendChild( + mxDomHelpers.button('+', function() { + graph.zoomIn(); + }) + ); + + buttons.appendChild( + mxDomHelpers.button('-', function() { + graph.zoomOut(); + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Markers.stories.js b/packages/html/stories/Markers.stories.js new file mode 100644 index 000000000..77bcffee0 --- /dev/null +++ b/packages/html/stories/Markers.stories.js @@ -0,0 +1,220 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Icon_Images/Markers', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEdgeHandler, + mxGraphHandler, + mxCellRenderer, + mxMarker, + mxCylinder, + mxArrow, + mxPoint + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Enables guides + mxGraphHandler.prototype.guidesEnabled = true; + mxEdgeHandler.prototype.snapToTerminals = true; + + // Registers and defines the custom marker + mxMarker.addMarker('dash', function( + canvas, + shape, + type, + pe, + unitX, + unitY, + size, + source, + sw, + filled + ) { + const nx = unitX * (size + sw + 1); + const ny = unitY * (size + sw + 1); + + return function() { + canvas.begin(); + canvas.moveTo(pe.x - nx / 2 - ny / 2, pe.y - ny / 2 + nx / 2); + canvas.lineTo( + pe.x + ny / 2 - (3 * nx) / 2, + pe.y - (3 * ny) / 2 - nx / 2 + ); + canvas.stroke(); + }; + }); + + // Defines custom message shape + class MessageShape extends mxCylinder { + redrawPath(path, x, y, w, h, isForeground) { + if (isForeground) { + path.moveTo(0, 0); + path.lineTo(w / 2, h / 2); + path.lineTo(w, 0); + } else { + path.moveTo(0, 0); + path.lineTo(w, 0); + path.lineTo(w, h); + path.lineTo(0, h); + path.close(); + } + } + } + mxCellRenderer.registerShape('message', MessageShape); + + // Defines custom edge shape + class LinkShape extends mxArrow { + paintEdgeShape(c, pts) { + const width = 10; + + // Base vector (between end points) + const p0 = pts[0]; + const pe = pts[pts.length - 1]; + + const dx = pe.x - p0.x; + const dy = pe.y - p0.y; + const dist = Math.sqrt(dx * dx + dy * dy); + const length = dist; + + // Computes the norm and the inverse norm + const nx = dx / dist; + const ny = dy / dist; + const basex = length * nx; + const basey = length * ny; + const floorx = (width * ny) / 3; + const floory = (-width * nx) / 3; + + // Computes points + const p0x = p0.x - floorx / 2; + const p0y = p0.y - floory / 2; + const p1x = p0x + floorx; + const p1y = p0y + floory; + const p2x = p1x + basex; + const p2y = p1y + basey; + const p3x = p2x + floorx; + const p3y = p2y + floory; + // p4 not necessary + const p5x = p3x - 3 * floorx; + const p5y = p3y - 3 * floory; + + c.begin(); + c.moveTo(p1x, p1y); + c.lineTo(p2x, p2y); + c.moveTo(p5x + floorx, p5y + floory); + c.lineTo(p0x, p0y); + c.stroke(); + } + } + mxCellRenderer.registerShape('link', LinkShape); + + // Creates the graph + const graph = new mxGraph(container); + + // Sets default styles + let style = graph.getStylesheet().getDefaultVertexStyle(); + style.fillColor = '#FFFFFF'; + style.strokeColor = '#000000'; + style.fontColor = '#000000'; + style.fontStyle = '1'; + + style = graph.getStylesheet().getDefaultEdgeStyle(); + style.strokeColor = '#000000'; + style.fontColor = '#000000'; + style.fontStyle = '0'; + style.fontStyle = '0'; + style.startSize = '8'; + style.endSize = '8'; + + // Populates the graph + const parent = graph.getDefaultParent(); + + graph.getModel().beginUpdate(); + try { + const v1 = graph.insertVertex(parent, null, 'v1', 20, 20, 80, 30); + const v2 = graph.insertVertex(parent, null, 'v2', 440, 20, 80, 30); + const e1 = graph.insertEdge( + parent, + null, + '', + v1, + v2, + 'dashed=1;' + + 'startArrow=oval;endArrow=block;sourcePerimeterSpacing=4;startFill=0;endFill=0;' + ); + const e11 = graph.insertVertex( + e1, + null, + 'Label', + 0, + 0, + 20, + 14, + 'shape=message;labelBackgroundColor=#ffffff;labelPosition=left;spacingRight=2;align=right;fontStyle=0;' + ); + e11.geometry.offset = new mxPoint(-10, -7); + e11.geometry.relative = true; + e11.connectable = false; + + const v3 = graph.insertVertex(parent, null, 'v3', 20, 120, 80, 30); + const v4 = graph.insertVertex(parent, null, 'v4', 440, 120, 80, 30); + const e2 = graph.insertEdge( + parent, + null, + 'Label', + v3, + v4, + 'startArrow=dash;startSize=12;endArrow=block;labelBackgroundColor=#FFFFFF;' + ); + + const v5 = graph.insertVertex( + parent, + null, + 'v5', + 40, + 220, + 40, + 40, + 'shape=ellipse;perimeter=ellipsePerimeter;' + ); + const v6 = graph.insertVertex( + parent, + null, + 'v6', + 460, + 220, + 40, + 40, + 'shape=doubleEllipse;perimeter=ellipsePerimeter;' + ); + const e3 = graph.insertEdge( + parent, + null, + 'Link', + v5, + v6, + 'shape=link;labelBackgroundColor=#FFFFFF;' + ); + } finally { + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Merge.stories.js b/packages/html/stories/Merge.stories.js new file mode 100644 index 000000000..bb7463be2 --- /dev/null +++ b/packages/html/stories/Merge.stories.js @@ -0,0 +1,232 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Misc/Merge', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxPerimeter, + mxConstants, + mxRubberband + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + mxConstants.SHADOWCOLOR = '#c0c0c0'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // No size handles, please... + graph.setCellsResizable(false); + + // Makes all cells round with a white, bold label + let style = graph.stylesheet.getDefaultVertexStyle(); + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; + style[mxConstants.STYLE_FONTCOLOR] = 'white'; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_FONTSTYLE] = mxConstants.FONT_BOLD; + style[mxConstants.STYLE_FONTSIZE] = 14; + style[mxConstants.STYLE_SHADOW] = true; + + // Makes all edge labels gray with a white background + style = graph.stylesheet.getDefaultEdgeStyle(); + style[mxConstants.STYLE_FONTCOLOR] = 'gray'; + style[mxConstants.STYLE_FONTSTYLE] = mxConstants.FONT_BOLD; + style[mxConstants.STYLE_FONTCOLOR] = 'black'; + style[mxConstants.STYLE_STROKEWIDTH] = 2; + + // Enables rubberband selection + if (args.rubberBand) + 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 target model in a single step + // using custom ids for the vertices and edges + const w = 40; + const h = 40; + + graph.getModel().beginUpdate(); + try { + const a = graph.insertVertex( + parent, + 'a', + 'A', + 20, + 20, + w, + h, + 'fillColor=blue' + ); + const b = graph.insertVertex( + parent, + 'b', + 'B', + 20, + 200, + w, + h, + 'fillColor=blue' + ); + const c = graph.insertVertex( + parent, + 'c', + 'C', + 200, + 20, + w, + h, + 'fillColor=red' + ); + const d = graph.insertVertex( + parent, + 'd', + 'D', + 200, + 200, + w, + h, + 'fillColor=red' + ); + const ac = graph.insertEdge( + parent, + 'ac', + 'ac', + a, + c, + 'strokeColor=blue;verticalAlign=bottom' + ); + const ad = graph.insertEdge( + parent, + 'ad', + 'ad', + a, + d, + 'strokeColor=blue;align=left;verticalAlign=bottom' + ); + const bd = graph.insertEdge( + parent, + 'bd', + 'bd', + b, + d, + 'strokeColor=blue;verticalAlign=bottom' + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + // Creates the second graph model (without a container) + const graph2 = new mxGraph(); + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent2 = graph2.getDefaultParent(); + + // Adds cells to the target model in a single step + // using custom ids for the vertices + graph2.getModel().beginUpdate(); + try { + const c = graph2.insertVertex( + parent2, + 'c', + 'C', + 200, + 20, + w, + h, + 'fillColor=green' + ); + const d = graph2.insertVertex( + parent2, + 'd', + 'D', + 200, + 200, + w, + h, + 'fillColor=green' + ); + const e = graph2.insertVertex( + parent2, + 'e', + 'E', + 400, + 20, + w, + h, + 'fillColor=green' + ); + const f = graph2.insertVertex( + parent2, + 'f', + 'F', + 400, + 200, + w, + h, + 'fillColor=green' + ); + const ce = graph2.insertEdge( + parent2, + 'ce', + 'ce', + c, + e, + 'strokeColor=green;verticalAlign=bottom' + ); + const ed = graph2.insertEdge( + parent2, + 'ed', + 'ed', + e, + d, + 'strokeColor=green;align=right;verticalAlign=bottom' + ); + const fd = graph2.insertEdge( + parent2, + 'bd', + 'fd', + f, + d, + 'strokeColor=green;verticalAlign=bottom' + ); + } finally { + // Updates the display + graph2.getModel().endUpdate(); + } + + // Merges the model from the second graph into the model of + // the first graph. Note: If you add a false to the parameter + // list then _not_ all edges will be cloned, that is, the + // edges are assumed to have an identity, and hence the edge + // "bd" will be changed to point from f to d, as specified in + // the edge for the same id in the second graph. + graph.getModel().mergeChildren(parent2, parent /* , false */); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Monitor.stories.js b/packages/html/stories/Monitor.stories.js new file mode 100644 index 000000000..86425177d --- /dev/null +++ b/packages/html/stories/Monitor.stories.js @@ -0,0 +1,287 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Misc/Monitor', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEdgeStyle, + mxDomHelpers, + mxXmlUtils, + mxPerimeter, + mxUtils, + mxConstants, + mxCloneUtils, + mxCodec + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + mxConstants.SHADOWCOLOR = '#e0e0e0'; + + // Creates the graph inside the given container + const graph = createGraph(container); + + // Creates a process display using the activity names as IDs to refer to the elements + const xml = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''; + const doc = mxXmlUtils.parseXml(xml); + const codec = new mxCodec(doc); + codec.decode(doc.documentElement, graph.getModel()); + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + // Creates a button to invoke the refresh function + buttons.appendChild( + mxDomHelpers.button('Update', function(evt) { + // XML is normally fetched from URL at server using mxUtils.get - this is a client-side + // string with randomized states to demonstrate the idea of the workflow monitor + const xml = + `` + + `` + + ``; + update(graph, xml); + }) + ); + + /** + * Updates the display of the given graph using the XML data + */ + function update(graph, xml) { + if (xml != null && xml.length > 0) { + const doc = mxXmlUtils.parseXml(xml); + + if (doc != null && doc.documentElement != null) { + const model = graph.getModel(); + const nodes = doc.documentElement.getElementsByTagName('update'); + + if (nodes != null && nodes.length > 0) { + model.beginUpdate(); + + try { + for (let i = 0; i < nodes.length; i++) { + // Processes the activity nodes inside the process node + const id = nodes[i].getAttribute('id'); + const state = nodes[i].getAttribute('state'); + + // Gets the cell for the given activity name from the model + const cell = model.getCell(id); + + // Updates the cell color and adds some tooltip information + if (cell != null) { + // Resets the fillcolor and the overlay + graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, 'white', [ + cell, + ]); + graph.removeCellOverlays(cell); + + // Changes the cell color for the known states + if (state == 'Running') { + graph.setCellStyles( + mxConstants.STYLE_FILLCOLOR, + '#f8cecc', + [cell] + ); + } else if (state == 'Waiting') { + graph.setCellStyles( + mxConstants.STYLE_FILLCOLOR, + '#fff2cc', + [cell] + ); + } else if (state == 'Completed') { + graph.setCellStyles( + mxConstants.STYLE_FILLCOLOR, + '#d4e1f5', + [cell] + ); + } + + // Adds tooltip information using an overlay icon + if (state != 'Init') { + // Sets the overlay for the cell in the graph + graph.addCellOverlay( + cell, + createOverlay(graph.warningImage, `State: ${state}`) + ); + } + } + } // for + } finally { + model.endUpdate(); + } + } + } + } + } + + /** + * Creates an overlay object using the given tooltip and text for the alert window + * which is being displayed on click. + */ + function createOverlay(image, tooltip) { + const overlay = new mxCellOverlay(image, tooltip); + + // Installs a handler for clicks on the overlay + overlay.addListener(mxEvent.CLICK, function(sender, evt) { + mxUtils.alert(`${tooltip}\nLast update: ${new Date()}`); + }); + + return overlay; + } + + /** + * Creates and returns an empty graph inside the given container. + */ + function createGraph(container) { + const graph = new mxGraph(container); + graph.setTooltips(true); + graph.setEnabled(false); + + // Disables folding + graph.isCellFoldable = function(cell, collapse) { + return false; + }; + + // Creates the stylesheet for the process display + let style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_FONTSIZE] = 11; + style[mxConstants.STYLE_FONTCOLOR] = 'black'; + style[mxConstants.STYLE_STROKECOLOR] = '#808080'; + style[mxConstants.STYLE_FILLCOLOR] = 'white'; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_GRADIENT_DIRECTION] = mxConstants.DIRECTION_EAST; + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_SHADOW] = true; + style[mxConstants.STYLE_FONTSTYLE] = 1; + + style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; + style[mxConstants.STYLE_STROKECOLOR] = '#808080'; + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_SHADOW] = true; + + style = []; + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; + style[mxConstants.STYLE_STROKECOLOR] = '#a0a0a0'; + style[mxConstants.STYLE_FONTCOLOR] = '#606060'; + style[mxConstants.STYLE_FILLCOLOR] = '#E0E0DF'; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_STARTSIZE] = 30; + style[mxConstants.STYLE_ROUNDED] = false; + style[mxConstants.STYLE_FONTSIZE] = 12; + style[mxConstants.STYLE_FONTSTYLE] = 0; + style[mxConstants.STYLE_HORIZONTAL] = false; + // To improve text quality for vertical labels in some old IE versions... + style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = '#efefef'; + + graph.getStylesheet().putCellStyle('swimlane', style); + + style = []; + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RHOMBUS; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter; + style[mxConstants.STYLE_STROKECOLOR] = '#91BCC0'; + style[mxConstants.STYLE_FONTCOLOR] = 'gray'; + style[mxConstants.STYLE_FILLCOLOR] = '#91BCC0'; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; + style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; + style[mxConstants.STYLE_FONTSIZE] = 16; + graph.getStylesheet().putCellStyle('step', style); + + style = []; + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; + style[mxConstants.STYLE_FONTCOLOR] = 'gray'; + style[mxConstants.STYLE_FILLCOLOR] = '#A0C88F'; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_STROKECOLOR] = '#A0C88F'; + style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; + style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; + style[mxConstants.STYLE_FONTSIZE] = 16; + graph.getStylesheet().putCellStyle('start', style); + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_FILLCOLOR] = '#DACCBC'; + style[mxConstants.STYLE_STROKECOLOR] = '#AF7F73'; + graph.getStylesheet().putCellStyle('end', style); + + return graph; + } + + /** + * Returns a random state. + */ + function getState() { + let state = 'Init'; + const rnd = Math.random() * 4; + + if (rnd > 3) { + state = 'Completed'; + } else if (rnd > 2) { + state = 'Running'; + } else if (rnd > 1) { + state = 'Waiting'; + } + + return state; + } + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Morph.stories.js b/packages/html/stories/Morph.stories.js new file mode 100644 index 000000000..e54bcdb0e --- /dev/null +++ b/packages/html/stories/Morph.stories.js @@ -0,0 +1,104 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Effects/Morph', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxDomHelpers, + mxMorphing, + mxEvent, + mxRubberband + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Disables the built-in context menu + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Enables rubberband selection + if (args.rubberBand) + 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(); + let v1; + var v2; + try { + v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30); + var 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(); + } + + let mult = 1; + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + buttons.appendChild( + mxDomHelpers.button('Morph', function() { + graph.clearSelection(); + + graph.getModel().beginUpdate(); + try { + let geo = graph.getCellGeometry(v1); + geo = geo.clone(); + geo.x += 180 * mult; + graph.getModel().setGeometry(v1, geo); + + geo = graph.getCellGeometry(v2); + geo = geo.clone(); + geo.x -= 180 * mult; + graph.getModel().setGeometry(v2, geo); + } finally { + // Arguments are number of steps, ease and delay + const morph = new mxMorphing(graph, 20, 1.2, 20); + morph.addListener(mxEvent.DONE, function() { + graph.getModel().endUpdate(); + }); + morph.startAnimation(); + } + + mult *= -1; + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/OffPage.stories.js b/packages/html/stories/OffPage.stories.js new file mode 100644 index 000000000..0e27e7002 --- /dev/null +++ b/packages/html/stories/OffPage.stories.js @@ -0,0 +1,202 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Zoom_OffPage/OffPage', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxCellTracker, + mxConstants, + mxEvent + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Use complete cell as highlight region + mxConstants.ACTIVE_REGION = 1; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setEnabled(false); + + // Highlights offpage connectors + const highlight = new mxCellTracker(graph, null, function(me) { + const cell = me.getCell(); + + if ( + cell != null && + cell.value != null && + typeof cell.value.create === 'function' + ) { + return cell; + } + + return null; + }); + + // Handles clicks on offpage connectors and + // executes function in user object + graph.addListener(mxEvent.CLICK, function(source, evt) { + const cell = evt.getProperty('cell'); + + if ( + cell != null && + cell.value != null && + typeof cell.value.create === 'function' + ) { + cell.value.create(); + } + }); + + // Handles clicks on offpage connectors and + // executes function in user object + graph.getCursorForCell = function(cell) { + if ( + cell != null && + cell.value != null && + typeof cell.value.create === 'function' + ) { + return 'pointer'; + } + }; + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + let first = null; + let second = null; + + first = function() { + const value = { + toString() { + return 'Next'; + }, + create: second, + }; + + // Adds cells to the model in a single step + graph.getModel().beginUpdate(); + try { + graph.getModel().setRoot(graph.getModel().createRoot()); + const parent = graph.getDefaultParent(); + + const v1 = graph.insertVertex( + parent, + null, + 'Click', + 30, + 20, + 80, + 30, + 'fillColor=#FFFF88;strokeColor=#FF1A00' + ); + const v2 = graph.insertVertex( + parent, + null, + 'Next', + 20, + 150, + 100, + 30, + 'fillColor=#FFFF88;strokeColor=#FF1A00' + ); + const v3 = graph.insertVertex( + parent, + null, + value, + 200, + 150, + 40, + 40, + 'shape=triangle;align=left;fillColor=#C3D9FF;strokeColor=#4096EE' + ); + const e1 = graph.insertEdge( + parent, + null, + null, + v1, + v2, + 'strokeColor=#FF1A00' + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + }; + + second = function() { + const value = { + toString() { + return 'Prev'; + }, + create: first, + }; + + // Adds cells to the model in a single step + graph.getModel().beginUpdate(); + try { + graph.getModel().setRoot(graph.getModel().createRoot()); + const parent = graph.getDefaultParent(); + + const v1 = graph.insertVertex( + parent, + null, + 'Click', + 30, + 20, + 80, + 30, + 'fillColor=#CDEB8B;strokeColor=#008C00' + ); + const v2 = graph.insertVertex( + parent, + null, + 'Prev', + 220, + 20, + 100, + 30, + 'fillColor=#CDEB8B;strokeColor=#008C00' + ); + const v3 = graph.insertVertex( + parent, + null, + value, + 30, + 150, + 40, + 40, + 'shape=triangle;align=right;fillColor=#C3D9FF;strokeColor=#4096EE;direction=west' + ); + const e1 = graph.insertEdge( + parent, + null, + null, + v1, + v2, + 'strokeColor=#008C00' + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + }; + + first(); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/OrgChart.stories.js b/packages/html/stories/OrgChart.stories.js new file mode 100644 index 000000000..e929f50dc --- /dev/null +++ b/packages/html/stories/OrgChart.stories.js @@ -0,0 +1,390 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/OrgChart', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxConstants, + mxEvent, + mxClient, + mxPoint, + mxOutline, + mxEdgeStyle, + mxKeyHandler, + mxCompactTreeLayout, + mxLayoutManager, + mxCellOverlay, + mxImage, + mxUtils, + mxToolbar + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Makes the shadow brighter + mxConstants.SHADOWCOLOR = '#C0C0C0'; + + const outline = document.getElementById('outlineContainer'); + + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + // Sets a gradient background + if (mxClient.IS_GC || mxClient.IS_SF) { + container.style.background = + '-webkit-gradient(linear, 0% 0%, 0% 100%, from(#FFFFFF), to(#E7E7E7))'; + } else if (mxClient.IS_NS) { + container.style.background = + '-moz-linear-gradient(top, #FFFFFF, #E7E7E7)'; + } + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Enables automatic sizing for vertices after editing and + // panning by using the left mouse button. + graph.setCellsMovable(false); + graph.setAutoSizeCells(true); + graph.setPanning(true); + graph.centerZoom = false; + graph.panningHandler.useLeftButtonForPanning = true; + + // Displays a popupmenu when the user clicks + // on a cell (using the left mouse button) but + // do not select the cell when the popup menu + // is displayed + graph.panningHandler.popupMenuHandler = false; + + // Creates the outline (navigator, overview) for moving + // around the graph in the top, right corner of the window. + const outln = new mxOutline(graph, outline); + + // Disables tooltips on touch devices + graph.setTooltips(!mxClient.IS_TOUCH); + + // Set some stylesheet options for the visual appearance of vertices + let style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_SHAPE] = 'label'; + + style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; + style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT; + style[mxConstants.STYLE_SPACING_LEFT] = 54; + + style[mxConstants.STYLE_GRADIENTCOLOR] = '#7d85df'; + style[mxConstants.STYLE_STROKECOLOR] = '#5d65df'; + style[mxConstants.STYLE_FILLCOLOR] = '#adc5ff'; + + style[mxConstants.STYLE_FONTCOLOR] = '#1d258f'; + style[mxConstants.STYLE_FONTFAMILY] = 'Verdana'; + style[mxConstants.STYLE_FONTSIZE] = '12'; + style[mxConstants.STYLE_FONTSTYLE] = '1'; + + style[mxConstants.STYLE_SHADOW] = '1'; + style[mxConstants.STYLE_ROUNDED] = '1'; + style[mxConstants.STYLE_GLASS] = '1'; + + style[mxConstants.STYLE_IMAGE] = '/images/dude3.png'; + style[mxConstants.STYLE_IMAGE_WIDTH] = '48'; + style[mxConstants.STYLE_IMAGE_HEIGHT] = '48'; + style[mxConstants.STYLE_SPACING] = 8; + + // Sets the default style for edges + style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_STROKEWIDTH] = 3; + style[mxConstants.STYLE_EXIT_X] = 0.5; // center + style[mxConstants.STYLE_EXIT_Y] = 1.0; // bottom + style[mxConstants.STYLE_EXIT_PERIMETER] = 0; // disabled + style[mxConstants.STYLE_ENTRY_X] = 0.5; // center + style[mxConstants.STYLE_ENTRY_Y] = 0; // top + style[mxConstants.STYLE_ENTRY_PERIMETER] = 0; // disabled + + // Disable the following for straight lines + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.TopToBottom; + + // Stops editing on enter or escape keypress + const keyHandler = new mxKeyHandler(graph); + + // Enables automatic layout on the graph and installs + // a tree layout for all groups who's children are + // being changed, added or removed. + const layout = new mxCompactTreeLayout(graph, false); + layout.useBoundingBox = false; + layout.edgeRouting = false; + layout.levelDistance = 60; + layout.nodeDistance = 16; + + // Allows the layout to move cells even though cells + // aren't movable in the graph + layout.isVertexMovable = function(cell) { + return true; + }; + + const layoutMgr = new mxLayoutManager(graph); + + layoutMgr.getLayout = function(cell) { + if (cell.getChildCount() > 0) { + return layout; + } + }; + + // Installs a popupmenu handler using local function (see below). + graph.popupMenuHandler.factoryMethod = function(menu, cell, evt) { + return createPopupMenu(graph, menu, cell, evt); + }; + + // Fix for wrong preferred size + const oldGetPreferredSizeForCell = graph.getPreferredSizeForCell; + graph.getPreferredSizeForCell = function(cell) { + const result = oldGetPreferredSizeForCell.apply(this, arguments); + + if (result != null) { + result.width = Math.max(120, result.width - 40); + } + + return result; + }; + + // Sets the maximum text scale to 1 + graph.cellRenderer.getTextScale = function(state) { + return Math.min(1, state.view.scale); + }; + + // Dynamically adds text to the label as we zoom in + // (without affecting the preferred size for new cells) + graph.cellRenderer.getLabelValue = function(state) { + let result = state.cell.value; + + if (state.cell.isVertex()) { + if (state.view.scale > 1) { + result += '\nDetails 1'; + } + + if (state.view.scale > 1.3) { + result += '\nDetails 2'; + } + } + + return result; + }; + + // 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 the root vertex of the tree + graph.getModel().beginUpdate(); + try { + const w = graph.container.offsetWidth; + const v1 = graph.insertVertex( + parent, + 'treeRoot', + 'Organization', + w / 2 - 30, + 20, + 140, + 60, + 'image=/images/house.png' + ); + graph.updateCellSize(v1); + addOverlays(graph, v1, false); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + const content = document.createElement('div'); + content.style.padding = '4px'; + div.appendChild(content); + const tb = new mxToolbar(content); + + tb.addItem('Zoom In', 'images/zoom_in32.png', function(evt) { + graph.zoomIn(); + }); + + tb.addItem('Zoom Out', 'images/zoom_out32.png', function(evt) { + graph.zoomOut(); + }); + + tb.addItem('Actual Size', 'images/view_1_132.png', function(evt) { + graph.zoomActual(); + }); + + tb.addItem('Print', 'images/print32.png', function(evt) { + const preview = new mxPrintPreview(graph, 1); + preview.open(); + }); + + tb.addItem('Poster Print', 'images/press32.png', function(evt) { + const pageCount = mxUtils.prompt('Enter maximum page count', '1'); + + if (pageCount != null) { + const scale = mxUtils.getScaleForPageCount(pageCount, graph); + const preview = new mxPrintPreview(graph, scale); + preview.open(); + } + }); + + // Function to create the entries in the popupmenu + function createPopupMenu(graph, menu, cell, evt) { + const model = graph.getModel(); + + if (cell != null) { + if (cell.isVertex()) { + menu.addItem( + 'Add child', + '/images/overlays/check.png', + function() { + addChild(graph, cell); + } + ); + } + + menu.addItem('Edit label', '/images/text.gif', function() { + graph.startEditingAtCell(cell); + }); + + if (cell.id != 'treeRoot' && cell.isVertex()) { + menu.addItem('Delete', '/images/delete.gif', function() { + deleteSubtree(graph, cell); + }); + } + + menu.addSeparator(); + } + + menu.addItem('Fit', '/images/zoom.gif', function() { + graph.fit(); + }); + + menu.addItem('Actual', '/images/zoomactual.gif', function() { + graph.zoomActual(); + }); + + menu.addSeparator(); + + menu.addItem('Print', '/images/print.gif', function() { + const preview = new mxPrintPreview(graph, 1); + preview.open(); + }); + + menu.addItem('Poster Print', '/images/print.gif', function() { + const pageCount = mxUtils.prompt('Enter maximum page count', '1'); + + if (pageCount != null) { + const scale = mxUtils.getScaleForPageCount(pageCount, graph); + const preview = new mxPrintPreview(graph, scale); + preview.open(); + } + }); + } + + function addOverlays(graph, cell, addDeleteIcon) { + let overlay = new mxCellOverlay( + new mxImage('images/add.png', 24, 24), + 'Add child' + ); + overlay.cursor = 'hand'; + overlay.align = mxConstants.ALIGN_CENTER; + overlay.addListener( + mxEvent.CLICK, + mxUtils.bind(this, function(sender, evt) { + addChild(graph, cell); + }) + ); + + graph.addCellOverlay(cell, overlay); + + if (addDeleteIcon) { + overlay = new mxCellOverlay( + new mxImage('images/close.png', 30, 30), + 'Delete' + ); + overlay.cursor = 'hand'; + overlay.offset = new mxPoint(-4, 8); + overlay.align = mxConstants.ALIGN_RIGHT; + overlay.verticalAlign = mxConstants.ALIGN_TOP; + overlay.addListener( + mxEvent.CLICK, + mxUtils.bind(this, function(sender, evt) { + deleteSubtree(graph, cell); + }) + ); + + graph.addCellOverlay(cell, overlay); + } + } + + function addChild(graph, cell) { + const model = graph.getModel(); + const parent = graph.getDefaultParent(); + let vertex; + + model.beginUpdate(); + try { + vertex = graph.insertVertex(parent, null, 'Double click to set name'); + const geometry = vertex.getGeometry(); + + // Updates the geometry of the vertex with the + // preferred size computed in the graph + const size = graph.getPreferredSizeForCell(vertex); + geometry.width = size.width; + geometry.height = size.height; + + // Adds the edge between the existing cell + // and the new vertex and executes the + // automatic layout on the parent + const edge = graph.insertEdge(parent, null, '', cell, vertex); + + // Configures the edge label "in-place" to reside + // at the end of the edge (x = 1) and with an offset + // of 20 pixels in negative, vertical direction. + edge.geometry.x = 1; + edge.geometry.y = 0; + edge.geometry.offset = new mxPoint(0, -20); + + addOverlays(graph, vertex, true); + } finally { + model.endUpdate(); + } + + return vertex; + } + + function deleteSubtree(graph, cell) { + // Gets the subtree from cell downwards + const cells = []; + graph.traverse(cell, true, function(vertex) { + cells.push(vertex); + + return true; + }); + + graph.removeCells(cells); + } + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Orthogonal.stories.js b/packages/html/stories/Orthogonal.stories.js new file mode 100644 index 000000000..7b4712c3d --- /dev/null +++ b/packages/html/stories/Orthogonal.stories.js @@ -0,0 +1,177 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Connections/Orthogonal', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxConnectionHandler, + mxGraphHandler, + mxGuide, + mxPoint, + mxCellState, + mxEdgeHandler, + mxGraphView + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Enables guides + mxGraphHandler.prototype.guidesEnabled = true; + + // Alt disables guides + mxGuide.prototype.isEnabledForEvent = function(evt) { + return !mxEvent.isAltDown(evt); + }; + + // Enables snapping waypoints to terminals + mxEdgeHandler.prototype.snapToTerminals = true; + + // Enables orthogonal connect preview in IE + mxConnectionHandler.prototype.movePreviewAway = false; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.disconnectOnMove = false; + graph.foldingEnabled = false; + graph.cellsResizable = false; + graph.extendParents = false; + graph.setConnectable(true); + + // Implements perimeter-less connection points as fixed points (computed before the edge style). + graph.view.updateFixedTerminalPoint = function( + edge, + terminal, + source, + constraint + ) { + mxGraphView.prototype.updateFixedTerminalPoint.apply(this, arguments); + + const pts = edge.absolutePoints; + const pt = pts[source ? 0 : pts.length - 1]; + + if ( + terminal != null && + pt == null && + this.getPerimeterFunction(terminal) == null + ) { + edge.setAbsoluteTerminalPoint( + new mxPoint( + this.getRoutingCenterX(terminal), + this.getRoutingCenterY(terminal) + ), + source + ); + } + }; + + // Changes the default edge style + graph.getStylesheet().getDefaultEdgeStyle().edgeStyle = + 'orthogonalEdgeStyle'; + delete graph.getStylesheet().getDefaultEdgeStyle().endArrow; + + // Implements the connect preview + graph.connectionHandler.createEdgeState = function(me) { + const edge = graph.createEdge(null, null, null, null, null); + + return new mxCellState( + this.graph.view, + edge, + this.graph.getCellStyle(edge) + ); + }; + + // Uncomment the following if you want the container + // to fit the size of the graph + // graph.setResizeContainer(true); + + // Enables rubberband selection + if (args.rubberBand) + 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, '', 40, 40, 40, 30); + v1.setConnectable(false); + const v11 = graph.insertVertex( + v1, + null, + '', + 0.5, + 0, + 10, + 40, + 'portConstraint=northsouth;', + true + ); + v11.geometry.offset = new mxPoint(-5, -5); + const v12 = graph.insertVertex( + v1, + null, + '', + 0, + 0.5, + 10, + 10, + 'portConstraint=west;shape=triangle;direction=west;perimeter=none;' + + 'routingCenterX=-0.5;routingCenterY=0;', + true + ); + v12.geometry.offset = new mxPoint(-10, -5); + const v13 = graph.insertVertex( + v1, + null, + '', + 1, + 0.5, + 10, + 10, + 'portConstraint=east;shape=triangle;direction=east;perimeter=none;' + + 'routingCenterX=0.5;routingCenterY=0;', + true + ); + v13.geometry.offset = new mxPoint(0, -5); + + const v2 = graph.addCell(graph.getModel().cloneCell(v1)); + v2.geometry.x = 200; + v2.geometry.y = 60; + + const v3 = graph.addCell(graph.getModel().cloneCell(v1)); + v3.geometry.x = 40; + v3.geometry.y = 150; + + const v4 = graph.addCell(graph.getModel().cloneCell(v1)); + v4.geometry.x = 200; + v4.geometry.y = 170; + + graph.insertEdge(parent, null, '', v1.getChildAt(2), v2.getChildAt(1)); + graph.insertEdge(parent, null, '', v2.getChildAt(2), v3.getChildAt(1)); + graph.insertEdge(parent, null, '', v3.getChildAt(2), v4.getChildAt(1)); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Overlays.stories.js b/packages/html/stories/Overlays.stories.js new file mode 100644 index 000000000..093a6102b --- /dev/null +++ b/packages/html/stories/Overlays.stories.js @@ -0,0 +1,107 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Effects/Overlays', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxDomHelpers, + mxCellOverlay, + mxEvent, + mxCellTracker, + mxUtils, + mxImage + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Disables basic selection and cell handling + graph.setEnabled(false); + + // Highlights the vertices when the mouse enters + const highlight = new mxCellTracker(graph, '#00FF00'); + + // Enables tooltips for the overlays + graph.setTooltips(true); + + // Installs a handler for click events in the graph + // that toggles the overlay for the respective cell + graph.addListener(mxEvent.CLICK, (sender, evt) => { + const cell = evt.getProperty('cell'); + + if (cell != null) { + const overlays = graph.getCellOverlays(cell); + + if (overlays == null) { + // Creates a new overlay with an image and a tooltip + const overlay = new mxCellOverlay( + new mxImage('/images/check.png', 16, 16), + 'Overlay tooltip' + ); + + // Installs a handler for clicks on the overlay + overlay.addListener(mxEvent.CLICK, (sender, evt2) => { + mxUtils.alert('Overlay clicked'); + }); + + // Sets the overlay for the cell in the graph + graph.addCellOverlay(cell, overlay); + } else { + graph.removeCellOverlays(cell); + } + } + }); + + // Installs a handler for double click events in the graph + // that shows an alert box + graph.addListener(mxEvent.DOUBLE_CLICK, (sender, evt) => { + const cell = evt.getProperty('cell'); + alert(`Doubleclick: ${cell != null ? 'Cell' : 'Graph'}`); + evt.consume(); + }); + + // 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: '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, + }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/PageBreaks.stories.js b/packages/html/stories/PageBreaks.stories.js new file mode 100644 index 000000000..23d0081f5 --- /dev/null +++ b/packages/html/stories/PageBreaks.stories.js @@ -0,0 +1,182 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Printing/PageBreaks', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxDomHelpers, + mxEvent + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.view.setScale(0.15); + graph.pageBreaksVisible = true; + graph.pageBreakDashed = true; + graph.preferPageSize = true; + graph.centerZoom = false; + graph.setPanning(true); + + // Account for the header and footer size in the page format + const headerSize = 100; + const footerSize = 100; + + // Removes header and footer from page height + graph.pageFormat.height -= headerSize + footerSize; + + // Takes zoom into account for moving cells + graph.graphHandler.scaleGrid = true; + + // Enables rubberband selection + if (args.rubberBand) + 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,', 10, 10, 280, 330); + const v2 = graph.insertVertex( + parent, + null, + 'World!', + graph.pageFormat.width * graph.pageScale - 280 - 10, + graph.pageFormat.height * graph.pageScale - 330 - 10, + 280, + 330 + ); + const e1 = graph.insertEdge(parent, null, '', v1, v2); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + buttons.appendChild( + mxDomHelpers.button('Toggle Page Breaks', function(evt) { + graph.pageBreaksVisible = !graph.pageBreaksVisible; + graph.sizeDidChange(); + }) + ); + + buttons.appendChild( + mxDomHelpers.button('Zoom In', function(evt) { + graph.zoomIn(); + }) + ); + + buttons.appendChild( + mxDomHelpers.button('Zoom Out', function(evt) { + graph.zoomOut(); + }) + ); + + buttons.appendChild( + mxDomHelpers.button('Print', function(evt) { + // Matches actual printer paper size and avoids blank pages + const scale = 0.5; + + // Applies scale to page + const pf = mxRectangle.fromRectangle( + graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT + ); + pf.width = Math.round(pf.width * scale * graph.pageScale); + pf.height = Math.round(pf.height * scale * graph.pageScale); + + // Finds top left corner of top left page + const bounds = mxRectangle.fromRectangle(graph.getGraphBounds()); + bounds.x -= graph.view.translate.x * graph.view.scale; + bounds.y -= graph.view.translate.y * graph.view.scale; + + const x0 = Math.floor(bounds.x / pf.width) * pf.width; + const y0 = Math.floor(bounds.y / pf.height) * pf.height; + + const preview = new mxPrintPreview(graph, scale, pf, 0, -x0, -y0); + preview.marginTop = headerSize * scale * graph.pageScale; + preview.marginBottom = footerSize * scale * graph.pageScale; + preview.autoOrigin = false; + + const oldRenderPage = preview.renderPage; + preview.renderPage = function(w, h, x, y, content, pageNumber) { + const div = oldRenderPage.apply(this, arguments); + + const header = document.createElement('div'); + header.style.position = 'absolute'; + header.style.boxSizing = 'border-box'; + header.style.fontFamily = 'Arial,Helvetica'; + header.style.height = `${this.marginTop - 10}px`; + header.style.textAlign = 'center'; + header.style.verticalAlign = 'middle'; + header.style.marginTop = 'auto'; + header.style.fontSize = '12px'; + header.style.width = '100%'; + + // Vertical centering for text in header/footer + header.style.lineHeight = `${this.marginTop - 10}px`; + + const footer = header.cloneNode(true); + + mxUtils.write(header, `Page ${pageNumber} - Header`); + header.style.borderBottom = '1px solid gray'; + header.style.top = '0px'; + + mxUtils.write(footer, `Page ${pageNumber} - Footer`); + footer.style.borderTop = '1px solid gray'; + footer.style.bottom = '0px'; + + div.firstChild.appendChild(footer); + div.firstChild.appendChild(header); + + return div; + }; + + preview.open(); + }) + ); + + buttons.appendChild( + mxDomHelpers.button('Reset View', function(evt) { + graph.view.scaleAndTranslate(0.15, 0, 0); + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Perimeter.stories.js b/packages/html/stories/Perimeter.stories.js new file mode 100644 index 000000000..01806ac03 --- /dev/null +++ b/packages/html/stories/Perimeter.stories.js @@ -0,0 +1,121 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Labels/Perimeter', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxGraphView, + mxUtils + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Redirects the perimeter to the label bounds if intersection + // between edge and label is found + const mxGraphViewGetPerimeterPoint = + mxGraphView.prototype.getPerimeterPoint; + mxGraphView.prototype.getPerimeterPoint = function( + terminal, + next, + orthogonal, + border + ) { + let point = mxGraphViewGetPerimeterPoint.apply(this, arguments); + + if (point != null) { + const perimeter = this.getPerimeterFunction(terminal); + + if (terminal.text != null && terminal.text.boundingBox != null) { + // Adds a small border to the label bounds + const b = terminal.text.boundingBox.clone(); + b.grow(3); + + if (mxUtils.rectangleIntersectsSegment(b, point, next)) { + point = perimeter(b, terminal, next, orthogonal); + } + } + } + + return point; + }; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setVertexLabelsMovable(true); + graph.setConnectable(true); + + // Uncomment the following if you want the container + // to fit the size of the graph + // graph.setResizeContainer(true); + + // Enables rubberband selection + if (args.rubberBand) + 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, + 'Label', + 20, + 20, + 80, + 30, + 'verticalLabelPosition=bottom' + ); + const v2 = graph.insertVertex( + parent, + null, + 'Label', + 200, + 20, + 80, + 30, + 'verticalLabelPosition=bottom' + ); + const v3 = graph.insertVertex( + parent, + null, + 'Label', + 20, + 150, + 80, + 30, + 'verticalLabelPosition=bottom' + ); + var e1 = graph.insertEdge(parent, null, '', v1, v2); + var e1 = graph.insertEdge(parent, null, '', v1, v3); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Permissions.stories.js b/packages/html/stories/Permissions.stories.js new file mode 100644 index 000000000..5468571aa --- /dev/null +++ b/packages/html/stories/Permissions.stories.js @@ -0,0 +1,232 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Misc/Permissions', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxConnectionHandler, + mxImage, + mxRubberband, + mxKeyHandler, + mxDomHelpers + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Defines an icon for creating new connections in the connection handler. + // This will automatically disable the highlighting of the source vertex. + mxConnectionHandler.prototype.connectImage = new mxImage( + 'images/connector.gif', + 16, + 16 + ); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Enable tooltips, disables mutligraphs, enable loops + graph.setMultigraph(false); + graph.setAllowLoops(true); + + // Enables rubberband selection and key handling + if (args.rubberBand) + new mxRubberband(graph); + + const keyHandler = new mxKeyHandler(graph); + + // Assigns the delete key + keyHandler.bindKey(46, function(evt) { + if (graph.isEnabled()) { + graph.removeCells(); + } + }); + + // Shared variable between child function scopes + // aka "private" variable + let currentPermission = null; + + const apply = function(permission) { + graph.clearSelection(); + permission.apply(graph); + graph.setEnabled(true); + graph.setTooltips(true); + + // Updates the icons on the shapes - rarely + // needed and very slow for large graphs + graph.refresh(); + currentPermission = permission; + }; + + apply(new Permission()); + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + let button = mxDomHelpers.button('Allow All', function(evt) { + apply(new Permission()); + }); + buttons.appendChild(button); + + button = mxDomHelpers.button('Connect Only', function(evt) { + apply(new Permission(false, true, false, false, true)); + }); + buttons.appendChild(button); + + button = mxDomHelpers.button('Edges Only', function(evt) { + apply(new Permission(false, false, true, false, false)); + }); + buttons.appendChild(button); + + button = mxDomHelpers.button('Vertices Only', function(evt) { + apply(new Permission(false, false, false, true, false)); + }); + buttons.appendChild(button); + + button = mxDomHelpers.button('Select Only', function(evt) { + apply(new Permission(false, false, false, false, false)); + }); + buttons.appendChild(button); + + button = mxDomHelpers.button('Locked', function(evt) { + apply(new Permission(true, false)); + }); + buttons.appendChild(button); + + button = mxDomHelpers.button('Disabled', function(evt) { + graph.clearSelection(); + graph.setEnabled(false); + graph.setTooltips(false); + }); + buttons.appendChild(button); + + // Extends hook functions to use permission object. This could + // be done by assigning the respective switches (eg. + // setMovable), but this approach is more flexible, doesn't + // override any existing behaviour or settings, and allows for + // dynamic conditions to be used in the functions. See the + // specification for more functions to extend (eg. + // isSelectable). + const oldDisconnectable = graph.isCellDisconnectable; + graph.isCellDisconnectable = function(cell, terminal, source) { + return ( + oldDisconnectable.apply(this, arguments) && currentPermission.editEdges + ); + }; + + const oldTerminalPointMovable = graph.isTerminalPointMovable; + graph.isTerminalPointMovable = function(cell) { + return ( + oldTerminalPointMovable.apply(this, arguments) && + currentPermission.editEdges + ); + }; + + const oldBendable = graph.isCellBendable; + graph.isCellBendable = function(cell) { + return oldBendable.apply(this, arguments) && currentPermission.editEdges; + }; + + const oldLabelMovable = graph.isLabelMovable; + graph.isLabelMovable = function(cell) { + return ( + oldLabelMovable.apply(this, arguments) && currentPermission.editEdges + ); + }; + + const oldMovable = graph.isCellMovable; + graph.isCellMovable = function(cell) { + return ( + oldMovable.apply(this, arguments) && currentPermission.editVertices + ); + }; + + const oldResizable = graph.isCellResizable; + graph.isCellResizable = function(cell) { + return ( + oldResizable.apply(this, arguments) && currentPermission.editVertices + ); + }; + + const oldEditable = graph.isCellEditable; + graph.isCellEditable = function(cell) { + return ( + (oldEditable.apply(this, arguments) && + cell.isVertex() && + currentPermission.editVertices) || + (cell.isEdge() && currentPermission.editEdges) + ); + }; + + const oldDeletable = graph.isCellDeletable; + graph.isCellDeletable = function(cell) { + return ( + (oldDeletable.apply(this, arguments) && + cell.isVertex() && + currentPermission.editVertices) || + (cell.isEdge() && currentPermission.editEdges) + ); + }; + + const oldCloneable = graph.isCellCloneable; + graph.isCellCloneable = function(cell) { + return ( + oldCloneable.apply(this, arguments) && currentPermission.cloneCells + ); + }; + + // 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, 'Hello,', 200, 20, 80, 30); + const v3 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); + const e1 = graph.insertEdge(parent, null, 'Connection', v1, v3); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return div; +} + +class Permission { + constructor(locked, createEdges, editEdges, editVertices, cloneCells) { + this.locked = locked != null ? locked : false; + this.createEdges = createEdges != null ? createEdges : true; + this.editEdges = editEdges != null ? editEdges : true; + this.editVertices = editVertices != null ? editVertices : true; + this.cloneCells = cloneCells != null ? cloneCells : true; + } + + apply(graph) { + graph.setConnectable(this.createEdges); + graph.setCellsLocked(this.locked); + } +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/PortRefs.stories.js b/packages/html/stories/PortRefs.stories.js new file mode 100644 index 000000000..1c35ab909 --- /dev/null +++ b/packages/html/stories/PortRefs.stories.js @@ -0,0 +1,282 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Connections/PortRefs', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxPoint, + mxEdgeHandler, + mxConstraintHandler, + mxImage, + mxShape, + mxTriangle, + mxConstants, + mxConnectionConstraint, + mxClient + } = mxgraph; + + mxClient.setImageBasePath('/images'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Replaces the port image + mxConstraintHandler.prototype.pointImage = new mxImage( + '/images/dot.gif', + 10, + 10 + ); + + const graph = new mxGraph(container); + graph.setConnectable(true); + + // Disables automatic handling of ports. This disables the reset of the + // respective style in mxGraph.cellConnected. Note that this feature may + // be useful if floating and fixed connections are combined. + graph.setPortsEnabled(false); + + // 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(); + + // Ports are equal for all shapes... + const ports = new Array(); + + // NOTE: Constraint is used later for orthogonal edge routing (currently ignored) + ports.w = { x: 0, y: 0.5, perimeter: true, constraint: 'west' }; + ports.e = { x: 1, y: 0.5, perimeter: true, constraint: 'east' }; + ports.n = { x: 0.5, y: 0, perimeter: true, constraint: 'north' }; + ports.s = { x: 0.5, y: 1, perimeter: true, constraint: 'south' }; + ports.nw = { x: 0, y: 0, perimeter: true, constraint: 'north west' }; + ports.ne = { x: 1, y: 0, perimeter: true, constraint: 'north east' }; + ports.sw = { x: 0, y: 1, perimeter: true, constraint: 'south west' }; + ports.se = { x: 1, y: 1, perimeter: true, constraint: 'south east' }; + + // ... except for triangles + const ports2 = new Array(); + + // NOTE: Constraint is used later for orthogonal edge routing (currently ignored) + ports2.in1 = { x: 0, y: 0, perimeter: true, constraint: 'west' }; + ports2.in2 = { x: 0, y: 0.25, perimeter: true, constraint: 'west' }; + ports2.in3 = { x: 0, y: 0.5, perimeter: true, constraint: 'west' }; + ports2.in4 = { x: 0, y: 0.75, perimeter: true, constraint: 'west' }; + ports2.in5 = { x: 0, y: 1, perimeter: true, constraint: 'west' }; + + ports2.out1 = { + x: 0.5, + y: 0, + perimeter: true, + constraint: 'north east', + }; + ports2.out2 = { x: 1, y: 0.5, perimeter: true, constraint: 'east' }; + ports2.out3 = { + x: 0.5, + y: 1, + perimeter: true, + constraint: 'south east', + }; + + // Extends shapes classes to return their ports + mxShape.prototype.getPorts = function() { + return ports; + }; + + mxTriangle.prototype.getPorts = function() { + return ports2; + }; + + // Disables floating connections (only connections via ports allowed) + graph.connectionHandler.isConnectableCell = function(cell) { + return false; + }; + mxEdgeHandler.prototype.isConnectableCell = function(cell) { + return graph.connectionHandler.isConnectableCell(cell); + }; + + // Disables existing port functionality + graph.view.getTerminalPort = function(state, terminal, source) { + return terminal; + }; + + // Returns all possible ports for a given terminal + graph.getAllConnectionConstraints = function(terminal, source) { + if ( + terminal != null && + terminal.shape != null && + terminal.shape.stencil != null + ) { + // for stencils with existing constraints... + if (terminal.shape.stencil != null) { + return terminal.shape.stencil.constraints; + } + } else if (terminal != null && terminal.cell.isVertex()) { + if (terminal.shape != null) { + const ports = terminal.shape.getPorts(); + const cstrs = new Array(); + + for (const id in ports) { + const port = ports[id]; + + const cstr = new mxConnectionConstraint( + new mxPoint(port.x, port.y), + port.perimeter + ); + cstr.id = id; + cstrs.push(cstr); + } + + return cstrs; + } + } + + return null; + }; + + // Sets the port for the given connection + graph.setConnectionConstraint = function( + edge, + terminal, + source, + constraint + ) { + if (constraint != null) { + const key = source + ? mxConstants.STYLE_SOURCE_PORT + : mxConstants.STYLE_TARGET_PORT; + + if (constraint == null || constraint.id == null) { + this.setCellStyles(key, null, [edge]); + } else if (constraint.id != null) { + this.setCellStyles(key, constraint.id, [edge]); + } + } + }; + + // Returns the port for the given connection + graph.getConnectionConstraint = function(edge, terminal, source) { + const key = source + ? mxConstants.STYLE_SOURCE_PORT + : mxConstants.STYLE_TARGET_PORT; + const id = edge.style[key]; + + if (id != null) { + const c = new mxConnectionConstraint(null, null); + c.id = id; + + return c; + } + + return null; + }; + + // Returns the actual point for a port by redirecting the constraint to the port + const graphGetConnectionPoint = graph.getConnectionPoint; + graph.getConnectionPoint = function(vertex, constraint) { + if (constraint.id != null && vertex != null && vertex.shape != null) { + const port = vertex.shape.getPorts()[constraint.id]; + + if (port != null) { + constraint = new mxConnectionConstraint( + new mxPoint(port.x, port.y), + port.perimeter + ); + } + } + + return graphGetConnectionPoint.apply(this, arguments); + }; + + // Adds cells to the model in a single step + graph.getModel().beginUpdate(); + try { + const v1 = graph.insertVertex(parent, null, 'A', 20, 20, 100, 40); + const v2 = graph.insertVertex( + parent, + null, + 'B', + 80, + 100, + 100, + 100, + 'shape=ellipse;perimeter=ellipsePerimeter' + ); + const v3 = graph.insertVertex( + parent, + null, + 'C', + 190, + 30, + 100, + 60, + 'shape=triangle;perimeter=trianglePerimeter;direction=south' + ); + const e1 = graph.insertEdge( + parent, + null, + '', + v1, + v2, + 'sourcePort=s;targetPort=nw' + ); + const e2 = graph.insertEdge( + parent, + null, + '', + v1, + v3, + 'sourcePort=e;targetPort=out3' + ); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + // Comming soon... Integration with orthogonal edge style + // Sets default edge style to use port constraints (needs to be moved up when uncommented) + // graph.getStylesheet().getDefaultEdgeStyle()['edgeStyle'] = 'orthogonalEdgeStyle'; + /* let mxUtilsGetPortConstraints = mxUtils.getPortConstraints; + mxUtils.getPortConstraints = function(terminal, edge, source, defaultValue) + { + let key = (source) ? mxConstants.STYLE_SOURCE_PORT : mxConstants.STYLE_TARGET_PORT; + let id = edge.style[key]; + + let port = terminal.shape.getPorts()[id]; + + // TODO: Add support for rotation, direction + if (port != null) + { + return port.constraint; + } + + return mxUtilsGetPortConstraints.apply(this, arguments); + }; + // Connect preview + graph.connectionHandler.createEdgeState = function(me) + { + let edge = graph.createEdge(null, null, null, null, null); + + return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge)); + }; + */ + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/RadialTreeLayout.stories.js b/packages/html/stories/RadialTreeLayout.stories.js new file mode 100644 index 000000000..eb046e7b1 --- /dev/null +++ b/packages/html/stories/RadialTreeLayout.stories.js @@ -0,0 +1,105 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/RadialTreeLayout', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxConstants, + mxRadialTreeLayout, + mxPerimeter + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Adds rubberband selection + if (args.rubberBand) + new mxRubberband(graph); + + // Changes the default vertex style in-place + let style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_PERIMETER_SPACING] = 6; + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_SHADOW] = true; + + style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_ROUNDED] = true; + + // Creates a layout algorithm to be used + // with the graph + const layout = new mxRadialTreeLayout(graph); + + const parent = graph.getDefaultParent(); + + // Load cells and layouts the graph + graph.getModel().beginUpdate(); + try { + const v1 = graph.insertVertex(parent, null, '1', 500, 500, 80, 30); + const v2 = graph.insertVertex(parent, null, '2.1', 0, 0, 80, 30); + const v3 = graph.insertVertex(parent, null, '2.2', 0, 0, 80, 30); + const v4 = graph.insertVertex(parent, null, '3.1', 0, 0, 80, 30); + const v4_1 = graph.insertVertex(parent, null, '3.2', 0, 0, 80, 30); + const v4_2 = graph.insertVertex(parent, null, '3.3', 0, 0, 80, 30); + const v4_3 = graph.insertVertex(parent, null, '3.6', 0, 0, 80, 30); + const v4_4 = graph.insertVertex(parent, null, '3.7', 0, 0, 80, 30); + const v5 = graph.insertVertex(parent, null, '3.4', 0, 0, 80, 30); + const v6 = graph.insertVertex(parent, null, '2.3', 0, 0, 80, 30); + const v7 = graph.insertVertex(parent, null, '4.1', 0, 0, 80, 30); + const v7_1 = graph.insertVertex(parent, null, '4.2', 0, 0, 80, 30); + const v7_2 = graph.insertVertex(parent, null, '4.3', 0, 0, 80, 30); + const v7_3 = graph.insertVertex(parent, null, '4.4', 0, 0, 80, 30); + const v7_4 = graph.insertVertex(parent, null, '4.5', 0, 0, 80, 30); + const v7_5 = graph.insertVertex(parent, null, '4.6', 0, 0, 80, 30); + const v7_6 = graph.insertVertex(parent, null, '4.7', 0, 0, 80, 30); + + const e1 = graph.insertEdge(parent, null, '', v1, v2); + const e2 = graph.insertEdge(parent, null, '', v1, v3); + const e3 = graph.insertEdge(parent, null, '', v3, v4); + const e3_1 = graph.insertEdge(parent, null, '', v3, v4_1); + const e3_2 = graph.insertEdge(parent, null, '', v3, v4_2); + const e3_3 = graph.insertEdge(parent, null, '', v3, v4_3); + const e3_4 = graph.insertEdge(parent, null, '', v3, v4_4); + const e4 = graph.insertEdge(parent, null, '', v2, v5); + const e5 = graph.insertEdge(parent, null, '', v1, v6); + const e6 = graph.insertEdge(parent, null, '', v4_3, v7); + var e6_1 = graph.insertEdge(parent, null, '', v4_4, v7_4); + var e6_2 = graph.insertEdge(parent, null, '', v4_4, v7_5); + var e6_3 = graph.insertEdge(parent, null, '', v4_4, v7_6); + var e6_1 = graph.insertEdge(parent, null, '', v4_3, v7_1); + var e6_2 = graph.insertEdge(parent, null, '', v4_3, v7_2); + var e6_3 = graph.insertEdge(parent, null, '', v4_3, v7_3); + + // Executes the layout + layout.execute(parent); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/SecondLabel.stories.js b/packages/html/stories/SecondLabel.stories.js new file mode 100644 index 000000000..59d8aa9b6 --- /dev/null +++ b/packages/html/stories/SecondLabel.stories.js @@ -0,0 +1,235 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Labels/SecondLabel', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRectangleShape, + mxDomHelpers, + mxText, + mxPoint, + mxRectangle, + mxConstants + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Simple solution to add additional text to the rectangle shape definition: + (function() { + const mxRectangleShapeIsHtmlAllowed = + mxRectangleShape.prototype.isHtmlAllowed; + mxRectangleShape.prototype.isHtmlAllowed = function() { + return ( + mxRectangleShapeIsHtmlAllowed.apply(this, arguments) && + this.state == null + ); + }; + + const mxRectangleShapePaintForeground = + mxRectangleShape.prototype.paintForeground; + mxRectangleShape.prototype.paintForeground = function(c, x, y, w, h) { + if ( + this.state != null && + this.state.cell.geometry != null && + !this.state.cell.geometry.relative + ) { + c.setFontColor('#a0a0a0'); + c.text(x + 2, y, 0, 0, this.state.cell.id, 'left', 'top'); + } + + mxRectangleShapePaintForeground.apply(this, arguments); + }; + })(); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Disables the folding icon + graph.isCellFoldable = function(cell) { + return false; + }; + + let secondLabelVisible = true; + + // Hook for returning shape number for a given cell + graph.getSecondLabel = function(cell) { + if (!cell.isEdge()) { + // Possible to return any string here + return `The ID of this cell is ${cell.id}`; + } + + return null; + }; + + let relativeChildVerticesVisible = true; + + // Overrides method to hide relative child vertices + // TODO this function is not used + const isVisible = function() { + return ( + !cell.isVertex() || + cell.geometry == null || + !cell.geometry.relative || + cell.geometry.relative == relativeChildVerticesVisible + ); + }; + + // Creates the shape for the shape number and puts it into the draw pane + const { redrawShape } = graph.cellRenderer; + graph.cellRenderer.redrawShape = function(state, force, rendering) { + const result = redrawShape.apply(this, arguments); + + if ( + result && + secondLabelVisible && + state.cell.geometry != null && + !state.cell.geometry.relative + ) { + const secondLabel = graph.getSecondLabel(state.cell); + + if ( + secondLabel != null && + state.shape != null && + state.secondLabel == null + ) { + state.secondLabel = new mxText( + secondLabel, + new mxRectangle(), + mxConstants.ALIGN_LEFT, + mxConstants.ALIGN_BOTTOM + ); + + // Styles the label + state.secondLabel.color = 'black'; + state.secondLabel.family = 'Verdana'; + state.secondLabel.size = 8; + state.secondLabel.fontStyle = mxConstants.FONT_ITALIC; + state.secondLabel.background = 'yellow'; + state.secondLabel.border = 'black'; + state.secondLabel.valign = 'bottom'; + state.secondLabel.dialect = state.shape.dialect; + state.secondLabel.dialect = mxConstants.DIALECT_STRICTHTML; + state.secondLabel.wrap = true; + graph.cellRenderer.initializeLabel(state, state.secondLabel); + } + } + + if (state.secondLabel != null) { + const scale = graph.getView().getScale(); + const bounds = new mxRectangle( + state.x + state.width - 8 * scale, + state.y + 8 * scale, + 35, + 0 + ); + state.secondLabel.state = state; + state.secondLabel.value = graph.getSecondLabel(state.cell); + state.secondLabel.scale = scale; + state.secondLabel.bounds = bounds; + state.secondLabel.redraw(); + } + + return result; + }; + + // Destroys the shape number + const { destroy } = graph.cellRenderer; + graph.cellRenderer.destroy = function(state) { + destroy.apply(this, arguments); + + if (state.secondLabel != null) { + state.secondLabel.destroy(); + state.secondLabel = null; + } + }; + + graph.cellRenderer.getShapesForState = function(state) { + return [state.shape, state.text, state.secondLabel, state.control]; + }; + + // 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,', 30, 40, 80, 30); + // Alternative solution of creating a second label by creating a realtive child vertex + // with size (0, 0). This will not be selectable and only the label colors can be used + // for coloring as the actual shape will have zero size. + const v11 = graph.insertVertex( + v1, + null, + 'World', + 1, + 1, + 0, + 0, + 'align=left;verticalAlign=top;labelBackgroundColor=red;labelBorderColor=black', + true + ); + v11.geometry.offset = new mxPoint(-8, -8); + const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); + // Another alternative solution of creating a second label as a relative child vertex + // but this time with an automatic size so that the cell is actually selectable and + // the background is painted as a shape. + const v21 = graph.insertVertex( + v2, + null, + 'World', + 1, + 1, + 0, + 0, + 'align=left;verticalAlign=top;fillColor=red;rounded=1;spacingLeft=4;spacingRight=4', + true + ); + v21.geometry.offset = new mxPoint(-8, -8); + graph.updateCellSize(v21); + const e1 = graph.insertEdge(parent, null, '', v1, v2); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + // Adds a button to execute the layout + buttons.appendChild( + mxDomHelpers.button('Toggle Child Vertices', function(evt) { + relativeChildVerticesVisible = !relativeChildVerticesVisible; + graph.refresh(); + }) + ); + + // Adds a button to execute the layout + buttons.appendChild( + mxDomHelpers.button('Toggle IDs', function(evt) { + secondLabelVisible = !secondLabelVisible; + graph.refresh(); + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Shape.stories.js b/packages/html/stories/Shape.stories.js new file mode 100644 index 000000000..45ca99e76 --- /dev/null +++ b/packages/html/stories/Shape.stories.js @@ -0,0 +1,128 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Shapes/Shape', + argTypes: { + ...globalTypes, + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxCylinder, + mxConstants, + mxCellRenderer + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + /* + The example shape is a "3D box" that looks like this: + ____ + / /| + /___/ | + | | / + |___|/ + + The code below defines the shape. The BoxShape function + it the constructor which creates a new object instance. + + The next lines use an mxCylinder instance to augment the + prototype of the shape ("inheritance") and reset the + constructor to the topmost function of the c'tor chain. + */ + + class BoxShape extends mxCylinder { + // Defines the extrusion of the box as a "static class variable" + extrude = 10; + + /* + Next, the mxCylinder's redrawPath method is "overridden". + This method has a isForeground argument to separate two + paths, one for the background (which must be closed and + might be filled) and one for the foreground, which is + just a stroke. + + Foreground: / + _____/ + | + | + ____ + Background: / | + / | + | / + |____/ + */ + redrawPath(path, x, y, w, h, isForeground) { + const dy = this.extrude * this.scale; + const dx = this.extrude * this.scale; + + if (isForeground) { + path.moveTo(0, dy); + path.lineTo(w - dx, dy); + path.lineTo(w, 0); + path.moveTo(w - dx, dy); + path.lineTo(w - dx, h); + } else { + path.moveTo(0, dy); + path.lineTo(dx, 0); + path.lineTo(w, 0); + path.lineTo(w, h - dy); + path.lineTo(w - dx, h); + path.lineTo(0, h); + path.lineTo(0, dy); + path.lineTo(dx, 0); + path.close(); + } + } + } + mxCellRenderer.registerShape('box', BoxShape); + + // Creates the graph inside the DOM node. + const graph = new mxGraph(container); + + // Disables basic selection and cell handling + graph.setEnabled(false); + + // Changes the default style for vertices "in-place" + // to use the custom shape. + const style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_SHAPE] = 'box'; + + // Adds a spacing for the label that matches the + // extrusion size + style[mxConstants.STYLE_SPACING_TOP] = BoxShape.prototype.extrude; + style[mxConstants.STYLE_SPACING_RIGHT] = BoxShape.prototype.extrude; + + // Adds a gradient and shadow to improve the user experience + style[mxConstants.STYLE_GRADIENTCOLOR] = '#FFFFFF'; + style[mxConstants.STYLE_SHADOW] = true; + + // 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, 'Custom', 20, 20, 80, 60); + const v2 = graph.insertVertex(parent, null, 'Shape', 200, 150, 80, 60); + const e1 = graph.insertEdge(parent, null, '', v1, v2); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Stencils.stories.js b/packages/html/stories/Stencils.stories.js new file mode 100644 index 000000000..acf4cb810 --- /dev/null +++ b/packages/html/stories/Stencils.stories.js @@ -0,0 +1,390 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Shapes/Stencils', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxConnectionHandler, + mxDomHelpers, + mxEdgeHandler, + mxPoint, + mxCellHighlight, + mxConstants, + mxVertexHandler, + mxShape, + mxCellRenderer, + mxUtils + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Sets the global shadow color + mxConstants.SHADOWCOLOR = '#C0C0C0'; + mxConstants.SHADOW_OPACITY = 0.5; + mxConstants.SHADOW_OFFSET_X = 4; + mxConstants.SHADOW_OFFSET_Y = 4; + mxConstants.HANDLE_FILLCOLOR = '#99ccff'; + mxConstants.HANDLE_STROKECOLOR = '#0088cf'; + mxConstants.VERTEX_SELECTION_COLOR = '#00a8ff'; + + // Enables connections along the outline + mxConnectionHandler.prototype.outlineConnect = true; + mxEdgeHandler.prototype.manageLabelHandle = true; + mxEdgeHandler.prototype.outlineConnect = true; + mxCellHighlight.prototype.keepOnTop = true; + + // Enable rotation handle + mxVertexHandler.prototype.rotationEnabled = true; + + // Uses the shape for resize previews + mxVertexHandler.prototype.createSelectionShape = function(bounds) { + const key = this.state.style[mxConstants.STYLE_SHAPE]; + const stencil = mxStencilRegistry.getStencil(key); + let shape = null; + + if (stencil != null) { + shape = new mxShape(stencil); + shape.apply(this.state); + } else { + shape = new this.state.shape.constructor(); + } + + shape.outline = true; + shape.bounds = bounds; + shape.stroke = mxConstants.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 CustomShape extends mxShape { + paintBackground(c, x, y, w, h) { + c.translate(x, y); + + // Head + c.ellipse(w / 4, 0, w / 2, h / 4); + c.fillAndStroke(); + + c.begin(); + c.moveTo(w / 2, h / 4); + c.lineTo(w / 2, (2 * h) / 3); + + // Arms + c.moveTo(w / 2, h / 3); + c.lineTo(0, h / 3); + c.moveTo(w / 2, h / 3); + c.lineTo(w, h / 3); + + // Legs + c.moveTo(w / 2, (2 * h) / 3); + c.lineTo(0, h); + c.moveTo(w / 2, (2 * h) / 3); + c.lineTo(w, h); + c.end(); + + c.stroke(); + } + } + + // Replaces existing actor shape + mxCellRenderer.registerShape('customShape', CustomShape); + + // Loads the stencils into the registry + const req = mxUtils.load('stencils.xml'); + const root = req.getDocumentElement(); + let shape = root.firstChild; + + while (shape != null) { + if (shape.nodeType === mxConstants.NODETYPE_ELEMENT) { + mxStencilRegistry.addStencil( + shape.getAttribute('name'), + new mxStencil(shape) + ); + } + + shape = shape.nextSibling; + } + + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setConnectable(true); + graph.setTooltips(true); + graph.setPanning(true); + + graph.getTooltipForCell = function(cell) { + if (cell != null) { + return cell.style; + } + + return null; + }; + + // Changes default styles + let style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_EDGE] = 'orthogonalEdgeStyle'; + style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_FILLCOLOR] = '#adc5ff'; + style[mxConstants.STYLE_GRADIENTCOLOR] = '#7d85df'; + style[mxConstants.STYLE_SHADOW] = '1'; + + // Enables rubberband selection + if (args.rubberBand) + 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, + 'A1', + 20, + 20, + 40, + 80, + 'shape=and' + ); + 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 mxPoint(90, 60), new mxPoint(90, 130)]; + const e2 = graph.insertEdge(parent, null, '', v2, v3); + e2.geometry.points = [new mxPoint(90, 260), new mxPoint(90, 170)]; + + const v4 = graph.insertVertex( + parent, + null, + 'A3', + 520, + 20, + 40, + 80, + 'shape=customShape;flipH=1' + ); + const v5 = graph.insertVertex( + parent, + null, + 'A4', + 520, + 220, + 40, + 80, + 'shape=and;flipH=1' + ); + const v6 = graph.insertVertex( + parent, + null, + 'X2', + 340, + 110, + 80, + 80, + 'shape=xor;flipH=1' + ); + const e3 = graph.insertEdge(parent, null, '', v4, v6); + e3.geometry.points = [new mxPoint(490, 60), new mxPoint(130, 130)]; + const e4 = graph.insertEdge(parent, null, '', v5, v6); + e4.geometry.points = [new mxPoint(490, 260), new mxPoint(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 mxPoint(310, 150)]; + const e6 = graph.insertEdge(parent, null, '', v3, v7); + e6.geometry.points = [new mxPoint(270, 150)]; + + const e7 = graph.insertEdge(parent, null, '', v7, v5); + e7.geometry.points = [new mxPoint(290, 370)]; + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + buttons.appendChild( + mxDomHelpers.button('FlipH', function() { + graph.toggleCellStyles(mxConstants.STYLE_FLIPH); + }) + ); + + buttons.appendChild( + mxDomHelpers.button('FlipV', function() { + graph.toggleCellStyles(mxConstants.STYLE_FLIPV); + }) + ); + + buttons.appendChild(document.createTextNode('\u00a0')); + buttons.appendChild(document.createTextNode('\u00a0')); + buttons.appendChild(document.createTextNode('\u00a0')); + buttons.appendChild(document.createTextNode('\u00a0')); + + buttons.appendChild( + mxDomHelpers.button('Rotate', function() { + const cell = graph.getSelectionCell(); + + if (cell != null) { + let geo = graph.getCellGeometry(cell); + + if (geo != null) { + graph.getModel().beginUpdate(); + try { + // Rotates the size and position in the geometry + geo = geo.clone(); + geo.x += geo.width / 2 - geo.height / 2; + geo.y += geo.height / 2 - geo.width / 2; + const tmp = geo.width; + geo.width = geo.height; + geo.height = tmp; + graph.getModel().setGeometry(cell, geo); + + // Reads the current direction and advances by 90 degrees + const state = graph.view.getState(cell); + + if (state != null) { + let dir = + state.style[mxConstants.STYLE_DIRECTION] || + 'east'; /* default */ + + if (dir === 'east') { + dir = 'south'; + } else if (dir === 'south') { + dir = 'west'; + } else if (dir === 'west') { + dir = 'north'; + } else if (dir === 'north') { + dir = 'east'; + } + + graph.setCellStyles(mxConstants.STYLE_DIRECTION, dir, [cell]); + } + } finally { + graph.getModel().endUpdate(); + } + } + } + }) + ); + + buttons.appendChild(document.createTextNode('\u00a0')); + buttons.appendChild(document.createTextNode('\u00a0')); + buttons.appendChild(document.createTextNode('\u00a0')); + buttons.appendChild(document.createTextNode('\u00a0')); + + buttons.appendChild( + mxDomHelpers.button('And', function() { + graph.setCellStyles(mxConstants.STYLE_SHAPE, 'and'); + }) + ); + buttons.appendChild( + mxDomHelpers.button('Or', function() { + graph.setCellStyles(mxConstants.STYLE_SHAPE, 'or'); + }) + ); + buttons.appendChild( + mxDomHelpers.button('Xor', function() { + graph.setCellStyles(mxConstants.STYLE_SHAPE, 'xor'); + }) + ); + + buttons.appendChild(document.createTextNode('\u00a0')); + buttons.appendChild(document.createTextNode('\u00a0')); + buttons.appendChild(document.createTextNode('\u00a0')); + buttons.appendChild(document.createTextNode('\u00a0')); + + buttons.appendChild( + mxDomHelpers.button('Style', function() { + const cell = graph.getSelectionCell(); + + if (cell != null) { + const style = mxUtils.prompt( + 'Style', + cell.getStyle() + ); + + if (style != null) { + graph.getModel().setStyle(cell, style); + } + } + }) + ); + + buttons.appendChild( + mxDomHelpers.button('+', function() { + graph.zoomIn(); + }) + ); + buttons.appendChild( + mxDomHelpers.button('-', function() { + graph.zoomOut(); + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Stylesheet.stories.js b/packages/html/stories/Stylesheet.stories.js new file mode 100644 index 000000000..f56e95b90 --- /dev/null +++ b/packages/html/stories/Stylesheet.stories.js @@ -0,0 +1,156 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Styles/Stylesheet', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxPerimeter, + mxConstants, + mxEdgeStyle + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the DOM node. + const graph = new mxGraph(container); + + // Disables basic selection and cell handling + graph.setEnabled(false); + + // Returns a special label for edges. Note: This does + // a supercall to use the default implementation. + graph.getLabel = function(cell) { + const label = mxGraph.prototype.getLabel.apply(this, arguments); + + if (cell.isEdge()) { + return `Transfer ${label}`; + } + return label; + }; + + // Installs a custom global tooltip + graph.setTooltips(true); + graph.getTooltip = function(state) { + const { cell } = state; + const model = this.getModel(); + + if (modcellel.isEdge()) { + const source = this.getLabel(cell.getTerminal(true)); + const target = this.getLabel(cell.getTerminal(false)); + + return `${source} -> ${target}`; + } + return this.getLabel(cell); + }; + + // Creates the default style for vertices + let style = []; + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; + style[mxConstants.STYLE_STROKECOLOR] = 'gray'; + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_FILLCOLOR] = '#EEEEEE'; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_FONTCOLOR] = '#774400'; + style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; + style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; + style[mxConstants.STYLE_FONTSIZE] = '12'; + style[mxConstants.STYLE_FONTSTYLE] = 1; + graph.getStylesheet().putDefaultVertexStyle(style); + + // Creates the default style for edges + style = []; + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_CONNECTOR; + style[mxConstants.STYLE_STROKECOLOR] = '#6482B9'; + style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; + style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; + style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC; + style[mxConstants.STYLE_FONTSIZE] = '10'; + graph.getStylesheet().putDefaultEdgeStyle(style); + + // 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, + 'Interval 1', + 20, + 20, + 180, + 30 + ); + const v2 = graph.insertVertex( + parent, + null, + 'Interval 2', + 140, + 80, + 280, + 30 + ); + const v3 = graph.insertVertex( + parent, + null, + 'Interval 3', + 200, + 140, + 360, + 30 + ); + const v4 = graph.insertVertex( + parent, + null, + 'Interval 4', + 480, + 200, + 120, + 30 + ); + const v5 = graph.insertVertex( + parent, + null, + 'Interval 5', + 60, + 260, + 400, + 30 + ); + const e1 = graph.insertEdge(parent, null, '1', v1, v2); + e1.getGeometry().points = [{ x: 160, y: 60 }]; + const e2 = graph.insertEdge(parent, null, '2', v1, v5); + e2.getGeometry().points = [{ x: 80, y: 60 }]; + const e3 = graph.insertEdge(parent, null, '3', v2, v3); + e3.getGeometry().points = [{ x: 280, y: 120 }]; + const e4 = graph.insertEdge(parent, null, '4', v3, v4); + e4.getGeometry().points = [{ x: 500, y: 180 }]; + const e5 = graph.insertEdge(parent, null, '5', v3, v5); + e5.getGeometry().points = [{ x: 380, y: 180 }]; + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/SwimLanes.stories.js b/packages/html/stories/SwimLanes.stories.js new file mode 100644 index 000000000..6b3f46d2d --- /dev/null +++ b/packages/html/stories/SwimLanes.stories.js @@ -0,0 +1,570 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/SwimLanes', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxEditor, + mxConnectionHandler, + mxImage, + mxUtils, + mxPerimeter, + mxPoint, + mxConstants, + mxCloneUtils, + mxEdgeStyle, + mxEvent, + mxSwimlaneManager, + mxStackLayout, + mxLayoutManager, + mxGraphModel + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Defines an icon for creating new connections in the connection handler. + // This will automatically disable the highlighting of the source vertex. + mxConnectionHandler.prototype.connectImage = new mxImage( + 'images/connector.gif', + 16, + 16 + ); + + // Creates a wrapper editor around a new graph inside + // the given container using an XML config for the + // keyboard bindings + // const config = mxUtils + // .load('editors/config/keyhandler-commons.xml') + // .getDocumentElement(); + // const editor = new mxEditor(config); + const editor = new mxEditor(null); + editor.setGraphContainer(container); + const { graph } = editor; + const model = graph.getModel(); + + // Auto-resizes the container + graph.border = 80; + graph.getView().translate = new mxPoint(graph.border / 2, graph.border / 2); + graph.setResizeContainer(true); + graph.graphHandler.setRemoveCellsFromParent(false); + + // Changes the default vertex style in-place + let style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE; + style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle'; + style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white'; + style[mxConstants.STYLE_FONTSIZE] = 11; + style[mxConstants.STYLE_STARTSIZE] = 22; + style[mxConstants.STYLE_HORIZONTAL] = false; + style[mxConstants.STYLE_FONTCOLOR] = 'black'; + style[mxConstants.STYLE_STROKECOLOR] = 'black'; + delete style[mxConstants.STYLE_FILLCOLOR]; + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; + style[mxConstants.STYLE_FONTSIZE] = 10; + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_HORIZONTAL] = true; + style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle'; + delete style[mxConstants.STYLE_STARTSIZE]; + style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'none'; + graph.getStylesheet().putCellStyle('process', style); + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; + delete style[mxConstants.STYLE_ROUNDED]; + graph.getStylesheet().putCellStyle('state', style); + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RHOMBUS; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter; + style[mxConstants.STYLE_VERTICAL_ALIGN] = 'top'; + style[mxConstants.STYLE_SPACING_TOP] = 40; + style[mxConstants.STYLE_SPACING_RIGHT] = 64; + graph.getStylesheet().putCellStyle('condition', style); + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_DOUBLE_ELLIPSE; + style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; + style[mxConstants.STYLE_SPACING_TOP] = 28; + style[mxConstants.STYLE_FONTSIZE] = 14; + style[mxConstants.STYLE_FONTSTYLE] = 1; + delete style[mxConstants.STYLE_SPACING_RIGHT]; + graph.getStylesheet().putCellStyle('end', style); + + style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; + style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_BLOCK; + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_FONTCOLOR] = 'black'; + style[mxConstants.STYLE_STROKECOLOR] = 'black'; + + style = mxCloneUtils.clone(style); + style[mxConstants.STYLE_DASHED] = true; + style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_OPEN; + style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_OVAL; + graph.getStylesheet().putCellStyle('crossover', style); + + // Installs double click on middle control point and + // changes style of edges between empty and this value + graph.alternateEdgeStyle = 'elbow=vertical'; + + // Adds automatic layout and various switches if the + // graph is enabled + if (graph.isEnabled()) { + // Allows new connections but no dangling edges + graph.setConnectable(true); + graph.setAllowDanglingEdges(false); + + // End-states are no valid sources + const previousIsValidSource = graph.isValidSource; + + graph.isValidSource = function(cell) { + if (previousIsValidSource.apply(this, arguments)) { + const style = cell.getStyle(); + + return ( + style == null || !(style == 'end' || style.indexOf('end') == 0) + ); + } + + return false; + }; + + // Start-states are no valid targets, we do not + // perform a call to the superclass function because + // this would call isValidSource + // Note: All states are start states in + // the example below, so we use the state + // style below + graph.isValidTarget = function(cell) { + const style = cell.getStyle(); + + return ( + !cell.isEdge() && + !this.isSwimlane(cell) && + (style == null || !(style == 'state' || style.indexOf('state') == 0)) + ); + }; + + // Allows dropping cells into new lanes and + // lanes into new pools, but disallows dropping + // cells on edges to split edges + graph.setDropEnabled(true); + graph.setSplitEnabled(false); + + // Returns true for valid drop operations + graph.isValidDropTarget = function(target, cells, evt) { + if (this.isSplitEnabled() && this.isSplitTarget(target, cells, evt)) { + return true; + } + + const model = this.getModel(); + let lane = false; + let pool = false; + let cell = false; + + // Checks if any lanes or pools are selected + for (let i = 0; i < cells.length; i++) { + const tmp = cells[i].getParent(); + lane = lane || this.isPool(tmp); + pool = pool || this.isPool(cells[i]); + + cell = cell || !(lane || pool); + } + + return ( + !pool && + cell != lane && + ((lane && this.isPool(target)) || + (cell && this.isPool(target.getParent()))) + ); + }; + + // Adds new method for identifying a pool + graph.isPool = function(cell) { + const model = this.getModel(); + const parent = cell.getParent(); + + return parent != null && parent.getParent() == model.getRoot(); + }; + + // Keeps widths on collapse/expand + const foldingHandler = function(sender, evt) { + const cells = evt.getProperty('cells'); + + for (let i = 0; i < cells.length; i++) { + const geo = cells[i].getGeometry(); + + if (geo.alternateBounds != null) { + geo.width = geo.alternateBounds.width; + } + } + }; + + graph.addListener(mxEvent.FOLD_CELLS, foldingHandler); + } + + // Changes swimlane orientation while collapsed + const getStyle = function() { + // TODO super cannot be used here + // let style = super.getStyle(); + let style; + if (this.isCellCollapsed()) { + if (style != null) { + style += ';'; + } else { + style = ''; + } + style += 'horizontal=1;align=left;spacingLeft=14;'; + } + return style; + }; + + // Applies size changes to siblings and parents + new mxSwimlaneManager(graph); + + // Creates a stack depending on the orientation of the swimlane + const layout = new mxStackLayout(graph, false); + + // Makes sure all children fit into the parent swimlane + layout.resizeParent = true; + + // Applies the size to children if parent size changes + layout.fill = true; + + // Only update the size of swimlanes + layout.isVertexIgnored = function(vertex) { + return !graph.isSwimlane(vertex); + }; + + // Keeps the lanes and pools stacked + const layoutMgr = new mxLayoutManager(graph); + + layoutMgr.getLayout = function(cell) { + if ( + !cell.isEdge() && + cell.getChildCount() > 0 && + (cell.getParent() == model.getRoot() || graph.isPool(cell)) + ) { + layout.fill = graph.isPool(cell); + + return layout; + } + + return null; + }; + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + const insertVertex = options => { + const v = graph.insertVertex(options); + v.getStyle = getStyle; + return v; + }; + + const insertEdge = options => { + const e = graph.insertEdge(options); + e.getStyle = getStyle; + return e; + }; + + // Adds cells to the model in a single step + model.batchUpdate(() => { + const pool1 = insertVertex({ + parent, + value: 'Pool 1', + position: [0, 0], + size: [640, 0], + }); + pool1.setConnectable(false); + + const lane1a = insertVertex({ + parent: pool1, + value: 'Lane A', + position: [0, 0], + size: [640, 110], + }); + lane1a.setConnectable(false); + + const lane1b = insertVertex({ + parent: pool1, + value: 'Lane B', + position: [0, 0], + size: [640, 110], + }); + lane1b.setConnectable(false); + + const pool2 = insertVertex({ + parent, + value: 'Pool 2', + position: [0, 0], + size: [640, 0], + }); + pool2.setConnectable(false); + + const lane2a = insertVertex({ + parent: pool2, + value: 'Lane A', + position: [0, 0], + size: [640, 140], + }); + lane2a.setConnectable(false); + + const lane2b = insertVertex({ + parent: pool2, + value: 'Lane B', + position: [0, 0], + size: [640, 110], + }); + lane2b.setConnectable(false); + + const start1 = insertVertex({ + parent: lane1a, + position: [40, 40], + size: [30, 30], + style: 'state', + }); + const end1 = insertVertex({ + parent: lane1a, + value: 'A', + position: [560, 40], + size: [30, 30], + style: 'end', + }); + + const step1 = insertVertex({ + parent: lane1a, + value: 'Contact\nProvider', + position: [90, 30], + size: [80, 50], + style: 'process', + }); + const step11 = insertVertex({ + parent: lane1a, + value: 'Complete\nAppropriate\nRequest', + position: [190, 30], + size: [80, 50], + style: 'process', + }); + const step111 = insertVertex({ + parent: lane1a, + value: 'Receive and\nAcknowledge', + position: [385, 30], + size: [80, 50], + style: 'process', + }); + + const start2 = insertVertex({ + parent: lane2b, + position: [40, 40], + size: [30, 30], + style: 'state', + }); + + const step2 = insertVertex({ + parent: lane2b, + value: 'Receive\nRequest', + position: [90, 30], + size: [80, 50], + style: 'process', + }); + const step22 = insertVertex({ + parent: lane2b, + value: 'Refer to Tap\nSystems\nCoordinator', + position: [190, 30], + size: [80, 50], + style: 'process', + }); + + const step3 = insertVertex({ + parent: lane1b, + value: 'Request 1st-\nGate\nInformation', + position: [190, 30], + size: [80, 50], + style: 'process', + }); + const step33 = insertVertex({ + parent: lane1b, + value: 'Receive 1st-\nGate\nInformation', + position: [290, 30], + size: [80, 50], + style: 'process', + }); + + const step4 = insertVertex({ + parent: lane2a, + value: 'Receive and\nAcknowledge', + position: [290, 20], + size: [80, 50], + style: 'process', + }); + const step44 = insertVertex({ + parent: lane2a, + value: 'Contract\nConstraints?', + position: [400, 20], + size: [50, 50], + style: 'condition', + }); + const step444 = insertVertex({ + parent: lane2a, + value: 'Tap for gas\ndelivery?', + position: [480, 20], + size: [50, 50], + style: 'condition', + }); + + const end2 = insertVertex({ + parent: lane2a, + value: 'B', + position: [560, 30], + size: [30, 30], + style: 'end', + }); + const end3 = insertVertex({ + parent: lane2a, + value: 'C', + position: [560, 84], + size: [30, 30], + style: 'end', + }); + + let e = null; + + insertEdge({ + parent: lane1a, + source: start1, + target: step1, + }); + insertEdge({ + parent: lane1a, + source: step1, + target: step11, + }); + insertEdge({ + parent: lane1a, + source: step11, + target: step111, + }); + + insertEdge({ + parent: lane2b, + source: start2, + target: step2, + }); + insertEdge({ + parent: lane2b, + source: step2, + target: step22, + }); + insertEdge({ + parent, + source: step22, + target: step3, + }); + + insertEdge({ + parent: lane1b, + source: step3, + target: step33, + }); + insertEdge({ + parent: lane2a, + source: step4, + target: step44, + }); + insertEdge({ + parent: lane2a, + value: 'No', + source: step44, + target: step444, + style: 'verticalAlign=bottom', + }); + insertEdge({ + parent, + value: 'Yes', + source: step44, + target: step111, + style: 'verticalAlign=bottom;horizontal=0;labelBackgroundColor=white;', + }); + + insertEdge({ + parent: lane2a, + value: 'Yes', + source: step444, + target: end2, + style: 'verticalAlign=bottom', + }); + e = insertEdge({ + parent: lane2a, + value: 'No', + source: step444, + target: end3, + style: 'verticalAlign=top', + }); + + e.geometry.points = [ + new mxPoint( + step444.geometry.x + step444.geometry.width / 2, + end3.geometry.y + end3.geometry.height / 2 + ), + ]; + + insertEdge({ + parent, + source: step1, + target: step2, + style: 'crossover', + }); + insertEdge({ + parent, + source: step3, + target: step11, + style: 'crossover', + }); + e = insertEdge({ + parent: lane1a, + source: step11, + target: step33, + style: 'crossover', + }); + + e.geometry.points = [ + new mxPoint( + step33.geometry.x + step33.geometry.width / 2 + 20, + step11.geometry.y + (step11.geometry.height * 4) / 5 + ), + ]; + + insertEdge({ + parent, + source: step33, + target: step4, + }); + insertEdge({ + parent: lane1a, + source: step111, + target: end1, + }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Thread.stories.js b/packages/html/stories/Thread.stories.js new file mode 100644 index 000000000..ae12a0478 --- /dev/null +++ b/packages/html/stories/Thread.stories.js @@ -0,0 +1,71 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Misc/Thread', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxClient + } = mxgraph; + + mxClient.setImageBasePath('/images'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Disables basic selection and cell handling + graph.setEnabled(false); + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + let v1; + let v2; + let e1; + + // Adds cells to the model in a single step + graph.getModel().beginUpdate(); + try { + v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30); + v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); + e1 = graph.insertEdge(parent, null, '', v1, v2); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + // Function to switch the overlay every 5 secs + const f = () => { + const overlays = graph.getCellOverlays(v1); + + if (overlays == null) { + graph.removeCellOverlays(v2); + graph.setCellWarning(v1, 'Tooltip'); + } else { + graph.removeCellOverlays(v1); + graph.setCellWarning(v2, 'Tooltip'); + } + }; + + window.setInterval(f, 1000); + f(); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Toolbar.stories.js b/packages/html/stories/Toolbar.stories.js new file mode 100644 index 000000000..6b0bca0d6 --- /dev/null +++ b/packages/html/stories/Toolbar.stories.js @@ -0,0 +1,171 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Toolbars/Toolbar', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxConnectionHandler, + mxImage, + mxToolbar, + mxGraphModel, + mxKeyHandler, + mxCell, + mxGeometry, + mxDragSource, + mxDomHelpers, + mxGestureUtils + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Defines an icon for creating new connections in the connection handler. + // This will automatically disable the highlighting of the source vertex. + mxConnectionHandler.prototype.connectImage = new mxImage( + '/images/connector.gif', + 16, + 16 + ); + + // Creates the div for the toolbar + const tbContainer = document.createElement('div'); + tbContainer.style.position = 'absolute'; + tbContainer.style.overflow = 'hidden'; + tbContainer.style.padding = '2px'; + tbContainer.style.left = '0px'; + tbContainer.style.top = '0px'; + tbContainer.style.width = '24px'; + tbContainer.style.bottom = '0px'; + + div.appendChild(tbContainer); + + // Creates new toolbar without event processing + const toolbar = new mxToolbar(tbContainer); + toolbar.enabled = false; + + // Creates the model and the graph inside the container + // using the fastest rendering available on the browser + const model = new mxGraphModel(); + const graph = new mxGraph(container, model); + graph.dropEnabled = true; + + // Matches DnD inside the graph + mxDragSource.prototype.getDropTarget = function(graph, x, y) { + let cell = graph.getCellAt(x, y); + if (!graph.isValidDropTarget(cell)) { + cell = null; + } + return cell; + }; + + // Enables new connections in the graph + graph.setConnectable(true); + graph.setMultigraph(false); + + // Stops editing on enter or escape keypress + const keyHandler = new mxKeyHandler(graph); + + if (args.rubberBand) + new mxRubberband(graph); + + const addVertex = (icon, w, h, style) => { + const vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style); + vertex.setVertex(true); + + addToolbarItem(graph, toolbar, vertex, icon); + }; + + addVertex( + '/images/swimlane.gif', + 120, + 160, + 'shape=swimlane;startSize=20;' + ); + addVertex('/images/rectangle.gif', 100, 40, ''); + addVertex('/images/rounded.gif', 100, 40, 'shape=rounded'); + addVertex('/images/ellipse.gif', 40, 40, 'shape=ellipse'); + addVertex('/images/rhombus.gif', 40, 40, 'shape=rhombus'); + addVertex('/images/triangle.gif', 40, 40, 'shape=triangle'); + addVertex('/images/cylinder.gif', 40, 40, 'shape=cylinder'); + addVertex('/images/actor.gif', 30, 40, 'shape=actor'); + toolbar.addLine(); + + const button = mxDomHelpers.button( + 'Create toolbar entry from selection', + evt => { + if (!graph.isSelectionEmpty()) { + // Creates a copy of the selection array to preserve its state + const cells = graph.getSelectionCells(); + const bounds = graph.getView().getBounds(cells); + + // Function that is executed when the image is dropped on + // the graph. The cell argument points to the cell under + // the mousepointer if there is one. + const funct = (graph, evt, cell) => { + graph.stopEditing(false); + + const pt = graph.getPointForEvent(evt); + const dx = pt.x - bounds.x; + const dy = pt.y - bounds.y; + + graph.setSelectionCells(graph.importCells(cells, dx, dy, cell)); + }; + + // Creates the image which is used as the drag icon (preview) + const img = toolbar.addMode( + null, + '/images/outline.gif', + funct + ); + mxGestureUtils.makeDraggable(img, graph, funct); + } + } + ); + + tbContainer.appendChild(button); + + function addToolbarItem(graph, toolbar, prototype, image) { + // Function that is executed when the image is dropped on + // the graph. The cell argument points to the cell under + // the mousepointer if there is one. + const funct = (graph, evt, cell) => { + graph.stopEditing(false); + + const pt = graph.getPointForEvent(evt); + const vertex = graph.getModel().cloneCell(prototype); + vertex.geometry.x = pt.x; + vertex.geometry.y = pt.y; + + graph.setSelectionCells(graph.importCells([vertex], 0, 0, cell)); + }; + + // Creates the image which is used as the drag icon (preview) + const img = toolbar.addMode(null, image, funct); + mxGestureUtils.makeDraggable(img, graph, funct); + } + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Tree.stories.js b/packages/html/stories/Tree.stories.js new file mode 100644 index 000000000..31b5fe727 --- /dev/null +++ b/packages/html/stories/Tree.stories.js @@ -0,0 +1,303 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Layouts/Tree', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxConstants, + mxCylinder, + mxCellRenderer, + mxGraphView, + mxImage, + mxClient, + mxEdgeStyle, + mxKeyHandler, + mxCompactTreeLayout, + mxLayoutManager, + mxRectangle, + mxPoint + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + mxClient.setImageBasePath('/images'); + + /* + Defines a custom shape for the tree node that includes the + upper half of the outgoing edge(s). + */ + class TreeNodeShape extends mxCylinder { + // Defines the length of the upper edge segment. + static segment = 20; + + constructor(bounds, fill, stroke, strokewidth) { + super(bounds, fill, stroke, strokewidth); + } + + // Needs access to the cell state for rendering + apply(state) { + super.apply(state); + this.state = state; + } + + redrawPath(path, x, y, w, h, isForeground) { + const { graph } = this.state.view; + const hasChildren = + graph.model.getOutgoingEdges(this.state.cell).length > 0; + + if (isForeground) { + if (hasChildren) { + // Painting outside of vertex bounds is used here + path.moveTo(w / 2, h + this.segment); + path.lineTo(w / 2, h); + path.end(); + } + } else { + path.moveTo(0, 0); + path.lineTo(w, 0); + path.lineTo(w, h); + path.lineTo(0, h); + path.close(); + } + } + } + mxCellRenderer.registerShape('treenode', TreeNodeShape); + + class MyCustomGraphView extends mxGraphView { + updateFloatingTerminalPoint(edge, start, end, source) { + // Defines a custom perimeter for the nodes in the tree + let pt = null; + + if (source) { + pt = new mxPoint( + start.x + start.width / 2, + start.y + start.height + TreeNodeShape.segment + ); + } else { + pt = new mxPoint(start.x + start.width / 2, start.y); + } + + edge.setAbsoluteTerminalPoint(pt, source); + } + } + + class MyCustomCellRenderer extends mxCellRenderer { + getControlBounds(state) { + // Defines the position of the folding icon + if (state.control != null) { + const oldScale = state.control.scale; + const w = state.control.bounds.width / oldScale; + const h = state.control.bounds.height / oldScale; + const s = state.view.scale; + + return new mxRectangle( + state.x + state.width / 2 - (w / 2) * s, + state.y + + state.height + + TreeNodeShape.segment * s - + (h / 2) * s, + w * s, + h * s + ); + } + return null; + } + } + + // Make the layout instance accessible by MyCustomGraph + let layout; + + class MyCustomGraph extends mxGraph { + // Sets the collapse and expand icons. The values below are the default + // values, but this is how to replace them if you need to. + collapsedImage = new mxImage( + `${mxClient.imageBasePath}/collapsed.gif`, + 9, + 9 + ); + + expandedImage = new mxImage( + `${mxClient.imageBasePath}/expanded.gif`, + 9, + 9 + ); + + isCellFoldable(cell) { + // Defines the condition for showing the folding icon + return this.model.getOutgoingEdges(cell).length > 0; + } + + createCellRenderer() { + return new MyCustomCellRenderer(); + } + + createGraphView() { + return new MyCustomGraphView(this); + } + + foldCells(collapse, recurse, cells) { + // Implements the click on a folding icon + this.model.beginUpdate(); + try { + this.toggleSubtree(this, cells[0], !collapse); + this.model.setCollapsed(cells[0], collapse); + + // Executes the layout for the new graph since + // changes to visiblity and collapsed state do + // not trigger a layout in the current manager. + layout.execute(this.getDefaultParent()); + } finally { + this.model.endUpdate(); + } + } + + toggleSubtree(cell, show) { + // Updates the visible state of a given subtree taking into + // account the collapsed state of the traversed branches + show = show != null ? show : true; + const cells = []; + + this.traverse(cell, true, function(vertex) { + if (vertex !== cell) { + cells.push(vertex); + } + + // Stops recursion if a collapsed cell is seen + return vertex === cell || !this.isCellCollapsed(vertex); + }); + + this.toggleCells(show, cells, true); + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + + // Disallow any selections + graph.setCellsSelectable(false); + + // Avoids overlap of edges and collapse icons + graph.keepEdgesInBackground = true; + + // Set some stylesheet options for the visual appearance + let style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_SHAPE] = 'treenode'; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_SHADOW] = true; + + style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.TopToBottom; + style[mxConstants.STYLE_ROUNDED] = true; + + // Enables automatic sizing for vertices after editing and + // panning by using the left mouse button. + graph.setAutoSizeCells(true); + graph.setPanning(true); + graph.panningHandler.useLeftButtonForPanning = true; + + // Stops editing on enter or escape keypress + const keyHandler = new mxKeyHandler(graph); + + // Enables automatic layout on the graph and installs + // a tree layout for all groups who's children are + // being changed, added or removed. + layout = new mxCompactTreeLayout(graph, false); + layout.useBoundingBox = false; + layout.edgeRouting = false; + layout.levelDistance = 30; + layout.nodeDistance = 10; + + const layoutMgr = new mxLayoutManager(graph); + + layoutMgr.getLayout = function(cell) { + if (cell.getChildCount() > 0) { + return layout; + } + }; + + // 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 the root vertex of the tree + graph.getModel().beginUpdate(); + try { + const w = graph.container.offsetWidth; + const root = graph.insertVertex( + parent, + 'treeRoot', + 'Root', + w / 2 - 30, + 20, + 60, + 40 + ); + + const v1 = graph.insertVertex(parent, 'v1', 'Child 1', 0, 0, 60, 40); + graph.insertEdge(parent, null, '', root, v1); + + const v2 = graph.insertVertex(parent, 'v2', 'Child 2', 0, 0, 60, 40); + graph.insertEdge(parent, null, '', root, v2); + + const v3 = graph.insertVertex(parent, 'v3', 'Child 3', 0, 0, 60, 40); + graph.insertEdge(parent, null, '', root, v3); + + const v11 = graph.insertVertex(parent, 'v11', 'Child 1.1', 0, 0, 60, 40); + graph.insertEdge(parent, null, '', v1, v11); + + const v12 = graph.insertVertex(parent, 'v12', 'Child 1.2', 0, 0, 60, 40); + graph.insertEdge(parent, null, '', v1, v12); + + const v21 = graph.insertVertex(parent, 'v21', 'Child 2.1', 0, 0, 60, 40); + graph.insertEdge(parent, null, '', v2, v21); + + const v22 = graph.insertVertex(parent, 'v22', 'Child 2.2', 0, 0, 60, 40); + graph.insertEdge(parent, null, '', v2, v22); + + const v221 = graph.insertVertex( + parent, + 'v221', + 'Child 2.2.1', + 0, + 0, + 60, + 40 + ); + graph.insertEdge(parent, null, '', v22, v221); + + const v222 = graph.insertVertex( + parent, + 'v222', + 'Child 2.2.2', + 0, + 0, + 60, + 40 + ); + graph.insertEdge(parent, null, '', v22, v222); + + const v31 = graph.insertVertex(parent, 'v31', 'Child 3.1', 0, 0, 60, 40); + graph.insertEdge(parent, null, '', v3, v31); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/UserObject.stories.js b/packages/html/stories/UserObject.stories.js new file mode 100644 index 000000000..9a0aadbbc --- /dev/null +++ b/packages/html/stories/UserObject.stories.js @@ -0,0 +1,305 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Xml_Json/UserObject', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRectangle, + mxDomHelpers, + mxKeyHandler, + mxEvent, + mxWindow, + mxXmlUtils, + mxCodec, + mxConstants, + mxUtils, + mxEdgeStyle, + mxDomUtils, + mxForm, + mxCellAttributeChange + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Note that these XML nodes will be enclosing the + // mxCell nodes for the model cells in the output + const doc = mxXmlUtils.createXmlDocument(); + + const person1 = doc.createElement('Person'); + person1.setAttribute('firstName', 'Daffy'); + person1.setAttribute('lastName', 'Duck'); + + const person2 = doc.createElement('Person'); + person2.setAttribute('firstName', 'Bugs'); + person2.setAttribute('lastName', 'Bunny'); + + const relation = doc.createElement('Knows'); + relation.setAttribute('since', '1985'); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Optional disabling of sizing + graph.setCellsResizable(false); + + // Configures the graph contains to resize and + // add a border at the bottom, right + graph.setResizeContainer(true); + graph.minimumContainerSize = new mxRectangle(0, 0, 500, 380); + graph.setBorder(60); + + // Stops editing on enter key, handles escape + new mxKeyHandler(graph); + + // Overrides method to disallow edge label editing + graph.isCellEditable = function(cell) { + return !cell.isEdge(); + }; + + // Overrides method to provide a cell label in the display + graph.convertValueToString = function(cell) { + if (mxDomUtils.isNode(cell.value)) { + if (cell.value.nodeName.toLowerCase() == 'person') { + const firstName = cell.getAttribute('firstName', ''); + const lastName = cell.getAttribute('lastName', ''); + + if (lastName != null && lastName.length > 0) { + return `${lastName}, ${firstName}`; + } + + return firstName; + } + if (cell.value.nodeName.toLowerCase() == 'knows') { + return `${cell.value.nodeName} (Since ${cell.getAttribute( + 'since', + '' + )})`; + } + } + + return ''; + }; + + // Overrides method to store a cell label in the model + const { cellLabelChanged } = graph; + graph.cellLabelChanged = function(cell, newValue, autoSize) { + if ( + mxDomUtils.isNode(cell.value) && + cell.value.nodeName.toLowerCase() == 'person' + ) { + const pos = newValue.indexOf(' '); + + const firstName = pos > 0 ? newValue.substring(0, pos) : newValue; + const lastName = + pos > 0 ? newValue.substring(pos + 1, newValue.length) : ''; + + // Clones the value for correct undo/redo + const elt = cell.value.cloneNode(true); + + elt.setAttribute('firstName', firstName); + elt.setAttribute('lastName', lastName); + + newValue = elt; + autoSize = true; + } + + cellLabelChanged.apply(this, arguments); + }; + + // Overrides method to create the editing value + const { getEditingValue } = graph; + graph.getEditingValue = function(cell) { + if ( + mxDomUtils.isNode(cell.value) && + cell.value.nodeName.toLowerCase() == 'person' + ) { + const firstName = cell.getAttribute('firstName', ''); + const lastName = cell.getAttribute('lastName', ''); + + return `${firstName} ${lastName}`; + } + }; + + // Adds a special tooltip for edges + graph.setTooltips(true); + + const { getTooltipForCell } = graph; + graph.getTooltipForCell = function(cell) { + // Adds some relation details for edges + if (cell.isEdge()) { + const src = this.getLabel(cell.getTerminal(true)); + const trg = this.getLabel(cell.getTerminal(false)); + + return `${src} ${cell.value.nodeName} ${trg}`; + } + + return getTooltipForCell.apply(this, arguments); + }; + + // Enables rubberband selection + if (args.rubberBand) + new mxRubberband(graph); + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + const properties = document.createElement('div'); + div.appendChild(properties); + + // Adds an option to view the XML of the graph + buttons.appendChild( + mxDomHelpers.button('View XML', function() { + const encoder = new mxCodec(); + const node = encoder.encode(graph.getModel()); + mxWindow.popup(mxUtils.getPrettyXml(node), true); + }) + ); + + // Changes the style for match the markup + // Creates the default style for vertices + let style = graph.getStylesheet().getDefaultVertexStyle(); + style[mxConstants.STYLE_STROKECOLOR] = 'gray'; + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_SHADOW] = true; + style[mxConstants.STYLE_FILLCOLOR] = '#DFDFDF'; + style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; + style[mxConstants.STYLE_FONTCOLOR] = 'black'; + style[mxConstants.STYLE_FONTSIZE] = '12'; + style[mxConstants.STYLE_SPACING] = 4; + + // Creates the default style for edges + style = graph.getStylesheet().getDefaultEdgeStyle(); + style[mxConstants.STYLE_STROKECOLOR] = '#0C0C0C'; + style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white'; + style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; + style[mxConstants.STYLE_ROUNDED] = true; + style[mxConstants.STYLE_FONTCOLOR] = 'black'; + style[mxConstants.STYLE_FONTSIZE] = '10'; + + // 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, person1, 40, 40, 80, 30); + const v2 = graph.insertVertex(parent, null, person2, 200, 150, 80, 30); + const e1 = graph.insertEdge(parent, null, relation, v1, v2); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + // Implements a properties panel that uses + // mxCellAttributeChange to change properties + graph + .getSelectionModel() + .addListener(mxEvent.CHANGE, function(sender, evt) { + selectionChanged(graph); + }); + + selectionChanged(graph); + + /** + * Updates the properties panel + */ + function selectionChanged(graph) { + const div = properties; + + // Forces focusout in IE + graph.container.focus(); + + // Clears the DIV the non-DOM way + div.innerHTML = ''; + + // Gets the selection cell + const cell = graph.getSelectionCell(); + + if (cell == null) { + mxDomUtils.writeln(div, 'Nothing selected.'); + } else { + // Writes the title + const center = document.createElement('center'); + mxDomUtils.writeln(center, `${cell.value.nodeName} (${cell.id})`); + div.appendChild(center); + mxDomUtils.br(div); + + // Creates the form from the attributes of the user object + const form = new mxForm(); + + const attrs = cell.value.attributes; + + for (let i = 0; i < attrs.length; i++) { + createTextField(graph, form, cell, attrs[i]); + } + + div.appendChild(form.getTable()); + mxDomUtils.br(div); + } + } + + /** + * Creates the textfield for the given property. + */ + function createTextField(graph, form, cell, attribute) { + const input = form.addText(`${attribute.nodeName}:`, attribute.nodeValue); + + const applyHandler = function() { + const newValue = input.value || ''; + const oldValue = cell.getAttribute(attribute.nodeName, ''); + + if (newValue != oldValue) { + graph.getModel().beginUpdate(); + + try { + const edit = new mxCellAttributeChange( + cell, + attribute.nodeName, + newValue + ); + graph.getModel().execute(edit); + graph.updateCellSize(cell); + } finally { + graph.getModel().endUpdate(); + } + } + }; + + mxEvent.addListener(input, 'keypress', function(evt) { + // Needs to take shift into account for textareas + if (evt.keyCode == /* enter */ 13 && !mxEvent.isShiftDown(evt)) { + input.blur(); + } + }); + + // Note: Known problem is the blurring of fields in + // Firefox by changing the selection, in which case + // no event is fired in FF and the change is lost. + // As a workaround you should use a local variable + // that stores the focused field and invoke blur + // explicitely where we do the graph.focus above. + mxEvent.addListener(input, 'blur', applyHandler); + } + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Validation.stories.js b/packages/html/stories/Validation.stories.js new file mode 100644 index 000000000..041a7c6b1 --- /dev/null +++ b/packages/html/stories/Validation.stories.js @@ -0,0 +1,164 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Misc/Validation', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxXmlUtils, + mxMultiplicity, + mxKeyHandler, + mxEvent + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + const xmlDocument = mxXmlUtils.createXmlDocument(); + const sourceNode = xmlDocument.createElement('Source'); + const targetNode = xmlDocument.createElement('Target'); + const subtargetNode = xmlDocument.createElement('Subtarget'); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + graph.setConnectable(true); + graph.setTooltips(true); + graph.setAllowDanglingEdges(false); + graph.setMultigraph(false); + + // Source nodes needs 1..2 connected Targets + graph.multiplicities.push( + new mxMultiplicity( + true, + 'Source', + null, + null, + 1, + 2, + ['Target'], + 'Source Must Have 1 or 2 Targets', + 'Source Must Connect to Target' + ) + ); + + // Source node does not want any incoming connections + graph.multiplicities.push( + new mxMultiplicity( + false, + 'Source', + null, + null, + 0, + 0, + null, + 'Source Must Have No Incoming Edge', + null + ) + ); // Type does not matter + + // Target needs exactly one incoming connection from Source + graph.multiplicities.push( + new mxMultiplicity( + false, + 'Target', + null, + null, + 1, + 1, + ['Source'], + 'Target Must Have 1 Source', + 'Target Must Connect From Source' + ) + ); + + // Enables rubberband selection + new mxRubberband(graph); + + // Removes cells when [DELETE] is pressed + const keyHandler = new mxKeyHandler(graph); + keyHandler.bindKey(46, function(evt) { + if (graph.isEnabled()) { + graph.removeCells(); + } + }); + + // Installs automatic validation (use editor.validation = true + // if you are using an mxEditor instance) + const listener = function(sender, evt) { + graph.validateGraph(); + }; + + graph.getModel().addListener(mxEvent.CHANGE, listener); + + // 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, sourceNode, 20, 20, 80, 30); + const v2 = graph.insertVertex(parent, null, targetNode, 200, 20, 80, 30); + const v3 = graph.insertVertex({ + parent, + value: targetNode.cloneNode(true), + position: [200, 80], + size: [80, 30], + }); + const v4 = graph.insertVertex( + parent, + null, + targetNode.cloneNode(true), + 200, + 140, + 80, + 30 + ); + const v5 = graph.insertVertex( + parent, + null, + subtargetNode, + 200, + 200, + 80, + 30 + ); + const v6 = graph.insertVertex( + parent, + null, + sourceNode.cloneNode(true), + 20, + 140, + 80, + 30 + ); + const e1 = graph.insertEdge(parent, null, '', v1, v2); + const e2 = graph.insertEdge(parent, null, '', v1, v3); + const e3 = graph.insertEdge(parent, null, '', v6, v4); + // var e4 = graph.insertEdge(parent, null, '', v1, v4); + } finally { + // Updates the display + graph.getModel().endUpdate(); + } + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Visibility.stories.js b/packages/html/stories/Visibility.stories.js new file mode 100644 index 000000000..a91412144 --- /dev/null +++ b/packages/html/stories/Visibility.stories.js @@ -0,0 +1,138 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Misc/Visibility', + argTypes: { + ...globalTypes, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxDomHelpers + } = mxgraph; + + const div = document.createElement('div'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + div.appendChild(container); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Enables rubberband selection + if (args.rubberBand) + 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(); + + let showOne = true; + let showTwo = true; + let showThree = true; + + // Overridden to implement dynamic conditions + const isVisible = function() { + // TODO super cannot be used here + // let result = super.isVisible(); + let result; + if (result && this.value != null) { + result = + (showOne && this.value == '1') || + (showTwo && this.value == '2') || + (showThree && this.value == '3'); + } + return result; + }; + + // Adds cells to the model in a single step + let v1; + graph.batchUpdate(() => { + v1 = graph.insertVertex({ + parent, + value: '1', + position: [20, 20], + size: [80, 30], + }); + v1.isVisible = isVisible; + + const v2 = graph.insertVertex({ + parent, + value: '2', + position: [200, 150], + size: [80, 30], + }); + v2.isVisible = isVisible; + + const e1 = graph.insertEdge({ + parent, + value: '3', + source: v1, + target: v2, + }); + e1.isVisible = isVisible; + }); + + const buttons = document.createElement('div'); + div.appendChild(buttons); + + // Dynamic conditions (requires refresh) + buttons.appendChild( + mxDomHelpers.button('Cond 1', function() { + showOne = !showOne; + graph.refresh(); + }) + ); + buttons.appendChild( + mxDomHelpers.button('Cond 2', function() { + showTwo = !showTwo; + graph.refresh(); + }) + ); + buttons.appendChild( + mxDomHelpers.button('Cond 3', function() { + showThree = !showThree; + graph.refresh(); + }) + ); + + // Explicit show/hide + buttons.appendChild( + mxDomHelpers.button('Toggle cell', function() { + graph.toggleCells(!v1.isVisible(), [v1], true); + }) + ); + + // Explicit remove/add + let removed = null; + + buttons.appendChild( + mxDomHelpers.button('Add/remove cell', function() { + if (removed != null) { + graph.addCells(removed); + removed = null; + } else { + removed = graph.removeCells([v1]); + } + }) + ); + + return div; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Window.stories.js b/packages/html/stories/Window.stories.js new file mode 100644 index 000000000..050b6f826 --- /dev/null +++ b/packages/html/stories/Window.stories.js @@ -0,0 +1,132 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Windows/Windows', + argTypes: { + ...globalTypes, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxWindow, + mxKeyHandler, + mxRubberband, + mxEvent, + mxLog, + mxDomUtils, + mxClient + } = mxgraph; + + mxClient.setImageBasePath('/images'); + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Note that we're using the container scrollbars for the graph so that the + // container extends to the parent div inside the window + let wnd = new mxWindow( + 'Scrollable, resizable, given height', + container, + 50, + 50, + 220, + 224, + true, + true + ); + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Adds rubberband selection and keystrokes + graph.setTooltips(true); + graph.setPanning(true); + + if (args.rubberBand) + new mxRubberband(graph); + + new mxKeyHandler(graph); + + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + // 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(); + } + + wnd.setMaximizable(true); + wnd.setResizable(true); + wnd.setVisible(true); + + const lorem = + 'Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. '; + let content = document.createElement('div'); + mxDomUtils.write(content, lorem + lorem + lorem); + + wnd = new mxWindow( + 'Scrollable, resizable, auto height', + content, + 300, + 50, + 200, + null, + true, + true + ); + wnd.setMaximizable(true); + wnd.setScrollable(true); + wnd.setResizable(true); + wnd.setVisible(true); + + content = content.cloneNode(true); + content.style.width = '400px'; + + wnd = new mxWindow( + 'Scrollable, resizable, fixed content', + content, + 520, + 50, + 220, + 200, + true, + true + ); + wnd.setMaximizable(true); + wnd.setScrollable(true); + wnd.setResizable(true); + wnd.setVisible(true); + + mxLog.show(); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Wrapping.stories.js b/packages/html/stories/Wrapping.stories.js new file mode 100644 index 000000000..a085636e9 --- /dev/null +++ b/packages/html/stories/Wrapping.stories.js @@ -0,0 +1,72 @@ +import mxgraph from '@mxgraph/core'; + +import { globalTypes } from '../.storybook/preview'; + +export default { + title: 'Labels/Wrapping', + argTypes: { + ...globalTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxRubberband, + mxGraphView, + mxUtils + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + // Creates the graph inside the given container + const graph = new mxGraph(container); + + // Enables HTML labels as wrapping is only available for those + graph.setHtmlLabels(true); + + // Disables in-place editing for edges + graph.isCellEditable = function(cell) { + return !cell.isEdge(); + }; + + // 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: 'Cum Caesar vidisset, portum plenum esse, iuxta navigavit.', + position: [20, 20], + size: [100, 70], + style: 'whiteSpace=wrap;', + }); + const v2 = graph.insertVertex({ + parent, + value: 'Cum Caesar vidisset, portum plenum esse, iuxta navigavit.', + position: [220, 150], + size: [80, 70], + style: 'whiteSpace=wrap;', + }); + const e1 = graph.insertEdge({ + parent, + value: 'Cum Caesar vidisset, portum plenum esse, iuxta navigavit.', + source: v1, + target: v2, + style: 'whiteSpace=wrap;', + }); + e1.geometry.width = 100; + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/src/pages/effects/Animation.css b/packages/html/stories/css/animation.css similarity index 100% rename from src/pages/effects/Animation.css rename to packages/html/stories/css/animation.css diff --git a/src/.eslintrc b/src/.eslintrc deleted file mode 100644 index 224b972ed..000000000 --- a/src/.eslintrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "@ijsto", - "rules": { - "newIsCap": 0, - "indent": ["error", 2, {"FunctionDeclaration": {"parameters": "first"}, - "FunctionExpression": {"parameters": "first"}}] - } -} \ No newline at end of file diff --git a/src/README.md b/src/README.md deleted file mode 100644 index b12f3e33e..000000000 --- a/src/README.md +++ /dev/null @@ -1,34 +0,0 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. - -[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. - -The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/src/package-lock.json b/src/package-lock.json deleted file mode 100644 index c9baa9f29..000000000 --- a/src/package-lock.json +++ /dev/null @@ -1,4116 +0,0 @@ -{ - "name": "mxgraph-examples", - "version": "0.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.11", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.11.tgz", - "integrity": "sha512-PhuoqeHoO9fc4ffMEVk4qb/w/s2iOSWohvbHxLtxui0eBg3Lg5gN1U8wp1V1u61hOWkPQJJyJzGH6Y+grwkq8Q==", - "dev": true - }, - "@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/runtime-corejs3": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.13.10.tgz", - "integrity": "sha512-x/XYVQ1h684pp1mJwOV4CyvqZXqbc8CMsMGUnAbuc82ZCdv1U63w5RSUzgDSXQHG5Rps/kiksH6g2D5BuaKyXg==", - "dev": true, - "requires": { - "core-js-pure": "^3.0.0", - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", - "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", - "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@hapi/accept": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-5.0.1.tgz", - "integrity": "sha512-fMr4d7zLzsAXo28PRRQPXR1o2Wmu+6z+VY1UzDp0iFo13Twj8WePakwXBiqn3E1aAlTpSNzCXdnnQXFhst8h8Q==", - "requires": { - "@hapi/boom": "9.x.x", - "@hapi/hoek": "9.x.x" - } - }, - "@hapi/boom": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.2.tgz", - "integrity": "sha512-uJEJtiNHzKw80JpngDGBCGAmWjBtzxDCz17A9NO2zCi8LLBlb5Frpq4pXwyN+2JQMod4pKz5BALwyneCgDg89Q==", - "requires": { - "@hapi/hoek": "9.x.x" - } - }, - "@hapi/hoek": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.1.1.tgz", - "integrity": "sha512-CAEbWH7OIur6jEOzaai83jq3FmKmv4PmX1JYfs9IrYcGEVI/lyL1EXJGCj7eFVJ0bg5QR8LMxBlEtA+xKiLpFw==" - }, - "@ijsto/eslint-config": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@ijsto/eslint-config/-/eslint-config-3.0.1.tgz", - "integrity": "sha512-toEM5Pvnj0yWM93cH5c10e42NUREVDZmtpjneT7FStfdnfHBPyFKGDZD1+I8BZ5iHeYeOg/tuLaXjWaogNHZJA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "read-pkg-up": "6.0.0", - "semver": "6.3.0" - } - }, - "@next/env": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@next/env/-/env-10.0.9.tgz", - "integrity": "sha512-MERX3DY5u0Ed29eAsXeFBCZlFAGBtmjf7+Nht0hfgB25MPKKkIbC/0MRPcX/PQcAgLHsAHO6ay1u9xKzR4Vzjw==" - }, - "@next/polyfill-module": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-10.0.9.tgz", - "integrity": "sha512-kPOP6ku/e8zdrK8hwxOrjUrPLcdDEj12huLHVz+DZU+20q6VlhMOtR8aKHW1460L4LoLE/DAa7YyIuxtArhDRg==" - }, - "@next/react-dev-overlay": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-10.0.9.tgz", - "integrity": "sha512-JsSh2Y004MEuPYqBD9eTl4PVZIjSzSy2GcD7MrW/gQcExYNpeMIJAbh8/OcyO1t+OnQeIHF5s/xTMsDHBGNcew==", - "requires": { - "@babel/code-frame": "7.12.11", - "anser": "1.4.9", - "chalk": "4.0.0", - "classnames": "2.2.6", - "css.escape": "1.5.1", - "data-uri-to-buffer": "3.0.1", - "platform": "1.3.6", - "shell-quote": "1.7.2", - "source-map": "0.8.0-beta.0", - "stacktrace-parser": "0.1.10", - "strip-ansi": "6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", - "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@next/react-refresh-utils": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.0.9.tgz", - "integrity": "sha512-LSoKnM+fI9MHHew+mBg1w2e4/gjwPQsI+mDTzmfwdBwje+j9U2Int6XOZftMqBPXSlL04vjC9SRBkp0+3h8cNA==" - }, - "@opentelemetry/api": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.14.0.tgz", - "integrity": "sha512-L7RMuZr5LzMmZiQSQDy9O1jo0q+DaLy6XpYJfIGfYSfoJA5qzYwUP3sP1uMIQ549DvxAgM3ng85EaPTM/hUHwQ==", - "requires": { - "@opentelemetry/context-base": "^0.14.0" - } - }, - "@opentelemetry/context-base": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-base/-/context-base-0.14.0.tgz", - "integrity": "sha512-sDOAZcYwynHFTbLo6n8kIbLiVF3a3BLkrmehJUyEbT9F+Smbi47kLGS2gG2g0fjBLR/Lr1InPD7kXL7FaTqEkw==" - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "@types/node": { - "version": "14.14.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz", - "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", - "dev": true - }, - "@types/react": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz", - "integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/scheduler": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", - "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==", - "dev": true - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "anser": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.9.tgz", - "integrity": "sha512-AI+BjTeGt2+WFk4eWcqbQ7snZpDBt8SaLlj0RT2h5xfdWaiy51OjYvqwMrNzJLGy8iOAL6nKDITWO+rd4MkYEA==" - }, - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - }, - "dependencies": { - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - } - }, - "array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" - } - }, - "array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - } - }, - "array.prototype.flatmap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", - "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "function-bind": "^1.1.1" - } - }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "ast-types": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz", - "integrity": "sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA==" - }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "axe-core": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.3.tgz", - "integrity": "sha512-vwPpH4Aj4122EW38mxO/fxhGKtwWTMLDIJfZ1He0Edbtjcfna/R3YB67yVhezUMzqc3Jr3+Ii50KRntlENL4xQ==", - "dev": true - }, - "axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", - "dev": true - }, - "babel-eslint": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-9.0.0.tgz", - "integrity": "sha512-itv1MwE3TMbY0QtNfeL7wzak1mV47Uy+n6HtSOO4Xd7rvmO+tsGQSgyOEEgo6Y2vHZKZphaoelNeSVj4vkLA1g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "^1.0.0" - } - }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" - }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz", - "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==", - "requires": { - "caniuse-lite": "^1.0.30001173", - "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.634", - "escalade": "^3.1.1", - "node-releases": "^1.1.69" - } - }, - "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001203", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001203.tgz", - "integrity": "sha512-/I9tvnzU/PHMH7wBPrfDMSuecDeUKerjCPX7D0xBbaJZPxoT9m+yYxt0zCTkcijCkjTdim3H56Zm0i5Adxch4w==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - } - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true - }, - "clipboard": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz", - "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==", - "optional": true, - "requires": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "confusing-browser-globals": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", - "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", - "dev": true - }, - "console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "core-js-pure": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.9.1.tgz", - "integrity": "sha512-laz3Zx0avrw9a4QEIdmIblnVuJz8W51leY9iLThatCsFawWxC3sE4guASC78JbCin+DkwMpCdp1AVAuzL/GN7A==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=" - }, - "cssnano-preset-simple": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cssnano-preset-simple/-/cssnano-preset-simple-1.2.2.tgz", - "integrity": "sha512-gtvrcRSGtP3hA/wS8mFVinFnQdEsEpm3v4I/s/KmNjpdWaThV/4E5EojAzFXxyT5OCSRPLlHR9iQexAqKHlhGQ==", - "requires": { - "caniuse-lite": "^1.0.30001179", - "postcss": "^7.0.32" - }, - "dependencies": { - "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cssnano-simple": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cssnano-simple/-/cssnano-simple-1.2.2.tgz", - "integrity": "sha512-4slyYc1w4JhSbhVX5xi9G0aQ42JnRyPg+7l7cqoNyoIDzfWx40Rq3JQZnoAWDu60A4AvKVp9ln/YSUOdhDX68g==", - "requires": { - "cssnano-preset-simple": "1.2.2", - "postcss": "^7.0.32" - }, - "dependencies": { - "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "csstype": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", - "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==", - "dev": true - }, - "damerau-levenshtein": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", - "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", - "dev": true - }, - "data-uri-to-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", - "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", - "optional": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", - "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==", - "dev": true - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true - } - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "electron-to-chromium": { - "version": "1.3.693", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.693.tgz", - "integrity": "sha512-vUdsE8yyeu30RecppQtI+XTz2++LWLVEIYmzeCaCRLSdtKZ2eXqdJcrs85KwLiPOPVc6PELgWyXBsfqIvzGZag==" - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", - "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.2", - "is-string": "^1.0.5", - "object-inspect": "^1.9.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, - "eslint-config-airbnb": { - "version": "18.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz", - "integrity": "sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg==", - "dev": true, - "requires": { - "eslint-config-airbnb-base": "^14.2.1", - "object.assign": "^4.1.2", - "object.entries": "^1.1.2" - } - }, - "eslint-config-airbnb-base": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", - "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", - "dev": true, - "requires": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.2" - } - }, - "eslint-config-prettier": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-4.3.0.tgz", - "integrity": "sha512-sZwhSTHVVz78+kYD3t5pCWSYEdVSBR0PXnwjDRsUs8ytIrK8PLXw+6FKp8r3Z7rx4ZszdetWlXYKOHoUrrwPlA==", - "dev": true, - "requires": { - "get-stdin": "^6.0.0" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - } - }, - "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - } - } - }, - "eslint-plugin-html": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-5.0.5.tgz", - "integrity": "sha512-v/33i3OD0fuXcRXexVyXXBOe4mLBLBQoF1UO1Uy9D+XLq4MC8K45GcQKfqjC/FnHAHp3pYUjpHHktYNCtShGmg==", - "dev": true, - "requires": { - "htmlparser2": "^3.10.0" - } - }, - "eslint-plugin-import": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", - "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", - "dev": true, - "requires": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.4", - "eslint-module-utils": "^2.6.0", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" - }, - "dependencies": { - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - } - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", - "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.11.2", - "aria-query": "^4.2.2", - "array-includes": "^3.1.1", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.0.2", - "axobject-query": "^2.2.0", - "damerau-levenshtein": "^1.0.6", - "emoji-regex": "^9.0.0", - "has": "^1.0.3", - "jsx-ast-utils": "^3.1.0", - "language-tags": "^1.0.5" - }, - "dependencies": { - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - } - } - }, - "eslint-plugin-prettier": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", - "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-plugin-react": { - "version": "7.22.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz", - "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==", - "dev": true, - "requires": { - "array-includes": "^3.1.1", - "array.prototype.flatmap": "^1.2.3", - "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "object.entries": "^1.1.2", - "object.fromentries": "^2.0.2", - "object.values": "^1.1.1", - "prop-types": "^15.7.2", - "resolve": "^1.18.1", - "string.prototype.matchall": "^4.0.2" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - } - } - }, - "eslint-plugin-react-hooks": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz", - "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==", - "dev": true - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-orientation": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-orientation/-/get-orientation-1.1.2.tgz", - "integrity": "sha512-/pViTfifW+gBbh/RnlFYHINvELT9Znt+SYyDKAUL6uV6By019AK/s+i9XP4jSwq7lwP38Fd8HVeTxym3+hkwmQ==", - "requires": { - "stream-parser": "^0.3.1" - } - }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", - "optional": true, - "requires": { - "delegate": "^3.1.2" - } - }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "dev": true, - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - } - }, - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", - "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", - "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", - "dev": true, - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true - }, - "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-number-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", - "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", - "dev": true - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", - "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.1" - } - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "requires": { - "minimist": "^1.2.0" - } - }, - "jsx-ast-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", - "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", - "dev": true, - "requires": { - "array-includes": "^3.1.2", - "object.assign": "^4.1.2" - } - }, - "language-subtag-registry": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", - "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==", - "dev": true - }, - "language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=", - "dev": true, - "requires": { - "language-subtag-registry": "~0.3.2" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "line-column": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/line-column/-/line-column-1.0.2.tgz", - "integrity": "sha1-0lryk2tvSEkXKzEuR5LR2Ye8NKI=", - "requires": { - "isarray": "^1.0.0", - "isobject": "^2.0.0" - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - } - } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - } - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "nanoid": { - "version": "3.1.22", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", - "integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==" - }, - "native-url": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/native-url/-/native-url-0.3.4.tgz", - "integrity": "sha512-6iM8R99ze45ivyH8vybJ7X0yekIcPf5GgLV5K0ENCbmRcaRIDoj37BC8iLEmaaBfqqb8enuZ5p0uhY+lVAbAcA==", - "requires": { - "querystring": "^0.2.0" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "next": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/next/-/next-10.0.9.tgz", - "integrity": "sha512-HyoVjYydcM6LaFAUOHSxVQCcKOsIimVO/IKXCuWUu1rr6DDgXbWNg/8ckH084qD46MOYlLzjViiZ3KCmNQL4Cw==", - "requires": { - "@babel/runtime": "7.12.5", - "@hapi/accept": "5.0.1", - "@next/env": "10.0.9", - "@next/polyfill-module": "10.0.9", - "@next/react-dev-overlay": "10.0.9", - "@next/react-refresh-utils": "10.0.9", - "@opentelemetry/api": "0.14.0", - "ast-types": "0.13.2", - "browserslist": "4.16.1", - "buffer": "5.6.0", - "caniuse-lite": "^1.0.30001179", - "chalk": "2.4.2", - "chokidar": "3.5.1", - "crypto-browserify": "3.12.0", - "cssnano-simple": "1.2.2", - "etag": "1.8.1", - "find-cache-dir": "3.3.1", - "get-orientation": "1.1.2", - "jest-worker": "24.9.0", - "native-url": "0.3.4", - "node-fetch": "2.6.1", - "node-html-parser": "1.4.9", - "node-libs-browser": "^2.2.1", - "p-limit": "3.1.0", - "path-browserify": "1.0.1", - "pnp-webpack-plugin": "1.6.4", - "postcss": "8.1.7", - "process": "0.11.10", - "prop-types": "15.7.2", - "raw-body": "2.4.1", - "react-is": "16.13.1", - "react-refresh": "0.8.3", - "stream-browserify": "3.0.0", - "styled-jsx": "3.3.2", - "use-subscription": "1.5.1", - "vm-browserify": "1.1.2", - "watchpack": "2.1.1" - } - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, - "node-html-parser": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz", - "integrity": "sha512-UVcirFD1Bn0O+TSmloHeHqZZCxHjvtIeGdVdGMhyZ8/PWlEiZaZ5iJzR189yKZr8p0FXN58BUeC7RHRkf/KYGw==", - "requires": { - "he": "1.2.0" - } - }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - } - } - }, - "node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==" - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", - "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "has": "^1.0.3" - } - }, - "object.fromentries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", - "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" - } - }, - "object.values": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", - "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - } - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", - "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "requires": { - "find-up": "^4.0.0" - } - }, - "platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" - }, - "pnp-webpack-plugin": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", - "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==", - "requires": { - "ts-pnp": "^1.1.6" - } - }, - "postcss": { - "version": "8.1.7", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.1.7.tgz", - "integrity": "sha512-llCQW1Pz4MOPwbZLmOddGM9eIJ8Bh7SZ2Oj5sxZva77uVaotYDsYTch1WBTNu7fUY0fpWp0fdt7uW40D4sRiiQ==", - "requires": { - "colorette": "^1.2.1", - "line-column": "^1.0.2", - "nanoid": "^3.1.16", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "prismjs": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", - "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", - "requires": { - "clipboard": "^2.0.0" - } - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "querystring": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz", - "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==" - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "raw-body": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", - "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.3", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "react": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", - "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "react-dom": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz", - "integrity": "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.1" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "react-refresh": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", - "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-6.0.0.tgz", - "integrity": "sha512-odtTvLl+EXo1eTsMnoUHRmg/XmXdTkwXVxy4VFE9Kp6cCq7b3l7QMdBndND3eAFzrbSAXC/WCUOQQ9rLjifKZw==", - "dev": true, - "requires": { - "find-up": "^4.0.0", - "read-pkg": "^5.1.1", - "type-fest": "^0.5.0" - }, - "dependencies": { - "type-fest": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", - "dev": true - } - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "requires": { - "picomatch": "^2.2.1" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "rxjs": { - "version": "6.6.6", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz", - "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "scheduler": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.1.tgz", - "integrity": "sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "select": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", - "optional": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shell-quote": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "requires": { - "whatwg-url": "^7.0.0" - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "stacktrace-parser": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", - "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", - "requires": { - "type-fest": "^0.7.1" - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "requires": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "stream-parser": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", - "integrity": "sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=", - "requires": { - "debug": "2" - } - }, - "string-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", - "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "string.prototype.matchall": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", - "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has-symbols": "^1.0.1", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.3.1", - "side-channel": "^1.0.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "styled-jsx": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-3.3.2.tgz", - "integrity": "sha512-daAkGd5mqhbBhLd6jYAjYBa9LpxYCzsgo/f6qzPdFxVB8yoGbhxvzQgkC0pfmCVvW3JuAEBn0UzFLBfkHVZG1g==", - "requires": { - "@babel/types": "7.8.3", - "babel-plugin-syntax-jsx": "6.18.0", - "convert-source-map": "1.7.0", - "loader-utils": "1.2.3", - "source-map": "0.7.3", - "string-hash": "1.1.3", - "stylis": "3.5.4", - "stylis-rule-sheet": "0.0.10" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } - } - }, - "stylis": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz", - "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==" - }, - "stylis-rule-sheet": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz", - "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "requires": { - "setimmediate": "^1.0.4" - } - }, - "tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", - "optional": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "requires": { - "punycode": "^2.1.0" - } - }, - "ts-pnp": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", - "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==" - }, - "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-fest": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", - "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==" - }, - "typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz", - "integrity": "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.0", - "has-symbols": "^1.0.0", - "which-boxed-primitive": "^1.0.1" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - } - } - }, - "use-subscription": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz", - "integrity": "sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==", - "requires": { - "object-assign": "^4.1.1" - } - }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" - }, - "watchpack": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz", - "integrity": "sha512-Oo7LXCmc1eE1AjyuSBmtC3+Wy4HcV8PxWh2kP6fOl8yTlNS7r0K9l1ao2lrrUza7V39Y3D/BbJgY8VeSlc5JKw==", - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - } - } -} diff --git a/src/package.json b/src/package.json deleted file mode 100644 index 96e8ae9cd..000000000 --- a/src/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "mxgraph-examples", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start" - }, - "dependencies": { - "next": "10.0.9", - "react": "17.0.1", - "react-dom": "17.0.1", - "prismjs": "^1.23.0" - }, - "devDependencies": { - "@ijsto/eslint-config": "^3.0.1", - "@types/node": "^14.14.37", - "@types/react": "^17.0.3", - "babel-eslint": "^9.0.0", - "eslint": "^6.8.0", - "eslint-config-airbnb": "^18.2.1", - "eslint-config-prettier": "^4.3.0", - "eslint-plugin-html": "^5.0.5", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-prettier": "^3.3.1", - "eslint-plugin-react": "^7.22.0", - "eslint-plugin-react-hooks": "^1.7.0", - "prettier": "^1.19.1", - "typescript": "^4.2.4" - } -} diff --git a/src/pages/PageTabs.js b/src/pages/PageTabs.js deleted file mode 100644 index 3a4110d69..000000000 --- a/src/pages/PageTabs.js +++ /dev/null @@ -1,56 +0,0 @@ -import Link from 'next/link'; - -const PageTabs = ({ curPageURL, children }) => { - const allPages = [ - ['/basic', 'Basic'], - ['/backgrounds', 'Backgrounds'], - ['/connections', 'Connections'], - ['/dnd_copypaste', 'Drag-and-drop/copy-paste'], - ['/editing', 'Editing'], - ['/effects', 'Effects'], - ['/events', 'Events'], - ['/icons_images', 'Icons/Images'], - ['/labels', 'Labels'], - ['/layout', 'Layout'], - ['/misc', 'Miscellaneous'], - // ['/printing', 'Printing'], - ['/shapes_stencils', 'Shapes/stencils'], - ['/styles', 'Styles'], - ['/toolbars', 'Toolbars'], - // ['/windows', 'Windows'], - ['/xml_json', 'XML/JSON'], - ['/zoom_offpage', 'Zoom/offpage'], - ]; - - const tabs = []; - for (const [pageURL, pageName] of allPages) { - tabs.push( -
  • - - {pageName} - -
  • - ); - } - - return ( -
    -

    mxGraph Reloaded Examples

    -
    - See also the{' '} - - GitHub repo - -
    -
      {tabs}
    - {children} -
    - ); -}; - -export default PageTabs; diff --git a/src/pages/Previews.js b/src/pages/Previews.js deleted file mode 100644 index f812c7b8f..000000000 --- a/src/pages/Previews.js +++ /dev/null @@ -1,49 +0,0 @@ -import React, { useState } from 'react'; - -import SourceCodeDisplay from './SourceCodeDisplay'; -import examplesListing from './examplesListing.json'; - -function Preview({ sourceKey, content }) { - const [sourceShown, setSourceShown] = useState(false); - - return ( - <> - {content} - - {sourceShown ? ( -
    - setSourceShown(false)} - style={{ float: 'right', color: 'blue', cursor: 'pointer' }} - > - hide source - -
    - -
    -
    - ) : ( -
    - setSourceShown(true)} - style={{ float: 'right', color: 'blue', cursor: 'pointer' }} - > - show source - -
    - )} - - ); -} - -export default Preview; diff --git a/src/pages/README.md b/src/pages/README.md deleted file mode 100644 index 902e70ee8..000000000 --- a/src/pages/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# mxGraph Examples - -This directory contains modified examples for mxGraph. -The original examples can be found at -https://jgraph.github.io/mxgraph/javascript/index.html. - -The main ways in which it differs from the original -samples are that the examples have been refactored and -converted to React with templates+logic code separated. - -The JavaScript prototypes of mxGraph classes have also been -replaced with subclasses to not make configuration -global for other mxGraph configurations on the same page. - -## How to View/Run Examples - -The examples are grouped by category tabs in the React -application, which you can view live at -https://mxgraph-mcyph.vercel.app/ or run locally by -typing the following: - - cd src - npm install - npm run dev - -From this project's root directory on the command line. -Note that this next application has a different `package.json` -and dependencies to the core mxGraph library, whose -`package.json` is located in the root directory of this -project. - -## Development Status+Plans - -Some of the examples are yet to be converted: these can -be found in the `/docs/stashed` folder. - -To add new tabs, go to `PageTabs.js` and add the route -and text of the tab to the list. Note that the examples -are served by next.js and the routes correspond to the -subdirectories, e.g. "/effects" will include -`/src/pages/effects/index.js`. - -To update the source code previews displayed in `Previews.js` -after modifying the examples, run `python3 copy_examples_to_json.py`. - -There are plans to remove the react+next example -dependencies: see also https://github.com/jsGraph/mxgraph/issues/8 -for the full discussion. - diff --git a/src/pages/SourceCodeDisplay.js b/src/pages/SourceCodeDisplay.js deleted file mode 100644 index eabb9c4cb..000000000 --- a/src/pages/SourceCodeDisplay.js +++ /dev/null @@ -1,60 +0,0 @@ -import { Component } from 'react'; -import Prism from 'prismjs'; -import 'prismjs/themes/prism-okaidia.css'; -import 'prismjs/components/prism-markup-templating'; -import 'prismjs/components/prism-handlebars.min'; -import 'prismjs/components/prism-jsx.min'; -import 'prismjs/components/prism-javascript.min'; - -// Adapted from -// https://betterstack.dev/blog/code-highlighting-in-react-using-prismjs/ - -export class SourceCodeDisplay extends Component { - /** - * - * @param code - * @param plugins - * @param language - */ - constructor({ code, plugins, language, theme, style }) { - if (plugins == null) { - plugins = ['line-numbers', 'show-language']; - } - super({ code, plugins, language, theme, style }); - } - - render() { - // TODO: Support theme!!! - return ( - <> -
    -           {
    -              this.el = el;
    -            }}
    -            className={`language-${this.props.language}`}
    -          >
    -            {(this.props.code || '').trim()}
    -          
    -        
    - - ); - } - - componentDidMount() { - if (this.el) { - Prism.highlightElement(this.el); - } - } - - componentDidUpdate() { - if (this.el) { - Prism.highlightElement(this.el); - } - } -} - -export default SourceCodeDisplay; diff --git a/src/pages/_app.js b/src/pages/_app.js deleted file mode 100644 index ccace7990..000000000 --- a/src/pages/_app.js +++ /dev/null @@ -1,9 +0,0 @@ -import '../styles/globals.css'; -import '../public/css/common.css'; -import './effects/Animation.css'; - -function MyApp({ Component, pageProps }) { - return ; -} - -export default MyApp; diff --git a/src/pages/backgrounds/Grid.js b/src/pages/backgrounds/Grid.js deleted file mode 100644 index 89782fa67..000000000 --- a/src/pages/backgrounds/Grid.js +++ /dev/null @@ -1,218 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxLog from '../../mxgraph/util/gui/mxLog'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxGraphView from '../../mxgraph/view/graph/mxGraphView'; - -class Grid extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Grid

    - This example demonstrates drawing a grid dynamically using HTML 5 - canvas. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '481px', - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - mxEvent.disableContextMenu(this.el); - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.graphHandler.scaleGrid = true; - graph.setPanning(true); - - // Enables rubberband selection - new mxRubberband(graph); - - let repaintGrid; - - // Create grid dynamically (requires canvas) - (function() { - try { - const canvas = document.createElement('canvas'); - canvas.style.position = 'absolute'; - canvas.style.top = '0px'; - canvas.style.left = '0px'; - canvas.style.zIndex = -1; - graph.container.appendChild(canvas); - - const ctx = canvas.getContext('2d'); - - // Modify event filtering to accept canvas as container - const mxGraphViewIsContainerEvent = - mxGraphView.prototype.isContainerEvent; - mxGraphView.prototype.isContainerEvent = function(evt) { - return ( - mxGraphViewIsContainerEvent.apply(this, arguments) || - mxEvent.getSource(evt) === canvas - ); - }; - - let s = 0; - let gs = 0; - let tr = new mxPoint(); - let w = 0; - let h = 0; - - repaintGrid = function() { - if (ctx != null) { - const bounds = graph.getGraphBounds(); - const width = Math.max( - bounds.x + bounds.width, - graph.container.clientWidth - ); - const height = Math.max( - bounds.y + bounds.height, - graph.container.clientHeight - ); - const sizeChanged = width !== w || height !== h; - - if ( - graph.view.scale !== s || - graph.view.translate.x !== tr.x || - graph.view.translate.y !== tr.y || - gs !== graph.gridSize || - sizeChanged - ) { - tr = graph.view.translate.clone(); - s = graph.view.scale; - gs = graph.gridSize; - w = width; - h = height; - - // Clears the background if required - if (!sizeChanged) { - ctx.clearRect(0, 0, w, h); - } else { - canvas.setAttribute('width', w); - canvas.setAttribute('height', h); - } - - const tx = tr.x * s; - const ty = tr.y * s; - - // Sets the distance of the grid lines in pixels - const minStepping = graph.gridSize; - let stepping = minStepping * s; - - if (stepping < minStepping) { - const count = - Math.round(Math.ceil(minStepping / stepping) / 2) * 2; - stepping = count * stepping; - } - - const xs = Math.floor((0 - tx) / stepping) * stepping + tx; - let xe = Math.ceil(w / stepping) * stepping; - const ys = Math.floor((0 - ty) / stepping) * stepping + ty; - let ye = Math.ceil(h / stepping) * stepping; - - xe += Math.ceil(stepping); - ye += Math.ceil(stepping); - - const ixs = Math.round(xs); - const ixe = Math.round(xe); - const iys = Math.round(ys); - const iye = Math.round(ye); - - // Draws the actual grid - ctx.strokeStyle = '#f6f6f6'; - ctx.beginPath(); - - for (let x = xs; x <= xe; x += stepping) { - x = Math.round((x - tx) / stepping) * stepping + tx; - const ix = Math.round(x); - - ctx.moveTo(ix + 0.5, iys + 0.5); - ctx.lineTo(ix + 0.5, iye + 0.5); - } - - for (let y = ys; y <= ye; y += stepping) { - y = Math.round((y - ty) / stepping) * stepping + ty; - const iy = Math.round(y); - - ctx.moveTo(ixs + 0.5, iy + 0.5); - ctx.lineTo(ixe + 0.5, iy + 0.5); - } - - ctx.closePath(); - ctx.stroke(); - } - } - }; - } catch (e) { - mxLog.show(); - mxLog.debug('Using background image'); - - this.el.style.backgroundImage = "url('editors/images/grid.gif')"; - } - - const mxGraphViewValidateBackground = - mxGraphView.prototype.validateBackground; - mxGraphView.prototype.validateBackground = function() { - mxGraphViewValidateBackground.apply(this, arguments); - repaintGrid(); - }; - })(); - - // 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(); - } - - graph.centerZoom = false; - - this.el2.appendChild( - mxUtils.button('+', function() { - graph.zoomIn(); - }) - ); - - this.el2.appendChild( - mxUtils.button('-', function() { - graph.zoomOut(); - }) - ); - } -} - -export default Grid; diff --git a/src/pages/backgrounds/index.js b/src/pages/backgrounds/index.js deleted file mode 100644 index 118a86b10..000000000 --- a/src/pages/backgrounds/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import Grid from './Grid'; -import Preview from '../Previews'; -import ExtendCanvas from './ExtendCanvas'; -import PageTabs from '../PageTabs'; - -export default function _Backgrounds() { - return ( - - } /> - } /> - - ); -} diff --git a/src/pages/basic/HelloWorld.js b/src/pages/basic/HelloWorld.js deleted file mode 100644 index 8266ab50e..000000000 --- a/src/pages/basic/HelloWorld.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2006-2018, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; - -class HelloWorld extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph with a grid wallpaper - return ( - <> -

    Hello, World!

    - This example demonstrates using a DOM node to create a graph and adding - vertices and edges. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Create a sample graph in the DOM node with the specified ID. - mxEvent.disableContextMenu(this.el); // Disable the built-in context menu - const graph = new mxGraph(this.el); // Create the graph inside the given container - new mxRubberband(graph); // Enable rubberband selection - - // Get the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - const parent = graph.getDefaultParent(); - - graph.batchUpdate(() => { - // Add cells to the model in a single step - const vertex1 = graph.insertVertex({ - parent, - value: 'Hello', - position: [20, 20], - size: [80, 30], - relative: false, - }); - const vertex2 = graph.insertVertex({ - parent, - value: 'World!', - position: [200, 150], - size: [80, 30], - relative: false, - }); - const edge = graph.insertEdge({ - parent, - // value: 'to the', - source: vertex1, - target: vertex2, - }); - }); - } -} - -export default HelloWorld; diff --git a/src/pages/basic/Template.js b/src/pages/basic/Template.js deleted file mode 100644 index 576cddd88..000000000 --- a/src/pages/basic/Template.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - - Template. This is used as a template HTML file by the - backends to demonstrate the deployment of the client with a graph embedded - in the page as XML data (see graph variable in the onload-handler). - - *** THIS FILE MUST BE DEPLOYED BY ONE OF THE BACKENDS! *** - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxCodec from '../../mxgraph/serialization/mxCodec'; - -class Template extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Hello, World!

    -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '241px', - background: - "url('/mxgraph/javascript/examples/editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Adds rubberband selection to the graph - new mxRubberband(graph); - - const doc = mxUtils.parseXml(xml); - const codec = new mxCodec(doc); - codec.decode(doc.documentElement, graph.getModel()); - } -} - -export default Template; diff --git a/src/pages/basic/index.js b/src/pages/basic/index.js deleted file mode 100644 index d306b4814..000000000 --- a/src/pages/basic/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import HelloWorld from './HelloWorld'; -import Preview from '../Previews'; -import PageTabs from '../PageTabs'; - -export default function _Basic() { - { - /* } /> */ - } - return ( - - } /> - - ); -} diff --git a/src/pages/connections/Anchors.js b/src/pages/connections/Anchors.js deleted file mode 100644 index b7ff28ae9..000000000 --- a/src/pages/connections/Anchors.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxShape from '../../mxgraph/shape/mxShape'; -import mxConnectionConstraint from '../../mxgraph/view/connection/mxConnectionConstraint'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxPolyline from '../../mxgraph/shape/edge/mxPolyline'; -import mxCellState from '../../mxgraph/view/cell/mxCellState'; -import mxGeometry from '../../mxgraph/util/datatypes/mxGeometry'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; - -class Anchors extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Anchors

    - This example demonstrates defining fixed connection points for all - shapes. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: 'url("editors/images/grid.gif")', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Disables the built-in context menu - mxEvent.disableContextMenu(this.el); - - class MyCustomConnectionHandler extends mxConnectionHandler { - // Enables connect preview for the default edge style - createEdgeState(me) { - const edge = graph.createEdge(null, null, null, null, null); - return new mxCellState( - this.graph.view, - edge, - this.graph.getCellStyle(edge) - ); - } - } - - class MyCustomGraph extends mxGraph { - getAllConnectionConstraints(terminal, source) { - // Overridden to define per-shape connection points - if (terminal != null && terminal.shape != null) { - if (terminal.shape.stencil != null) { - if (terminal.shape.stencil.constraints != null) { - return terminal.shape.stencil.constraints; - } - } else if (terminal.shape.constraints != null) { - return terminal.shape.constraints; - } - } - return null; - } - - createConnectionHandler() { - return new MyCustomConnectionHandler(this); - } - } - - class MyCustomGeometryClass extends mxGeometry { - // Defines the default constraints for the vertices - constraints = [ - new mxConnectionConstraint(new mxPoint(0.25, 0), true), - new mxConnectionConstraint(new mxPoint(0.5, 0), true), - new mxConnectionConstraint(new mxPoint(0.75, 0), true), - new mxConnectionConstraint(new mxPoint(0, 0.25), true), - new mxConnectionConstraint(new mxPoint(0, 0.5), true), - new mxConnectionConstraint(new mxPoint(0, 0.75), true), - new mxConnectionConstraint(new mxPoint(1, 0.25), true), - new mxConnectionConstraint(new mxPoint(1, 0.5), true), - new mxConnectionConstraint(new mxPoint(1, 0.75), true), - new mxConnectionConstraint(new mxPoint(0.25, 1), true), - new mxConnectionConstraint(new mxPoint(0.5, 1), true), - new mxConnectionConstraint(new mxPoint(0.75, 1), true), - ]; - } - - // Edges have no connection points - mxPolyline.prototype.constraints = null; - - // Creates the graph inside the given container - const graph = new MyCustomGraph(this.el); - graph.setConnectable(true); - - // Specifies the default edge style - graph.getStylesheet().getDefaultEdgeStyle().edgeStyle = - 'orthogonalEdgeStyle'; - - // 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], - geometryClass: MyCustomGeometryClass, - }); - const v2 = graph.insertVertex({ - parent, - value: 'World!', - position: [200, 150], - size: [80, 30], - geometryClass: MyCustomGeometryClass, - }); - const e1 = graph.insertEdge({ - parent, - value: '', - position: v1, - size: v2, - }); - }); - } -} - -export default Anchors; diff --git a/src/pages/connections/EdgeTolerance.js b/src/pages/connections/EdgeTolerance.js deleted file mode 100644 index 7f72825c7..000000000 --- a/src/pages/connections/EdgeTolerance.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class EdgeTolerance extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Edge tolerance

    - This example demonstrates increasing the tolerance for hit detection on - edges. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '481px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - const { el } = this; - - class MyCustomGraph extends mxGraph { - fireMouseEvent(evtName, me, sender) { - // Overrides the mouse event dispatching mechanism to update the - // cell which is associated with the event in case the native hit - // detection did not return anything. - - // Checks if native hit detection did not return anything - if (me.getState() == null) { - // Updates the graph coordinates in the event since we need - // them here. Storing them in the event means the overridden - // method doesn't have to do this again. - if (me.graphX == null || me.graphY == null) { - const pt = mxUtils.convertPoint(el, me.getX(), me.getY()); - - me.graphX = pt.x; - me.graphY = pt.y; - } - - const cell = this.getCellAt(me.graphX, me.graphY); - if (cell.isEdge()) { - me.state = this.view.getState(cell); - - if (me.state != null && me.state.shape != null) { - this.container.style.cursor = me.state.shape.node.style.cursor; - } - } - } - - if (me.state == null) { - this.container.style.cursor = 'default'; - } - - super.fireMouseEvent(evtName, me, sender); - } - - dblClick(evt, cell) { - // Overrides double click handling to use the tolerance - if (cell == null) { - const pt = mxUtils.convertPoint( - el, - mxEvent.getClientX(evt), - mxEvent.getClientY(evt) - ); - cell = this.getCellAt(pt.x, pt.y); - } - super.dblClick(evt, cell); - } - } - - // Creates the graph inside the given container - const graph = new MyCustomGraph(this.el); - graph.setTolerance(20); - - // 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: [120, 120], - size: [80, 30], - }); - const v2 = graph.insertVertex({ - parent, - value: 'World!', - position: [400, 250], - size: [80, 30], - }); - const e1 = graph.insertEdge({ - parent, - source: v1, - target: v2, - style: 'edgeStyle=orthogonalEdgeStyle;', - }); - const e2 = graph.insertEdge({ - parent, - source: v2, - target: v1, - style: 'edgeStyle=orthogonalEdgeStyle;', - }); - }); - } -} - -export default EdgeTolerance; diff --git a/src/pages/connections/FixedPoints.js b/src/pages/connections/FixedPoints.js deleted file mode 100644 index dc6d8fb6e..000000000 --- a/src/pages/connections/FixedPoints.js +++ /dev/null @@ -1,274 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxConstraintHandler from '../../mxgraph/handler/mxConstraintHandler'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; -import mxEdgeHandler from '../../mxgraph/handler/mxEdgeHandler'; -import mxConnectionConstraint from '../../mxgraph/view/connection/mxConnectionConstraint'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxCellState from '../../mxgraph/view/cell/mxCellState'; - -class FixedPoints extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Fixed points

    - This example demonstrates using fixed connection points for connecting - edges to vertices. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - class MyCustomConstraintHandler extends mxConstraintHandler { - // Snaps to fixed points - intersects(icon, point, source, existingEdge) { - return ( - !source || existingEdge || mxUtils.intersects(icon.bounds, point) - ); - } - } - - class MyCustomConnectionHandler extends mxConnectionHandler { - // connectImage = new mxImage('images/connector.gif', 16, 16); - - isConnectableCell(cell) { - return false; - } - - /* - * Special case: Snaps source of new connections to fixed points - * Without a connect preview in connectionHandler.createEdgeState mouseMove - * and getSourcePerimeterPoint should be overriden by setting sourceConstraint - * sourceConstraint to null in mouseMove and updating it and returning the - * nearest point (cp) in getSourcePerimeterPoint (see below) - */ - updateEdgeState(pt, constraint) { - if (pt != null && this.previous != null) { - const constraints = this.graph.getAllConnectionConstraints( - this.previous - ); - let nearestConstraint = null; - let dist = null; - - for (let i = 0; i < constraints.length; i++) { - const cp = this.graph.getConnectionPoint( - this.previous, - constraints[i] - ); - - if (cp != null) { - const tmp = - (cp.x - pt.x) * (cp.x - pt.x) + (cp.y - pt.y) * (cp.y - pt.y); - - if (dist == null || tmp < dist) { - nearestConstraint = constraints[i]; - dist = tmp; - } - } - } - - if (nearestConstraint != null) { - this.sourceConstraint = nearestConstraint; - } - - // In case the edge style must be changed during the preview: - // this.edgeState.style['edgeStyle'] = 'orthogonalEdgeStyle'; - // And to use the new edge style in the new edge inserted into the graph, - // update the cell style as follows: - // this.edgeState.cell.style = mxUtils.setStyle(this.edgeState.cell.style, 'edgeStyle', this.edgeState.style['edgeStyle']); - } - return super.updateEdgeState(pt, constraint); - } - - createEdgeState(me) { - // Connect preview - const edge = this.graph.createEdge( - null, - null, - null, - null, - null, - 'edgeStyle=orthogonalEdgeStyle' - ); - - return new mxCellState( - this.graph.view, - edge, - this.graph.getCellStyle(edge) - ); - } - } - - class MyCustomEdgeHandler extends mxEdgeHandler { - // Disables floating connections (only use with no connect image) - isConnectableCell(cell) { - return graph.connectionHandler.isConnectableCell(cell); - } - } - - class MyCustomGraph extends mxGraph { - createConnectionHandler() { - const r = new MyCustomConnectionHandler(); - r.constraintHandler = new MyCustomConstraintHandler(this); - return r; - } - - createEdgeHandler(state, edgeStyle) { - const r = new MyCustomEdgeHandler(state, edgeStyle); - r.constraintHandler = new MyCustomConstraintHandler(this); - return r; - } - - getAllConnectionConstraints(terminal) { - if (terminal != null && terminal.cell.isVertex()) { - return [ - new mxConnectionConstraint(new mxPoint(0, 0), true), - new mxConnectionConstraint(new mxPoint(0.5, 0), true), - new mxConnectionConstraint(new mxPoint(1, 0), true), - new mxConnectionConstraint(new mxPoint(0, 0.5), true), - new mxConnectionConstraint(new mxPoint(1, 0.5), true), - new mxConnectionConstraint(new mxPoint(0, 1), true), - new mxConnectionConstraint(new mxPoint(0.5, 1), true), - new mxConnectionConstraint(new mxPoint(1, 1), true), - ]; - } - return null; - } - } - - // Creates the graph inside the given container - const graph = new MyCustomGraph(this.el); - graph.setConnectable(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, 60], - style: 'shape=triangle;perimeter=trianglePerimeter', - }); - const v2 = graph.insertVertex({ - parent, - value: 'World!', - position: [200, 150], - size: [80, 60], - style: 'shape=ellipse;perimeter=ellipsePerimeter', - }); - const v3 = graph.insertVertex({ - parent, - value: 'Hello,', - position: [200, 20], - size: [80, 30], - }); - const e1 = graph.insertEdge({ - parent, - value: '', - source: v1, - target: v2, - style: - 'edgeStyle=elbowEdgeStyle;elbow=horizontal;' + - 'exitX=0.5;exitY=1;exitPerimeter=1;entryX=0;entryY=0;entryPerimeter=1;', - }); - const e2 = graph.insertEdge({ - parent, - value: '', - source: v3, - target: v2, - style: - 'edgeStyle=elbowEdgeStyle;elbow=horizontal;orthogonal=0;' + - 'entryX=0;entryY=0;entryPerimeter=1;', - }); - }); - - // Use this code to snap the source point for new connections without a connect preview, - // ie. without an overridden graph.connectionHandler.createEdgeState - /* - let mxConnectionHandlerMouseMove = mxConnectionHandler.prototype.mouseMove; - mxConnectionHandler.prototype.mouseMove = function(sender, me) - { - this.sourceConstraint = null; - - mxConnectionHandlerMouseMove.apply(this, arguments); - }; - - let mxConnectionHandlerGetSourcePerimeterPoint = mxConnectionHandler.prototype.getSourcePerimeterPoint; - mxConnectionHandler.prototype.getSourcePerimeterPoint = function(state, pt, me) - { - let result = null; - - if (this.previous != null && pt != null) - { - let constraints = this.graph.getAllConnectionConstraints(this.previous); - let nearestConstraint = null; - let nearest = null; - let dist = null; - - for (let i = 0; i < constraints.length; i++) - { - let cp = this.graph.getConnectionPoint(this.previous, constraints[i]); - - if (cp != null) - { - let tmp = (cp.x - pt.x) * (cp.x - pt.x) + (cp.y - pt.y) * (cp.y - pt.y); - - if (dist == null || tmp < dist) - { - nearestConstraint = constraints[i]; - nearest = cp; - dist = tmp; - } - } - } - - if (nearestConstraint != null) - { - this.sourceConstraint = nearestConstraint; - result = nearest; - } - } - - if (result == null) - { - result = mxConnectionHandlerGetSourcePerimeterPoint.apply(this, arguments); - } - - return result; - }; - */ - } -} - -export default FixedPoints; diff --git a/src/pages/connections/HelloPort.js b/src/pages/connections/HelloPort.js deleted file mode 100644 index 25d194b43..000000000 --- a/src/pages/connections/HelloPort.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxCodec from '../../mxgraph/serialization/mxCodec'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class HelloPort extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Hello Port

    - This example demonstrates using the isPort hook for visually connecting - to another cell. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.setConnectable(true); - graph.setTooltips(true); - - // Sets the default edge style - const style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - - // Ports are not used as terminals for edges, they are - // only used to compute the graphical connection point - graph.isPort = function(cell) { - const geo = this.getCellGeometry(cell); - - return geo != null ? geo.relative : false; - }; - - // Implements a tooltip that shows the actual - // source and target of an edge - graph.getTooltipForCell = function(cell) { - if (cell.isEdge()) { - return `${this.convertValueToString( - cell.getTerminal(true) - )} => ${this.convertValueToString( - cell.getTerminal(false) - )}`; - } - - return mxGraph.prototype.getTooltipForCell.apply(this, arguments); - }; - - // Removes the folding icon and disables any folding - graph.isCellFoldable = function(cell) { - return false; - }; - - // 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, 80, 80, 30); - v1.setConnectable(false); - const v11 = graph.insertVertex(v1, null, '', 1, 1, 10, 10); - v11.geometry.offset = new mxPoint(-5, -5); - v11.geometry.relative = true; - const v12 = graph.insertVertex(v1, null, '', 1, 0, 10, 10); - v12.geometry.offset = new mxPoint(-5, -5); - v12.geometry.relative = true; - const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); - const v3 = graph.insertVertex(parent, null, 'World2', 200, 20, 80, 30); - var e1 = graph.insertEdge(parent, null, '', v11, v2); - var e1 = graph.insertEdge(parent, null, '', v12, v3); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - const button = mxUtils.button('View XML', function() { - const encoder = new mxCodec(); - const node = encoder.encode(graph.getModel()); - mxUtils.popup(mxUtils.getPrettyXml(node), true); - }); - - this.el2.appendChild(button); - } -} - -export default HelloPort; diff --git a/src/pages/connections/Orthogonal.js b/src/pages/connections/Orthogonal.js deleted file mode 100644 index 2dd2d7bb9..000000000 --- a/src/pages/connections/Orthogonal.js +++ /dev/null @@ -1,189 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxGraphHandler from '../../mxgraph/handler/mxGraphHandler'; -import mxGuide from '../../mxgraph/util/mxGuide'; -import mxEdgeHandler from '../../mxgraph/handler/mxEdgeHandler'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; -import mxGraphView from '../../mxgraph/view/graph/mxGraphView'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxCellState from '../../mxgraph/view/cell/mxCellState'; - -class Orthogonal extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Orthogonal

    - This example demonstrates the use of port constraints and orthogonal - edge styles and handlers. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Enables guides - mxGraphHandler.prototype.guidesEnabled = true; - - // Alt disables guides - mxGuide.prototype.isEnabledForEvent = function(evt) { - return !mxEvent.isAltDown(evt); - }; - - // Enables snapping waypoints to terminals - mxEdgeHandler.prototype.snapToTerminals = true; - - // Enables orthogonal connect preview in IE - mxConnectionHandler.prototype.movePreviewAway = false; - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.disconnectOnMove = false; - graph.foldingEnabled = false; - graph.cellsResizable = false; - graph.extendParents = false; - graph.setConnectable(true); - - // Implements perimeter-less connection points as fixed points (computed before the edge style). - graph.view.updateFixedTerminalPoint = function( - edge, - terminal, - source, - constraint - ) { - mxGraphView.prototype.updateFixedTerminalPoint.apply(this, arguments); - - const pts = edge.absolutePoints; - const pt = pts[source ? 0 : pts.length - 1]; - - if ( - terminal != null && - pt == null && - this.getPerimeterFunction(terminal) == null - ) { - edge.setAbsoluteTerminalPoint( - new mxPoint( - this.getRoutingCenterX(terminal), - this.getRoutingCenterY(terminal) - ), - source - ); - } - }; - - // Changes the default edge style - graph.getStylesheet().getDefaultEdgeStyle().edgeStyle = - 'orthogonalEdgeStyle'; - delete graph.getStylesheet().getDefaultEdgeStyle().endArrow; - - // Implements the connect preview - graph.connectionHandler.createEdgeState = function(me) { - const edge = graph.createEdge(null, null, null, null, null); - - return new mxCellState( - this.graph.view, - edge, - this.graph.getCellStyle(edge) - ); - }; - - // 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, '', 40, 40, 40, 30); - v1.setConnectable(false); - const v11 = graph.insertVertex( - v1, - null, - '', - 0.5, - 0, - 10, - 40, - 'portConstraint=northsouth;', - true - ); - v11.geometry.offset = new mxPoint(-5, -5); - const v12 = graph.insertVertex( - v1, - null, - '', - 0, - 0.5, - 10, - 10, - 'portConstraint=west;shape=triangle;direction=west;perimeter=none;' + - 'routingCenterX=-0.5;routingCenterY=0;', - true - ); - v12.geometry.offset = new mxPoint(-10, -5); - const v13 = graph.insertVertex( - v1, - null, - '', - 1, - 0.5, - 10, - 10, - 'portConstraint=east;shape=triangle;direction=east;perimeter=none;' + - 'routingCenterX=0.5;routingCenterY=0;', - true - ); - v13.geometry.offset = new mxPoint(0, -5); - - const v2 = graph.addCell(graph.getModel().cloneCell(v1)); - v2.geometry.x = 200; - v2.geometry.y = 60; - - const v3 = graph.addCell(graph.getModel().cloneCell(v1)); - v3.geometry.x = 40; - v3.geometry.y = 150; - - const v4 = graph.addCell(graph.getModel().cloneCell(v1)); - v4.geometry.x = 200; - v4.geometry.y = 170; - - graph.insertEdge(parent, null, '', v1.getChildAt(2), v2.getChildAt(1)); - graph.insertEdge(parent, null, '', v2.getChildAt(2), v3.getChildAt(1)); - graph.insertEdge(parent, null, '', v3.getChildAt(2), v4.getChildAt(1)); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Orthogonal; diff --git a/src/pages/connections/PortRefs.js b/src/pages/connections/PortRefs.js deleted file mode 100644 index 750b5f587..000000000 --- a/src/pages/connections/PortRefs.js +++ /dev/null @@ -1,294 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxConstraintHandler from '../../mxgraph/handler/mxConstraintHandler'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxShape from '../../mxgraph/shape/mxShape'; -import mxTriangle from '../../mxgraph/shape/mxTriangle'; -import mxEdgeHandler from '../../mxgraph/handler/mxEdgeHandler'; -import mxConnectionConstraint from '../../mxgraph/view/connection/mxConnectionConstraint'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxConstants from '../../mxgraph/util/mxConstants'; - -class PortRefs extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Port References Example

    - This example demonstrates referencing connection points by ID. The main - difference to the implementation where the connection point is stored in - the connecting edge is that changes to the original port will be - reflected in all existing connections since they reference that port. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Replaces the port image - mxConstraintHandler.prototype.pointImage = new mxImage( - 'images/dot.gif', - 10, - 10 - ); - - const graph = new mxGraph(this.el); - graph.setConnectable(true); - - // Disables automatic handling of ports. This disables the reset of the - // respective style in mxGraph.cellConnected. Note that this feature may - // be useful if floating and fixed connections are combined. - graph.setPortsEnabled(false); - - // 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(); - - // Ports are equal for all shapes... - const ports = new Array(); - - // NOTE: Constraint is used later for orthogonal edge routing (currently ignored) - ports.w = { x: 0, y: 0.5, perimeter: true, constraint: 'west' }; - ports.e = { x: 1, y: 0.5, perimeter: true, constraint: 'east' }; - ports.n = { x: 0.5, y: 0, perimeter: true, constraint: 'north' }; - ports.s = { x: 0.5, y: 1, perimeter: true, constraint: 'south' }; - ports.nw = { x: 0, y: 0, perimeter: true, constraint: 'north west' }; - ports.ne = { x: 1, y: 0, perimeter: true, constraint: 'north east' }; - ports.sw = { x: 0, y: 1, perimeter: true, constraint: 'south west' }; - ports.se = { x: 1, y: 1, perimeter: true, constraint: 'south east' }; - - // ... except for triangles - const ports2 = new Array(); - - // NOTE: Constraint is used later for orthogonal edge routing (currently ignored) - ports2.in1 = { x: 0, y: 0, perimeter: true, constraint: 'west' }; - ports2.in2 = { x: 0, y: 0.25, perimeter: true, constraint: 'west' }; - ports2.in3 = { x: 0, y: 0.5, perimeter: true, constraint: 'west' }; - ports2.in4 = { x: 0, y: 0.75, perimeter: true, constraint: 'west' }; - ports2.in5 = { x: 0, y: 1, perimeter: true, constraint: 'west' }; - - ports2.out1 = { - x: 0.5, - y: 0, - perimeter: true, - constraint: 'north east', - }; - ports2.out2 = { x: 1, y: 0.5, perimeter: true, constraint: 'east' }; - ports2.out3 = { - x: 0.5, - y: 1, - perimeter: true, - constraint: 'south east', - }; - - // Extends shapes classes to return their ports - mxShape.prototype.getPorts = function() { - return ports; - }; - - mxTriangle.prototype.getPorts = function() { - return ports2; - }; - - // Disables floating connections (only connections via ports allowed) - graph.connectionHandler.isConnectableCell = function(cell) { - return false; - }; - mxEdgeHandler.prototype.isConnectableCell = function(cell) { - return graph.connectionHandler.isConnectableCell(cell); - }; - - // Disables existing port functionality - graph.view.getTerminalPort = function(state, terminal, source) { - return terminal; - }; - - // Returns all possible ports for a given terminal - graph.getAllConnectionConstraints = function(terminal, source) { - if ( - terminal != null && - terminal.shape != null && - terminal.shape.stencil != null - ) { - // for stencils with existing constraints... - if (terminal.shape.stencil != null) { - return terminal.shape.stencil.constraints; - } - } else if (terminal != null && terminal.cell.isVertex()) { - if (terminal.shape != null) { - const ports = terminal.shape.getPorts(); - const cstrs = new Array(); - - for (const id in ports) { - const port = ports[id]; - - const cstr = new mxConnectionConstraint( - new mxPoint(port.x, port.y), - port.perimeter - ); - cstr.id = id; - cstrs.push(cstr); - } - - return cstrs; - } - } - - return null; - }; - - // Sets the port for the given connection - graph.setConnectionConstraint = function( - edge, - terminal, - source, - constraint - ) { - if (constraint != null) { - const key = source - ? mxConstants.STYLE_SOURCE_PORT - : mxConstants.STYLE_TARGET_PORT; - - if (constraint == null || constraint.id == null) { - this.setCellStyles(key, null, [edge]); - } else if (constraint.id != null) { - this.setCellStyles(key, constraint.id, [edge]); - } - } - }; - - // Returns the port for the given connection - graph.getConnectionConstraint = function(edge, terminal, source) { - const key = source - ? mxConstants.STYLE_SOURCE_PORT - : mxConstants.STYLE_TARGET_PORT; - const id = edge.style[key]; - - if (id != null) { - const c = new mxConnectionConstraint(null, null); - c.id = id; - - return c; - } - - return null; - }; - - // Returns the actual point for a port by redirecting the constraint to the port - const graphGetConnectionPoint = graph.getConnectionPoint; - graph.getConnectionPoint = function(vertex, constraint) { - if (constraint.id != null && vertex != null && vertex.shape != null) { - const port = vertex.shape.getPorts()[constraint.id]; - - if (port != null) { - constraint = new mxConnectionConstraint( - new mxPoint(port.x, port.y), - port.perimeter - ); - } - } - - return graphGetConnectionPoint.apply(this, arguments); - }; - - // Adds cells to the model in a single step - graph.getModel().beginUpdate(); - try { - const v1 = graph.insertVertex(parent, null, 'A', 20, 20, 100, 40); - const v2 = graph.insertVertex( - parent, - null, - 'B', - 80, - 100, - 100, - 100, - 'shape=ellipse;perimeter=ellipsePerimeter' - ); - const v3 = graph.insertVertex( - parent, - null, - 'C', - 190, - 30, - 100, - 60, - 'shape=triangle;perimeter=trianglePerimeter;direction=south' - ); - const e1 = graph.insertEdge( - parent, - null, - '', - v1, - v2, - 'sourcePort=s;targetPort=nw' - ); - const e2 = graph.insertEdge( - parent, - null, - '', - v1, - v3, - 'sourcePort=e;targetPort=out3' - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - // Comming soon... Integration with orthogonal edge style - // Sets default edge style to use port constraints (needs to be moved up when uncommented) - // graph.getStylesheet().getDefaultEdgeStyle()['edgeStyle'] = 'orthogonalEdgeStyle'; - /* let mxUtilsGetPortConstraints = mxUtils.getPortConstraints; - mxUtils.getPortConstraints = function(terminal, edge, source, defaultValue) - { - let key = (source) ? mxConstants.STYLE_SOURCE_PORT : mxConstants.STYLE_TARGET_PORT; - let id = edge.style[key]; - - let port = terminal.shape.getPorts()[id]; - - // TODO: Add support for rotation, direction - if (port != null) - { - return port.constraint; - } - - return mxUtilsGetPortConstraints.apply(this, arguments); - }; - // Connect preview - graph.connectionHandler.createEdgeState = function(me) - { - let edge = graph.createEdge(null, null, null, null, null); - - return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge)); - }; - */ - } -} - -export default PortRefs; diff --git a/src/pages/connections/index.js b/src/pages/connections/index.js deleted file mode 100644 index eb2aec2ab..000000000 --- a/src/pages/connections/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import Anchors from './Anchors'; -import EdgeTolerance from './EdgeTolerance'; -import FixedPoints from './FixedPoints'; -import HelloPort from './HelloPort'; -import Orthogonal from './Orthogonal'; -import PortRefs from './PortRefs'; -import PageTabs from '../PageTabs'; - -export default function _Connections() { - return ( - - } /> - } /> - } /> - } /> - } /> - } /> - - ); -} diff --git a/src/pages/copy_examples_to_json.py b/src/pages/copy_examples_to_json.py deleted file mode 100644 index dbb0f03dc..000000000 --- a/src/pages/copy_examples_to_json.py +++ /dev/null @@ -1,10 +0,0 @@ -import json -import pathlib - -out = {} -for js_path in pathlib.Path('').rglob('*.js'): - print(js_path) - out[js_path.name.rpartition('.')[0]] = js_path.read_text(encoding='utf-8') - -with open("examplesListing.json", "w", encoding="utf-8") as f: - f.write(json.dumps(out, ensure_ascii=False, indent=2)) diff --git a/src/pages/dnd_copypaste/Clipboard.js b/src/pages/dnd_copypaste/Clipboard.js deleted file mode 100644 index cc2524dc1..000000000 --- a/src/pages/dnd_copypaste/Clipboard.js +++ /dev/null @@ -1,357 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxClipboard from '../../mxgraph/util/storage/mxClipboard'; -import mxClient from '../../mxgraph/mxClient'; -import mxCodec from '../../mxgraph/serialization/mxCodec'; -import mxGraphModel from '../../mxgraph/view/graph/mxGraphModel'; - -class Clipboard extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Clipboard

    - This example demonstrates using the clipboard for providing cross-tab - and cross-browser copy and paste. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - }; - - componentDidMount() { - // Disables the built-in context menu - mxEvent.disableContextMenu(this.el); - - // Creates the graph inside the given this.el - const graph = new mxGraph(this.el); - - // Public helper method for shared clipboard. - mxClipboard.cellsToString = function(cells) { - const codec = new mxCodec(); - const model = new mxGraphModel(); - const parent = model.getRoot().getChildAt(0); - - for (let i = 0; i < cells.length; i++) { - model.add(parent, cells[i]); - } - - return mxUtils.getXml(codec.encode(model)); - }; - - // Focused but invisible textarea during control or meta key events - const textInput = document.createElement('textarea'); - mxUtils.setOpacity(textInput, 0); - textInput.style.width = '1px'; - textInput.style.height = '1px'; - let restoreFocus = false; - const gs = graph.gridSize; - let lastPaste = null; - let dx = 0; - let dy = 0; - - // Workaround for no copy event in IE/FF if empty - textInput.value = ' '; - - // Shows a textare when control/cmd is pressed to handle native clipboard actions - mxEvent.addListener(document, 'keydown', function(evt) { - // No dialog visible - const source = mxEvent.getSource(evt); - - if ( - graph.isEnabled() && - !graph.isMouseDown && - !graph.isEditing() && - source.nodeName !== 'INPUT' - ) { - if ( - evt.keyCode === 224 /* FF */ || - (!mxClient.IS_MAC && evt.keyCode === 17) /* Control */ || - (mxClient.IS_MAC && - (evt.keyCode === 91 || evt.keyCode === 93)) /* Left/Right Meta */ - ) { - // Cannot use parentNode for check in IE - if (!restoreFocus) { - // Avoid autoscroll but allow handling of events - textInput.style.position = 'absolute'; - textInput.style.left = `${graph.container.scrollLeft + 10}px`; - textInput.style.top = `${graph.container.scrollTop + 10}px`; - graph.container.appendChild(textInput); - - restoreFocus = true; - textInput.focus(); - textInput.select(); - } - } - } - }); - - // Restores focus on graph this.el and removes text input from DOM - mxEvent.addListener(document, 'keyup', function(evt) { - if ( - restoreFocus && - (evt.keyCode === 224 /* FF */ || - evt.keyCode === 17 /* Control */ || - evt.keyCode === 91 || - evt.keyCode === 93) /* Meta */ - ) { - restoreFocus = false; - - if (!graph.isEditing()) { - graph.container.focus(); - } - - textInput.parentNode.removeChild(textInput); - } - }); - - // Inserts the XML for the given cells into the text input for copy - const copyCells = function(graph, cells) { - if (cells.length > 0) { - const clones = graph.cloneCells(cells); - - // Checks for orphaned relative children and makes absolute - for (let i = 0; i < clones.length; i++) { - const state = graph.view.getState(cells[i]); - - if (state != null) { - const geo = graph.getCellGeometry(clones[i]); - - if (geo != null && geo.relative) { - geo.relative = false; - geo.x = state.x / state.view.scale - state.view.translate.x; - geo.y = state.y / state.view.scale - state.view.translate.y; - } - } - } - - textInput.value = mxClipboard.cellsToString(clones); - } - - textInput.select(); - lastPaste = textInput.value; - }; - - // Handles copy event by putting XML for current selection into text input - mxEvent.addListener( - textInput, - 'copy', - mxUtils.bind(this, function(evt) { - if (graph.isEnabled() && !graph.isSelectionEmpty()) { - copyCells( - graph, - mxUtils.sortCells( - graph.model.getTopmostCells(graph.getSelectionCells()) - ) - ); - dx = 0; - dy = 0; - } - }) - ); - - // Handles cut event by removing cells putting XML into text input - mxEvent.addListener( - textInput, - 'cut', - mxUtils.bind(this, function(evt) { - if (graph.isEnabled() && !graph.isSelectionEmpty()) { - copyCells(graph, graph.removeCells()); - dx = -gs; - dy = -gs; - } - }) - ); - - // Merges XML into existing graph and layers - const importXml = function(xml, dx, dy) { - dx = dx != null ? dx : 0; - dy = dy != null ? dy : 0; - let cells = []; - - try { - const doc = mxUtils.parseXml(xml); - const node = doc.documentElement; - - if (node != null) { - const model = new mxGraphModel(); - const codec = new mxCodec(node.ownerDocument); - codec.decode(node, model); - - const childCount = model.getRoot().getChildCount(); - const targetChildCount = graph.model.getRoot().getChildCount(); - - // Merges existing layers and adds new layers - graph.model.beginUpdate(); - try { - for (let i = 0; i < childCount; i++) { - let parent = model.getRoot().getChildAt(i); - - // Adds cells to existing layers if not locked - if (targetChildCount > i) { - // Inserts into active layer if only one layer is being pasted - const target = - childCount === 1 - ? graph.getDefaultParent() - : graph.model.getRoot().getChildAt(i); - - if (!graph.isCellLocked(target)) { - const children = parent.getChildren(); - cells = cells.concat( - graph.importCells(children, dx, dy, target) - ); - } - } else { - // Delta is non cascading, needs separate move for layers - parent = graph.importCells( - [parent], - 0, - 0, - graph.model.getRoot() - )[0]; - const children = parent.getChildren(); - graph.moveCells(children, dx, dy); - cells = cells.concat(children); - } - } - } finally { - graph.model.endUpdate(); - } - } - } catch (e) { - alert(e); - throw e; - } - - return cells; - }; - - // Parses and inserts XML into graph - const pasteText = function(text) { - const xml = mxUtils.trim(text); - const x = - graph.container.scrollLeft / graph.view.scale - graph.view.translate.x; - const y = - graph.container.scrollTop / graph.view.scale - graph.view.translate.y; - - if (xml.length > 0) { - if (lastPaste !== xml) { - lastPaste = xml; - dx = 0; - dy = 0; - } else { - dx += gs; - dy += gs; - } - - // Standard paste via control-v - if (xml.substring(0, 14) === '') { - graph.setSelectionCells(importXml(xml, dx, dy)); - graph.scrollCellToVisible(graph.getSelectionCell()); - } - } - }; - - // Function to fetch text from paste events - const extractGraphModelFromEvent = function(evt) { - let data = null; - - if (evt != null) { - const provider = - evt.dataTransfer != null ? evt.dataTransfer : evt.clipboardData; - - if (provider != null) { - data = - mxUtils.indexOf(provider.types, 'text/html') >= 0 - ? provider.getData('text/html') - : null; - - if ( - mxUtils.indexOf( - provider.types, - 'text/plain' && (data == null || data.length === 0) - ) - ) { - data = provider.getData('text/plain'); - } - } - } - - return data; - }; - - // Handles paste event by parsing and inserting XML - mxEvent.addListener(textInput, 'paste', function(evt) { - // Clears existing contents before paste - should not be needed - // because all text is selected, but doesn't hurt since the - // actual pasting of the new text is delayed in all cases. - textInput.value = ''; - - if (graph.isEnabled()) { - const xml = extractGraphModelFromEvent(evt); - - if (xml != null && xml.length > 0) { - pasteText(xml); - } else { - // Timeout for new value to appear - window.setTimeout( - mxUtils.bind(this, function() { - pasteText(textInput.value); - }), - 0 - ); - } - } - - textInput.select(); - }); - - // 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 }); - }); - }; -} - -export default Clipboard; diff --git a/src/pages/dnd_copypaste/DragSource.js b/src/pages/dnd_copypaste/DragSource.js deleted file mode 100644 index af80bfc9c..000000000 --- a/src/pages/dnd_copypaste/DragSource.js +++ /dev/null @@ -1,225 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxCell from '../../mxgraph/view/cell/mxCell'; -import mxGeometry from '../../mxgraph/util/datatypes/mxGeometry'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxDragSource from '../../mxgraph/util/drag_pan/mxDragSource'; -import mxGraphHandler from '../../mxgraph/handler/mxGraphHandler'; -import mxGuide from '../../mxgraph/util/mxGuide'; -import mxEdgeHandler from '../../mxgraph/handler/mxEdgeHandler'; - -class DragSource extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Dragsource

    - This example demonstrates using one drag source for multiple graphs and - changing the drag icon. -
    { - this.el = el; - }} - style={{}} - /> - - ); - } - - componentDidMount() { - class MyCustomGuide extends mxGuide { - isEnabledForEvent(evt) { - // Alt disables guides - return !mxEvent.isAltDown(evt); - } - } - - class MyCustomGraphHandler extends mxGraphHandler { - // Enables guides - guidesEnabled = 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 = []; - - // Creates the graph inside the given container - for (let i = 0; i < 2; i++) { - const container = document.createElement('div'); - container.style.overflow = 'hidden'; - container.style.position = 'relative'; - container.style.width = '321px'; - container.style.height = '241px'; - container.style.background = "url('editors/images/grid.gif')"; - container.style.cursor = 'default'; - - this.el.appendChild(container); - - const graph = new MyCustomGraph(container); - graph.gridSize = 30; - - // 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, - }); - }); - - graphs.push(graph); - } - - // Returns the graph under the mouse - const graphF = evt => { - const x = mxEvent.getClientX(evt); - const y = mxEvent.getClientY(evt); - const elt = document.elementFromPoint(x, y); - - for (const graph of graphs) { - if (mxUtils.isAncestorNode(graph.container, elt)) { - return graph; - } - } - - return null; - }; - - // Inserts a cell at the given location - 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); - - if (cells != null && cells.length > 0) { - graph.scrollCellToVisible(cells[0]); - graph.setSelectionCells(cells); - } - }; - - // Creates a DOM node that acts as the drag source - const img = mxUtils.createImage('images/icons48/gear.png'); - img.style.width = '48px'; - img.style.height = '48px'; - this.el.appendChild(img); - - // Creates the element that is being for the actual preview. - const dragElt = document.createElement('div'); - dragElt.style.border = 'dashed black 1px'; - dragElt.style.width = '120px'; - dragElt.style.height = '40px'; - - // Drag source is configured to use dragElt for preview and as drag icon - // if scalePreview (last) argument is true. Dx and dy are null to force - // the use of the defaults. Note that dx and dy are only used for the - // drag icon but not for the preview. - const ds = mxUtils.makeDraggable( - img, - graphF, - funct, - dragElt, - null, - null, - 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 = () => { - return graphs[0].graphHandler.guidesEnabled; - }; - - // Restores original drag icon while outside of graph - ds.createDragElement = mxDragSource.prototype.createDragElement; - } - - // NOTE: To enable cross-document DnD (eg. between frames), - // the following methods need to be overridden: - /* mxDragSourceMouseUp = mxDragSource.prototype.mouseUp; -mxDragSource.prototype.mouseUp = function(evt) -{ - let doc = this.element.ownerDocument; - - if (doc != document) - { - let mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - - if (this.mouseUpHandler != null) - { - mxEvent.removeListener(doc, mu, this.mouseUpHandler); - } - } - - mxDragSourceMouseUp.apply(this, arguments); -}; */ - - /* mxDragSourceMouseDown = mxDragSource.prototype.mouseDown; -mxDragSource.prototype.mouseDown = function(evt) -{ - if (this.enabled && !mxEvent.isConsumed(evt)) - { - mxDragSourceMouseDown.apply(this, arguments); - let doc = this.element.ownerDocument; - - if (doc != document) - { - let mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup'; - mxEvent.addListener(doc, mu, this.mouseUpHandler); - } - } -}; */ -} - -export default DragSource; diff --git a/src/pages/dnd_copypaste/Drop.js b/src/pages/dnd_copypaste/Drop.js deleted file mode 100644 index 6de89beca..000000000 --- a/src/pages/dnd_copypaste/Drop.js +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxClient from '../../mxgraph/mxClient'; - -class Drop extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Drop

    - This example demonstrates handling native drag and drop of images - (requires modern browser). -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '441px', - background: `url('editors/images/grid.gif')`, - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Checks if the browser is supported - const fileSupport = - window.File != null && - window.FileReader != null && - window.FileList != null; - - if (!fileSupport || !mxClient.isBrowserSupported()) { - // Displays an error message if the browser is not supported. - mxUtils.error('Browser is not supported!', 200, false); - } else { - // Disables the built-in context menu - mxEvent.disableContextMenu(this.el); - - // Creates the graph inside the given this.el - const graph = new mxGraph(this.el); - - // Enables rubberband selection - new mxRubberband(graph); - - mxEvent.addListener(this.el, 'dragover', function(evt) { - if (graph.isEnabled()) { - evt.stopPropagation(); - evt.preventDefault(); - } - }); - - mxEvent.addListener(this.el, 'drop', evt => { - if (graph.isEnabled()) { - evt.stopPropagation(); - evt.preventDefault(); - - // Gets drop location point for vertex - const pt = mxUtils.convertPoint( - graph.container, - mxEvent.getClientX(evt), - mxEvent.getClientY(evt) - ); - const tr = graph.view.translate; - const { scale } = graph.view; - const x = pt.x / scale - tr.x; - const y = pt.y / scale - tr.y; - - // Converts local images to data urls - const filesArray = evt.dataTransfer.files; - - for (let i = 0; i < filesArray.length; i++) { - this.handleDrop(graph, filesArray[i], x + i * 10, y + i * 10); - } - } - }); - } - } - - handleDrop(graph, file, x, y) { - // Handles each file as a separate insert for simplicity. - // Use barrier to handle multiple files as a single insert. - - if (file.type.substring(0, 5) === 'image') { - const reader = new FileReader(); - - reader.onload = function(e) { - // Gets size of image for vertex - let data = e.target.result; - - // SVG needs special handling to add viewbox if missing and - // find initial size from SVG attributes (only for IE11) - if (file.type.substring(0, 9) === 'image/svg') { - const comma = data.indexOf(','); - const svgText = atob(data.substring(comma + 1)); - const root = mxUtils.parseXml(svgText); - - // Parses SVG to find width and height - if (root != null) { - const svgs = root.getElementsByTagName('svg'); - - if (svgs.length > 0) { - const svgRoot = svgs[0]; - let w = parseFloat(svgRoot.getAttribute('width')); - let h = parseFloat(svgRoot.getAttribute('height')); - - // Check if viewBox attribute already exists - const vb = svgRoot.getAttribute('viewBox'); - - if (vb == null || vb.length === 0) { - svgRoot.setAttribute('viewBox', `0 0 ${w} ${h}`); - } - // Uses width and height from viewbox for - // missing width and height attributes - else if (Number.isNaN(w) || Number.isNaN(h)) { - const tokens = vb.split(' '); - - if (tokens.length > 3) { - w = parseFloat(tokens[2]); - h = parseFloat(tokens[3]); - } - } - - w = Math.max(1, Math.round(w)); - h = Math.max(1, Math.round(h)); - - data = `data:image/svg+xml,${btoa( - mxUtils.getXml(svgs[0], '\n') - )}`; - graph.insertVertex({ - position: [x, y], - size: [w, h], - style: `shape=image;image=${data};`, - }); - } - } - } else { - const img = new Image(); - - img.onload = () => { - const w = Math.max(1, img.width); - const h = Math.max(1, img.height); - - // Converts format of data url to cell style value for use in vertex - const semi = data.indexOf(';'); - - if (semi > 0) { - data = - data.substring(0, semi) + - data.substring(data.indexOf(',', semi + 1)); - } - - graph.insertVertex({ - position: [x, y], - size: [w, h], - style: `shape=image;image=${data};`, - }); - }; - - img.src = data; - } - }; - - reader.readAsDataURL(file); - } - } -} - -export default Drop; diff --git a/src/pages/dnd_copypaste/index.js b/src/pages/dnd_copypaste/index.js deleted file mode 100644 index ea1efd7b3..000000000 --- a/src/pages/dnd_copypaste/index.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import Clipboard from './Clipboard'; -import DragSource from './DragSource'; -import Drop from './Drop'; -import PageTabs from '../PageTabs'; - -export default function _DnDCopyPaste() { - return ( - - } /> - } /> - } /> - - ); -} diff --git a/src/pages/editing/Editing.js b/src/pages/editing/Editing.js deleted file mode 100644 index 9564f43d9..000000000 --- a/src/pages/editing/Editing.js +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; - -class Editing extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Editing

    - This example demonstrates using the in-place editor trigger to specify - the editing value and write the new value into a specific field of the - user object. Wrapping and DOM nodes as labels are also demonstrated - here. -
    -
    - Double-click the upper/lower half of the cell to edit different fields - of the user object. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '241px', - background: "url('editors/images/grid.gif')", - }} - /> - - ); - } - - componentDidMount() { - class MyCustomGraph extends mxGraph { - getLabel(cell) { - // Returns a HTML representation of the cell where the - // upper half is the first value, lower half is second - // value - - const table = document.createElement('table'); - table.style.height = '100%'; - table.style.width = '100%'; - - const body = document.createElement('tbody'); - const tr1 = document.createElement('tr'); - const td1 = document.createElement('td'); - td1.style.textAlign = 'center'; - td1.style.fontSize = '12px'; - td1.style.color = '#774400'; - mxUtils.write(td1, cell.value.first); - - const tr2 = document.createElement('tr'); - const td2 = document.createElement('td'); - td2.style.textAlign = 'center'; - td2.style.fontSize = '12px'; - td2.style.color = '#774400'; - mxUtils.write(td2, cell.value.second); - - tr1.appendChild(td1); - tr2.appendChild(td2); - body.appendChild(tr1); - body.appendChild(tr2); - table.appendChild(body); - - return table; - } - - getEditingValue(cell, evt) { - // Returns the editing value for the given cell and event - evt.fieldname = this.__getFieldnameForEvent(cell, evt); - return cell.value[evt.fieldname] || ''; - } - - __getFieldnameForEvent(cell, evt) { - // Helper method that returns the fieldname to be used for - // a mouse event - if (evt != null) { - // Finds the relative coordinates inside the cell - const point = mxUtils.convertPoint( - this.container, - mxEvent.getClientX(evt), - mxEvent.getClientY(evt) - ); - const state = this.getView().getState(cell); - - if (state != null) { - point.x -= state.x; - point.y -= state.y; - - // Returns second if mouse in second half of cell - if (point.y > state.height / 2) { - return 'second'; - } - } - } - return 'first'; - } - - labelChanged(cell, newValue, trigger) { - // Sets the new value for the given cell and trigger - const name = trigger != null ? trigger.fieldname : null; - - if (name != null) { - // Clones the user object for correct undo and puts - // the new value in the correct field. - const value = mxUtils.clone(cell.value); - value[name] = newValue; - newValue = value; - - super.labelChanged(cell, newValue, trigger); - } - } - } - - // Creates the graph inside the given container - const graph = new MyCustomGraph(this.el); - graph.setHtmlLabels(true); - - // Adds handling of return and escape keystrokes for editing - const keyHandler = new mxKeyHandler(graph); - - // Sample user objects with 2 fields - const value = {}; - value.first = 'First value'; - value.second = 'Second value'; - - // 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, - position: [100, 60], - size: [120, 80], - style: 'overflow=fill;', - }); - }); - } -} - -export default Editing; diff --git a/src/pages/editing/index.js b/src/pages/editing/index.js deleted file mode 100644 index 7426d674b..000000000 --- a/src/pages/editing/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import Editing from './Editing'; -import PageTabs from '../PageTabs'; - -export default function _Editing() { - return ( - - } /> - - ); -} diff --git a/src/pages/effects/Animation.js b/src/pages/effects/Animation.js deleted file mode 100644 index 39f5c7dc9..000000000 --- a/src/pages/effects/Animation.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2006-2017, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; - -class Animation extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Animation

    - This example demonstrates using SVG animations on edges to visualize the - flow in a pipe. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: 'url("editors/images/grid.gif")', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - const graph = new mxGraph(this.el); - graph.setEnabled(false); - const parent = graph.getDefaultParent(); - - const vertexStyle = - 'shape=cylinder;strokeWidth=2;fillColor=#ffffff;strokeColor=black;' + - 'gradientColor=#a0a0a0;fontColor=black;fontStyle=1;spacingTop=14;'; - - graph.getModel().beginUpdate(); - try { - const v1 = graph.insertVertex({ - parent, - value: 'Pump', - position: [20, 20], - size: [60, 60], - style: vertexStyle, - }); - const v2 = graph.insertVertex({ - parent, - value: 'Tank', - position: [200, 150], - size: [60, 60], - style: vertexStyle, - }); - var e1 = graph.insertEdge({ - parent, - source: v1, - target: v2, - style: - 'strokeWidth=3;endArrow=block;endSize=2;endFill=1;strokeColor=black;rounded=1;', - }); - e1.geometry.points = [new mxPoint(230, 50)]; - graph.orderCells(true, [e1]); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - // Adds animation to edge shape and makes "pipe" visible - const state = graph.view.getState(e1); - state.shape.node - .getElementsByTagName('path')[0] - .removeAttribute('visibility'); - state.shape.node - .getElementsByTagName('path')[0] - .setAttribute('stroke-width', '6'); - state.shape.node - .getElementsByTagName('path')[0] - .setAttribute('stroke', 'lightGray'); - state.shape.node - .getElementsByTagName('path')[1] - .setAttribute('class', 'flow'); - } -} - -export default Animation; diff --git a/src/pages/effects/Morph.js b/src/pages/effects/Morph.js deleted file mode 100644 index ec9a22476..000000000 --- a/src/pages/effects/Morph.js +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxMorphing from '../../mxgraph/util/animate/mxMorphing'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class Morph extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Morph

    - This example demonstrates using mxMorphing for simple cell animations. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Disables the built-in context menu - mxEvent.disableContextMenu(this.el); - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // 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(); - let v1; - var v2; - try { - v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30); - var 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(); - } - - let mult = 1; - - this.el2.appendChild( - mxUtils.button('Morph', function() { - graph.clearSelection(); - - graph.getModel().beginUpdate(); - try { - let geo = graph.getCellGeometry(v1); - geo = geo.clone(); - geo.x += 180 * mult; - graph.getModel().setGeometry(v1, geo); - - geo = graph.getCellGeometry(v2); - geo = geo.clone(); - geo.x -= 180 * mult; - graph.getModel().setGeometry(v2, geo); - } finally { - // Arguments are number of steps, ease and delay - const morph = new mxMorphing(graph, 20, 1.2, 20); - morph.addListener(mxEvent.DONE, function() { - graph.getModel().endUpdate(); - }); - morph.startAnimation(); - } - - mult *= -1; - }) - ); - } -} - -export default Morph; diff --git a/src/pages/effects/Overlays.js b/src/pages/effects/Overlays.js deleted file mode 100644 index 42003331c..000000000 --- a/src/pages/effects/Overlays.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxCellTracker from '../../mxgraph/handler/mxCellTracker'; -import mxCellOverlay from '../../mxgraph/view/cell/mxCellOverlay'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class Overlays extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Overlays

    - This example demonstrates cell highlighting, overlays and handling click - and double click events. See also: events.html for more event handling. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '241px', - background: "url('editors/images/grid.gif')", - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Disables basic selection and cell handling - graph.setEnabled(false); - - // Highlights the vertices when the mouse enters - const highlight = new mxCellTracker(graph, '#00FF00'); - - // Enables tooltips for the overlays - graph.setTooltips(true); - - // Installs a handler for click events in the graph - // that toggles the overlay for the respective cell - graph.addListener(mxEvent.CLICK, (sender, evt) => { - const cell = evt.getProperty('cell'); - - if (cell != null) { - const overlays = graph.getCellOverlays(cell); - - if (overlays == null) { - // Creates a new overlay with an image and a tooltip - const overlay = new mxCellOverlay( - new mxImage('editors/images/overlays/check.png', 16, 16), - 'Overlay tooltip' - ); - - // Installs a handler for clicks on the overlay - overlay.addListener(mxEvent.CLICK, (sender, evt2) => { - mxUtils.alert('Overlay clicked'); - }); - - // Sets the overlay for the cell in the graph - graph.addCellOverlay(cell, overlay); - } else { - graph.removeCellOverlays(cell); - } - } - }); - - // Installs a handler for double click events in the graph - // that shows an alert box - graph.addListener(mxEvent.DOUBLE_CLICK, (sender, evt) => { - const cell = evt.getProperty('cell'); - mxUtils.alert(`Doubleclick: ${cell != null ? 'Cell' : 'Graph'}`); - evt.consume(); - }); - - // 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: '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, - }); - }); - } -} - -export default Overlays; diff --git a/src/pages/effects/index.js b/src/pages/effects/index.js deleted file mode 100644 index a48a341fa..000000000 --- a/src/pages/effects/index.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import Animation from './Animation'; -import Preview from '../Previews'; -import Morph from './Morph'; -import Overlays from './Overlays'; -import PageTabs from '../PageTabs'; - -export default function Effects() { - return ( - - } /> - } /> - } /> - - ); -} diff --git a/src/pages/events/Boundary.js b/src/pages/events/Boundary.js deleted file mode 100644 index a44a06413..000000000 --- a/src/pages/events/Boundary.js +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxGraphHandler from '../../mxgraph/handler/mxGraphHandler'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class Boundary extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Boundary

    - This example demonstrates implementing boundary events in BPMN diagrams. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: 'url("editors/images/grid.gif")', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Disables the built-in context menu - mxEvent.disableContextMenu(this.el); - - class MyCustomGraph extends mxGraph { - // Enables moving of relative children - isCellLocked(cell) { - return false; - } - - // Removes folding icon for relative children - isCellFoldable(cell, collapse) { - const childCount = cell.getChildCount(); - - for (let i = 0; i < childCount; i++) { - const child = cell.getChildAt(i); - const geo = this.getCellGeometry(child); - - if (geo != null && geo.relative) { - return false; - } - } - - return childCount > 0; - } - - // Returns the relative position of the given child - getRelativePosition(state, dx, dy) { - if (state != null) { - const model = graph.getModel(); - const geo = state.cell.getGeometry(); - - if (geo != null && geo.relative && !state.cell.isEdge()) { - const parent = state.cell.getParent(); - - if (parent.isVertex()) { - const pstate = graph.view.getState(parent); - - if (pstate != null) { - const { scale } = graph.view; - let x = state.x + dx; - let y = state.y + dy; - - if (geo.offset != null) { - x -= geo.offset.x * scale; - y -= geo.offset.y * scale; - } - - x = (x - pstate.x) / pstate.width; - y = (y - pstate.y) / pstate.height; - - if (Math.abs(y - 0.5) <= Math.abs((x - 0.5) / 2)) { - x = x > 0.5 ? 1 : 0; - y = Math.min(1, Math.max(0, y)); - } else { - x = Math.min(1, Math.max(0, x)); - y = y > 0.5 ? 1 : 0; - } - - return new mxPoint(x, y); - } - } - } - } - - return null; - } - - // Replaces translation for relative children - translateCell(cell, dx, dy) { - const rel = this.getRelativePosition( - this.view.getState(cell), - dx * graph.view.scale, - dy * graph.view.scale - ); - - if (rel != null) { - let geo = cell.getGeometry(); - - if (geo != null && geo.relative) { - geo = geo.clone(); - geo.x = rel.x; - geo.y = rel.y; - - this.model.setGeometry(cell, geo); - } - } else { - mxGraph.prototype.translateCell.apply(this, arguments); - } - } - } - - // Creates the graph inside the given this.el - const graph = new MyCustomGraph(this.el); - - // Sets the base style for all vertices - const style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_FILLCOLOR] = '#ffffff'; - style[mxConstants.STYLE_STROKECOLOR] = '#000000'; - style[mxConstants.STYLE_STROKEWIDTH] = '2'; - style[mxConstants.STYLE_FONTCOLOR] = '#000000'; - style[mxConstants.STYLE_FONTSIZE] = '12'; - style[mxConstants.STYLE_FONTSTYLE] = 1; - graph.getStylesheet().putDefaultVertexStyle(style); - - // Replaces move preview for relative children - graph.graphHandler.getDelta = function(me) { - const point = mxUtils.convertPoint( - this.graph.container, - me.getX(), - me.getY() - ); - let delta = new mxPoint(point.x - this.first.x, point.y - this.first.y); - - if ( - this.cells != null && - this.cells.length > 0 && - this.cells[0] != null - ) { - const state = this.graph.view.getState(this.cells[0]); - const rel = graph.getRelativePosition(state, delta.x, delta.y); - - if (rel != null) { - const pstate = this.graph.view.getState( - state.cell.getParent() - ); - - if (pstate != null) { - delta = new mxPoint( - pstate.x + pstate.width * rel.x - state.getCenterX(), - pstate.y + pstate.height * rel.y - state.getCenterY() - ); - } - } - } - - return delta; - }; - - // Relative children cannot be removed from parent - graph.graphHandler.shouldRemoveCellsFromParent = function( - parent, - cells, - evt - ) { - return ( - cells.length === 0 && - !cells[0].geometry.relative && - mxGraphHandler.prototype.shouldRemoveCellsFromParent.apply( - this, - arguments - ) - ); - }; - - // 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: 'Process', - position: [60, 60], - size: [90, 40], - }); - - const v2 = graph.insertVertex({ - parent: v1, - value: 'in', - position: [0, 0.5], - size: [20, 20], - style: 'fontSize=9;shape=ellipse;resizable=0;', - }); - v2.geometry.offset = new mxPoint(-10, -10); - v2.geometry.relative = true; - - const v3 = graph.insertVertex({ - parent: v1, - value: 'out', - position: [1, 0.5], - size: [20, 20], - style: 'fontSize=9;shape=ellipse;resizable=0;', - }); - v3.geometry.offset = new mxPoint(-10, -10); - v3.geometry.relative = true; - }); - } -} - -export default Boundary; diff --git a/src/pages/events/Events.js b/src/pages/events/Events.js deleted file mode 100644 index 5001b3bae..000000000 --- a/src/pages/events/Events.js +++ /dev/null @@ -1,187 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; -import mxLayoutManager from '../../mxgraph/view/graph/mxLayoutManager'; -import mxParallelEdgeLayout from '../../mxgraph/layout/mxParallelEdgeLayout'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxClient from '../../mxgraph/mxClient'; - -class Events extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Events

    - Events. This example demonstrates creating a graph container and using - the mxDivResizer to update the size, interaction on the graph, including - marquee selection, custom tooltips, context menu handling and changing - the default menu opacity. It also demonstrates how to use an edgestyle - in the default stylesheet, and handle the doubleclick on the adjustment - point. See also: overlays.html for click event handling. -
    { - this.el = el; - }} - style={{}} - /> - - ); - } - - componentDidMount() { - // Program starts here. Creates a sample graph in the dynamically - // created DOM node called container which is created below. - - class MyCustomConnectionHandler extends mxConnectionHandler { - // Sets the image to be used for creating new connections - connectImage = new mxImage('images/green-dot.gif', 14, 14); - } - - const container = document.createElement('div'); - container.style.overflow = 'hidden'; - container.style.height = '400px'; - container.style.background = 'url("editors/images/grid.gif")'; - - // Disables built-in context menu - mxEvent.disableContextMenu(container); - this.el.appendChild(container); - - class MyCustomGraph extends mxGraph { - alternateEdgeStyle = 'elbow=vertical'; - - getTooltipForCell(cell) { - // Installs a custom tooltip for cells - return 'Doubleclick and right- or shiftclick'; - } - - createConnectionHandler() { - return new MyCustomConnectionHandler(this); - } - } - - // Creates the graph inside the DOM node. - // Optionally you can enable panning, tooltips and connections - // using graph.setPanning(), setTooltips() & setConnectable(). - // To enable rubberband selection and basic keyboard events, - // use new mxRubberband(graph) and new mxKeyHandler(graph). - const graph = new MyCustomGraph(container); - - // Enables tooltips, new connections and panning - graph.setPanning(true); - graph.setTooltips(true); - graph.setConnectable(true); - - // Automatically handle parallel edges - const layout = new mxParallelEdgeLayout(graph); - const layoutMgr = new mxLayoutManager(graph); - - layoutMgr.getLayout = function(cell) { - if (cell.getChildCount() > 0) { - return layout; - } - }; - - // Enables rubberband (marquee) selection and a handler - // for basic keystrokes (eg. return, escape during editing). - const rubberband = new mxRubberband(graph); - const keyHandler = new mxKeyHandler(graph); - - // Changes the default style for edges "in-place" and assigns - // an alternate edge style which is applied in mxGraph.flip - // when the user double clicks on the adjustment control point - // of the edge. The ElbowConnector edge style switches to TopToBottom - // if the horizontal style is true. - const style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - - // Installs a popupmenu handler using local function (see below). - graph.popupMenuHandler.factoryMethod = (menu, cell, evt) => { - return this.createPopupMenu(graph, menu, cell, evt); - }; - - // 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, - 'Doubleclick', - 20, - 20, - 80, - 30 - ); - const v2 = graph.insertVertex( - parent, - null, - 'Right-/Shiftclick', - 200, - 150, - 120, - 30 - ); - const v3 = graph.insertVertex( - parent, - null, - 'Connect/Reconnect', - 200, - 20, - 120, - 30 - ); - const v4 = graph.insertVertex( - parent, - null, - 'Control-Drag', - 20, - 150, - 100, - 30 - ); - const e1 = graph.insertEdge(parent, null, 'Tooltips', v1, v2); - const e2 = graph.insertEdge(parent, null, '', v2, v3); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } - - createPopupMenu(graph, menu, cell, evt) { - // Function to create the entries in the popupmenu - if (cell != null) { - menu.addItem('Cell Item', 'editors/images/image.gif', () => { - mxUtils.alert('MenuItem1'); - }); - } else { - menu.addItem('No-Cell Item', 'editors/images/image.gif', () => { - mxUtils.alert('MenuItem2'); - }); - } - menu.addSeparator(); - menu.addItem('MenuItem3', '../src/images/warning.gif', () => { - mxUtils.alert(`MenuItem3: ${graph.getSelectionCount()} selected`); - }); - } -} - -export default Events; diff --git a/src/pages/events/index.js b/src/pages/events/index.js deleted file mode 100644 index 84dfa3a94..000000000 --- a/src/pages/events/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import Boundary from './Boundary'; -import Preview from '../Previews'; -import Events from './Events'; -import PageTabs from '../PageTabs'; - -export default function _Events() { - return ( - - } /> - } /> - - ); -} diff --git a/src/pages/examplesListing.json b/src/pages/examplesListing.json deleted file mode 100644 index 9323be2be..000000000 --- a/src/pages/examplesListing.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "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

    Morph

    \n This example demonstrates using mxMorphing for simple cell animations.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n let v1;\n var v2;\n try {\n v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n var v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n let mult = 1;\n\n this.el2.appendChild(\n mxUtils.button('Morph', function() {\n graph.clearSelection();\n\n graph.getModel().beginUpdate();\n try {\n let geo = graph.getCellGeometry(v1);\n geo = geo.clone();\n geo.x += 180 * mult;\n graph.getModel().setGeometry(v1, geo);\n\n geo = graph.getCellGeometry(v2);\n geo = geo.clone();\n geo.x -= 180 * mult;\n graph.getModel().setGeometry(v2, geo);\n } finally {\n // Arguments are number of steps, ease and delay\n const morph = new mxMorphing(graph, 20, 1.2, 20);\n morph.addListener(mxEvent.DONE, function() {\n graph.getModel().endUpdate();\n });\n morph.startAnimation();\n }\n\n mult *= -1;\n })\n );\n }\n}\n\nexport default Morph;\n", - "FixedPoints": "/**\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 mxConstraintHandler from '../mxgraph/handler/mxConstraintHandler';\nimport mxConnectionHandler from '../mxgraph/handler/mxConnectionHandler';\nimport mxEdgeHandler from '../mxgraph/handler/mxEdgeHandler';\nimport mxConnectionConstraint from '../mxgraph/view/mxConnectionConstraint';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxCellState from '../mxgraph/view/mxCellState';\n\nclass FixedPoints extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Fixed points

    \n This example demonstrates using fixed connection points for connecting\n edges to vertices.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Snaps to fixed points\n mxConstraintHandler.prototype.intersects = function(\n icon,\n point,\n source,\n existingEdge\n ) {\n return !source || existingEdge || mxUtils.intersects(icon.bounds, point);\n };\n\n // Special case: Snaps source of new connections to fixed points\n // Without a connect preview in connectionHandler.createEdgeState mouseMove\n // and getSourcePerimeterPoint should be overriden by setting sourceConstraint\n // sourceConstraint to null in mouseMove and updating it and returning the\n // nearest point (cp) in getSourcePerimeterPoint (see below)\n const mxConnectionHandlerUpdateEdgeState =\n mxConnectionHandler.prototype.updateEdgeState;\n mxConnectionHandler.prototype.updateEdgeState = function(pt, constraint) {\n if (pt != null && this.previous != null) {\n const constraints = this.graph.getAllConnectionConstraints(\n this.previous\n );\n let nearestConstraint = null;\n let dist = null;\n\n for (let i = 0; i < constraints.length; i++) {\n const cp = this.graph.getConnectionPoint(\n this.previous,\n constraints[i]\n );\n\n if (cp != null) {\n const tmp =\n (cp.x - pt.x) * (cp.x - pt.x) + (cp.y - pt.y) * (cp.y - pt.y);\n\n if (dist == null || tmp < dist) {\n nearestConstraint = constraints[i];\n dist = tmp;\n }\n }\n }\n\n if (nearestConstraint != null) {\n this.sourceConstraint = nearestConstraint;\n }\n\n // In case the edge style must be changed during the preview:\n // this.edgeState.style['edgeStyle'] = 'orthogonalEdgeStyle';\n // And to use the new edge style in the new edge inserted into the graph,\n // update the cell style as follows:\n // this.edgeState.cell.style = mxUtils.setStyle(this.edgeState.cell.style, 'edgeStyle', this.edgeState.style['edgeStyle']);\n }\n\n mxConnectionHandlerUpdateEdgeState.apply(this, arguments);\n };\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setConnectable(true);\n\n // graph.connectionHandler.connectImage = new mxImage('images/connector.gif', 16, 16);\n\n // Disables floating connections (only use with no connect image)\n if (graph.connectionHandler.connectImage == null) {\n graph.connectionHandler.isConnectableCell = function(cell) {\n return false;\n };\n mxEdgeHandler.prototype.isConnectableCell = function(cell) {\n return graph.connectionHandler.isConnectableCell(cell);\n };\n }\n\n graph.getAllConnectionConstraints = function(terminal) {\n if (terminal != null && this.model.isVertex(terminal.cell)) {\n return [\n new mxConnectionConstraint(new mxPoint(0, 0), true),\n new mxConnectionConstraint(new mxPoint(0.5, 0), true),\n new mxConnectionConstraint(new mxPoint(1, 0), true),\n new mxConnectionConstraint(new mxPoint(0, 0.5), true),\n new mxConnectionConstraint(new mxPoint(1, 0.5), true),\n new mxConnectionConstraint(new mxPoint(0, 1), true),\n new mxConnectionConstraint(new mxPoint(0.5, 1), true),\n new mxConnectionConstraint(new mxPoint(1, 1), true),\n ];\n }\n\n return null;\n };\n\n // Connect preview\n graph.connectionHandler.createEdgeState = function(me) {\n const edge = graph.createEdge(\n null,\n null,\n null,\n null,\n null,\n 'edgeStyle=orthogonalEdgeStyle'\n );\n\n return new mxCellState(\n this.graph.view,\n edge,\n this.graph.getCellStyle(edge)\n );\n };\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(\n parent,\n null,\n 'Hello,',\n 20,\n 20,\n 80,\n 60,\n 'shape=triangle;perimeter=trianglePerimeter'\n );\n const v2 = graph.insertVertex(\n parent,\n null,\n 'World!',\n 200,\n 150,\n 80,\n 60,\n 'shape=ellipse;perimeter=ellipsePerimeter'\n );\n const v3 = graph.insertVertex(parent, null, 'Hello,', 200, 20, 80, 30);\n const e1 = graph.insertEdge(\n parent,\n null,\n '',\n v1,\n v2,\n 'edgeStyle=elbowEdgeStyle;elbow=horizontal;' +\n 'exitX=0.5;exitY=1;exitPerimeter=1;entryX=0;entryY=0;entryPerimeter=1;'\n );\n const e2 = graph.insertEdge(\n parent,\n null,\n '',\n v3,\n v2,\n 'edgeStyle=elbowEdgeStyle;elbow=horizontal;orthogonal=0;' +\n 'entryX=0;entryY=0;entryPerimeter=1;'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n // Use this code to snap the source point for new connections without a connect preview,\n // ie. without an overridden graph.connectionHandler.createEdgeState\n /*\n let mxConnectionHandlerMouseMove = mxConnectionHandler.prototype.mouseMove;\n mxConnectionHandler.prototype.mouseMove = function(sender, me)\n {\n this.sourceConstraint = null;\n\n mxConnectionHandlerMouseMove.apply(this, arguments);\n };\n\n let mxConnectionHandlerGetSourcePerimeterPoint = mxConnectionHandler.prototype.getSourcePerimeterPoint;\n mxConnectionHandler.prototype.getSourcePerimeterPoint = function(state, pt, me)\n {\n let result = null;\n\n if (this.previous != null && pt != null)\n {\n let constraints = this.graph.getAllConnectionConstraints(this.previous);\n let nearestConstraint = null;\n let nearest = null;\n let dist = null;\n\n for (let i = 0; i < constraints.length; i++)\n {\n let cp = this.graph.getConnectionPoint(this.previous, constraints[i]);\n\n if (cp != null)\n {\n let tmp = (cp.x - pt.x) * (cp.x - pt.x) + (cp.y - pt.y) * (cp.y - pt.y);\n\n if (dist == null || tmp < dist)\n {\n nearestConstraint = constraints[i];\n nearest = cp;\n dist = tmp;\n }\n }\n }\n\n if (nearestConstraint != null)\n {\n this.sourceConstraint = nearestConstraint;\n result = nearest;\n }\n }\n\n if (result == null)\n {\n result = mxConnectionHandlerGetSourcePerimeterPoint.apply(this, arguments);\n }\n\n return result;\n };\n */\n };\n}\n\nexport default FixedPoints;\n", - "FileIO": "/**\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 mxCellTracker from '../mxgraph/handler/mxCellTracker';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxFastOrganicLayout from '../mxgraph/layout/mxFastOrganicLayout';\nimport mxEventObject from '../mxgraph/util/mxEventObject';\nimport mxCodec from '../mxgraph/io/mxCodec';\nimport mxPerimeter from '../mxgraph/view/mxPerimeter';\nimport mxClient from '../mxgraph/mxClient';\n\nclass FileIO extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    File I/O

    \n This example demonstrates reading an XML file, writing a custom parser,\n applying an automatic layout and defining a 2-way edge.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'auto',\n height: '80vh',\n borderTop: 'gray 1px solid',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Program starts here. Creates a sample graph in the\n // DOM node with the specified ID. This function is invoked\n // from the onLoad event handler of the document (see below).\n function main(container) {\n // Checks if browser is supported\n if (!mxClient.isBrowserSupported()) {\n // Displays an error message if the browser is\n // not supported.\n mxUtils.error('Browser is not supported!', 200, false);\n } else {\n // Creates the graph inside the given container\n const graph = new mxGraph(container);\n\n graph.setEnabled(false);\n graph.setPanning(true);\n graph.setTooltips(true);\n graph.panningHandler.useLeftButtonForPanning = true;\n\n // Adds a highlight on the cell under the mousepointer\n new mxCellTracker(graph);\n\n // Changes the default vertex style in-place\n let style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ROUNDED;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_PERIMETER_SPACING] = 4;\n style[mxConstants.STYLE_SHADOW] = true;\n\n style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white';\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_CLASSIC;\n graph.getStylesheet().putCellStyle('2way', style);\n\n graph.isHtmlLabel = function(cell) {\n return true;\n };\n\n // Larger grid size yields cleaner layout result\n graph.gridSize = 20;\n\n // Creates a layout algorithm to be used\n // with the graph\n const layout = new mxFastOrganicLayout(graph);\n\n // Moves stuff wider apart than usual\n layout.forceConstant = 140;\n\n // Adds a button to execute the layout\n this.el2.appendChild(\n mxUtils.button('Arrange', function(evt) {\n const parent = graph.getDefaultParent();\n layout.execute(parent);\n })\n );\n\n // Load cells and layouts the graph\n graph.getModel().beginUpdate();\n try {\n // Loads the custom file format (TXT file)\n parse(graph, 'fileio.txt');\n\n // Loads the mxGraph file format (XML file)\n // read(graph, 'fileio.xml');\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Executes the layout\n layout.execute(parent);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n graph.dblClick = function(evt, cell) {\n const mxe = new mxEventObject(\n mxEvent.DOUBLE_CLICK,\n 'event',\n evt,\n 'cell',\n cell\n );\n this.fireEvent(mxe);\n\n if (\n this.isEnabled() &&\n !mxEvent.isConsumed(evt) &&\n !mxe.isConsumed() &&\n cell != null\n ) {\n mxUtils.alert(\n `Show properties for cell ${cell.customId || cell.getId()}`\n );\n }\n };\n }\n }\n\n // Custom parser for simple file format\n function parse(graph, filename) {\n const model = graph.getModel();\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n const req = mxUtils.load(filename);\n const text = req.getText();\n\n const lines = text.split('\\n');\n\n // Creates the lookup table for the vertices\n const vertices = [];\n\n // Parses all lines (vertices must be first in the file)\n graph.getModel().beginUpdate();\n try {\n for (let i = 0; i < lines.length; i++) {\n // Ignores comments (starting with #)\n const colon = lines[i].indexOf(':');\n\n if (lines[i].substring(0, 1) != '#' || colon == -1) {\n const comma = lines[i].indexOf(',');\n const value = lines[i].substring(colon + 2, lines[i].length);\n\n if (comma == -1 || comma > colon) {\n const key = lines[i].substring(0, colon);\n\n if (key.length > 0) {\n vertices[key] = graph.insertVertex(\n parent,\n null,\n value,\n 0,\n 0,\n 80,\n 70\n );\n }\n } else if (comma < colon) {\n // Looks up the vertices in the lookup table\n const source = vertices[lines[i].substring(0, comma)];\n const target = vertices[lines[i].substring(comma + 1, colon)];\n\n if (source != null && target != null) {\n const e = graph.insertEdge(parent, null, value, source, target);\n\n // Uses the special 2-way style for 2-way labels\n if (value.indexOf('2-Way') >= 0) {\n e.style = '2way';\n }\n }\n }\n }\n }\n } finally {\n graph.getModel().endUpdate();\n }\n }\n\n // Parses the mxGraph XML file format\n function read(graph, filename) {\n const req = mxUtils.load(filename);\n const root = req.getDocumentElement();\n const dec = new mxCodec(root.ownerDocument);\n\n dec.decode(root, graph.getModel());\n }\n };\n}\n\nexport default FileIO;\n", - "Grid": "/**\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 mxPoint from '../mxgraph/util/mxPoint';\nimport mxLog from '../mxgraph/util/mxLog';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxGraphView from '../mxgraph/view/mxGraphView';\n\nclass Grid extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Grid

    \n This example demonstrates drawing a grid dynamically using HTML 5\n canvas.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '481px',\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.graphHandler.scaleGrid = true;\n graph.setPanning(true);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n let repaintGrid;\n\n // Create grid dynamically (requires canvas)\n (function() {\n try {\n const canvas = document.createElement('canvas');\n canvas.style.position = 'absolute';\n canvas.style.top = '0px';\n canvas.style.left = '0px';\n canvas.style.zIndex = -1;\n graph.container.appendChild(canvas);\n\n const ctx = canvas.getContext('2d');\n\n // Modify event filtering to accept canvas as container\n const mxGraphViewIsContainerEvent =\n mxGraphView.prototype.isContainerEvent;\n mxGraphView.prototype.isContainerEvent = function(evt) {\n return (\n mxGraphViewIsContainerEvent.apply(this, arguments) ||\n mxEvent.getSource(evt) === canvas\n );\n };\n\n let s = 0;\n let gs = 0;\n let tr = new mxPoint();\n let w = 0;\n let h = 0;\n\n repaintGrid = function() {\n if (ctx != null) {\n const bounds = graph.getGraphBounds();\n const width = Math.max(\n bounds.x + bounds.width,\n graph.container.clientWidth\n );\n const height = Math.max(\n bounds.y + bounds.height,\n graph.container.clientHeight\n );\n const sizeChanged = width !== w || height !== h;\n\n if (\n graph.view.scale !== s ||\n graph.view.translate.x !== tr.x ||\n graph.view.translate.y !== tr.y ||\n gs !== graph.gridSize ||\n sizeChanged\n ) {\n tr = graph.view.translate.clone();\n s = graph.view.scale;\n gs = graph.gridSize;\n w = width;\n h = height;\n\n // Clears the background if required\n if (!sizeChanged) {\n ctx.clearRect(0, 0, w, h);\n } else {\n canvas.setAttribute('width', w);\n canvas.setAttribute('height', h);\n }\n\n const tx = tr.x * s;\n const ty = tr.y * s;\n\n // Sets the distance of the grid lines in pixels\n const minStepping = graph.gridSize;\n let stepping = minStepping * s;\n\n if (stepping < minStepping) {\n const count =\n Math.round(Math.ceil(minStepping / stepping) / 2) * 2;\n stepping = count * stepping;\n }\n\n const xs = Math.floor((0 - tx) / stepping) * stepping + tx;\n let xe = Math.ceil(w / stepping) * stepping;\n const ys = Math.floor((0 - ty) / stepping) * stepping + ty;\n let ye = Math.ceil(h / stepping) * stepping;\n\n xe += Math.ceil(stepping);\n ye += Math.ceil(stepping);\n\n const ixs = Math.round(xs);\n const ixe = Math.round(xe);\n const iys = Math.round(ys);\n const iye = Math.round(ye);\n\n // Draws the actual grid\n ctx.strokeStyle = '#f6f6f6';\n ctx.beginPath();\n\n for (let x = xs; x <= xe; x += stepping) {\n x = Math.round((x - tx) / stepping) * stepping + tx;\n const ix = Math.round(x);\n\n ctx.moveTo(ix + 0.5, iys + 0.5);\n ctx.lineTo(ix + 0.5, iye + 0.5);\n }\n\n for (let y = ys; y <= ye; y += stepping) {\n y = Math.round((y - ty) / stepping) * stepping + ty;\n const iy = Math.round(y);\n\n ctx.moveTo(ixs + 0.5, iy + 0.5);\n ctx.lineTo(ixe + 0.5, iy + 0.5);\n }\n\n ctx.closePath();\n ctx.stroke();\n }\n }\n };\n } catch (e) {\n mxLog.show();\n mxLog.debug('Using background image');\n\n this.el.style.backgroundImage = \"url('editors/images/grid.gif')\";\n }\n\n const mxGraphViewValidateBackground =\n mxGraphView.prototype.validateBackground;\n mxGraphView.prototype.validateBackground = function() {\n mxGraphViewValidateBackground.apply(this, arguments);\n repaintGrid();\n };\n })();\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n graph.centerZoom = false;\n\n this.el2.appendChild(\n mxUtils.button('+', function() {\n graph.zoomIn();\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('-', function() {\n graph.zoomOut();\n })\n );\n }\n}\n\nexport default Grid;\n", - "Handles": "/**\n * Copyright (c) 2006-2014, 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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxVertexHandler from '../mxgraph/handler/mxVertexHandler';\nimport mxCellRenderer from '../mxgraph/view/mxCellRenderer';\nimport mxRectangle from '../mxgraph/util/mxRectangle';\nimport mxCylinder from '../mxgraph/shape/mxCylinder';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxHandle from '../mxgraph/handler/mxHandle';\n\nclass Handles extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Handles

    \n This example demonstrates using mxHandle to change custom styles\n interactively.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '441px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n class MyShape extends mxCylinder {\n defaultPos1 = 20;\n\n defaultPos2 = 60;\n\n getLabelBounds(rect) {\n const pos1 =\n mxUtils.getValue(this.style, 'pos1', this.defaultPos1) * this.scale;\n const pos2 =\n mxUtils.getValue(this.style, 'pos2', this.defaultPos2) * this.scale;\n return new mxRectangle(\n rect.x,\n rect.y + pos1,\n rect.width,\n Math.min(rect.height, pos2) - Math.max(0, pos1)\n );\n }\n\n redrawPath(path, x, y, w, h, isForeground) {\n const pos1 = mxUtils.getValue(this.style, 'pos1', this.defaultPos1);\n const pos2 = mxUtils.getValue(this.style, 'pos2', this.defaultPos2);\n\n if (isForeground) {\n if (pos1 < h) {\n path.moveTo(0, pos1);\n path.lineTo(w, pos1);\n }\n\n if (pos2 < h) {\n path.moveTo(0, pos2);\n path.lineTo(w, pos2);\n }\n } else {\n path.rect(0, 0, w, h);\n }\n }\n }\n mxCellRenderer.registerShape('myShape', MyShape);\n\n class MyCustomVertexHandler extends mxVertexHandler {\n livePreview = true;\n\n rotationEnabled = true;\n\n createCustomHandles() {\n if (this.state.style.shape === 'myShape') {\n // Implements the handle for the first divider\n const firstHandle = new mxHandle(this.state);\n\n firstHandle.getPosition = function(bounds) {\n const pos2 = Math.max(\n 0,\n Math.min(\n bounds.height,\n parseFloat(\n mxUtils.getValue(\n this.state.style,\n 'pos2',\n MyShape.prototype.defaultPos2\n )\n )\n )\n );\n const pos1 = Math.max(\n 0,\n Math.min(\n pos2,\n parseFloat(\n mxUtils.getValue(\n this.state.style,\n 'pos1',\n MyShape.prototype.defaultPos1\n )\n )\n )\n );\n\n return new mxPoint(bounds.getCenterX(), bounds.y + pos1);\n };\n\n firstHandle.setPosition = function(bounds, pt) {\n const pos2 = Math.max(\n 0,\n Math.min(\n bounds.height,\n parseFloat(\n mxUtils.getValue(\n this.state.style,\n 'pos2',\n MyShape.prototype.defaultPos2\n )\n )\n )\n );\n\n this.state.style.pos1 = Math.round(\n Math.max(0, Math.min(pos2, pt.y - bounds.y))\n );\n };\n\n firstHandle.execute = function() {\n this.copyStyle('pos1');\n };\n\n firstHandle.ignoreGrid = true;\n\n // Implements the handle for the second divider\n const secondHandle = new mxHandle(this.state);\n\n secondHandle.getPosition = function(bounds) {\n const pos1 = Math.max(\n 0,\n Math.min(\n bounds.height,\n parseFloat(\n mxUtils.getValue(\n this.state.style,\n 'pos1',\n MyShape.prototype.defaultPos1\n )\n )\n )\n );\n const pos2 = Math.max(\n pos1,\n Math.min(\n bounds.height,\n parseFloat(\n mxUtils.getValue(\n this.state.style,\n 'pos2',\n MyShape.prototype.defaultPos2\n )\n )\n )\n );\n\n return new mxPoint(bounds.getCenterX(), bounds.y + pos2);\n };\n\n secondHandle.setPosition = function(bounds, pt) {\n const pos1 = Math.max(\n 0,\n Math.min(\n bounds.height,\n parseFloat(\n mxUtils.getValue(\n this.state.style,\n 'pos1',\n MyShape.prototype.defaultPos1\n )\n )\n )\n );\n\n this.state.style.pos2 = Math.round(\n Math.max(pos1, Math.min(bounds.height, pt.y - bounds.y))\n );\n };\n\n secondHandle.execute = function() {\n this.copyStyle('pos2');\n };\n\n secondHandle.ignoreGrid = true;\n\n return [firstHandle, secondHandle];\n }\n\n return null;\n }\n }\n\n class MyCustomGraph extends mxGraph {\n createVertexHandler(state) {\n return new MyCustomVertexHandler(state);\n }\n }\n\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given container\n const graph = new MyCustomGraph(this.el);\n graph.setCellsCloneable(true);\n graph.setHtmlLabels(true);\n graph.setPanning(true);\n graph.centerZoom = false;\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(\n parent,\n null,\n 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n 20,\n 20,\n 240,\n 120,\n 'shape=myShape;whiteSpace=wrap;overflow=hidden;pos1=30;pos2=80;'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n this.el2.appendChild(\n mxUtils.button('+', function() {\n graph.zoomIn();\n })\n );\n this.el2.appendChild(\n mxUtils.button('-', function() {\n graph.zoomOut();\n })\n );\n }\n}\n\nexport default Handles;\n", - "Windows": "/**\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 mxLog from '../mxgraph/util/mxLog';\nimport mxWindow from '../mxgraph/util/mxWindow';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\n\nclass Windows extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Windows

    \n This example demonstrates using the mxWindow class for displaying\n windows.\n {\n this.el = el;\n }}\n style={{\n overflow: 'auto',\n position: 'relative',\n height: '500px',\n background: 'lightyellow',\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Note that we're using the container scrollbars for the graph so that the\n // container extends to the parent div inside the window\n let wnd = new mxWindow(\n 'Scrollable, resizable, given height',\n this.el,\n 50,\n 50,\n 220,\n 224,\n true,\n true\n );\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Adds rubberband selection and keystrokes\n graph.setTooltips(true);\n graph.setPanning(true);\n const rubberband = new mxRubberband(graph);\n new mxKeyHandler(graph);\n\n mxEvent.disableContextMenu(this.el);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n wnd.setMaximizable(true);\n wnd.setResizable(true);\n wnd.setVisible(true);\n\n const lorem =\n 'Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ';\n let content = document.createElement('div');\n mxUtils.write(content, lorem + lorem + lorem);\n\n wnd = new mxWindow(\n 'Scrollable, resizable, auto height',\n content,\n 300,\n 50,\n 200,\n null,\n true,\n true\n );\n wnd.setMaximizable(true);\n wnd.setScrollable(true);\n wnd.setResizable(true);\n wnd.setVisible(true);\n\n content = content.cloneNode(true);\n content.style.width = '400px';\n\n wnd = new mxWindow(\n 'Scrollable, resizable, fixed content',\n content,\n 520,\n 50,\n 220,\n 200,\n true,\n true\n );\n wnd.setMaximizable(true);\n wnd.setScrollable(true);\n wnd.setResizable(true);\n wnd.setVisible(true);\n\n mxLog.show();\n }\n}\n\nexport default Windows;\n", - "Template": "/**\n * Copyright (c) 2006-2013, JGraph Ltd\n \n Template. This is used as a template HTML file by the\n backends to demonstrate the deployment of the client with a graph embedded\n in the page as XML data (see graph variable in the onload-handler).\n \n *** THIS FILE MUST BE DEPLOYED BY ONE OF THE BACKENDS! ***\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 mxCodec from '../mxgraph/io/mxCodec';\n\nclass Template extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Hello, World!

    \n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '241px',\n background:\n \"url('/mxgraph/javascript/examples/editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Adds rubberband selection to the graph\n new mxRubberband(graph);\n\n const doc = mxUtils.parseXml(xml);\n const codec = new mxCodec(doc);\n codec.decode(doc.documentElement, graph.getModel());\n }\n}\n\nexport default Template;\n", - "Anchors": "/**\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 mxShape from '../mxgraph/shape/mxShape';\nimport mxConnectionConstraint from '../mxgraph/view/mxConnectionConstraint';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxPolyline from '../mxgraph/shape/mxPolyline';\nimport mxCellState from '../mxgraph/view/mxCellState';\n\nclass Anchors extends React.Component {\n constructor(props) {\n super(props);\n }\n\n componentDidMount() {\n // Overridden to define per-shape connection points\n mxGraph.prototype.getAllConnectionConstraints = function(terminal, source) {\n if (terminal != null && terminal.shape != null) {\n if (terminal.shape.stencil != null) {\n if (terminal.shape.stencil.constraints != null) {\n return terminal.shape.stencil.constraints;\n }\n } else if (terminal.shape.constraints != null) {\n return terminal.shape.constraints;\n }\n }\n return null;\n };\n\n // Defines the default constraints for all shapes\n mxShape.prototype.constraints = [\n new mxConnectionConstraint(new mxPoint(0.25, 0), true),\n new mxConnectionConstraint(new mxPoint(0.5, 0), true),\n new mxConnectionConstraint(new mxPoint(0.75, 0), true),\n new mxConnectionConstraint(new mxPoint(0, 0.25), true),\n new mxConnectionConstraint(new mxPoint(0, 0.5), true),\n new mxConnectionConstraint(new mxPoint(0, 0.75), true),\n new mxConnectionConstraint(new mxPoint(1, 0.25), true),\n new mxConnectionConstraint(new mxPoint(1, 0.5), true),\n new mxConnectionConstraint(new mxPoint(1, 0.75), true),\n new mxConnectionConstraint(new mxPoint(0.25, 1), true),\n new mxConnectionConstraint(new mxPoint(0.5, 1), true),\n new mxConnectionConstraint(new mxPoint(0.75, 1), true),\n ];\n\n // Edges have no connection points\n mxPolyline.prototype.constraints = null;\n\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given this.el\n const graph = new mxGraph(this.el);\n graph.setConnectable(true);\n\n // Enables connect preview for the default edge style\n graph.connectionHandler.createEdgeState = function(me) {\n const edge = graph.createEdge(null, null, null, null, null);\n return new mxCellState(\n this.graph.view,\n edge,\n this.graph.getCellStyle(edge)\n );\n };\n\n // Specifies the default edge style\n graph.getStylesheet().getDefaultEdgeStyle().edgeStyle =\n 'orthogonalEdgeStyle';\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex({\n parent,\n value: 'Hello,',\n position: [20, 20],\n size: [80, 30],\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [200, 150],\n size: [80, 30],\n });\n const e1 = graph.insertEdge({\n parent,\n value: '',\n position: v1,\n size: v2,\n });\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Anchors

    \n This example demonstrates defining fixed connection points for all\n shapes.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: 'url(\"editors/images/grid.gif\")',\n cursor: 'default',\n }}\n />\n \n );\n };\n}\n\nexport default Anchors;\n", - "SecondLabel": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxRectangle from '../mxgraph/util/mxRectangle';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxRectangleShape from '../mxgraph/shape/mxRectangleShape';\nimport mxText from '../mxgraph/shape/mxText';\n\nclass SecondLabel extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Second label

    \n This example demonstrates how to add another string label to vertices.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Simple solution to add additional text to the rectangle shape definition:\n (function() {\n const mxRectangleShapeIsHtmlAllowed =\n mxRectangleShape.prototype.isHtmlAllowed;\n mxRectangleShape.prototype.isHtmlAllowed = function() {\n return (\n mxRectangleShapeIsHtmlAllowed.apply(this, arguments) &&\n this.state == null\n );\n };\n\n const mxRectangleShapePaintForeground =\n mxRectangleShape.prototype.paintForeground;\n mxRectangleShape.prototype.paintForeground = function(c, x, y, w, h) {\n if (\n this.state != null &&\n this.state.cell.geometry != null &&\n !this.state.cell.geometry.relative\n ) {\n c.setFontColor('#a0a0a0');\n c.text(x + 2, y, 0, 0, this.state.cell.id, 'left', 'top');\n }\n\n mxRectangleShapePaintForeground.apply(this, arguments);\n };\n })();\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Disables the folding icon\n graph.isCellFoldable = function(cell) {\n return false;\n };\n\n let secondLabelVisible = true;\n\n // Hook for returning shape number for a given cell\n graph.getSecondLabel = function(cell) {\n if (!this.model.isEdge(cell)) {\n // Possible to return any string here\n return `The ID of this cell is ${cell.id}`;\n }\n\n return null;\n };\n\n let relativeChildVerticesVisible = true;\n\n // Overrides method to hide relative child vertices\n graph.isCellVisible = function(cell) {\n return (\n !this.model.isVertex(cell) ||\n cell.geometry == null ||\n !cell.geometry.relative ||\n cell.geometry.relative == relativeChildVerticesVisible\n );\n };\n\n // Creates the shape for the shape number and puts it into the draw pane\n const { redrawShape } = graph.cellRenderer;\n graph.cellRenderer.redrawShape = function(state, force, rendering) {\n const result = redrawShape.apply(this, arguments);\n\n if (\n result &&\n secondLabelVisible &&\n state.cell.geometry != null &&\n !state.cell.geometry.relative\n ) {\n const secondLabel = graph.getSecondLabel(state.cell);\n\n if (\n secondLabel != null &&\n state.shape != null &&\n state.secondLabel == null\n ) {\n state.secondLabel = new mxText(\n secondLabel,\n new mxRectangle(),\n mxConstants.ALIGN_LEFT,\n mxConstants.ALIGN_BOTTOM\n );\n\n // Styles the label\n state.secondLabel.color = 'black';\n state.secondLabel.family = 'Verdana';\n state.secondLabel.size = 8;\n state.secondLabel.fontStyle = mxConstants.FONT_ITALIC;\n state.secondLabel.background = 'yellow';\n state.secondLabel.border = 'black';\n state.secondLabel.valign = 'bottom';\n state.secondLabel.dialect = state.shape.dialect;\n state.secondLabel.dialect = mxConstants.DIALECT_STRICTHTML;\n state.secondLabel.wrap = true;\n graph.cellRenderer.initializeLabel(state, state.secondLabel);\n }\n }\n\n if (state.secondLabel != null) {\n const scale = graph.getView().getScale();\n const bounds = new mxRectangle(\n state.x + state.width - 8 * scale,\n state.y + 8 * scale,\n 35,\n 0\n );\n state.secondLabel.state = state;\n state.secondLabel.value = graph.getSecondLabel(state.cell);\n state.secondLabel.scale = scale;\n state.secondLabel.bounds = bounds;\n state.secondLabel.redraw();\n }\n\n return result;\n };\n\n // Destroys the shape number\n const { destroy } = graph.cellRenderer;\n graph.cellRenderer.destroy = function(state) {\n destroy.apply(this, arguments);\n\n if (state.secondLabel != null) {\n state.secondLabel.destroy();\n state.secondLabel = null;\n }\n };\n\n graph.cellRenderer.getShapesForState = function(state) {\n return [state.shape, state.text, state.secondLabel, state.control];\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 30, 40, 80, 30);\n // Alternative solution of creating a second label by creating a realtive child vertex\n // with size (0, 0). This will not be selectable and only the label colors can be used\n // for coloring as the actual shape will have zero size.\n const v11 = graph.insertVertex(\n v1,\n null,\n 'World',\n 1,\n 1,\n 0,\n 0,\n 'align=left;verticalAlign=top;labelBackgroundColor=red;labelBorderColor=black',\n true\n );\n v11.geometry.offset = new mxPoint(-8, -8);\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n // Another alternative solution of creating a second label as a relative child vertex\n // but this time with an automatic size so that the cell is actually selectable and\n // the background is painted as a shape.\n const v21 = graph.insertVertex(\n v2,\n null,\n 'World',\n 1,\n 1,\n 0,\n 0,\n 'align=left;verticalAlign=top;fillColor=red;rounded=1;spacingLeft=4;spacingRight=4',\n true\n );\n v21.geometry.offset = new mxPoint(-8, -8);\n graph.updateCellSize(v21);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n // Adds a button to execute the layout\n this.el2.appendChild(\n mxUtils.button('Toggle Child Vertices', function(evt) {\n relativeChildVerticesVisible = !relativeChildVerticesVisible;\n graph.refresh();\n })\n );\n\n // Adds a button to execute the layout\n this.el2.appendChild(\n mxUtils.button('Toggle IDs', function(evt) {\n secondLabelVisible = !secondLabelVisible;\n graph.refresh();\n })\n );\n }\n}\n\nexport default SecondLabel;\n", - "PageBreaks": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxPrintPreview from '../mxgraph/view/mxPrintPreview';\n\nclass PageBreaks extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Pagebreaks

    \n This example demonstrates using the pageBreaksVisible and preferPageSize\n switches and adding headers and footers to print output.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '481px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.view.setScale(0.15);\n graph.pageBreaksVisible = true;\n graph.pageBreakDashed = true;\n graph.preferPageSize = true;\n graph.centerZoom = false;\n graph.setPanning(true);\n\n // Account for the header and footer size in the page format\n const headerSize = 100;\n const footerSize = 100;\n\n // Removes header and footer from page height\n graph.pageFormat.height -= headerSize + footerSize;\n\n // Takes zoom into account for moving cells\n graph.graphHandler.scaleGrid = true;\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 10, 10, 280, 330);\n const v2 = graph.insertVertex(\n parent,\n null,\n 'World!',\n graph.pageFormat.width * graph.pageScale - 280 - 10,\n graph.pageFormat.height * graph.pageScale - 330 - 10,\n 280,\n 330\n );\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n this.el2.appendChild(\n mxUtils.button('Toggle Page Breaks', function(evt) {\n graph.pageBreaksVisible = !graph.pageBreaksVisible;\n graph.sizeDidChange();\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('Zoom In', function(evt) {\n graph.zoomIn();\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('Zoom Out', function(evt) {\n graph.zoomOut();\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('Print', function(evt) {\n // Matches actual printer paper size and avoids blank pages\n const scale = 0.5;\n\n // Applies scale to page\n const pf = mxRectangle.fromRectangle(\n graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT\n );\n pf.width = Math.round(pf.width * scale * graph.pageScale);\n pf.height = Math.round(pf.height * scale * graph.pageScale);\n\n // Finds top left corner of top left page\n const bounds = mxRectangle.fromRectangle(graph.getGraphBounds());\n bounds.x -= graph.view.translate.x * graph.view.scale;\n bounds.y -= graph.view.translate.y * graph.view.scale;\n\n const x0 = Math.floor(bounds.x / pf.width) * pf.width;\n const y0 = Math.floor(bounds.y / pf.height) * pf.height;\n\n const preview = new mxPrintPreview(graph, scale, pf, 0, -x0, -y0);\n preview.marginTop = headerSize * scale * graph.pageScale;\n preview.marginBottom = footerSize * scale * graph.pageScale;\n preview.autoOrigin = false;\n\n const oldRenderPage = preview.renderPage;\n preview.renderPage = function(w, h, x, y, content, pageNumber) {\n const div = oldRenderPage.apply(this, arguments);\n\n const header = document.createElement('div');\n header.style.position = 'absolute';\n header.style.boxSizing = 'border-box';\n header.style.fontFamily = 'Arial,Helvetica';\n header.style.height = `${this.marginTop - 10}px`;\n header.style.textAlign = 'center';\n header.style.verticalAlign = 'middle';\n header.style.marginTop = 'auto';\n header.style.fontSize = '12px';\n header.style.width = '100%';\n\n // Vertical centering for text in header/footer\n header.style.lineHeight = `${this.marginTop - 10}px`;\n\n const footer = header.cloneNode(true);\n\n mxUtils.write(header, `Page ${pageNumber} - Header`);\n header.style.borderBottom = '1px solid gray';\n header.style.top = '0px';\n\n mxUtils.write(footer, `Page ${pageNumber} - Footer`);\n footer.style.borderTop = '1px solid gray';\n footer.style.bottom = '0px';\n\n div.firstChild.appendChild(footer);\n div.firstChild.appendChild(header);\n\n return div;\n };\n\n preview.open();\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('Reset View', function(evt) {\n graph.view.scaleAndTranslate(0.15, 0, 0);\n })\n );\n }\n}\n\nexport default PageBreaks;\n", - "SwimLanes": "/**\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 mxPoint from '../mxgraph/util/mxPoint';\nimport mxStackLayout from '../mxgraph/layout/mxStackLayout';\nimport mxSwimlaneManager from '../mxgraph/view/mxSwimlaneManager';\nimport mxGraphModel from '../mxgraph/model/mxGraphModel';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxPerimeter from '../mxgraph/view/mxPerimeter';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxEditor from '../mxgraph/editor/mxEditor';\nimport mxConnectionHandler from '../mxgraph/handler/mxConnectionHandler';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxLayoutManager from '../mxgraph/view/mxLayoutManager';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\n\nclass SwimLanes extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Swimlanes

    \n This example demonstrates using swimlanes for pools and lanes and adding\n cells and edges between them. This also demonstrates using the stack\n layout as an automatic layout.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '400px',\n border: 'gray dotted 1px',\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Defines an icon for creating new connections in the connection handler.\n // This will automatically disable the highlighting of the source vertex.\n mxConnectionHandler.prototype.connectImage = new mxImage(\n 'images/connector.gif',\n 16,\n 16\n );\n\n // Creates a wrapper editor around a new graph inside\n // the given container using an XML config for the\n // keyboard bindings\n const config = mxUtils\n .load('editors/config/keyhandler-commons.xml')\n .getDocumentElement();\n const editor = new mxEditor(config);\n editor.setGraphContainer(this.el);\n const { graph } = editor;\n const model = graph.getModel();\n\n // Auto-resizes the container\n graph.border = 80;\n graph.getView().translate = new mxPoint(graph.border / 2, graph.border / 2);\n graph.setResizeContainer(true);\n graph.graphHandler.setRemoveCellsFromParent(false);\n\n // Changes the default vertex style in-place\n let style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE;\n style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle';\n style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white';\n style[mxConstants.STYLE_FONTSIZE] = 11;\n style[mxConstants.STYLE_STARTSIZE] = 22;\n style[mxConstants.STYLE_HORIZONTAL] = false;\n style[mxConstants.STYLE_FONTCOLOR] = 'black';\n style[mxConstants.STYLE_STROKECOLOR] = 'black';\n delete style[mxConstants.STYLE_FILLCOLOR];\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;\n style[mxConstants.STYLE_FONTSIZE] = 10;\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_HORIZONTAL] = true;\n style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle';\n delete style[mxConstants.STYLE_STARTSIZE];\n style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'none';\n graph.getStylesheet().putCellStyle('process', style);\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter;\n delete style[mxConstants.STYLE_ROUNDED];\n graph.getStylesheet().putCellStyle('state', style);\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RHOMBUS;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter;\n style[mxConstants.STYLE_VERTICAL_ALIGN] = 'top';\n style[mxConstants.STYLE_SPACING_TOP] = 40;\n style[mxConstants.STYLE_SPACING_RIGHT] = 64;\n graph.getStylesheet().putCellStyle('condition', style);\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_DOUBLE_ELLIPSE;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter;\n style[mxConstants.STYLE_SPACING_TOP] = 28;\n style[mxConstants.STYLE_FONTSIZE] = 14;\n style[mxConstants.STYLE_FONTSTYLE] = 1;\n delete style[mxConstants.STYLE_SPACING_RIGHT];\n graph.getStylesheet().putCellStyle('end', style);\n\n style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;\n style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_BLOCK;\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_FONTCOLOR] = 'black';\n style[mxConstants.STYLE_STROKECOLOR] = 'black';\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_DASHED] = true;\n style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_OPEN;\n style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_OVAL;\n graph.getStylesheet().putCellStyle('crossover', style);\n\n // Installs double click on middle control point and\n // changes style of edges between empty and this value\n graph.alternateEdgeStyle = 'elbow=vertical';\n\n // Adds automatic layout and various switches if the\n // graph is enabled\n if (graph.isEnabled()) {\n // Allows new connections but no dangling edges\n graph.setConnectable(true);\n graph.setAllowDanglingEdges(false);\n\n // End-states are no valid sources\n const previousIsValidSource = graph.isValidSource;\n\n graph.isValidSource = function(cell) {\n if (previousIsValidSource.apply(this, arguments)) {\n const style = this.getModel().getStyle(cell);\n\n return (\n style == null || !(style == 'end' || style.indexOf('end') == 0)\n );\n }\n\n return false;\n };\n\n // Start-states are no valid targets, we do not\n // perform a call to the superclass function because\n // this would call isValidSource\n // Note: All states are start states in\n // the example below, so we use the state\n // style below\n graph.isValidTarget = function(cell) {\n const style = this.getModel().getStyle(cell);\n\n return (\n !this.getModel().isEdge(cell) &&\n !this.isSwimlane(cell) &&\n (style == null || !(style == 'state' || style.indexOf('state') == 0))\n );\n };\n\n // Allows dropping cells into new lanes and\n // lanes into new pools, but disallows dropping\n // cells on edges to split edges\n graph.setDropEnabled(true);\n graph.setSplitEnabled(false);\n\n // Returns true for valid drop operations\n graph.isValidDropTarget = function(target, cells, evt) {\n if (this.isSplitEnabled() && this.isSplitTarget(target, cells, evt)) {\n return true;\n }\n\n const model = this.getModel();\n let lane = false;\n let pool = false;\n let cell = false;\n\n // Checks if any lanes or pools are selected\n for (let i = 0; i < cells.length; i++) {\n const tmp = model.getParent(cells[i]);\n lane = lane || this.isPool(tmp);\n pool = pool || this.isPool(cells[i]);\n\n cell = cell || !(lane || pool);\n }\n\n return (\n !pool &&\n cell != lane &&\n ((lane && this.isPool(target)) ||\n (cell && this.isPool(model.getParent(target))))\n );\n };\n\n // Adds new method for identifying a pool\n graph.isPool = function(cell) {\n const model = this.getModel();\n const parent = model.getParent(cell);\n\n return parent != null && model.getParent(parent) == model.getRoot();\n };\n\n // Changes swimlane orientation while collapsed\n graph.model.getStyle = function(cell) {\n let style = mxGraphModel.prototype.getStyle.apply(this, arguments);\n\n if (graph.isCellCollapsed(cell)) {\n if (style != null) {\n style += ';';\n } else {\n style = '';\n }\n\n style += 'horizontal=1;align=left;spacingLeft=14;';\n }\n\n return style;\n };\n\n // Keeps widths on collapse/expand\n const foldingHandler = function(sender, evt) {\n const cells = evt.getProperty('cells');\n\n for (let i = 0; i < cells.length; i++) {\n const geo = graph.model.getGeometry(cells[i]);\n\n if (geo.alternateBounds != null) {\n geo.width = geo.alternateBounds.width;\n }\n }\n };\n\n graph.addListener(mxEvent.FOLD_CELLS, foldingHandler);\n }\n\n // Applies size changes to siblings and parents\n new mxSwimlaneManager(graph);\n\n // Creates a stack depending on the orientation of the swimlane\n const layout = new mxStackLayout(graph, false);\n\n // Makes sure all children fit into the parent swimlane\n layout.resizeParent = true;\n\n // Applies the size to children if parent size changes\n layout.fill = true;\n\n // Only update the size of swimlanes\n layout.isVertexIgnored = function(vertex) {\n return !graph.isSwimlane(vertex);\n };\n\n // Keeps the lanes and pools stacked\n const layoutMgr = new mxLayoutManager(graph);\n\n layoutMgr.getLayout = function(cell) {\n if (\n !model.isEdge(cell) &&\n graph.getModel().getChildCount(cell) > 0 &&\n (model.getParent(cell) == model.getRoot() || graph.isPool(cell))\n ) {\n layout.fill = graph.isPool(cell);\n\n return layout;\n }\n\n return null;\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n model.beginUpdate();\n try {\n const pool1 = graph.insertVertex(parent, null, 'Pool 1', 0, 0, 640, 0);\n pool1.setConnectable(false);\n\n const lane1a = graph.insertVertex(pool1, null, 'Lane A', 0, 0, 640, 110);\n lane1a.setConnectable(false);\n\n const lane1b = graph.insertVertex(pool1, null, 'Lane B', 0, 0, 640, 110);\n lane1b.setConnectable(false);\n\n const pool2 = graph.insertVertex(parent, null, 'Pool 2', 0, 0, 640, 0);\n pool2.setConnectable(false);\n\n const lane2a = graph.insertVertex(pool2, null, 'Lane A', 0, 0, 640, 140);\n lane2a.setConnectable(false);\n\n const lane2b = graph.insertVertex(pool2, null, 'Lane B', 0, 0, 640, 110);\n lane2b.setConnectable(false);\n\n const start1 = graph.insertVertex(\n lane1a,\n null,\n null,\n 40,\n 40,\n 30,\n 30,\n 'state'\n );\n const end1 = graph.insertVertex(\n lane1a,\n null,\n 'A',\n 560,\n 40,\n 30,\n 30,\n 'end'\n );\n\n const step1 = graph.insertVertex(\n lane1a,\n null,\n 'Contact\\nProvider',\n 90,\n 30,\n 80,\n 50,\n 'process'\n );\n const step11 = graph.insertVertex(\n lane1a,\n null,\n 'Complete\\nAppropriate\\nRequest',\n 190,\n 30,\n 80,\n 50,\n 'process'\n );\n const step111 = graph.insertVertex(\n lane1a,\n null,\n 'Receive and\\nAcknowledge',\n 385,\n 30,\n 80,\n 50,\n 'process'\n );\n\n const start2 = graph.insertVertex(\n lane2b,\n null,\n null,\n 40,\n 40,\n 30,\n 30,\n 'state'\n );\n\n const step2 = graph.insertVertex(\n lane2b,\n null,\n 'Receive\\nRequest',\n 90,\n 30,\n 80,\n 50,\n 'process'\n );\n const step22 = graph.insertVertex(\n lane2b,\n null,\n 'Refer to Tap\\nSystems\\nCoordinator',\n 190,\n 30,\n 80,\n 50,\n 'process'\n );\n\n const step3 = graph.insertVertex(\n lane1b,\n null,\n 'Request 1st-\\nGate\\nInformation',\n 190,\n 30,\n 80,\n 50,\n 'process'\n );\n const step33 = graph.insertVertex(\n lane1b,\n null,\n 'Receive 1st-\\nGate\\nInformation',\n 290,\n 30,\n 80,\n 50,\n 'process'\n );\n\n const step4 = graph.insertVertex(\n lane2a,\n null,\n 'Receive and\\nAcknowledge',\n 290,\n 20,\n 80,\n 50,\n 'process'\n );\n const step44 = graph.insertVertex(\n lane2a,\n null,\n 'Contract\\nConstraints?',\n 400,\n 20,\n 50,\n 50,\n 'condition'\n );\n const step444 = graph.insertVertex(\n lane2a,\n null,\n 'Tap for gas\\ndelivery?',\n 480,\n 20,\n 50,\n 50,\n 'condition'\n );\n\n const end2 = graph.insertVertex(\n lane2a,\n null,\n 'B',\n 560,\n 30,\n 30,\n 30,\n 'end'\n );\n const end3 = graph.insertVertex(\n lane2a,\n null,\n 'C',\n 560,\n 84,\n 30,\n 30,\n 'end'\n );\n\n let e = null;\n\n graph.insertEdge(lane1a, null, null, start1, step1);\n graph.insertEdge(lane1a, null, null, step1, step11);\n graph.insertEdge(lane1a, null, null, step11, step111);\n\n graph.insertEdge(lane2b, null, null, start2, step2);\n graph.insertEdge(lane2b, null, null, step2, step22);\n graph.insertEdge(parent, null, null, step22, step3);\n\n graph.insertEdge(lane1b, null, null, step3, step33);\n graph.insertEdge(lane2a, null, null, step4, step44);\n graph.insertEdge(\n lane2a,\n null,\n 'No',\n step44,\n step444,\n 'verticalAlign=bottom'\n );\n graph.insertEdge(\n parent,\n null,\n 'Yes',\n step44,\n step111,\n 'verticalAlign=bottom;horizontal=0;labelBackgroundColor=white;'\n );\n\n graph.insertEdge(\n lane2a,\n null,\n 'Yes',\n step444,\n end2,\n 'verticalAlign=bottom'\n );\n e = graph.insertEdge(\n lane2a,\n null,\n 'No',\n step444,\n end3,\n 'verticalAlign=top'\n );\n e.geometry.points = [\n new mxPoint(\n step444.geometry.x + step444.geometry.width / 2,\n end3.geometry.y + end3.geometry.height / 2\n ),\n ];\n\n graph.insertEdge(parent, null, null, step1, step2, 'crossover');\n graph.insertEdge(parent, null, null, step3, step11, 'crossover');\n e = graph.insertEdge(lane1a, null, null, step11, step33, 'crossover');\n e.geometry.points = [\n new mxPoint(\n step33.geometry.x + step33.geometry.width / 2 + 20,\n step11.geometry.y + (step11.geometry.height * 4) / 5\n ),\n ];\n graph.insertEdge(parent, null, null, step33, step4);\n graph.insertEdge(lane1a, null, null, step111, end1);\n } finally {\n // Updates the display\n model.endUpdate();\n }\n }\n}\n\nexport default SwimLanes;\n", - "Previews": "import React, { useState } from 'react';\n\nimport SourceCodeDisplay from './SourceCodeDisplay';\nimport examplesListing from './examplesListing.json';\n\nfunction Preview({ sourceKey, content }) {\n const [sourceShown, setSourceShown] = useState(false);\n\n return (\n <>\n {content}\n\n {sourceShown ? (\n
    \n setSourceShown(false)}\n style={{ float: 'right', color: 'blue', cursor: 'pointer' }}\n >\n hide source\n \n \n \n
    \n
    \n ) : (\n
    \n setSourceShown(true)}\n style={{ float: 'right', color: 'blue', cursor: 'pointer' }}\n >\n show source\n \n
    \n )}\n \n );\n}\n\nexport default Preview;\n", - "Folding": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\nimport mxLayoutManager from '../mxgraph/view/mxLayoutManager';\nimport mxStackLayout from '../mxgraph/layout/mxStackLayout';\n\nclass Folding extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Folding

    \n This example demonstrates using a layout to implement a nested group\n structure.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Enables crisp rendering of rectangles in SVG\n mxConstants.ENTITY_SEGMENT = 20;\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setDropEnabled(true);\n\n // Disables global features\n graph.collapseToPreferredSize = false;\n graph.constrainChildren = false;\n graph.cellsSelectable = false;\n graph.extendParentsOnAdd = false;\n graph.extendParents = false;\n graph.border = 10;\n\n // Sets global styles\n let style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.EntityRelation;\n style[mxConstants.STYLE_ROUNDED] = true;\n\n style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_FILLCOLOR] = '#ffffff';\n style[mxConstants.STYLE_SHAPE] = 'swimlane';\n style[mxConstants.STYLE_STARTSIZE] = 30;\n\n style = [];\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;\n style[mxConstants.STYLE_STROKECOLOR] = 'none';\n style[mxConstants.STYLE_FILLCOLOR] = 'none';\n style[mxConstants.STYLE_FOLDABLE] = false;\n graph.getStylesheet().putCellStyle('column', style);\n\n // Installs auto layout for all levels\n const layout = new mxStackLayout(graph, true);\n layout.border = graph.border;\n const layoutMgr = new mxLayoutManager(graph);\n layoutMgr.getLayout = function(cell) {\n if (!cell.collapsed) {\n if (cell.parent !== graph.model.root) {\n layout.resizeParent = true;\n layout.horizontal = false;\n layout.spacing = 10;\n } else {\n layout.resizeParent = true;\n layout.horizontal = true;\n layout.spacing = 40;\n }\n\n return layout;\n }\n\n return null;\n };\n\n // Resizes the container\n graph.setResizeContainer(true);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const col1 = graph.insertVertex(parent, null, '', 0, 0, 120, 0, 'column');\n\n const v1 = graph.insertVertex(col1, null, '1', 0, 0, 100, 30);\n v1.collapsed = true;\n\n const v11 = graph.insertVertex(v1, null, '1.1', 0, 0, 80, 30);\n v11.collapsed = true;\n\n const v111 = graph.insertVertex(v11, null, '1.1.1', 0, 0, 60, 30);\n const v112 = graph.insertVertex(v11, null, '1.1.2', 0, 0, 60, 30);\n\n const v12 = graph.insertVertex(v1, null, '1.2', 0, 0, 80, 30);\n\n const col2 = graph.insertVertex(parent, null, '', 0, 0, 120, 0, 'column');\n\n const v2 = graph.insertVertex(col2, null, '2', 0, 0, 100, 30);\n v2.collapsed = true;\n\n const v21 = graph.insertVertex(v2, null, '2.1', 0, 0, 80, 30);\n v21.collapsed = true;\n\n const v211 = graph.insertVertex(v21, null, '2.1.1', 0, 0, 60, 30);\n const v212 = graph.insertVertex(v21, null, '2.1.2', 0, 0, 60, 30);\n\n const v22 = graph.insertVertex(v2, null, '2.2', 0, 0, 80, 30);\n\n const v3 = graph.insertVertex(col2, null, '3', 0, 0, 100, 30);\n v3.collapsed = true;\n\n const v31 = graph.insertVertex(v3, null, '3.1', 0, 0, 80, 30);\n v31.collapsed = true;\n\n const v311 = graph.insertVertex(v31, null, '3.1.1', 0, 0, 60, 30);\n const v312 = graph.insertVertex(v31, null, '3.1.2', 0, 0, 60, 30);\n\n const v32 = graph.insertVertex(v3, null, '3.2', 0, 0, 80, 30);\n\n graph.insertEdge(parent, null, '', v111, v211);\n graph.insertEdge(parent, null, '', v112, v212);\n graph.insertEdge(parent, null, '', v112, v22);\n\n graph.insertEdge(parent, null, '', v12, v311);\n graph.insertEdge(parent, null, '', v12, v312);\n graph.insertEdge(parent, null, '', v12, v32);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n };\n}\n\nexport default Folding;\n", - "EdgeTolerance": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\n\nclass EdgeTolerance extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Edge tolerance

    \n This example demonstrates increasing the tolerance for hit detection on\n edges.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '481px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n const { el } = this;\n\n class MyCustomGraph extends mxGraph {\n fireMouseEvent(evtName, me, sender) {\n // Overrides the mouse event dispatching mechanism to update the\n // cell which is associated with the event in case the native hit\n // detection did not return anything.\n\n // Checks if native hit detection did not return anything\n if (me.getState() == null) {\n // Updates the graph coordinates in the event since we need\n // them here. Storing them in the event means the overridden\n // method doesn't have to do this again.\n if (me.graphX == null || me.graphY == null) {\n const pt = mxUtils.convertPoint(el, me.getX(), me.getY());\n\n me.graphX = pt.x;\n me.graphY = pt.y;\n }\n\n const cell = this.getCellAt(me.graphX, me.graphY);\n if (this.getModel().isEdge(cell)) {\n me.state = this.view.getState(cell);\n\n if (me.state != null && me.state.shape != null) {\n this.container.style.cursor = me.state.shape.node.style.cursor;\n }\n }\n }\n\n if (me.state == null) {\n this.container.style.cursor = 'default';\n }\n\n super.fireMouseEvent(evtName, me, sender);\n }\n\n dblClick(evt, cell) {\n // Overrides double click handling to use the tolerance\n if (cell == null) {\n const pt = mxUtils.convertPoint(\n el,\n mxEvent.getClientX(evt),\n mxEvent.getClientY(evt)\n );\n cell = this.getCellAt(pt.x, pt.y);\n }\n super.dblClick(evt, cell);\n }\n }\n\n // Creates the graph inside the given container\n const graph = new MyCustomGraph(this.el);\n graph.setTolerance(20);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n value: 'Hello,',\n position: [120, 120],\n size: [80, 30],\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [400, 250],\n size: [80, 30],\n });\n const e1 = graph.insertEdge({\n parent,\n source: v1,\n target: v2,\n style: 'edgeStyle=orthogonalEdgeStyle;',\n });\n const e2 = graph.insertEdge({\n parent,\n source: v2,\n target: v1,\n style: 'edgeStyle=orthogonalEdgeStyle;',\n });\n });\n }\n}\n\nexport default EdgeTolerance;\n", - "Events": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\nimport mxLayoutManager from '../mxgraph/view/mxLayoutManager';\nimport mxParallelEdgeLayout from '../mxgraph/layout/mxParallelEdgeLayout';\nimport mxConnectionHandler from '../mxgraph/handler/mxConnectionHandler';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxClient from '../mxgraph/mxClient';\n\nclass Events extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Events

    \n Events. This example demonstrates creating a graph container and using\n the mxDivResizer to update the size, interaction on the graph, including\n marquee selection, custom tooltips, context menu handling and changing\n the default menu opacity. It also demonstrates how to use an edgestyle\n in the default stylesheet, and handle the doubleclick on the adjustment\n point. See also: overlays.html for click event handling.\n {\n this.el = el;\n }}\n style={{}}\n />\n \n );\n }\n\n componentDidMount() {\n // Program starts here. Creates a sample graph in the dynamically\n // created DOM node called container which is created below.\n\n class MyCustomConnectionHandler extends mxConnectionHandler {\n // Sets the image to be used for creating new connections\n connectImage = new mxImage('images/green-dot.gif', 14, 14);\n }\n\n const container = document.createElement('div');\n container.style.position = 'absolute';\n container.style.overflow = 'hidden';\n container.style.left = '0px';\n container.style.top = '0px';\n container.style.right = '0px';\n container.style.bottom = '0px';\n container.style.background = 'url(\"editors/images/grid.gif\")';\n\n // Disables built-in context menu\n mxEvent.disableContextMenu(container);\n this.el.appendChild(container);\n\n class MyCustomGraph extends mxGraph {\n alternateEdgeStyle = 'elbow=vertical';\n\n getTooltipForCell(cell) {\n // Installs a custom tooltip for cells\n return 'Doubleclick and right- or shiftclick';\n }\n\n createConnectionHandler() {\n return new MyCustomConnectionHandler(this);\n }\n }\n\n // Creates the graph inside the DOM node.\n // Optionally you can enable panning, tooltips and connections\n // using graph.setPanning(), setTooltips() & setConnectable().\n // To enable rubberband selection and basic keyboard events,\n // use new mxRubberband(graph) and new mxKeyHandler(graph).\n const graph = new MyCustomGraph(container);\n\n // Enables tooltips, new connections and panning\n graph.setPanning(true);\n graph.setTooltips(true);\n graph.setConnectable(true);\n\n // Automatically handle parallel edges\n const layout = new mxParallelEdgeLayout(graph);\n const layoutMgr = new mxLayoutManager(graph);\n\n layoutMgr.getLayout = function(cell) {\n if (cell.getChildCount() > 0) {\n return layout;\n }\n };\n\n // Enables rubberband (marquee) selection and a handler\n // for basic keystrokes (eg. return, escape during editing).\n const rubberband = new mxRubberband(graph);\n const keyHandler = new mxKeyHandler(graph);\n\n // Changes the default style for edges \"in-place\" and assigns\n // an alternate edge style which is applied in mxGraph.flip\n // when the user double clicks on the adjustment control point\n // of the edge. The ElbowConnector edge style switches to TopToBottom\n // if the horizontal style is true.\n const style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;\n\n // Installs a popupmenu handler using local function (see below).\n graph.popupMenuHandler.factoryMethod = (menu, cell, evt) => {\n return this.createPopupMenu(graph, menu, cell, evt);\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(\n parent,\n null,\n 'Doubleclick',\n 20,\n 20,\n 80,\n 30\n );\n const v2 = graph.insertVertex(\n parent,\n null,\n 'Right-/Shiftclick',\n 200,\n 150,\n 120,\n 30\n );\n const v3 = graph.insertVertex(\n parent,\n null,\n 'Connect/Reconnect',\n 200,\n 20,\n 120,\n 30\n );\n const v4 = graph.insertVertex(\n parent,\n null,\n 'Control-Drag',\n 20,\n 150,\n 100,\n 30\n );\n const e1 = graph.insertEdge(parent, null, 'Tooltips', v1, v2);\n const e2 = graph.insertEdge(parent, null, '', v2, v3);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n\n createPopupMenu(graph, menu, cell, evt) {\n // Function to create the entries in the popupmenu\n if (cell != null) {\n menu.addItem('Cell Item', 'editors/images/image.gif', () => {\n mxUtils.alert('MenuItem1');\n });\n } else {\n menu.addItem('No-Cell Item', 'editors/images/image.gif', () => {\n mxUtils.alert('MenuItem2');\n });\n }\n menu.addSeparator();\n menu.addItem('MenuItem3', '../src/images/warning.gif', () => {\n mxUtils.alert(`MenuItem3: ${graph.getSelectionCount()} selected`);\n });\n }\n}\n\nexport default Events;\n", - "Layers": "/**\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 mxCell from '../mxgraph/model/mxCell';\nimport mxGraphModel from '../mxgraph/model/mxGraphModel';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxUtils from '../mxgraph/util/mxUtils';\n\nclass Layers extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Layers

    \n This example demonstrates using multiple layers to contain cells.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container using a model\n // with a custom root and two layers. Layers can also be added\n // dynamically using let layer = model.add(root, new mxCell()).\n const root = new mxCell();\n const layer0 = root.insert(new mxCell());\n const layer1 = root.insert(new mxCell());\n const model = new mxGraphModel(root);\n\n const graph = new mxGraph(this.el, model);\n\n // Disables basic selection and cell handling\n graph.setEnabled(false);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n model.beginUpdate();\n try {\n const v1 = graph.insertVertex(\n layer1,\n null,\n 'Hello,',\n 20,\n 20,\n 80,\n 30,\n 'fillColor=#C0C0C0'\n );\n const v2 = graph.insertVertex(\n layer1,\n null,\n 'Hello,',\n 200,\n 20,\n 80,\n 30,\n 'fillColor=#C0C0C0'\n );\n const v3 = graph.insertVertex(layer0, null, 'World!', 110, 150, 80, 30);\n const e1 = graph.insertEdge(\n layer1,\n null,\n '',\n v1,\n v3,\n 'strokeColor=#0C0C0C'\n );\n e1.geometry.points = [new mxPoint(60, 165)];\n const e2 = graph.insertEdge(layer0, null, '', v2, v3);\n e2.geometry.points = [new mxPoint(240, 165)];\n const e3 = graph.insertEdge(\n layer0,\n null,\n '',\n v1,\n v2,\n 'edgeStyle=topToBottomEdgeStyle'\n );\n e3.geometry.points = [new mxPoint(150, 30)];\n const e4 = graph.insertEdge(\n layer1,\n null,\n '',\n v2,\n v1,\n 'strokeColor=#0C0C0C;edgeStyle=topToBottomEdgeStyle'\n );\n e4.geometry.points = [new mxPoint(150, 40)];\n } finally {\n // Updates the display\n model.endUpdate();\n }\n\n this.el2.appendChild(\n mxUtils.button('Layer 0', function() {\n model.setVisible(layer0, !model.isVisible(layer0));\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('Layer 1', function() {\n model.setVisible(layer1, !model.isVisible(layer1));\n })\n );\n }\n}\n\nexport default Layers;\n", - "Monitor": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\nimport mxCellOverlay from '../mxgraph/view/mxCellOverlay';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxCodec from '../mxgraph/io/mxCodec';\nimport mxPerimeter from '../mxgraph/view/mxPerimeter';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\n\nclass Monitor extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Workflow Monitor

    \n This example demonstrates using a graph to display the current state of\n a workflow.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '406px',\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n mxConstants.SHADOWCOLOR = '#e0e0e0';\n\n // Creates the graph inside the given container\n const graph = createGraph(this.el);\n\n // Creates a process display using the activity names as IDs to refer to the elements\n const xml =\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '' +\n '';\n const doc = mxUtils.parseXml(xml);\n const codec = new mxCodec(doc);\n codec.decode(doc.documentElement, graph.getModel());\n\n // Creates a button to invoke the refresh function\n this.el2.appendChild(\n mxUtils.button('Update', function(evt) {\n // XML is normally fetched from URL at server using mxUtils.get - this is a client-side\n // string with randomized states to demonstrate the idea of the workflow monitor\n const xml =\n `` +\n `` +\n ``;\n update(graph, xml);\n })\n );\n\n /**\n * Updates the display of the given graph using the XML data\n */\n function update(graph, xml) {\n if (xml != null && xml.length > 0) {\n const doc = mxUtils.parseXml(xml);\n\n if (doc != null && doc.documentElement != null) {\n const model = graph.getModel();\n const nodes = doc.documentElement.getElementsByTagName('update');\n\n if (nodes != null && nodes.length > 0) {\n model.beginUpdate();\n\n try {\n for (let i = 0; i < nodes.length; i++) {\n // Processes the activity nodes inside the process node\n const id = nodes[i].getAttribute('id');\n const state = nodes[i].getAttribute('state');\n\n // Gets the cell for the given activity name from the model\n const cell = model.getCell(id);\n\n // Updates the cell color and adds some tooltip information\n if (cell != null) {\n // Resets the fillcolor and the overlay\n graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, 'white', [\n cell,\n ]);\n graph.removeCellOverlays(cell);\n\n // Changes the cell color for the known states\n if (state == 'Running') {\n graph.setCellStyles(\n mxConstants.STYLE_FILLCOLOR,\n '#f8cecc',\n [cell]\n );\n } else if (state == 'Waiting') {\n graph.setCellStyles(\n mxConstants.STYLE_FILLCOLOR,\n '#fff2cc',\n [cell]\n );\n } else if (state == 'Completed') {\n graph.setCellStyles(\n mxConstants.STYLE_FILLCOLOR,\n '#d4e1f5',\n [cell]\n );\n }\n\n // Adds tooltip information using an overlay icon\n if (state != 'Init') {\n // Sets the overlay for the cell in the graph\n graph.addCellOverlay(\n cell,\n createOverlay(graph.warningImage, `State: ${state}`)\n );\n }\n }\n } // for\n } finally {\n model.endUpdate();\n }\n }\n }\n }\n }\n\n /**\n * Creates an overlay object using the given tooltip and text for the alert window\n * which is being displayed on click.\n */\n function createOverlay(image, tooltip) {\n const overlay = new mxCellOverlay(image, tooltip);\n\n // Installs a handler for clicks on the overlay\n overlay.addListener(mxEvent.CLICK, function(sender, evt) {\n mxUtils.alert(`${tooltip}\\nLast update: ${new Date()}`);\n });\n\n return overlay;\n }\n\n /**\n * Creates and returns an empty graph inside the given container.\n */\n function createGraph(container) {\n const graph = new mxGraph(container);\n graph.setTooltips(true);\n graph.setEnabled(false);\n\n // Disables folding\n graph.isCellFoldable = function(cell, collapse) {\n return false;\n };\n\n // Creates the stylesheet for the process display\n let style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_FONTSIZE] = 11;\n style[mxConstants.STYLE_FONTCOLOR] = 'black';\n style[mxConstants.STYLE_STROKECOLOR] = '#808080';\n style[mxConstants.STYLE_FILLCOLOR] = 'white';\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_GRADIENT_DIRECTION] = mxConstants.DIRECTION_EAST;\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_SHADOW] = true;\n style[mxConstants.STYLE_FONTSTYLE] = 1;\n\n style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;\n style[mxConstants.STYLE_STROKECOLOR] = '#808080';\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_SHADOW] = true;\n\n style = [];\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;\n style[mxConstants.STYLE_STROKECOLOR] = '#a0a0a0';\n style[mxConstants.STYLE_FONTCOLOR] = '#606060';\n style[mxConstants.STYLE_FILLCOLOR] = '#E0E0DF';\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_STARTSIZE] = 30;\n style[mxConstants.STYLE_ROUNDED] = false;\n style[mxConstants.STYLE_FONTSIZE] = 12;\n style[mxConstants.STYLE_FONTSTYLE] = 0;\n style[mxConstants.STYLE_HORIZONTAL] = false;\n // To improve text quality for vertical labels in some old IE versions...\n style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = '#efefef';\n\n graph.getStylesheet().putCellStyle('swimlane', style);\n\n style = [];\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RHOMBUS;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter;\n style[mxConstants.STYLE_STROKECOLOR] = '#91BCC0';\n style[mxConstants.STYLE_FONTCOLOR] = 'gray';\n style[mxConstants.STYLE_FILLCOLOR] = '#91BCC0';\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;\n style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;\n style[mxConstants.STYLE_FONTSIZE] = 16;\n graph.getStylesheet().putCellStyle('step', style);\n\n style = [];\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter;\n style[mxConstants.STYLE_FONTCOLOR] = 'gray';\n style[mxConstants.STYLE_FILLCOLOR] = '#A0C88F';\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_STROKECOLOR] = '#A0C88F';\n style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;\n style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;\n style[mxConstants.STYLE_FONTSIZE] = 16;\n graph.getStylesheet().putCellStyle('start', style);\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_FILLCOLOR] = '#DACCBC';\n style[mxConstants.STYLE_STROKECOLOR] = '#AF7F73';\n graph.getStylesheet().putCellStyle('end', style);\n\n return graph;\n }\n\n /**\n * Returns a random state.\n */\n function getState() {\n let state = 'Init';\n const rnd = Math.random() * 4;\n\n if (rnd > 3) {\n state = 'Completed';\n } else if (rnd > 2) {\n state = 'Running';\n } else if (rnd > 1) {\n state = 'Waiting';\n }\n\n return state;\n }\n }\n}\n\nexport default Monitor;\n", - "Permissions": "/**\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 mxConnectionHandler from '../mxgraph/handler/mxConnectionHandler';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxUtils from '../mxgraph/util/mxUtils';\n\nclass Permission {\n constructor(locked, createEdges, editEdges, editVertices, cloneCells) {\n this.locked = locked != null ? locked : false;\n this.createEdges = createEdges != null ? createEdges : true;\n this.editEdges = editEdges != null ? editEdges : true;\n this.editVertices = editVertices != null ? editVertices : true;\n this.cloneCells = cloneCells != null ? cloneCells : true;\n }\n\n apply(graph) {\n graph.setConnectable(this.createEdges);\n graph.setCellsLocked(this.locked);\n }\n}\n\nclass Permissions extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Permissions

    \n This example demonstrates creating permissions to define the available\n operations a the graph.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '300px',\n // background: \"url('editors/images/grid.gif')\",\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Defines an icon for creating new connections in the connection handler.\n // This will automatically disable the highlighting of the source vertex.\n mxConnectionHandler.prototype.connectImage = new mxImage(\n 'images/connector.gif',\n 16,\n 16\n );\n\n // Creates the div for the graph\n const container = document.createElement('div');\n container.style.position = 'absolute';\n container.style.overflow = 'hidden';\n container.style.left = '00px';\n container.style.top = '40px';\n container.style.right = '0px';\n container.style.bottom = '0px';\n container.style.background = 'url(\"editors/images/grid.gif\")';\n\n this.el.appendChild(container);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(container);\n\n // Enable tooltips, disables mutligraphs, enable loops\n graph.setMultigraph(false);\n graph.setAllowLoops(true);\n\n // Enables rubberband selection and key handling\n const rubberband = new mxRubberband(graph);\n const keyHandler = new mxKeyHandler(graph);\n\n // Assigns the delete key\n keyHandler.bindKey(46, function(evt) {\n if (graph.isEnabled()) {\n graph.removeCells();\n }\n });\n\n // Shared variable between child function scopes\n // aka \"private\" variable\n let currentPermission = null;\n\n const apply = function(permission) {\n graph.clearSelection();\n permission.apply(graph);\n graph.setEnabled(true);\n graph.setTooltips(true);\n\n // Updates the icons on the shapes - rarely\n // needed and very slow for large graphs\n graph.refresh();\n currentPermission = permission;\n };\n\n apply(new Permission());\n\n let button = mxUtils.button('Allow All', function(evt) {\n apply(new Permission());\n });\n this.el.appendChild(button);\n\n button = mxUtils.button('Connect Only', function(evt) {\n apply(new Permission(false, true, false, false, true));\n });\n this.el.appendChild(button);\n\n button = mxUtils.button('Edges Only', function(evt) {\n apply(new Permission(false, false, true, false, false));\n });\n this.el.appendChild(button);\n\n button = mxUtils.button('Vertices Only', function(evt) {\n apply(new Permission(false, false, false, true, false));\n });\n this.el.appendChild(button);\n\n button = mxUtils.button('Select Only', function(evt) {\n apply(new Permission(false, false, false, false, false));\n });\n this.el.appendChild(button);\n\n button = mxUtils.button('Locked', function(evt) {\n apply(new Permission(true, false));\n });\n this.el.appendChild(button);\n\n button = mxUtils.button('Disabled', function(evt) {\n graph.clearSelection();\n graph.setEnabled(false);\n graph.setTooltips(false);\n });\n this.el.appendChild(button);\n\n // Extends hook functions to use permission object. This could\n // be done by assigning the respective switches (eg.\n // setMovable), but this approach is more flexible, doesn't\n // override any existing behaviour or settings, and allows for\n // dynamic conditions to be used in the functions. See the\n // specification for more functions to extend (eg.\n // isSelectable).\n const oldDisconnectable = graph.isCellDisconnectable;\n graph.isCellDisconnectable = function(cell, terminal, source) {\n return (\n oldDisconnectable.apply(this, arguments) && currentPermission.editEdges\n );\n };\n\n const oldTerminalPointMovable = graph.isTerminalPointMovable;\n graph.isTerminalPointMovable = function(cell) {\n return (\n oldTerminalPointMovable.apply(this, arguments) &&\n currentPermission.editEdges\n );\n };\n\n const oldBendable = graph.isCellBendable;\n graph.isCellBendable = function(cell) {\n return oldBendable.apply(this, arguments) && currentPermission.editEdges;\n };\n\n const oldLabelMovable = graph.isLabelMovable;\n graph.isLabelMovable = function(cell) {\n return (\n oldLabelMovable.apply(this, arguments) && currentPermission.editEdges\n );\n };\n\n const oldMovable = graph.isCellMovable;\n graph.isCellMovable = function(cell) {\n return (\n oldMovable.apply(this, arguments) && currentPermission.editVertices\n );\n };\n\n const oldResizable = graph.isCellResizable;\n graph.isCellResizable = function(cell) {\n return (\n oldResizable.apply(this, arguments) && currentPermission.editVertices\n );\n };\n\n const oldEditable = graph.isCellEditable;\n graph.isCellEditable = function(cell) {\n return (\n (oldEditable.apply(this, arguments) &&\n this.getModel().isVertex(cell) &&\n currentPermission.editVertices) ||\n (this.getModel().isEdge(cell) && currentPermission.editEdges)\n );\n };\n\n const oldDeletable = graph.isCellDeletable;\n graph.isCellDeletable = function(cell) {\n return (\n (oldDeletable.apply(this, arguments) &&\n this.getModel().isVertex(cell) &&\n currentPermission.editVertices) ||\n (this.getModel().isEdge(cell) && currentPermission.editEdges)\n );\n };\n\n const oldCloneable = graph.isCellCloneable;\n graph.isCellCloneable = function(cell) {\n return (\n oldCloneable.apply(this, arguments) && currentPermission.cloneCells\n );\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n const v2 = graph.insertVertex(parent, null, 'Hello,', 200, 20, 80, 30);\n const v3 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n const e1 = graph.insertEdge(parent, null, 'Connection', v1, v3);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Permissions;\n", - "index": "import Head from 'next/head';\nimport styles from '../styles/Home.module.css';\n\nimport HelloWorld from './HelloWorld';\nimport Anchors from './Anchors';\nimport AutoLayout from './AutoLayout';\nimport Animation from './Animation';\nimport Boundary from './Boundary';\nimport Clipboard from './Clipboard';\nimport DragSource from './DragSource';\nimport Control from './Control';\nimport ContextIcons from './ContextIcons';\nimport Collapse from './Collapse';\nimport Constituent from './Constituent';\nimport DynamicLoading from './DynamicLoading';\nimport Drop from './Drop';\nimport DynamicStyle from './DynamicStyle';\nimport DynamicToolbar from './DynamicToolbar';\nimport EdgeTolerance from './EdgeTolerance';\nimport Editing from './Editing';\nimport Tree from './Tree';\nimport Validation from './Validation';\nimport SwimLanes from './SwimLanes';\nimport Wrapping from './Wrapping';\n// import Windows from \"./Windows\";\nimport Visibility from './Visibility';\nimport UserObject from './UserObject';\nimport Toolbar from './Toolbar';\nimport Thread from './Thread';\n// import Template from \"./Template\";\nimport Stylesheet from './Stylesheet';\nimport Stencils from './Stencils';\nimport SecondLabel from './SecondLabel';\nimport Shape from './Shape';\nimport Resources from './Resources';\nimport RadialTreeLayout from './RadialTreeLayout';\nimport PortRefs from './PortRefs';\nimport Permissions from './Permissions';\nimport Perimeter from './Perimeter';\nimport PageBreaks from './PageBreaks';\nimport Overlays from './Overlays';\nimport Orthogonal from './Orthogonal';\nimport OrgChart from './OrgChart';\nimport OffPage from './OffPage';\nimport Morph from './Morph';\nimport Monitor from './Monitor';\nimport Merge from './Merge';\nimport Markers from './Markers';\nimport LOD from './LOD';\nimport Layers from './Layers';\nimport Labels from './Labels';\nimport LabelPosition from './LabelPosition';\nimport JsonData from './JsonData';\nimport Indicators from './Indicators';\nimport Images from './Images';\nimport HoverIcons from './HoverIcons';\nimport HoverStyle from './HoverStyle';\nimport HierarchicalLayout from './HierarchicalLayout';\nimport HelloPort from './HelloPort';\nimport Handles from './Handles';\nimport Guides from './Guides';\nimport Groups from './Groups';\nimport Grid from './Grid';\nimport Folding from './Folding';\nimport FixedPoints from './FixedPoints';\nimport FixedIcon from './FixedIcon';\nimport Preview from './Previews';\n\nexport default function Home() {\n return (\n \n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n {/* } /> */}\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n {/* } /> */}\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n {/* } /> */}\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n {/* } /> */}\n } />\n } />\n {/* } /> */}\n } />\n } />\n } />\n\n } />\n } />\n } />\n {/* } /> */}\n } />\n
    \n );\n}\n", - "Boundary": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxGraphHandler from '../mxgraph/handler/mxGraphHandler';\nimport mxUtils from '../mxgraph/util/mxUtils';\n\nclass Boundary extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Boundary

    \n This example demonstrates implementing boundary events in BPMN diagrams.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: 'url(\"editors/images/grid.gif\")',\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n class MyCustomGraph extends mxGraph {\n // Enables moving of relative children\n isCellLocked(cell) {\n return false;\n }\n\n // Removes folding icon for relative children\n isCellFoldable(cell, collapse) {\n const childCount = this.model.getChildCount(cell);\n\n for (let i = 0; i < childCount; i++) {\n const child = this.model.getChildAt(cell, i);\n const geo = this.getCellGeometry(child);\n\n if (geo != null && geo.relative) {\n return false;\n }\n }\n\n return childCount > 0;\n }\n\n // Returns the relative position of the given child\n getRelativePosition(state, dx, dy) {\n if (state != null) {\n const model = graph.getModel();\n const geo = model.getGeometry(state.cell);\n\n if (geo != null && geo.relative && !model.isEdge(state.cell)) {\n const parent = model.getParent(state.cell);\n\n if (model.isVertex(parent)) {\n const pstate = graph.view.getState(parent);\n\n if (pstate != null) {\n const { scale } = graph.view;\n let x = state.x + dx;\n let y = state.y + dy;\n\n if (geo.offset != null) {\n x -= geo.offset.x * scale;\n y -= geo.offset.y * scale;\n }\n\n x = (x - pstate.x) / pstate.width;\n y = (y - pstate.y) / pstate.height;\n\n if (Math.abs(y - 0.5) <= Math.abs((x - 0.5) / 2)) {\n x = x > 0.5 ? 1 : 0;\n y = Math.min(1, Math.max(0, y));\n } else {\n x = Math.min(1, Math.max(0, x));\n y = y > 0.5 ? 1 : 0;\n }\n\n return new mxPoint(x, y);\n }\n }\n }\n }\n\n return null;\n }\n\n // Replaces translation for relative children\n translateCell(cell, dx, dy) {\n const rel = this.getRelativePosition(\n this.view.getState(cell),\n dx * graph.view.scale,\n dy * graph.view.scale\n );\n\n if (rel != null) {\n let geo = this.model.getGeometry(cell);\n\n if (geo != null && geo.relative) {\n geo = geo.clone();\n geo.x = rel.x;\n geo.y = rel.y;\n\n this.model.setGeometry(cell, geo);\n }\n } else {\n mxGraph.prototype.translateCell.apply(this, arguments);\n }\n }\n }\n\n // Creates the graph inside the given this.el\n const graph = new MyCustomGraph(this.el);\n\n // Sets the base style for all vertices\n const style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_FILLCOLOR] = '#ffffff';\n style[mxConstants.STYLE_STROKECOLOR] = '#000000';\n style[mxConstants.STYLE_STROKEWIDTH] = '2';\n style[mxConstants.STYLE_FONTCOLOR] = '#000000';\n style[mxConstants.STYLE_FONTSIZE] = '12';\n style[mxConstants.STYLE_FONTSTYLE] = 1;\n graph.getStylesheet().putDefaultVertexStyle(style);\n\n // Replaces move preview for relative children\n graph.graphHandler.getDelta = function(me) {\n const point = mxUtils.convertPoint(\n this.graph.container,\n me.getX(),\n me.getY()\n );\n let delta = new mxPoint(point.x - this.first.x, point.y - this.first.y);\n\n if (\n this.cells != null &&\n this.cells.length > 0 &&\n this.cells[0] != null\n ) {\n const state = this.graph.view.getState(this.cells[0]);\n const rel = graph.getRelativePosition(state, delta.x, delta.y);\n\n if (rel != null) {\n const pstate = this.graph.view.getState(\n this.graph.model.getParent(state.cell)\n );\n\n if (pstate != null) {\n delta = new mxPoint(\n pstate.x + pstate.width * rel.x - state.getCenterX(),\n pstate.y + pstate.height * rel.y - state.getCenterY()\n );\n }\n }\n }\n\n return delta;\n };\n\n // Relative children cannot be removed from parent\n graph.graphHandler.shouldRemoveCellsFromParent = function(\n parent,\n cells,\n evt\n ) {\n return (\n cells.length === 0 &&\n !cells[0].geometry.relative &&\n mxGraphHandler.prototype.shouldRemoveCellsFromParent.apply(\n this,\n arguments\n )\n );\n };\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n value: 'Process',\n position: [60, 60],\n size: [90, 40],\n });\n\n const v2 = graph.insertVertex({\n parent: v1,\n value: 'in',\n position: [0, 0.5],\n size: [20, 20],\n style: 'fontSize=9;shape=ellipse;resizable=0;',\n });\n v2.geometry.offset = new mxPoint(-10, -10);\n v2.geometry.relative = true;\n\n const v3 = graph.insertVertex({\n parent: v1,\n value: 'out',\n position: [1, 0.5],\n size: [20, 20],\n style: 'fontSize=9;shape=ellipse;resizable=0;',\n });\n v3.geometry.offset = new mxPoint(-10, -10);\n v3.geometry.relative = true;\n });\n };\n}\n\nexport default Boundary;\n", - "HoverStyle": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\n\nclass HoverStyle extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Hoverstyle

    \n This example shows hot to change the style of a vertex on mouseover.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n function updateStyle(state, hover) {\n if (hover) {\n state.style[mxConstants.STYLE_FILLCOLOR] = '#ff0000';\n }\n\n // Sets rounded style for both cases since the rounded style\n // is not set in the default style and is therefore inherited\n // once it is set, whereas the above overrides the default value\n state.style[mxConstants.STYLE_ROUNDED] = hover ? '1' : '0';\n state.style[mxConstants.STYLE_STROKEWIDTH] = hover ? '4' : '1';\n state.style[mxConstants.STYLE_FONTSTYLE] = hover\n ? mxConstants.FONT_BOLD\n : '0';\n }\n\n // Changes fill color to red on mouseover\n graph.addMouseListener({\n currentState: null,\n previousStyle: null,\n mouseDown(sender, me) {\n if (this.currentState != null) {\n this.dragLeave(me.getEvent(), this.currentState);\n this.currentState = null;\n }\n },\n mouseMove(sender, me) {\n if (this.currentState != null && me.getState() == this.currentState) {\n return;\n }\n\n let tmp = graph.view.getState(me.getCell());\n\n // Ignores everything but vertices\n if (\n graph.isMouseDown ||\n (tmp != null && !graph.getModel().isVertex(tmp.cell))\n ) {\n tmp = null;\n }\n\n if (tmp != this.currentState) {\n if (this.currentState != null) {\n this.dragLeave(me.getEvent(), this.currentState);\n }\n\n this.currentState = tmp;\n\n if (this.currentState != null) {\n this.dragEnter(me.getEvent(), this.currentState);\n }\n }\n },\n mouseUp(sender, me) {},\n dragEnter(evt, state) {\n if (state != null) {\n this.previousStyle = state.style;\n state.style = mxUtils.clone(state.style);\n updateStyle(state, true);\n state.shape.apply(state);\n state.shape.redraw();\n\n if (state.text != null) {\n state.text.apply(state);\n state.text.redraw();\n }\n }\n },\n dragLeave(evt, state) {\n if (state != null) {\n state.style = this.previousStyle;\n updateStyle(state, false);\n state.shape.apply(state);\n state.shape.redraw();\n\n if (state.text != null) {\n state.text.apply(state);\n state.text.redraw();\n }\n }\n },\n });\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default HoverStyle;\n", - "HelloWorld": "/*\n * Copyright (c) 2006-2018, 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';\n\nclass HelloWorld extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph with a grid wallpaper\n return (\n <>\n

    Hello, World!

    \n This example demonstrates using a DOM node to create a graph and adding\n vertices and edges.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Create a sample graph in the DOM node with the specified ID.\n mxEvent.disableContextMenu(this.el); // Disable the built-in context menu\n const graph = new mxGraph(this.el); // Create the graph inside the given container\n new mxRubberband(graph); // Enable rubberband selection\n\n // Get the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n graph.batchUpdate(() => {\n // Add cells to the model in a single step\n const vertex1 = graph.insertVertex({\n parent,\n value: 'Hello',\n position: [20, 20],\n size: [80, 30],\n relative: false,\n });\n const vertex2 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [200, 150],\n size: [80, 30],\n relative: false,\n });\n const edge = graph.insertEdge({\n parent,\n // value: 'to the',\n source: vertex1,\n target: vertex2,\n });\n });\n };\n}\n\nexport default HelloWorld;\n", - "DynamicToolbar": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxConnectionHandler from '../mxgraph/handler/mxConnectionHandler';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxToolbar from '../mxgraph/util/mxToolbar';\nimport mxGraphModel from '../mxgraph/model/mxGraphModel';\nimport mxCell from '../mxgraph/model/mxCell';\nimport mxGeometry from '../mxgraph/model/mxGeometry';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\n\nclass DynamicToolbar extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Dynamic Toolbar

    \n This example demonstrates changing the state of the toolbar at runtime.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n position: 'relative',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Defines an icon for creating new connections in the connection handler.\n // This will automatically disable the highlighting of the source vertex.\n mxConnectionHandler.prototype.connectImage = new mxImage(\n 'images/connector.gif',\n 16,\n 16\n );\n\n // Creates the div for the toolbar\n const tbContainer = document.createElement('div');\n tbContainer.style.position = 'absolute';\n tbContainer.style.overflow = 'hidden';\n tbContainer.style.padding = '2px';\n tbContainer.style.left = '0px';\n tbContainer.style.top = '0px';\n tbContainer.style.width = '24px';\n tbContainer.style.bottom = '0px';\n\n this.el.appendChild(tbContainer);\n\n // Creates new toolbar without event processing\n const toolbar = (this.toolbar = new mxToolbar(tbContainer));\n toolbar.enabled = false;\n\n // Creates the div for the graph\n const container = document.createElement('div');\n container.style.position = 'absolute';\n container.style.overflow = 'hidden';\n container.style.left = '24px';\n container.style.top = '0px';\n container.style.right = '0px';\n container.style.bottom = '0px';\n container.style.background = 'url(\"editors/images/grid.gif\")';\n\n this.el.appendChild(container);\n\n // Creates the model and the graph inside the container\n // using the fastest rendering available on the browser\n const model = new mxGraphModel();\n const graph = (this.graph = new mxGraph(container, model));\n\n // Enables new connections in the graph\n graph.setConnectable(true);\n graph.setMultigraph(false);\n\n // Stops editing on enter or escape keypress\n const keyHandler = new mxKeyHandler(graph);\n const rubberband = new mxRubberband(graph);\n\n this.addVertex('editors/images/rectangle.gif', 100, 40, '');\n this.addVertex('editors/images/rounded.gif', 100, 40, 'shape=rounded');\n this.addVertex('editors/images/ellipse.gif', 40, 40, 'shape=ellipse');\n this.addVertex('editors/images/rhombus.gif', 40, 40, 'shape=rhombus');\n this.addVertex('editors/images/triangle.gif', 40, 40, 'shape=triangle');\n this.addVertex('editors/images/cylinder.gif', 40, 40, 'shape=cylinder');\n this.addVertex('editors/images/actor.gif', 30, 40, 'shape=actor');\n }\n\n addVertex(icon, w, h, style) {\n const vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style);\n vertex.setVertex(true);\n\n const img = this.addToolbarItem(this.graph, this.toolbar, vertex, icon);\n img.enabled = true;\n\n this.graph.getSelectionModel().addListener(mxEvent.CHANGE, () => {\n const tmp = this.graph.isSelectionEmpty();\n mxUtils.setOpacity(img, tmp ? 100 : 20);\n img.enabled = tmp;\n });\n }\n\n addToolbarItem(graph, toolbar, prototype, image) {\n // Function that is executed when the image is dropped on\n // the graph. The cell argument points to the cell under\n // the mousepointer if there is one.\n const funct = (graph, evt, cell, x, y) => {\n graph.stopEditing(false);\n\n const vertex = graph.getModel().cloneCell(prototype);\n vertex.geometry.x = x;\n vertex.geometry.y = y;\n\n graph.addCell(vertex);\n graph.setSelectionCell(vertex);\n };\n\n // Creates the image which is used as the drag icon (preview)\n const img = toolbar.addMode(null, image, (evt, cell) => {\n const pt = this.graph.getPointForEvent(evt);\n funct(graph, evt, cell, pt.x, pt.y);\n });\n\n // Disables dragging if element is disabled. This is a workaround\n // for wrong event order in IE. Following is a dummy listener that\n // is invoked as the last listener in IE.\n mxEvent.addListener(img, 'mousedown', evt => {\n // do nothing\n });\n\n // This listener is always called first before any other listener\n // in all browsers.\n mxEvent.addListener(img, 'mousedown', evt => {\n if (img.enabled == false) {\n mxEvent.consume(evt);\n }\n });\n\n mxUtils.makeDraggable(img, graph, funct);\n return img;\n }\n}\n\nexport default DynamicToolbar;\n", - "SourceCodeDisplay": "import { Component } from 'react';\nimport Prism from 'prismjs';\nimport 'prismjs/themes/prism-okaidia.css';\nimport 'prismjs/components/prism-markup-templating';\nimport 'prismjs/components/prism-handlebars.min.js';\nimport 'prismjs/components/prism-lua.min.js';\nimport 'prismjs/components/prism-c.min.js';\nimport 'prismjs/components/prism-cpp.min.js';\nimport 'prismjs/components/prism-ruby.min.js';\nimport 'prismjs/components/prism-java.min.js';\nimport 'prismjs/components/prism-javascript.min.js';\nimport 'prismjs/components/prism-bash.min.js';\nimport 'prismjs/components/prism-csharp.min.js';\nimport 'prismjs/components/prism-css.min.js';\nimport 'prismjs/components/prism-typescript.min.js';\nimport 'prismjs/components/prism-yaml.min.js';\nimport 'prismjs/components/prism-json.min.js';\nimport 'prismjs/components/prism-swift.min.js';\nimport 'prismjs/components/prism-jsx.min.js';\nimport 'prismjs/components/prism-dart.min.js';\nimport 'prismjs/components/prism-sql.min.js';\nimport 'prismjs/components/prism-rust.min.js';\nimport 'prismjs/components/prism-php.min.js';\nimport 'prismjs/components/prism-perl.min.js';\nimport 'prismjs/components/prism-go.min.js';\nimport 'prismjs/components/prism-docker.min.js';\nimport 'prismjs/components/prism-python.min.js';\n\n// Adapted from\n// https://betterstack.dev/blog/code-highlighting-in-react-using-prismjs/\n\nexport class SourceCodeDisplay extends Component {\n /**\n *\n * @param code\n * @param plugins\n * @param language\n */\n constructor({ code, plugins, language, theme, style }) {\n if (plugins == null) {\n plugins = ['line-numbers', 'show-language'];\n }\n super({ code, plugins, language, theme, style });\n }\n\n render() {\n // TODO: Support theme!!!\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

    Dynamic Style

    \n This example demonstrates changing the style of a cell dynamically by\n overriding mxGraphModel.getStyle.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Disables moving of edge labels in this examples\n graph.edgeLabelsMovable = false;\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Needs to set a flag to check for dynamic style changes,\n // that is, changes to styles on cells where the style was\n // not explicitely changed using mxStyleChange\n graph.getView().updateStyle = true;\n\n // Overrides mxGraphModel.getStyle to return a specific style\n // for edges that reflects their target terminal (in this case\n // the strokeColor will be equal to the target's fillColor).\n const previous = graph.model.getStyle;\n\n graph.model.getStyle = function(cell) {\n if (cell != null) {\n let style = previous.apply(this, arguments);\n\n if (this.isEdge(cell)) {\n const target = this.getTerminal(cell, false);\n\n if (target != null) {\n const targetStyle = graph.getCurrentCellStyle(target);\n const fill = mxUtils.getValue(\n targetStyle,\n mxConstants.STYLE_FILLCOLOR\n );\n\n if (fill != null) {\n style += `;strokeColor=${fill}`;\n }\n }\n } else if (this.isVertex(cell)) {\n const geometry = this.getGeometry(cell);\n\n if (geometry != null && geometry.width > 80) {\n style += ';fillColor=green';\n }\n }\n\n return style;\n }\n\n return null;\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n value: 'Hello,',\n position: [20, 20],\n size: [80, 30],\n style: 'fillColor=green',\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [200, 150],\n size: [80, 30],\n style: 'fillColor=blue',\n });\n const v3 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [20, 150],\n size: [80, 30],\n style: 'fillColor=red',\n });\n const e1 = graph.insertEdge({\n parent,\n value: 'Connect',\n source: v1,\n target: v2,\n style: 'perimeterSpacing=4;strokeWidth=4;labelBackgroundColor=white;fontStyle=1',\n });\n });\n };\n}\n\nexport default DynamicStyle;\n", - "PortRefs": "/**\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 mxConstraintHandler from '../mxgraph/handler/mxConstraintHandler';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxShape from '../mxgraph/shape/mxShape';\nimport mxTriangle from '../mxgraph/shape/mxTriangle';\nimport mxEdgeHandler from '../mxgraph/handler/mxEdgeHandler';\nimport mxConnectionConstraint from '../mxgraph/view/mxConnectionConstraint';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxConstants from '../mxgraph/util/mxConstants';\n\nclass PortRefs extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Port References Example

    \n This example demonstrates referencing connection points by ID. The main\n difference to the implementation where the connection point is stored in\n the connecting edge is that changes to the original port will be\n reflected in all existing connections since they reference that port.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Replaces the port image\n mxConstraintHandler.prototype.pointImage = new mxImage(\n 'images/dot.gif',\n 10,\n 10\n );\n\n const graph = new mxGraph(this.el);\n graph.setConnectable(true);\n\n // Disables automatic handling of ports. This disables the reset of the\n // respective style in mxGraph.cellConnected. Note that this feature may\n // be useful if floating and fixed connections are combined.\n graph.setPortsEnabled(false);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Ports are equal for all shapes...\n const ports = new Array();\n\n // NOTE: Constraint is used later for orthogonal edge routing (currently ignored)\n ports.w = { x: 0, y: 0.5, perimeter: true, constraint: 'west' };\n ports.e = { x: 1, y: 0.5, perimeter: true, constraint: 'east' };\n ports.n = { x: 0.5, y: 0, perimeter: true, constraint: 'north' };\n ports.s = { x: 0.5, y: 1, perimeter: true, constraint: 'south' };\n ports.nw = { x: 0, y: 0, perimeter: true, constraint: 'north west' };\n ports.ne = { x: 1, y: 0, perimeter: true, constraint: 'north east' };\n ports.sw = { x: 0, y: 1, perimeter: true, constraint: 'south west' };\n ports.se = { x: 1, y: 1, perimeter: true, constraint: 'south east' };\n\n // ... except for triangles\n const ports2 = new Array();\n\n // NOTE: Constraint is used later for orthogonal edge routing (currently ignored)\n ports2.in1 = { x: 0, y: 0, perimeter: true, constraint: 'west' };\n ports2.in2 = { x: 0, y: 0.25, perimeter: true, constraint: 'west' };\n ports2.in3 = { x: 0, y: 0.5, perimeter: true, constraint: 'west' };\n ports2.in4 = { x: 0, y: 0.75, perimeter: true, constraint: 'west' };\n ports2.in5 = { x: 0, y: 1, perimeter: true, constraint: 'west' };\n\n ports2.out1 = {\n x: 0.5,\n y: 0,\n perimeter: true,\n constraint: 'north east',\n };\n ports2.out2 = { x: 1, y: 0.5, perimeter: true, constraint: 'east' };\n ports2.out3 = {\n x: 0.5,\n y: 1,\n perimeter: true,\n constraint: 'south east',\n };\n\n // Extends shapes classes to return their ports\n mxShape.prototype.getPorts = function() {\n return ports;\n };\n\n mxTriangle.prototype.getPorts = function() {\n return ports2;\n };\n\n // Disables floating connections (only connections via ports allowed)\n graph.connectionHandler.isConnectableCell = function(cell) {\n return false;\n };\n mxEdgeHandler.prototype.isConnectableCell = function(cell) {\n return graph.connectionHandler.isConnectableCell(cell);\n };\n\n // Disables existing port functionality\n graph.view.getTerminalPort = function(state, terminal, source) {\n return terminal;\n };\n\n // Returns all possible ports for a given terminal\n graph.getAllConnectionConstraints = function(terminal, source) {\n if (\n terminal != null &&\n terminal.shape != null &&\n terminal.shape.stencil != null\n ) {\n // for stencils with existing constraints...\n if (terminal.shape.stencil != null) {\n return terminal.shape.stencil.constraints;\n }\n } else if (terminal != null && this.model.isVertex(terminal.cell)) {\n if (terminal.shape != null) {\n const ports = terminal.shape.getPorts();\n const cstrs = new Array();\n\n for (const id in ports) {\n const port = ports[id];\n\n const cstr = new mxConnectionConstraint(\n new mxPoint(port.x, port.y),\n port.perimeter\n );\n cstr.id = id;\n cstrs.push(cstr);\n }\n\n return cstrs;\n }\n }\n\n return null;\n };\n\n // Sets the port for the given connection\n graph.setConnectionConstraint = function(\n edge,\n terminal,\n source,\n constraint\n ) {\n if (constraint != null) {\n const key = source\n ? mxConstants.STYLE_SOURCE_PORT\n : mxConstants.STYLE_TARGET_PORT;\n\n if (constraint == null || constraint.id == null) {\n this.setCellStyles(key, null, [edge]);\n } else if (constraint.id != null) {\n this.setCellStyles(key, constraint.id, [edge]);\n }\n }\n };\n\n // Returns the port for the given connection\n graph.getConnectionConstraint = function(edge, terminal, source) {\n const key = source\n ? mxConstants.STYLE_SOURCE_PORT\n : mxConstants.STYLE_TARGET_PORT;\n const id = edge.style[key];\n\n if (id != null) {\n const c = new mxConnectionConstraint(null, null);\n c.id = id;\n\n return c;\n }\n\n return null;\n };\n\n // Returns the actual point for a port by redirecting the constraint to the port\n const graphGetConnectionPoint = graph.getConnectionPoint;\n graph.getConnectionPoint = function(vertex, constraint) {\n if (constraint.id != null && vertex != null && vertex.shape != null) {\n const port = vertex.shape.getPorts()[constraint.id];\n\n if (port != null) {\n constraint = new mxConnectionConstraint(\n new mxPoint(port.x, port.y),\n port.perimeter\n );\n }\n }\n\n return graphGetConnectionPoint.apply(this, arguments);\n };\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'A', 20, 20, 100, 40);\n const v2 = graph.insertVertex(\n parent,\n null,\n 'B',\n 80,\n 100,\n 100,\n 100,\n 'shape=ellipse;perimeter=ellipsePerimeter'\n );\n const v3 = graph.insertVertex(\n parent,\n null,\n 'C',\n 190,\n 30,\n 100,\n 60,\n 'shape=triangle;perimeter=trianglePerimeter;direction=south'\n );\n const e1 = graph.insertEdge(\n parent,\n null,\n '',\n v1,\n v2,\n 'sourcePort=s;targetPort=nw'\n );\n const e2 = graph.insertEdge(\n parent,\n null,\n '',\n v1,\n v3,\n 'sourcePort=e;targetPort=out3'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n // Comming soon... Integration with orthogonal edge style\n // Sets default edge style to use port constraints (needs to be moved up when uncommented)\n // graph.getStylesheet().getDefaultEdgeStyle()['edgeStyle'] = 'orthogonalEdgeStyle';\n /* let mxUtilsGetPortConstraints = mxUtils.getPortConstraints;\n mxUtils.getPortConstraints = function(terminal, edge, source, defaultValue)\n {\n let key = (source) ? mxConstants.STYLE_SOURCE_PORT : mxConstants.STYLE_TARGET_PORT;\n let id = edge.style[key];\n\n let port = terminal.shape.getPorts()[id];\n\n // TODO: Add support for rotation, direction\n if (port != null)\n {\n return port.constraint;\n }\n\n return mxUtilsGetPortConstraints.apply(this, arguments);\n };\n // Connect preview\n graph.connectionHandler.createEdgeState = function(me)\n {\n let edge = graph.createEdge(null, null, null, null, null);\n\n return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge));\n };\n */\n }\n}\n\nexport default PortRefs;\n", - "Groups": "/**\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 mxGraphHandler from '../mxgraph/handler/mxGraphHandler';\nimport mxPopupMenuHandler from '../mxgraph/handler/mxPopupMenuHandler';\n\nclass Groups extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Groups

    \n This example demonstrates using cells as parts of other cells.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Overrides check for valid roots\n mxGraph.prototype.isValidRoot = function() {\n return false;\n };\n\n // Don't clear selection if multiple cells selected\n const graphHandlerMouseDown = mxGraphHandler.prototype.mouseDown;\n mxGraphHandler.prototype.mouseDown = function(sender, me) {\n graphHandlerMouseDown.apply(this, arguments);\n\n if (\n this.graph.isCellSelected(me.getCell()) &&\n this.graph.getSelectionCount() > 1\n ) {\n this.delayedSelection = false;\n }\n };\n\n // Selects descendants before children selection mode\n const graphHandlerGetInitialCellForEvent =\n mxGraphHandler.prototype.getInitialCellForEvent;\n mxGraphHandler.prototype.getInitialCellForEvent = function(me) {\n const model = this.graph.getModel();\n const psel = model.getParent(this.graph.getSelectionCell());\n let cell = graphHandlerGetInitialCellForEvent.apply(this, arguments);\n let parent = model.getParent(cell);\n\n if (psel == null || (psel != cell && psel != parent)) {\n while (\n !this.graph.isCellSelected(cell) &&\n !this.graph.isCellSelected(parent) &&\n model.isVertex(parent) &&\n !this.graph.isValidRoot(parent)\n ) {\n cell = parent;\n parent = this.cell.getParent();\n }\n }\n\n return cell;\n };\n\n // Selection is delayed to mouseup if child selected\n const graphHandlerIsDelayedSelection =\n mxGraphHandler.prototype.isDelayedSelection;\n mxGraphHandler.prototype.isDelayedSelection = function(cell) {\n let result = graphHandlerIsDelayedSelection.apply(this, arguments);\n const model = this.graph.getModel();\n const psel = model.getParent(this.graph.getSelectionCell());\n const parent = model.getParent(cell);\n\n if (psel == null || (psel != cell && psel != parent)) {\n if (\n !this.graph.isCellSelected(cell) &&\n model.isVertex(parent) &&\n !this.graph.isValidRoot(parent)\n ) {\n result = true;\n }\n }\n\n return result;\n };\n\n // Delayed selection of parent group\n mxGraphHandler.prototype.selectDelayed = function(me) {\n let cell = me.getCell();\n\n if (cell == null) {\n cell = this.cell;\n }\n\n const model = this.graph.getModel();\n let parent = model.getParent(cell);\n\n while (\n this.graph.isCellSelected(cell) &&\n model.isVertex(parent) &&\n !this.graph.isValidRoot(parent)\n ) {\n cell = parent;\n parent = model.getParent(cell);\n }\n\n this.graph.selectCellForEvent(cell, me.getEvent());\n };\n\n // Returns last selected ancestor\n mxPopupMenuHandler.prototype.getCellForPopupEvent = function(me) {\n let cell = me.getCell();\n const model = this.graph.getModel();\n let parent = model.getParent(cell);\n\n while (model.isVertex(parent) && !this.graph.isValidRoot(parent)) {\n if (this.graph.isCellSelected(parent)) {\n cell = parent;\n }\n\n parent = model.getParent(parent);\n }\n\n return cell;\n };\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.constrainChildren = false;\n graph.extendParents = false;\n graph.extendParentsOnAdd = false;\n\n // Uncomment the following if you want the container\n // to fit the size of the graph\n // graph.setResizeContainer(true);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 120, 60);\n const v2 = graph.insertVertex(v1, null, 'World!', 90, 20, 60, 20);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Groups;\n", - "ContextIcons": "/**\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 mxVertexHandler from '../mxgraph/handler/mxVertexHandler';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxClient from '../mxgraph/mxClient';\n\nclass ContextIcons extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Context icons

    \n This example demonstrates adding icons to selected vertices to carry out\n special operations.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n class mxVertexToolHandler extends mxVertexHandler {\n // Defines a subclass for mxVertexHandler that adds a set of clickable\n // icons to every selected vertex.\n\n domNode = null;\n\n init() {\n super.init();\n\n // In this example we force the use of DIVs for images in IE. This\n // handles transparency in PNG images properly in IE and fixes the\n // problem that IE routes all mouse events for a gesture via the\n // initial IMG node, which means the target vertices\n this.domNode = document.createElement('div');\n this.domNode.style.position = 'absolute';\n this.domNode.style.whiteSpace = 'nowrap';\n\n // Workaround for event redirection via image tag in quirks and IE8\n const createImage = src => {\n return mxUtils.createImage(src);\n };\n\n // Delete\n let img = createImage('images/delete2.png');\n img.setAttribute('title', 'Delete');\n img.style.cursor = 'pointer';\n img.style.width = '16px';\n img.style.height = '16px';\n mxEvent.addGestureListeners(img, evt => {\n // Disables dragging the image\n mxEvent.consume(evt);\n });\n mxEvent.addListener(img, 'click', evt => {\n this.graph.removeCells([this.state.cell]);\n mxEvent.consume(evt);\n });\n this.domNode.appendChild(img);\n\n // Size\n img = createImage('images/fit_to_size.png');\n img.setAttribute('title', 'Resize');\n img.style.cursor = 'se-resize';\n img.style.width = '16px';\n img.style.height = '16px';\n\n mxEvent.addGestureListeners(img, evt => {\n this.start(mxEvent.getClientX(evt), mxEvent.getClientY(evt), 7);\n this.graph.isMouseDown = true;\n this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt);\n mxEvent.consume(evt);\n });\n this.domNode.appendChild(img);\n\n // Move\n img = createImage('images/plus.png');\n img.setAttribute('title', 'Move');\n img.style.cursor = 'move';\n img.style.width = '16px';\n img.style.height = '16px';\n\n mxEvent.addGestureListeners(img, evt => {\n this.graph.graphHandler.start(\n this.state.cell,\n mxEvent.getClientX(evt),\n mxEvent.getClientY(evt)\n );\n this.graph.graphHandler.cellWasClicked = true;\n this.graph.isMouseDown = true;\n this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt);\n mxEvent.consume(evt);\n });\n this.domNode.appendChild(img);\n\n // Connect\n img = createImage('images/check.png');\n img.setAttribute('title', 'Connect');\n img.style.cursor = 'pointer';\n img.style.width = '16px';\n img.style.height = '16px';\n\n mxEvent.addGestureListeners(img, evt => {\n const pt = mxUtils.convertPoint(\n this.graph.container,\n mxEvent.getClientX(evt),\n mxEvent.getClientY(evt)\n );\n this.graph.connectionHandler.start(this.state, pt.x, pt.y);\n this.graph.isMouseDown = true;\n this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt);\n mxEvent.consume(evt);\n });\n this.domNode.appendChild(img);\n\n this.graph.container.appendChild(this.domNode);\n this.redrawTools();\n }\n\n redraw() {\n super.redraw();\n this.redrawTools();\n }\n\n redrawTools() {\n if (this.state != null && this.domNode != null) {\n const dy = 4;\n this.domNode.style.left = `${this.state.x + this.state.width - 56}px`;\n this.domNode.style.top = `${this.state.y + this.state.height + dy}px`;\n }\n }\n\n destroy(sender, me) {\n super.destroy(sender, me);\n\n if (this.domNode != null) {\n this.domNode.parentNode.removeChild(this.domNode);\n this.domNode = null;\n }\n }\n }\n\n class MyCustomGraph extends mxGraph {\n createHandler(state) {\n if (state != null && this.model.isVertex(state.cell)) {\n return new mxVertexToolHandler(state);\n }\n return super.createHandler(state);\n }\n }\n\n // Creates the graph inside the given container\n const graph = new MyCustomGraph(this.el);\n graph.setConnectable(true);\n graph.connectionHandler.createTarget = true;\n\n // Uncomment the following if you want the container\n // to fit the size of the graph\n // graph.setResizeContainer(true);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n value: 'Hello,',\n position: [20, 20],\n size: [80, 30],\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [200, 150],\n size: [80, 30],\n });\n const e1 = graph.insertEdge({\n parent,\n source: v1,\n target: v2,\n });\n });\n };\n}\n\nexport default ContextIcons;\n", - "RadialTreeLayout": "/**\n * Copyright (c) 2006-2014, 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 mxPerimeter from '../mxgraph/view/mxPerimeter';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxRadialTreeLayout from '../mxgraph/layout/mxRadialTreeLayout';\n\nclass RadialTreeLayout extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Radial Tree (Hierarchical) Layout

    \n This example demonstrates the use of the hierarchical and organic\n layouts. Note that the hierarchical layout requires another script tag\n in the head of the page.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'auto',\n height: '800px',\n borderTop: 'gray 1px solid',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Adds rubberband selection\n new mxRubberband(graph);\n\n // Changes the default vertex style in-place\n let style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_PERIMETER_SPACING] = 6;\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_SHADOW] = true;\n\n style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_ROUNDED] = true;\n\n // Creates a layout algorithm to be used\n // with the graph\n const layout = new mxRadialTreeLayout(graph);\n\n const parent = graph.getDefaultParent();\n\n // Load cells and layouts the graph\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, '1', 500, 500, 80, 30);\n const v2 = graph.insertVertex(parent, null, '2.1', 0, 0, 80, 30);\n const v3 = graph.insertVertex(parent, null, '2.2', 0, 0, 80, 30);\n const v4 = graph.insertVertex(parent, null, '3.1', 0, 0, 80, 30);\n const v4_1 = graph.insertVertex(parent, null, '3.2', 0, 0, 80, 30);\n const v4_2 = graph.insertVertex(parent, null, '3.3', 0, 0, 80, 30);\n const v4_3 = graph.insertVertex(parent, null, '3.6', 0, 0, 80, 30);\n const v4_4 = graph.insertVertex(parent, null, '3.7', 0, 0, 80, 30);\n const v5 = graph.insertVertex(parent, null, '3.4', 0, 0, 80, 30);\n const v6 = graph.insertVertex(parent, null, '2.3', 0, 0, 80, 30);\n const v7 = graph.insertVertex(parent, null, '4.1', 0, 0, 80, 30);\n const v7_1 = graph.insertVertex(parent, null, '4.2', 0, 0, 80, 30);\n const v7_2 = graph.insertVertex(parent, null, '4.3', 0, 0, 80, 30);\n const v7_3 = graph.insertVertex(parent, null, '4.4', 0, 0, 80, 30);\n const v7_4 = graph.insertVertex(parent, null, '4.5', 0, 0, 80, 30);\n const v7_5 = graph.insertVertex(parent, null, '4.6', 0, 0, 80, 30);\n const v7_6 = graph.insertVertex(parent, null, '4.7', 0, 0, 80, 30);\n\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n const e2 = graph.insertEdge(parent, null, '', v1, v3);\n const e3 = graph.insertEdge(parent, null, '', v3, v4);\n const e3_1 = graph.insertEdge(parent, null, '', v3, v4_1);\n const e3_2 = graph.insertEdge(parent, null, '', v3, v4_2);\n const e3_3 = graph.insertEdge(parent, null, '', v3, v4_3);\n const e3_4 = graph.insertEdge(parent, null, '', v3, v4_4);\n const e4 = graph.insertEdge(parent, null, '', v2, v5);\n const e5 = graph.insertEdge(parent, null, '', v1, v6);\n const e6 = graph.insertEdge(parent, null, '', v4_3, v7);\n var e6_1 = graph.insertEdge(parent, null, '', v4_4, v7_4);\n var e6_2 = graph.insertEdge(parent, null, '', v4_4, v7_5);\n var e6_3 = graph.insertEdge(parent, null, '', v4_4, v7_6);\n var e6_1 = graph.insertEdge(parent, null, '', v4_3, v7_1);\n var e6_2 = graph.insertEdge(parent, null, '', v4_3, v7_2);\n var e6_3 = graph.insertEdge(parent, null, '', v4_3, v7_3);\n\n // Executes the layout\n layout.execute(parent);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default RadialTreeLayout;\n", - "HelloPort": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxCodec from '../mxgraph/io/mxCodec';\nimport mxUtils from '../mxgraph/util/mxUtils';\n\nclass HelloPort extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Hello Port

    \n This example demonstrates using the isPort hook for visually connecting\n to another cell.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setConnectable(true);\n graph.setTooltips(true);\n\n // Sets the default edge style\n const style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;\n\n // Ports are not used as terminals for edges, they are\n // only used to compute the graphical connection point\n graph.isPort = function(cell) {\n const geo = this.getCellGeometry(cell);\n\n return geo != null ? geo.relative : false;\n };\n\n // Implements a tooltip that shows the actual\n // source and target of an edge\n graph.getTooltipForCell = function(cell) {\n if (this.model.isEdge(cell)) {\n return `${this.convertValueToString(\n this.model.getTerminal(cell, true)\n )} => ${this.convertValueToString(\n this.model.getTerminal(cell, false)\n )}`;\n }\n\n return mxGraph.prototype.getTooltipForCell.apply(this, arguments);\n };\n\n // Removes the folding icon and disables any folding\n graph.isCellFoldable = function(cell) {\n return false;\n };\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello', 20, 80, 80, 30);\n v1.setConnectable(false);\n const v11 = graph.insertVertex(v1, null, '', 1, 1, 10, 10);\n v11.geometry.offset = new mxPoint(-5, -5);\n v11.geometry.relative = true;\n const v12 = graph.insertVertex(v1, null, '', 1, 0, 10, 10);\n v12.geometry.offset = new mxPoint(-5, -5);\n v12.geometry.relative = true;\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n const v3 = graph.insertVertex(parent, null, 'World2', 200, 20, 80, 30);\n var e1 = graph.insertEdge(parent, null, '', v11, v2);\n var e1 = graph.insertEdge(parent, null, '', v12, v3);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n const button = mxUtils.button('View XML', function() {\n const encoder = new mxCodec();\n const node = encoder.encode(graph.getModel());\n mxUtils.popup(mxUtils.getPrettyXml(node), true);\n });\n\n this.el2.appendChild(button);\n }\n}\n\nexport default HelloPort;\n", - "Clipboard": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxClipboard from '../mxgraph/util/mxClipboard';\nimport mxClient from '../mxgraph/mxClient';\nimport mxCodec from '../mxgraph/io/mxCodec';\nimport mxGraphModel from '../mxgraph/model/mxGraphModel';\n\nclass Clipboard extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Clipboard

    \n This example demonstrates using the clipboard for providing cross-tab\n and cross-browser copy and paste.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given this.el\n const graph = new mxGraph(this.el);\n\n // Public helper method for shared clipboard.\n mxClipboard.cellsToString = function(cells) {\n const codec = new mxCodec();\n const model = new mxGraphModel();\n const parent = model.getChildAt(model.getRoot(), 0);\n\n for (let i = 0; i < cells.length; i++) {\n model.add(parent, cells[i]);\n }\n\n return mxUtils.getXml(codec.encode(model));\n };\n\n // Focused but invisible textarea during control or meta key events\n const textInput = document.createElement('textarea');\n mxUtils.setOpacity(textInput, 0);\n textInput.style.width = '1px';\n textInput.style.height = '1px';\n let restoreFocus = false;\n const gs = graph.gridSize;\n let lastPaste = null;\n let dx = 0;\n let dy = 0;\n\n // Workaround for no copy event in IE/FF if empty\n textInput.value = ' ';\n\n // Shows a textare when control/cmd is pressed to handle native clipboard actions\n mxEvent.addListener(document, 'keydown', function(evt) {\n // No dialog visible\n const source = mxEvent.getSource(evt);\n\n if (\n graph.isEnabled() &&\n !graph.isMouseDown &&\n !graph.isEditing() &&\n source.nodeName !== 'INPUT'\n ) {\n if (\n evt.keyCode === 224 /* FF */ ||\n (!mxClient.IS_MAC && evt.keyCode === 17) /* Control */ ||\n (mxClient.IS_MAC &&\n (evt.keyCode === 91 || evt.keyCode === 93)) /* Left/Right Meta */\n ) {\n // Cannot use parentNode for check in IE\n if (!restoreFocus) {\n // Avoid autoscroll but allow handling of events\n textInput.style.position = 'absolute';\n textInput.style.left = `${graph.container.scrollLeft + 10}px`;\n textInput.style.top = `${graph.container.scrollTop + 10}px`;\n graph.container.appendChild(textInput);\n\n restoreFocus = true;\n textInput.focus();\n textInput.select();\n }\n }\n }\n });\n\n // Restores focus on graph this.el and removes text input from DOM\n mxEvent.addListener(document, 'keyup', function(evt) {\n if (\n restoreFocus &&\n (evt.keyCode === 224 /* FF */ ||\n evt.keyCode === 17 /* Control */ ||\n evt.keyCode === 91 ||\n evt.keyCode === 93) /* Meta */\n ) {\n restoreFocus = false;\n\n if (!graph.isEditing()) {\n graph.container.focus();\n }\n\n textInput.parentNode.removeChild(textInput);\n }\n });\n\n // Inserts the XML for the given cells into the text input for copy\n const copyCells = function(graph, cells) {\n if (cells.length > 0) {\n const clones = graph.cloneCells(cells);\n\n // Checks for orphaned relative children and makes absolute\n for (let i = 0; i < clones.length; i++) {\n const state = graph.view.getState(cells[i]);\n\n if (state != null) {\n const geo = graph.getCellGeometry(clones[i]);\n\n if (geo != null && geo.relative) {\n geo.relative = false;\n geo.x = state.x / state.view.scale - state.view.translate.x;\n geo.y = state.y / state.view.scale - state.view.translate.y;\n }\n }\n }\n\n textInput.value = mxClipboard.cellsToString(clones);\n }\n\n textInput.select();\n lastPaste = textInput.value;\n };\n\n // Handles copy event by putting XML for current selection into text input\n mxEvent.addListener(\n textInput,\n 'copy',\n mxUtils.bind(this, function(evt) {\n if (graph.isEnabled() && !graph.isSelectionEmpty()) {\n copyCells(\n graph,\n mxUtils.sortCells(\n graph.model.getTopmostCells(graph.getSelectionCells())\n )\n );\n dx = 0;\n dy = 0;\n }\n })\n );\n\n // Handles cut event by removing cells putting XML into text input\n mxEvent.addListener(\n textInput,\n 'cut',\n mxUtils.bind(this, function(evt) {\n if (graph.isEnabled() && !graph.isSelectionEmpty()) {\n copyCells(graph, graph.removeCells());\n dx = -gs;\n dy = -gs;\n }\n })\n );\n\n // Merges XML into existing graph and layers\n const importXml = function(xml, dx, dy) {\n dx = dx != null ? dx : 0;\n dy = dy != null ? dy : 0;\n let cells = [];\n\n try {\n const doc = mxUtils.parseXml(xml);\n const node = doc.documentElement;\n\n if (node != null) {\n const model = new mxGraphModel();\n const codec = new mxCodec(node.ownerDocument);\n codec.decode(node, model);\n\n const childCount = model.getChildCount(model.getRoot());\n const targetChildCount = graph.model.getChildCount(\n graph.model.getRoot()\n );\n\n // Merges existing layers and adds new layers\n graph.model.beginUpdate();\n try {\n for (let i = 0; i < childCount; i++) {\n let parent = model.getChildAt(model.getRoot(), i);\n\n // Adds cells to existing layers if not locked\n if (targetChildCount > i) {\n // Inserts into active layer if only one layer is being pasted\n const target =\n childCount === 1\n ? graph.getDefaultParent()\n : graph.model.getChildAt(graph.model.getRoot(), i);\n\n if (!graph.isCellLocked(target)) {\n const children = model.getChildren(parent);\n cells = cells.concat(\n graph.importCells(children, dx, dy, target)\n );\n }\n } else {\n // Delta is non cascading, needs separate move for layers\n parent = graph.importCells(\n [parent],\n 0,\n 0,\n graph.model.getRoot()\n )[0];\n const children = graph.model.getChildren(parent);\n graph.moveCells(children, dx, dy);\n cells = cells.concat(children);\n }\n }\n } finally {\n graph.model.endUpdate();\n }\n }\n } catch (e) {\n alert(e);\n throw e;\n }\n\n return cells;\n };\n\n // Parses and inserts XML into graph\n const pasteText = function(text) {\n const xml = mxUtils.trim(text);\n const x =\n graph.container.scrollLeft / graph.view.scale - graph.view.translate.x;\n const y =\n graph.container.scrollTop / graph.view.scale - graph.view.translate.y;\n\n if (xml.length > 0) {\n if (lastPaste !== xml) {\n lastPaste = xml;\n dx = 0;\n dy = 0;\n } else {\n dx += gs;\n dy += gs;\n }\n\n // Standard paste via control-v\n if (xml.substring(0, 14) === '') {\n graph.setSelectionCells(importXml(xml, dx, dy));\n graph.scrollCellToVisible(graph.getSelectionCell());\n }\n }\n };\n\n // Function to fetch text from paste events\n const extractGraphModelFromEvent = function(evt) {\n let data = null;\n\n if (evt != null) {\n const provider =\n evt.dataTransfer != null ? evt.dataTransfer : evt.clipboardData;\n\n if (provider != null) {\n data =\n mxUtils.indexOf(provider.types, 'text/html') >= 0\n ? provider.getData('text/html')\n : null;\n\n if (\n mxUtils.indexOf(\n provider.types,\n 'text/plain' && (data == null || data.length === 0)\n )\n ) {\n data = provider.getData('text/plain');\n }\n }\n }\n\n return data;\n };\n\n // Handles paste event by parsing and inserting XML\n mxEvent.addListener(textInput, 'paste', function(evt) {\n // Clears existing contents before paste - should not be needed\n // because all text is selected, but doesn't hurt since the\n // actual pasting of the new text is delayed in all cases.\n textInput.value = '';\n\n if (graph.isEnabled()) {\n const xml = extractGraphModelFromEvent(evt);\n\n if (xml != null && xml.length > 0) {\n pasteText(xml);\n } else {\n // Timeout for new value to appear\n window.setTimeout(\n mxUtils.bind(this, function() {\n pasteText(textInput.value);\n }),\n 0\n );\n }\n }\n\n textInput.select();\n });\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n value: 'Hello,',\n position: [20, 20],\n size: [80, 30],\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [200, 150],\n size: [80, 30],\n });\n const e1 = graph.insertEdge({ parent, source: v1, target: v2 });\n });\n };\n}\n\nexport default Clipboard;\n", - "__template": "import React from 'react';\nimport mxEvent from '../mxgraph/util/mxEvent';\nimport mxGraph from '../mxgraph/view/mxGraph';\nimport mxRubberband from '../mxgraph/handler/mxRubberband';\n\nclass MYNAMEHERE 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 {\n this.el = el;\n }}\n style={{}}\n />\n \n );\n }\n\n componentDidMount() {}\n}\n\nexport default MYNAMEHERE;\n", - "Drop": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxClient from '../mxgraph/mxClient';\n\nclass Drop extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Drop

    \n This example demonstrates handling native drag and drop of images\n (requires modern browser).\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '441px',\n background: `url('editors/images/grid.gif')`,\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Checks if the browser is supported\n const fileSupport =\n window.File != null &&\n window.FileReader != null &&\n window.FileList != null;\n\n if (!fileSupport || !mxClient.isBrowserSupported()) {\n // Displays an error message if the browser is not supported.\n mxUtils.error('Browser is not supported!', 200, false);\n } else {\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given this.el\n const graph = new mxGraph(this.el);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n mxEvent.addListener(this.el, 'dragover', function(evt) {\n if (graph.isEnabled()) {\n evt.stopPropagation();\n evt.preventDefault();\n }\n });\n\n mxEvent.addListener(this.el, 'drop', evt => {\n if (graph.isEnabled()) {\n evt.stopPropagation();\n evt.preventDefault();\n\n // Gets drop location point for vertex\n const pt = mxUtils.convertPoint(\n graph.container,\n mxEvent.getClientX(evt),\n mxEvent.getClientY(evt)\n );\n const tr = graph.view.translate;\n const { scale } = graph.view;\n const x = pt.x / scale - tr.x;\n const y = pt.y / scale - tr.y;\n\n // Converts local images to data urls\n const filesArray = evt.dataTransfer.files;\n\n for (let i = 0; i < filesArray.length; i++) {\n this.handleDrop(graph, filesArray[i], x + i * 10, y + i * 10);\n }\n }\n });\n }\n }\n\n handleDrop(graph, file, x, y) {\n // Handles each file as a separate insert for simplicity.\n // Use barrier to handle multiple files as a single insert.\n\n if (file.type.substring(0, 5) === 'image') {\n const reader = new FileReader();\n\n reader.onload = function(e) {\n // Gets size of image for vertex\n let data = e.target.result;\n\n // SVG needs special handling to add viewbox if missing and\n // find initial size from SVG attributes (only for IE11)\n if (file.type.substring(0, 9) === 'image/svg') {\n const comma = data.indexOf(',');\n const svgText = atob(data.substring(comma + 1));\n const root = mxUtils.parseXml(svgText);\n\n // Parses SVG to find width and height\n if (root != null) {\n const svgs = root.getElementsByTagName('svg');\n\n if (svgs.length > 0) {\n const svgRoot = svgs[0];\n let w = parseFloat(svgRoot.getAttribute('width'));\n let h = parseFloat(svgRoot.getAttribute('height'));\n\n // Check if viewBox attribute already exists\n const vb = svgRoot.getAttribute('viewBox');\n\n if (vb == null || vb.length === 0) {\n svgRoot.setAttribute('viewBox', `0 0 ${w} ${h}`);\n }\n // Uses width and height from viewbox for\n // missing width and height attributes\n else if (Number.isNaN(w) || Number.isNaN(h)) {\n const tokens = vb.split(' ');\n\n if (tokens.length > 3) {\n w = parseFloat(tokens[2]);\n h = parseFloat(tokens[3]);\n }\n }\n\n w = Math.max(1, Math.round(w));\n h = Math.max(1, Math.round(h));\n\n data = `data:image/svg+xml,${btoa(\n mxUtils.getXml(svgs[0], '\\n')\n )}`;\n graph.insertVertex({\n position: [x, y],\n size: [w, h],\n style: `shape=image;image=${data};`,\n });\n }\n }\n } else {\n const img = new Image();\n\n img.onload = () => {\n const w = Math.max(1, img.width);\n const h = Math.max(1, img.height);\n\n // Converts format of data url to cell style value for use in vertex\n const semi = data.indexOf(';');\n\n if (semi > 0) {\n data =\n data.substring(0, semi) +\n data.substring(data.indexOf(',', semi + 1));\n }\n\n graph.insertVertex({\n position: [x, y],\n size: [w, h],\n style: `shape=image;image=${data};`,\n });\n };\n\n img.src = data;\n }\n };\n\n reader.readAsDataURL(file);\n }\n }\n}\n\nexport default Drop;\n", - "Markers": "/**\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 mxPoint from '../mxgraph/util/mxPoint';\nimport mxCellRenderer from '../mxgraph/view/mxCellRenderer';\nimport mxEdgeHandler from '../mxgraph/handler/mxEdgeHandler';\nimport mxGraphHandler from '../mxgraph/handler/mxGraphHandler';\nimport mxCylinder from '../mxgraph/shape/mxCylinder';\nimport mxMarker from '../mxgraph/shape/mxMarker';\nimport mxArrow from '../mxgraph/shape/mxArrow';\n\nclass Markers extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Markers

    \n This example demonstrates creating custom markers and customizing the\n built-in markers.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '381px',\n border: '1px solid gray',\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Enables guides\n mxGraphHandler.prototype.guidesEnabled = true;\n mxEdgeHandler.prototype.snapToTerminals = true;\n\n // Registers and defines the custom marker\n mxMarker.addMarker('dash', function(\n canvas,\n shape,\n type,\n pe,\n unitX,\n unitY,\n size,\n source,\n sw,\n filled\n ) {\n const nx = unitX * (size + sw + 1);\n const ny = unitY * (size + sw + 1);\n\n return function() {\n canvas.begin();\n canvas.moveTo(pe.x - nx / 2 - ny / 2, pe.y - ny / 2 + nx / 2);\n canvas.lineTo(\n pe.x + ny / 2 - (3 * nx) / 2,\n pe.y - (3 * ny) / 2 - nx / 2\n );\n canvas.stroke();\n };\n });\n\n // Defines custom message shape\n class MessageShape extends mxCylinder {\n redrawPath(path, x, y, w, h, isForeground) {\n if (isForeground) {\n path.moveTo(0, 0);\n path.lineTo(w / 2, h / 2);\n path.lineTo(w, 0);\n } else {\n path.moveTo(0, 0);\n path.lineTo(w, 0);\n path.lineTo(w, h);\n path.lineTo(0, h);\n path.close();\n }\n }\n }\n mxCellRenderer.registerShape('message', MessageShape);\n\n // Defines custom edge shape\n class LinkShape extends mxArrow {\n paintEdgeShape(c, pts) {\n const width = 10;\n\n // Base vector (between end points)\n const p0 = pts[0];\n const pe = pts[pts.length - 1];\n\n const dx = pe.x - p0.x;\n const dy = pe.y - p0.y;\n const dist = Math.sqrt(dx * dx + dy * dy);\n const length = dist;\n\n // Computes the norm and the inverse norm\n const nx = dx / dist;\n const ny = dy / dist;\n const basex = length * nx;\n const basey = length * ny;\n const floorx = (width * ny) / 3;\n const floory = (-width * nx) / 3;\n\n // Computes points\n const p0x = p0.x - floorx / 2;\n const p0y = p0.y - floory / 2;\n const p1x = p0x + floorx;\n const p1y = p0y + floory;\n const p2x = p1x + basex;\n const p2y = p1y + basey;\n const p3x = p2x + floorx;\n const p3y = p2y + floory;\n // p4 not necessary\n const p5x = p3x - 3 * floorx;\n const p5y = p3y - 3 * floory;\n\n c.begin();\n c.moveTo(p1x, p1y);\n c.lineTo(p2x, p2y);\n c.moveTo(p5x + floorx, p5y + floory);\n c.lineTo(p0x, p0y);\n c.stroke();\n }\n }\n mxCellRenderer.registerShape('link', LinkShape);\n\n // Creates the graph\n const graph = new mxGraph(this.el);\n\n // Sets default styles\n let style = graph.getStylesheet().getDefaultVertexStyle();\n style.fillColor = '#FFFFFF';\n style.strokeColor = '#000000';\n style.fontColor = '#000000';\n style.fontStyle = '1';\n\n style = graph.getStylesheet().getDefaultEdgeStyle();\n style.strokeColor = '#000000';\n style.fontColor = '#000000';\n style.fontStyle = '0';\n style.fontStyle = '0';\n style.startSize = '8';\n style.endSize = '8';\n\n // Populates the graph\n const parent = graph.getDefaultParent();\n\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'v1', 20, 20, 80, 30);\n const v2 = graph.insertVertex(parent, null, 'v2', 440, 20, 80, 30);\n const e1 = graph.insertEdge(\n parent,\n null,\n '',\n v1,\n v2,\n 'dashed=1;' +\n 'startArrow=oval;endArrow=block;sourcePerimeterSpacing=4;startFill=0;endFill=0;'\n );\n const e11 = graph.insertVertex(\n e1,\n null,\n 'Label',\n 0,\n 0,\n 20,\n 14,\n 'shape=message;labelBackgroundColor=#ffffff;labelPosition=left;spacingRight=2;align=right;fontStyle=0;'\n );\n e11.geometry.offset = new mxPoint(-10, -7);\n e11.geometry.relative = true;\n e11.connectable = false;\n\n const v3 = graph.insertVertex(parent, null, 'v3', 20, 120, 80, 30);\n const v4 = graph.insertVertex(parent, null, 'v4', 440, 120, 80, 30);\n const e2 = graph.insertEdge(\n parent,\n null,\n 'Label',\n v3,\n v4,\n 'startArrow=dash;startSize=12;endArrow=block;labelBackgroundColor=#FFFFFF;'\n );\n\n const v5 = graph.insertVertex(\n parent,\n null,\n 'v5',\n 40,\n 220,\n 40,\n 40,\n 'shape=ellipse;perimeter=ellipsePerimeter;'\n );\n const v6 = graph.insertVertex(\n parent,\n null,\n 'v6',\n 460,\n 220,\n 40,\n 40,\n 'shape=doubleEllipse;perimeter=ellipsePerimeter;'\n );\n const e3 = graph.insertEdge(\n parent,\n null,\n 'Link',\n v5,\n v6,\n 'shape=link;labelBackgroundColor=#FFFFFF;'\n );\n } finally {\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Markers;\n", - "Overlays": "/**\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 mxCellTracker from '../mxgraph/handler/mxCellTracker';\nimport mxCellOverlay from '../mxgraph/view/mxCellOverlay';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxUtils from '../mxgraph/util/mxUtils';\n\nclass Overlays extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Overlays

    \n This example demonstrates cell highlighting, overlays and handling click\n and double click events. See also: events.html for more event handling.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Disables basic selection and cell handling\n graph.setEnabled(false);\n\n // Highlights the vertices when the mouse enters\n const highlight = new mxCellTracker(graph, '#00FF00');\n\n // Enables tooltips for the overlays\n graph.setTooltips(true);\n\n // Installs a handler for click events in the graph\n // that toggles the overlay for the respective cell\n graph.addListener(mxEvent.CLICK, (sender, evt) => {\n const cell = evt.getProperty('cell');\n\n if (cell != null) {\n const overlays = graph.getCellOverlays(cell);\n\n if (overlays == null) {\n // Creates a new overlay with an image and a tooltip\n const overlay = new mxCellOverlay(\n new mxImage('editors/images/overlays/check.png', 16, 16),\n 'Overlay tooltip'\n );\n\n // Installs a handler for clicks on the overlay\n overlay.addListener(mxEvent.CLICK, (sender, evt2) => {\n mxUtils.alert('Overlay clicked');\n });\n\n // Sets the overlay for the cell in the graph\n graph.addCellOverlay(cell, overlay);\n } else {\n graph.removeCellOverlays(cell);\n }\n }\n });\n\n // Installs a handler for double click events in the graph\n // that shows an alert box\n graph.addListener(mxEvent.DOUBLE_CLICK, (sender, evt) => {\n const cell = evt.getProperty('cell');\n mxUtils.alert(`Doubleclick: ${cell != null ? 'Cell' : 'Graph'}`);\n evt.consume();\n });\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n value: 'Click,',\n position: [20, 20],\n size: [60, 40],\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'Doubleclick',\n position: [200, 150],\n size: [100, 40],\n });\n const e1 = graph.insertEdge({\n parent,\n source: v1,\n target: v2,\n });\n });\n }\n}\n\nexport default Overlays;\n", - "Constituent": "/**\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 mxGraphHandler from '../mxgraph/handler/mxGraphHandler';\n\nclass Constituent extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Constituent

    \n This example demonstrates using cells as parts of other cells.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: 'url(\"editors/images/grid.gif\")',\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n class MyCustomGraphHandler extends mxGraphHandler {\n /**\n * Redirects start drag to parent.\n */\n getInitialCellForEvent(me) {\n let cell = super.getInitialCellForEvent(me);\n if (this.graph.isPart(cell)) {\n cell = this.cell.getParent();\n }\n return cell;\n }\n }\n\n class MyCustomGraph extends mxGraph {\n foldingEnabled = false;\n\n recursiveResize = true;\n\n isPart(cell) {\n // Helper method to mark parts with constituent=1 in the style\n return this.getCurrentCellStyle(cell).constituent == '1';\n }\n\n selectCellForEvent(cell, evt) {\n // Redirects selection to parent\n if (this.isPart(cell)) {\n cell = this.model.getParent(cell);\n }\n super.selectCellForEvent(cell, evt);\n }\n\n createGraphHandler() {\n return new MyCustomGraphHandler(this);\n }\n }\n\n // Creates the graph inside the given container\n const graph = new MyCustomGraph(this.el);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n position: [20, 20],\n size: [120, 70],\n });\n const v2 = graph.insertVertex({\n parent: v1,\n value: 'Constituent',\n position: [20, 20],\n size: [80, 30],\n style: 'constituent=1;',\n });\n });\n }\n}\n\nexport default Constituent;\n", - "Editing": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\n\nclass Editing extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Editing

    \n This example demonstrates using the in-place editor trigger to specify\n the editing value and write the new value into a specific field of the\n user object. Wrapping and DOM nodes as labels are also demonstrated\n here.\n
    \n
    \n Double-click the upper/lower half of the cell to edit different fields\n of the user object.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n }}\n />\n \n );\n }\n\n componentDidMount() {\n class MyCustomGraph extends mxGraph {\n getLabel(cell) {\n // Returns a HTML representation of the cell where the\n // upper half is the first value, lower half is second\n // value\n\n const table = document.createElement('table');\n table.style.height = '100%';\n table.style.width = '100%';\n\n const body = document.createElement('tbody');\n const tr1 = document.createElement('tr');\n const td1 = document.createElement('td');\n td1.style.textAlign = 'center';\n td1.style.fontSize = '12px';\n td1.style.color = '#774400';\n mxUtils.write(td1, cell.value.first);\n\n const tr2 = document.createElement('tr');\n const td2 = document.createElement('td');\n td2.style.textAlign = 'center';\n td2.style.fontSize = '12px';\n td2.style.color = '#774400';\n mxUtils.write(td2, cell.value.second);\n\n tr1.appendChild(td1);\n tr2.appendChild(td2);\n body.appendChild(tr1);\n body.appendChild(tr2);\n table.appendChild(body);\n\n return table;\n }\n\n getEditingValue(cell, evt) {\n // Returns the editing value for the given cell and event\n evt.fieldname = this.__getFieldnameForEvent(cell, evt);\n return cell.value[evt.fieldname] || '';\n }\n\n __getFieldnameForEvent(cell, evt) {\n // Helper method that returns the fieldname to be used for\n // a mouse event\n if (evt != null) {\n // Finds the relative coordinates inside the cell\n const point = mxUtils.convertPoint(\n this.container,\n mxEvent.getClientX(evt),\n mxEvent.getClientY(evt)\n );\n const state = this.getView().getState(cell);\n\n if (state != null) {\n point.x -= state.x;\n point.y -= state.y;\n\n // Returns second if mouse in second half of cell\n if (point.y > state.height / 2) {\n return 'second';\n }\n }\n }\n return 'first';\n }\n\n labelChanged(cell, newValue, trigger) {\n // Sets the new value for the given cell and trigger\n const name = trigger != null ? trigger.fieldname : null;\n\n if (name != null) {\n // Clones the user object for correct undo and puts\n // the new value in the correct field.\n const value = mxUtils.clone(cell.value);\n value[name] = newValue;\n newValue = value;\n\n super.labelChanged(cell, newValue, trigger);\n }\n }\n }\n\n // Creates the graph inside the given container\n const graph = new MyCustomGraph(this.el);\n graph.setHtmlLabels(true);\n\n // Adds handling of return and escape keystrokes for editing\n const keyHandler = new mxKeyHandler(graph);\n\n // Sample user objects with 2 fields\n const value = {};\n value.first = 'First value';\n value.second = 'Second value';\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(\n parent,\n null,\n value,\n 100,\n 60,\n 120,\n 80,\n 'overflow=fill;'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Editing;\n", - "HierarchicalLayout": "/**\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 mxHierarchicalLayout from '../mxgraph/layout/hierarchical/mxHierarchicalLayout';\nimport mxFastOrganicLayout from '../mxgraph/layout/mxFastOrganicLayout';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxPerimeter from '../mxgraph/view/mxPerimeter';\nimport mxUtils from '../mxgraph/util/mxUtils';\n\nclass HierarchicalLayout extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Hierarchical Layout

    \n This example demonstrates the use of the hierarchical and organic\n layouts. Note that the hierarchical layout requires another script tag\n in the head of the page.\n {\n this.el = el;\n }}\n style={{\n position: 'absolute',\n overflow: 'auto',\n top: '36px',\n bottom: '0px',\n left: '0px',\n right: '0px',\n borderTop: 'gray 1px solid',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Adds rubberband selection\n new mxRubberband(graph);\n\n // Changes the default vertex style in-place\n let style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_PERIMETER_SPACING] = 6;\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_SHADOW] = true;\n\n style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_ROUNDED] = true;\n\n // Creates a layout algorithm to be used\n // with the graph\n const layout = new mxHierarchicalLayout(graph);\n const organic = new mxFastOrganicLayout(graph);\n organic.forceConstant = 120;\n\n const parent = graph.getDefaultParent();\n\n // Adds a button to execute the layout\n let button = document.createElement('button');\n mxUtils.write(button, 'Hierarchical');\n mxEvent.addListener(button, 'click', function(evt) {\n layout.execute(parent);\n });\n this.el2.appendChild(button);\n\n // Adds a button to execute the layout\n button = document.createElement('button');\n mxUtils.write(button, 'Organic');\n\n mxEvent.addListener(button, 'click', function(evt) {\n organic.execute(parent);\n });\n\n this.el2.appendChild(button);\n\n // Load cells and layouts the graph\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, '1', 0, 0, 80, 30);\n const v2 = graph.insertVertex(parent, null, '2', 0, 0, 80, 30);\n const v3 = graph.insertVertex(parent, null, '3', 0, 0, 80, 30);\n const v4 = graph.insertVertex(parent, null, '4', 0, 0, 80, 30);\n const v5 = graph.insertVertex(parent, null, '5', 0, 0, 80, 30);\n const v6 = graph.insertVertex(parent, null, '6', 0, 0, 80, 30);\n const v7 = graph.insertVertex(parent, null, '7', 0, 0, 80, 30);\n const v8 = graph.insertVertex(parent, null, '8', 0, 0, 80, 30);\n const v9 = graph.insertVertex(parent, null, '9', 0, 0, 80, 30);\n\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n const e2 = graph.insertEdge(parent, null, '', v1, v3);\n const e3 = graph.insertEdge(parent, null, '', v3, v4);\n const e4 = graph.insertEdge(parent, null, '', v2, v5);\n const e5 = graph.insertEdge(parent, null, '', v1, v6);\n const e6 = graph.insertEdge(parent, null, '', v2, v3);\n const e7 = graph.insertEdge(parent, null, '', v6, v4);\n const e8 = graph.insertEdge(parent, null, '', v6, v1);\n const e9 = graph.insertEdge(parent, null, '', v6, v7);\n const e10 = graph.insertEdge(parent, null, '', v7, v8);\n const e11 = graph.insertEdge(parent, null, '', v7, v9);\n const e12 = graph.insertEdge(parent, null, '', v7, v6);\n const e13 = graph.insertEdge(parent, null, '', v7, v5);\n\n // Executes the layout\n layout.execute(parent);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default HierarchicalLayout;\n", - "OffPage": "/**\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 mxCellTracker from '../mxgraph/handler/mxCellTracker';\nimport mxConstants from '../mxgraph/util/mxConstants';\n\nclass OffPage extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Offpage connector

    \n This example demonstrates creating offpage connectors in a graph and\n loading a new diagram on a single click.\n {\n this.el = el;\n }}\n style={{}}\n />\n \n );\n }\n\n componentDidMount() {\n // Use complete cell as highlight region\n mxConstants.ACTIVE_REGION = 1;\n\n const container = document.createElement('div');\n container.style.position = 'relative';\n container.style.overflow = 'hidden';\n container.style.height = '80vhpx';\n container.style.background = 'url(\"editors/images/grid.gif\")';\n\n this.el.appendChild(container);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(container);\n graph.setEnabled(false);\n\n // Highlights offpage connectors\n const highlight = new mxCellTracker(graph, null, function(me) {\n const cell = me.getCell();\n\n if (\n cell != null &&\n cell.value != null &&\n typeof cell.value.create === 'function'\n ) {\n return cell;\n }\n\n return null;\n });\n\n // Handles clicks on offpage connectors and\n // executes function in user object\n graph.addListener(mxEvent.CLICK, function(source, evt) {\n const cell = evt.getProperty('cell');\n\n if (\n cell != null &&\n cell.value != null &&\n typeof cell.value.create === 'function'\n ) {\n cell.value.create();\n }\n });\n\n // Handles clicks on offpage connectors and\n // executes function in user object\n graph.getCursorForCell = function(cell) {\n if (\n cell != null &&\n cell.value != null &&\n typeof cell.value.create === 'function'\n ) {\n return 'pointer';\n }\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n let first = null;\n let second = null;\n\n first = function() {\n const value = {\n toString() {\n return 'Next';\n },\n create: second,\n };\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n graph.getModel().setRoot(graph.getModel().createRoot());\n const parent = graph.getDefaultParent();\n\n const v1 = graph.insertVertex(\n parent,\n null,\n 'Click',\n 30,\n 20,\n 80,\n 30,\n 'fillColor=#FFFF88;strokeColor=#FF1A00'\n );\n const v2 = graph.insertVertex(\n parent,\n null,\n 'Next',\n 20,\n 150,\n 100,\n 30,\n 'fillColor=#FFFF88;strokeColor=#FF1A00'\n );\n const v3 = graph.insertVertex(\n parent,\n null,\n value,\n 200,\n 150,\n 40,\n 40,\n 'shape=triangle;align=left;fillColor=#C3D9FF;strokeColor=#4096EE'\n );\n const e1 = graph.insertEdge(\n parent,\n null,\n null,\n v1,\n v2,\n 'strokeColor=#FF1A00'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n };\n\n second = function() {\n const value = {\n toString() {\n return 'Prev';\n },\n create: first,\n };\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n graph.getModel().setRoot(graph.getModel().createRoot());\n const parent = graph.getDefaultParent();\n\n const v1 = graph.insertVertex(\n parent,\n null,\n 'Click',\n 30,\n 20,\n 80,\n 30,\n 'fillColor=#CDEB8B;strokeColor=#008C00'\n );\n const v2 = graph.insertVertex(\n parent,\n null,\n 'Prev',\n 220,\n 20,\n 100,\n 30,\n 'fillColor=#CDEB8B;strokeColor=#008C00'\n );\n const v3 = graph.insertVertex(\n parent,\n null,\n value,\n 30,\n 150,\n 40,\n 40,\n 'shape=triangle;align=right;fillColor=#C3D9FF;strokeColor=#4096EE;direction=west'\n );\n const e1 = graph.insertEdge(\n parent,\n null,\n null,\n v1,\n v2,\n 'strokeColor=#008C00'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n };\n\n first();\n }\n}\n\nexport default OffPage;\n", - "Resources": "/**\n * Copyright (c) 2006-2018, JGraph Ltd\n \n\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 mxClient from '../mxgraph/mxClient';\n\nclass Resources extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Resources

    \n This example demonstrates disabling the Synchronous XMLHttpRequest on\n main thread warning.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Async indirection to load resources asynchronously (see above)\n // Alternatively you can remove the line that sets mxLoadResources\n // anove and change the code to not use this callback.\n\n mxClient.loadResources(() => {\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n });\n }\n}\n\nexport default Resources;\n", - "Indicators": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\n\nclass Indicators extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Indicators

    \n This example demonstrates the use of indicators, which are small\n subshapes inside a parent shape, typically an mxLabel.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '300ph',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setConnectable(true);\n new mxKeyHandler(graph);\n\n // Enables moving of vertex labels\n graph.vertexLabelsMovable = true;\n\n // Creates a style with an indicator\n let style = graph.getStylesheet().getDefaultVertexStyle();\n\n style[mxConstants.STYLE_SHAPE] = 'label';\n style[mxConstants.STYLE_VERTICAL_ALIGN] = 'bottom';\n style[mxConstants.STYLE_INDICATOR_SHAPE] = 'ellipse';\n style[mxConstants.STYLE_INDICATOR_WIDTH] = 34;\n style[mxConstants.STYLE_INDICATOR_HEIGHT] = 34;\n style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = 'top'; // indicator v-alignment\n style[mxConstants.STYLE_IMAGE_ALIGN] = 'center';\n style[mxConstants.STYLE_INDICATOR_COLOR] = 'green';\n delete style[mxConstants.STYLE_STROKECOLOR]; // transparent\n delete style[mxConstants.STYLE_FILLCOLOR]; // transparent\n\n // Creates a style with an indicator\n style = graph.getStylesheet().getDefaultEdgeStyle();\n\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;\n style[mxConstants.STYLE_ELBOW] = mxConstants.ELBOW_VERTICAL;\n style[mxConstants.STYLE_ROUNDED] = true;\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n graph.insertVertex(parent, null, 'Bottom Label', 80, 80, 80, 60);\n graph.insertVertex(\n parent,\n null,\n 'Top Label',\n 200,\n 80,\n 60,\n 60,\n 'indicatorShape=actor;indicatorWidth=28;indicatorColor=blue;imageVerticalAlign=bottom;verticalAlign=top'\n );\n graph.insertVertex(\n parent,\n null,\n 'Right Label',\n 300,\n 80,\n 120,\n 60,\n 'indicatorShape=cloud;indicatorWidth=40;indicatorColor=#00FFFF;imageVerticalAlign=center;verticalAlign=middle;imageAlign=left;align=left;spacingLeft=44'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Indicators;\n", - "HoverIcons": "/**\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 mxConnectionHandler from '../mxgraph/handler/mxConnectionHandler';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxRectangle from '../mxgraph/util/mxRectangle';\nimport mxImage from '../mxgraph/util/mxImage';\n\nclass HoverIcons extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Hover icons

    \n This example demonstrates showing icons on vertices as mouse hovers over\n them.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Defines an icon for creating new connections in the connection handler.\n // This will automatically disable the highlighting of the source vertex.\n mxConnectionHandler.prototype.connectImage = new mxImage(\n 'images/connector.gif',\n 16,\n 16\n );\n\n // Defines a new class for all icons\n function mxIconSet(state) {\n this.images = [];\n const { graph } = state.view;\n\n // Icon1\n let img = mxUtils.createImage('images/copy.png');\n img.setAttribute('title', 'Duplicate');\n img.style.position = 'absolute';\n img.style.cursor = 'pointer';\n img.style.width = '16px';\n img.style.height = '16px';\n img.style.left = `${state.x + state.width}px`;\n img.style.top = `${state.y + state.height}px`;\n\n mxEvent.addGestureListeners(img, evt => {\n const s = graph.gridSize;\n graph.setSelectionCells(graph.moveCells([state.cell], s, s, true));\n mxEvent.consume(evt);\n this.destroy();\n });\n\n state.view.graph.container.appendChild(img);\n this.images.push(img);\n\n // Delete\n img = mxUtils.createImage('images/delete2.png');\n img.setAttribute('title', 'Delete');\n img.style.position = 'absolute';\n img.style.cursor = 'pointer';\n img.style.width = '16px';\n img.style.height = '16px';\n img.style.left = `${state.x + state.width}px`;\n img.style.top = `${state.y - 16}px`;\n\n mxEvent.addGestureListeners(img, evt => {\n // Disables dragging the image\n mxEvent.consume(evt);\n });\n\n mxEvent.addListener(img, 'click', evt => {\n graph.removeCells([state.cell]);\n mxEvent.consume(evt);\n this.destroy();\n });\n\n state.view.graph.container.appendChild(img);\n this.images.push(img);\n }\n\n mxIconSet.prototype.destroy = function() {\n if (this.images != null) {\n for (let i = 0; i < this.images.length; i++) {\n const img = this.images[i];\n img.parentNode.removeChild(img);\n }\n }\n\n this.images = null;\n };\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setConnectable(true);\n\n // Defines the tolerance before removing the icons\n const iconTolerance = 20;\n\n // Shows icons if the mouse is over a cell\n graph.addMouseListener({\n currentState: null,\n currentIconSet: null,\n mouseDown(sender, me) {\n // Hides icons on mouse down\n if (this.currentState != null) {\n this.dragLeave(me.getEvent(), this.currentState);\n this.currentState = null;\n }\n },\n mouseMove(sender, me) {\n if (\n this.currentState != null &&\n (me.getState() == this.currentState || me.getState() == null)\n ) {\n const tol = iconTolerance;\n const tmp = new mxRectangle(\n me.getGraphX() - tol,\n me.getGraphY() - tol,\n 2 * tol,\n 2 * tol\n );\n\n if (mxUtils.intersects(tmp, this.currentState)) {\n return;\n }\n }\n\n let tmp = graph.view.getState(me.getCell());\n\n // Ignores everything but vertices\n if (\n graph.isMouseDown ||\n (tmp != null && !graph.getModel().isVertex(tmp.cell))\n ) {\n tmp = null;\n }\n\n if (tmp != this.currentState) {\n if (this.currentState != null) {\n this.dragLeave(me.getEvent(), this.currentState);\n }\n\n this.currentState = tmp;\n\n if (this.currentState != null) {\n this.dragEnter(me.getEvent(), this.currentState);\n }\n }\n },\n mouseUp(sender, me) {},\n dragEnter(evt, state) {\n if (this.currentIconSet == null) {\n this.currentIconSet = new mxIconSet(state);\n }\n },\n dragLeave(evt, state) {\n if (this.currentIconSet != null) {\n this.currentIconSet.destroy();\n this.currentIconSet = null;\n }\n },\n });\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default HoverIcons;\n", - "Collapse": "/**\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 mxRectangle from '../mxgraph/util/mxRectangle';\nimport mxGraphModel from '../mxgraph/model/mxGraphModel';\n\nclass Collapse extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Collapse

    \n This example demonstrates changing the style of a cell based on its\n collapsed state.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n class MyCustomModel extends mxGraphModel {\n getStyle(cell) {\n // Extends mxGraphModel.getStyle to show an image when collapsed\n if (cell != null) {\n let style = super.getStyle(cell);\n if (this.isCollapsed(cell)) {\n style =\n `${style};shape=image;image=http://www.jgraph.com/images/mxgraph.gif;` +\n `noLabel=1;imageBackground=#C3D9FF;imageBorder=#6482B9`;\n }\n return style;\n }\n return null;\n }\n }\n\n const graph = new mxGraph(this.el, new MyCustomModel());\n const parent = graph.getDefaultParent();\n\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n value: 'Container',\n position: [20, 20],\n size: [200, 200],\n style: 'shape=swimlane;startSize=20;',\n });\n v1.geometry.alternateBounds = new mxRectangle(0, 0, 110, 70);\n\n const v11 = graph.insertVertex({\n parent: v1,\n value: 'Hello,',\n position: [10, 40],\n size: [120, 80],\n });\n });\n };\n}\n\nexport default Collapse;\n", - "LOD": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\n\nclass LOD extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Level of detail

    \n This example demonstrates implementing a level of detail per cell.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '441px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.centerZoom = false;\n\n // Links level of detail to zoom level but can be independent of zoom\n graph.isCellVisible = function(cell) {\n return cell.lod == null || cell.lod / 2 < this.view.scale;\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, '1', 20, 20, 80, 30);\n v1.lod = 1;\n const v2 = graph.insertVertex(parent, null, '1', 200, 150, 80, 30);\n v2.lod = 1;\n const v3 = graph.insertVertex(parent, null, '2', 20, 150, 40, 20);\n v3.lod = 2;\n const v4 = graph.insertVertex(parent, null, '3', 200, 10, 20, 20);\n v4.lod = 3;\n const e1 = graph.insertEdge(parent, null, '2', v1, v2, 'strokeWidth=2');\n e1.lod = 2;\n var e2 = graph.insertEdge(parent, null, '2', v3, v4, 'strokeWidth=2');\n e2.lod = 2;\n var e2 = graph.insertEdge(parent, null, '3', v1, v4, 'strokeWidth=1');\n e2.lod = 3;\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n this.el2.appendChild(\n mxUtils.button('+', function() {\n graph.zoomIn();\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('-', function() {\n graph.zoomOut();\n })\n );\n }\n}\n\nexport default LOD;\n", - "Tree": "/**\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 mxPoint from '../mxgraph/util/mxPoint';\nimport mxGraphView from '../mxgraph/view/mxGraphView';\nimport mxCellRenderer from '../mxgraph/view/mxCellRenderer';\nimport mxCylinder from '../mxgraph/shape/mxCylinder';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\nimport mxCompactTreeLayout from '../mxgraph/layout/mxCompactTreeLayout';\nimport mxLayoutManager from '../mxgraph/view/mxLayoutManager';\nimport mxRectangle from '../mxgraph/util/mxRectangle';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxClient from '../mxgraph/mxClient';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\n\nclass Tree extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Tree

    \n This example demonstrates folding of subtrees in a acyclic graph (tree).\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '400px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n /*\n Defines a custom shape for the tree node that includes the\n upper half of the outgoing edge(s).\n */\n class TreeNodeShape extends mxCylinder {\n // Defines the length of the upper edge segment.\n segment = 20;\n\n constructor(bounds, fill, stroke, strokewidth) {\n super(bounds, fill, stroke, strokewidth);\n }\n\n // Needs access to the cell state for rendering\n apply(state) {\n super.apply(state);\n this.state = state;\n }\n\n redrawPath(path, x, y, w, h, isForeground) {\n const { graph } = this.state.view;\n const hasChildren =\n graph.model.getOutgoingEdges(this.state.cell).length > 0;\n\n if (isForeground) {\n if (hasChildren) {\n // Painting outside of vertex bounds is used here\n path.moveTo(w / 2, h + this.segment);\n path.lineTo(w / 2, h);\n path.end();\n }\n } else {\n path.moveTo(0, 0);\n path.lineTo(w, 0);\n path.lineTo(w, h);\n path.lineTo(0, h);\n path.close();\n }\n }\n }\n mxCellRenderer.registerShape('treenode', TreeNodeShape);\n\n class MyCustomGraphView extends mxGraphView {\n updateFloatingTerminalPoint(edge, start, end, source) {\n // Defines a custom perimeter for the nodes in the tree\n let pt = null;\n\n if (source) {\n pt = new mxPoint(\n start.x + start.width / 2,\n start.y + start.height + TreeNodeShape.prototype.segment\n );\n } else {\n pt = new mxPoint(start.x + start.width / 2, start.y);\n }\n\n edge.setAbsoluteTerminalPoint(pt, source);\n }\n }\n\n class MyCustomCellRenderer extends mxCellRenderer {\n getControlBounds(state) {\n // Defines the position of the folding icon\n if (state.control != null) {\n const oldScale = state.control.scale;\n const w = state.control.bounds.width / oldScale;\n const h = state.control.bounds.height / oldScale;\n const s = state.view.scale;\n\n return new mxRectangle(\n state.x + state.width / 2 - (w / 2) * s,\n state.y +\n state.height +\n TreeNodeShape.prototype.segment * s -\n (h / 2) * s,\n w * s,\n h * s\n );\n }\n return null;\n }\n }\n\n // Make the layout instance accessible by MyCustomGraph\n let layout;\n\n class MyCustomGraph extends mxGraph {\n // Sets the collapse and expand icons. The values below are the default\n // values, but this is how to replace them if you need to.\n collapsedImage = new mxImage(\n `${mxClient.imageBasePath}/collapsed.gif`,\n 9,\n 9\n );\n\n expandedImage = new mxImage(\n `${mxClient.imageBasePath}/expanded.gif`,\n 9,\n 9\n );\n\n isCellFoldable(cell) {\n // Defines the condition for showing the folding icon\n return this.model.getOutgoingEdges(cell).length > 0;\n }\n\n createCellRenderer() {\n return new MyCustomCellRenderer();\n }\n\n createGraphView() {\n return new MyCustomGraphView(this);\n }\n\n foldCells(collapse, recurse, cells) {\n // Implements the click on a folding icon\n this.model.beginUpdate();\n try {\n this.toggleSubtree(this, cells[0], !collapse);\n this.model.setCollapsed(cells[0], collapse);\n\n // Executes the layout for the new graph since\n // changes to visiblity and collapsed state do\n // not trigger a layout in the current manager.\n layout.execute(this.getDefaultParent());\n } finally {\n this.model.endUpdate();\n }\n }\n\n toggleSubtree(cell, show) {\n // Updates the visible state of a given subtree taking into\n // account the collapsed state of the traversed branches\n show = show != null ? show : true;\n const cells = [];\n\n this.traverse(cell, true, function(vertex) {\n if (vertex !== cell) {\n cells.push(vertex);\n }\n\n // Stops recursion if a collapsed cell is seen\n return vertex === cell || !this.isCellCollapsed(vertex);\n });\n\n this.toggleCells(show, cells, true);\n }\n }\n\n // Creates the graph inside the given container\n const graph = new MyCustomGraph(this.el);\n\n // Disallow any selections\n graph.setCellsSelectable(false);\n\n // Avoids overlap of edges and collapse icons\n graph.keepEdgesInBackground = true;\n\n // Set some stylesheet options for the visual appearance\n let style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_SHAPE] = 'treenode';\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_SHADOW] = true;\n\n style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.TopToBottom;\n style[mxConstants.STYLE_ROUNDED] = true;\n\n // Enables automatic sizing for vertices after editing and\n // panning by using the left mouse button.\n graph.setAutoSizeCells(true);\n graph.setPanning(true);\n graph.panningHandler.useLeftButtonForPanning = true;\n\n // Stops editing on enter or escape keypress\n const keyHandler = new mxKeyHandler(graph);\n\n // Enables automatic layout on the graph and installs\n // a tree layout for all groups who's children are\n // being changed, added or removed.\n layout = new mxCompactTreeLayout(graph, false);\n layout.useBoundingBox = false;\n layout.edgeRouting = false;\n layout.levelDistance = 30;\n layout.nodeDistance = 10;\n\n const layoutMgr = new mxLayoutManager(graph);\n\n layoutMgr.getLayout = function(cell) {\n if (cell.getChildCount() > 0) {\n return layout;\n }\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds the root vertex of the tree\n graph.getModel().beginUpdate();\n try {\n const w = graph.container.offsetWidth;\n const root = graph.insertVertex(\n parent,\n 'treeRoot',\n 'Root',\n w / 2 - 30,\n 20,\n 60,\n 40\n );\n\n const v1 = graph.insertVertex(parent, 'v1', 'Child 1', 0, 0, 60, 40);\n graph.insertEdge(parent, null, '', root, v1);\n\n const v2 = graph.insertVertex(parent, 'v2', 'Child 2', 0, 0, 60, 40);\n graph.insertEdge(parent, null, '', root, v2);\n\n const v3 = graph.insertVertex(parent, 'v3', 'Child 3', 0, 0, 60, 40);\n graph.insertEdge(parent, null, '', root, v3);\n\n const v11 = graph.insertVertex(parent, 'v11', 'Child 1.1', 0, 0, 60, 40);\n graph.insertEdge(parent, null, '', v1, v11);\n\n const v12 = graph.insertVertex(parent, 'v12', 'Child 1.2', 0, 0, 60, 40);\n graph.insertEdge(parent, null, '', v1, v12);\n\n const v21 = graph.insertVertex(parent, 'v21', 'Child 2.1', 0, 0, 60, 40);\n graph.insertEdge(parent, null, '', v2, v21);\n\n const v22 = graph.insertVertex(parent, 'v22', 'Child 2.2', 0, 0, 60, 40);\n graph.insertEdge(parent, null, '', v2, v22);\n\n const v221 = graph.insertVertex(\n parent,\n 'v221',\n 'Child 2.2.1',\n 0,\n 0,\n 60,\n 40\n );\n graph.insertEdge(parent, null, '', v22, v221);\n\n const v222 = graph.insertVertex(\n parent,\n 'v222',\n 'Child 2.2.2',\n 0,\n 0,\n 60,\n 40\n );\n graph.insertEdge(parent, null, '', v22, v222);\n\n const v31 = graph.insertVertex(parent, 'v31', 'Child 3.1', 0, 0, 60, 40);\n graph.insertEdge(parent, null, '', v3, v31);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Tree;\n", - "Labels": "/**\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 mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxRectangle from '../mxgraph/util/mxRectangle';\n\nclass Labels extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Labels

    \n This example demonstrates the use of wrapping and clipping for HTML\n labels of vertices, truncating labels to fit the size of a vertex, and\n manually placing vertex labels and relative children that act as\n \"sublabels\".\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '300px',\n background: \"url('editors/images/grid.gif')\",\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setTooltips(true);\n graph.htmlLabels = true;\n graph.vertexLabelsMovable = true;\n new mxRubberband(graph);\n new mxKeyHandler(graph);\n\n // Do not allow removing labels from parents\n graph.graphHandler.removeCellsFromParent = false;\n\n // Autosize labels on insert where autosize=1\n graph.autoSizeCellsOnAdd = true;\n\n // Allows moving of relative cells\n graph.isCellLocked = function(cell) {\n return this.isCellsLocked();\n };\n\n graph.isCellResizable = function(cell) {\n const geo = this.model.getGeometry(cell);\n\n return geo == null || !geo.relative;\n };\n\n // Truncates the label to the size of the vertex\n graph.getLabel = function(cell) {\n const label = this.labelsVisible ? this.convertValueToString(cell) : '';\n const geometry = this.model.getGeometry(cell);\n\n if (\n !this.model.isCollapsed(cell) &&\n geometry != null &&\n (geometry.offset == null ||\n (geometry.offset.x == 0 && geometry.offset.y == 0)) &&\n this.model.isVertex(cell) &&\n geometry.width >= 2\n ) {\n const style = this.getCellStyle(cell);\n const fontSize =\n style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE;\n const max = geometry.width / (fontSize * 0.625);\n\n if (max < label.length) {\n return `${label.substring(0, max)}...`;\n }\n }\n\n return label;\n };\n\n // Enables wrapping for vertex labels\n graph.isWrapping = function(cell) {\n return this.model.isCollapsed(cell);\n };\n\n // Enables clipping of vertex labels if no offset is defined\n graph.isLabelClipped = function(cell) {\n const geometry = this.model.getGeometry(cell);\n\n return (\n geometry != null &&\n !geometry.relative &&\n (geometry.offset == null ||\n (geometry.offset.x == 0 && geometry.offset.y == 0))\n );\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(\n parent,\n null,\n 'vertexLabelsMovable',\n 20,\n 20,\n 80,\n 30\n );\n\n // Places sublabels inside the vertex\n const label11 = graph.insertVertex(\n v1,\n null,\n 'Label1',\n 0.5,\n 1,\n 0,\n 0,\n null,\n true\n );\n const label12 = graph.insertVertex(\n v1,\n null,\n 'Label2',\n 0.5,\n 0,\n 0,\n 0,\n null,\n true\n );\n\n const v2 = graph.insertVertex(\n parent,\n null,\n 'Wrapping and clipping is enabled only if the cell is collapsed, otherwise the label is truncated if there is no manual offset.',\n 200,\n 150,\n 80,\n 30\n );\n v2.geometry.alternateBounds = new mxRectangle(0, 0, 80, 30);\n const e1 = graph.insertEdge(parent, null, 'edgeLabelsMovable', v1, v2);\n\n // Places sublabels inside the vertex\n const label21 = graph.insertVertex(\n v2,\n null,\n 'Label1',\n 0.5,\n 1,\n 0,\n 0,\n null,\n true\n );\n const label22 = graph.insertVertex(\n v2,\n null,\n 'Label2',\n 0.5,\n 0,\n 0,\n 0,\n null,\n true\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Labels;\n", - "Control": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxRectangle from '../mxgraph/util/mxRectangle';\nimport mxCellRenderer from '../mxgraph/view/mxCellRenderer';\nimport mxImageShape from '../mxgraph/shape/mxImageShape';\nimport mxImage from '../mxgraph/util/mxImage';\n\nclass Control extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Control

    \n This example demonstrates adding controls to specific cells in a graph.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '441px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Specifies the URL and size of the new control\n const deleteImage = new mxImage(\n 'editors/images/overlays/forbidden.png',\n 16,\n 16\n );\n\n class MyCustomCellRenderer extends mxCellRenderer {\n createControl(state) {\n super.createControl(state);\n\n const { graph } = state.view;\n\n if (graph.getModel().isVertex(state.cell)) {\n if (state.deleteControl == null) {\n const b = new mxRectangle(\n 0,\n 0,\n deleteImage.width,\n deleteImage.height\n );\n state.deleteControl = new mxImageShape(b, deleteImage.src);\n state.deleteControl.dialect = graph.dialect;\n state.deleteControl.preserveImageAspect = false;\n\n this.initControl(state, state.deleteControl, false, function(evt) {\n if (graph.isEnabled()) {\n graph.removeCells([state.cell]);\n mxEvent.consume(evt);\n }\n });\n }\n } else if (state.deleteControl != null) {\n state.deleteControl.destroy();\n state.deleteControl = null;\n }\n }\n\n getDeleteControlBounds(state) {\n // Helper function to compute the bounds of the control\n if (state.deleteControl != null) {\n const oldScale = state.deleteControl.scale;\n const w = state.deleteControl.bounds.width / oldScale;\n const h = state.deleteControl.bounds.height / oldScale;\n const s = state.view.scale;\n\n return state.view.graph.getModel().isEdge(state.cell)\n ? new mxRectangle(\n state.x + state.width / 2 - (w / 2) * s,\n state.y + state.height / 2 - (h / 2) * s,\n w * s,\n h * s\n )\n : new mxRectangle(\n state.x + state.width - w * s,\n state.y,\n w * s,\n h * s\n );\n }\n return null;\n }\n\n redrawControl(state) {\n // Overridden to update the scale and bounds of the control\n super.redrawControl(state);\n\n if (state.deleteControl != null) {\n const bounds = this.getDeleteControlBounds(state);\n const s = state.view.scale;\n\n if (\n state.deleteControl.scale !== s ||\n !state.deleteControl.bounds.equals(bounds)\n ) {\n state.deleteControl.bounds = bounds;\n state.deleteControl.scale = s;\n state.deleteControl.redraw();\n }\n }\n }\n\n destroy(state) {\n // Overridden to remove the control if the state is destroyed\n super.destroy(state);\n\n if (state.deleteControl != null) {\n state.deleteControl.destroy();\n state.deleteControl = null;\n }\n }\n }\n\n class MyCustomGraph extends mxGraph {\n createCellRenderer() {\n return new MyCustomCellRenderer();\n }\n }\n\n // Creates the graph inside the given container\n const graph = new MyCustomGraph(this.el);\n graph.setPanning(true);\n\n // Uncomment the following if you want the container\n // to fit the size of the graph\n // graph.setResizeContainer(true);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex({\n parent,\n value: 'Hello,',\n position: [20, 20],\n size: [80, 30],\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [200, 150],\n size: [80, 30],\n });\n const e1 = graph.insertEdge({\n parent,\n source: v1,\n target: v2,\n });\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n graph.centerZoom = false;\n\n this.el2.appendChild(\n mxUtils.button('Zoom In', () => {\n graph.zoomIn();\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('Zoom Out', () => {\n graph.zoomOut();\n })\n );\n };\n}\n\nexport default Control;\n", - "LabelPosition": "/**\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';\n\nclass LabelPosition extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Label Position

    \n This example demonstrates the use of the label position styles to set\n the position of vertex labels.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '300px',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Defines the common part of all cell styles as a string-prefix\n const prefix = 'shape=image;image=images/icons48/keys.png;';\n\n // Adds cells to the model in a single step and set the vertex\n // label positions using the label position styles. Vertical\n // and horizontal label position styles can be combined.\n // Note: Alternatively, vertex labels can be set be overriding\n // mxCellRenderer.getLabelBounds.\n graph.getModel().beginUpdate();\n try {\n graph.insertVertex(\n parent,\n null,\n 'Bottom',\n 60,\n 60,\n 60,\n 60,\n `${prefix}verticalLabelPosition=bottom;verticalAlign=top`\n );\n graph.insertVertex(\n parent,\n null,\n 'Top',\n 140,\n 60,\n 60,\n 60,\n `${prefix}verticalLabelPosition=top;verticalAlign=bottom`\n );\n graph.insertVertex(\n parent,\n null,\n 'Left',\n 60,\n 160,\n 60,\n 60,\n `${prefix}labelPosition=left;align=right`\n );\n graph.insertVertex(\n parent,\n null,\n 'Right',\n 140,\n 160,\n 60,\n 60,\n `${prefix}labelPosition=right;align=left`\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default LabelPosition;\n", - "Validation": "/**\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 mxClient from '../mxgraph/mxClient';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxMultiplicity from '../mxgraph/view/mxMultiplicity';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\n\nclass Validation extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Validation

    \n This example demonstrates using multiplicities for automatically\n validating a graph.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '281px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n const xmlDocument = mxUtils.createXmlDocument();\n const sourceNode = xmlDocument.createElement('Source');\n const targetNode = xmlDocument.createElement('Target');\n const subtargetNode = xmlDocument.createElement('Subtarget');\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setConnectable(true);\n graph.setTooltips(true);\n graph.setAllowDanglingEdges(false);\n graph.setMultigraph(false);\n\n // Source nodes needs 1..2 connected Targets\n graph.multiplicities.push(\n new mxMultiplicity(\n true,\n 'Source',\n null,\n null,\n 1,\n 2,\n ['Target'],\n 'Source Must Have 1 or 2 Targets',\n 'Source Must Connect to Target'\n )\n );\n\n // Source node does not want any incoming connections\n graph.multiplicities.push(\n new mxMultiplicity(\n false,\n 'Source',\n null,\n null,\n 0,\n 0,\n null,\n 'Source Must Have No Incoming Edge',\n null\n )\n ); // Type does not matter\n\n // Target needs exactly one incoming connection from Source\n graph.multiplicities.push(\n new mxMultiplicity(\n false,\n 'Target',\n null,\n null,\n 1,\n 1,\n ['Source'],\n 'Target Must Have 1 Source',\n 'Target Must Connect From Source'\n )\n );\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Removes cells when [DELETE] is pressed\n const keyHandler = new mxKeyHandler(graph);\n keyHandler.bindKey(46, function(evt) {\n if (graph.isEnabled()) {\n graph.removeCells();\n }\n });\n\n // Installs automatic validation (use editor.validation = true\n // if you are using an mxEditor instance)\n const listener = function(sender, evt) {\n graph.validateGraph();\n };\n\n graph.getModel().addListener(mxEvent.CHANGE, listener);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, sourceNode, 20, 20, 80, 30);\n const v2 = graph.insertVertex(parent, null, targetNode, 200, 20, 80, 30);\n const v3 = graph.insertVertex({\n parent,\n value: targetNode.cloneNode(true),\n position: [200, 80],\n size: [80, 30],\n });\n const v4 = graph.insertVertex(\n parent,\n null,\n targetNode.cloneNode(true),\n 200,\n 140,\n 80,\n 30\n );\n const v5 = graph.insertVertex(\n parent,\n null,\n subtargetNode,\n 200,\n 200,\n 80,\n 30\n );\n const v6 = graph.insertVertex(\n parent,\n null,\n sourceNode.cloneNode(true),\n 20,\n 140,\n 80,\n 30\n );\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n const e2 = graph.insertEdge(parent, null, '', v1, v3);\n const e3 = graph.insertEdge(parent, null, '', v6, v4);\n // var e4 = graph.insertEdge(parent, null, '', v1, v4);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Validation;\n", - "Toolbar": "/**\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 mxDragSource from '../mxgraph/util/mxDragSource';\nimport mxGraphModel from '../mxgraph/model/mxGraphModel';\nimport mxToolbar from '../mxgraph/util/mxToolbar';\nimport mxConnectionHandler from '../mxgraph/handler/mxConnectionHandler';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxGeometry from '../mxgraph/model/mxGeometry';\nimport mxCell from '../mxgraph/model/mxCell';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\n\nclass Toolbar extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Toolbar

    \n This example demonstrates using existing cells as templates for creating\n new cells.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '400px',\n border: 'gray dotted 1px',\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Defines an icon for creating new connections in the connection handler.\n // This will automatically disable the highlighting of the source vertex.\n mxConnectionHandler.prototype.connectImage = new mxImage(\n 'images/connector.gif',\n 16,\n 16\n );\n\n // Creates the div for the toolbar\n const tbContainer = document.createElement('div');\n tbContainer.style.position = 'absolute';\n tbContainer.style.overflow = 'hidden';\n tbContainer.style.padding = '2px';\n tbContainer.style.left = '0px';\n tbContainer.style.top = '26px';\n tbContainer.style.width = '24px';\n tbContainer.style.bottom = '0px';\n\n this.el.appendChild(tbContainer);\n\n // Creates new toolbar without event processing\n const toolbar = new mxToolbar(tbContainer);\n toolbar.enabled = false;\n\n // Creates the div for the graph\n const container = document.createElement('div');\n container.style.position = 'absolute';\n container.style.overflow = 'hidden';\n container.style.left = '24px';\n container.style.top = '26px';\n container.style.right = '0px';\n container.style.bottom = '0px';\n container.style.background = 'url(\"editors/images/grid.gif\")';\n\n this.el.appendChild(container);\n\n // Creates the model and the graph inside the container\n // using the fastest rendering available on the browser\n const model = new mxGraphModel();\n const graph = new mxGraph(container, model);\n graph.dropEnabled = true;\n\n // Matches DnD inside the graph\n mxDragSource.prototype.getDropTarget = function(graph, x, y) {\n let cell = graph.getCellAt(x, y);\n if (!graph.isValidDropTarget(cell)) {\n cell = null;\n }\n return cell;\n };\n\n // Enables new connections in the graph\n graph.setConnectable(true);\n graph.setMultigraph(false);\n\n // Stops editing on enter or escape keypress\n const keyHandler = new mxKeyHandler(graph);\n const rubberband = new mxRubberband(graph);\n\n const addVertex = (icon, w, h, style) => {\n const vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style);\n vertex.setVertex(true);\n\n this.addToolbarItem(graph, toolbar, vertex, icon);\n };\n\n addVertex(\n 'editors/images/swimlane.gif',\n 120,\n 160,\n 'shape=swimlane;startSize=20;'\n );\n addVertex('editors/images/rectangle.gif', 100, 40, '');\n addVertex('editors/images/rounded.gif', 100, 40, 'shape=rounded');\n addVertex('editors/images/ellipse.gif', 40, 40, 'shape=ellipse');\n addVertex('editors/images/rhombus.gif', 40, 40, 'shape=rhombus');\n addVertex('editors/images/triangle.gif', 40, 40, 'shape=triangle');\n addVertex('editors/images/cylinder.gif', 40, 40, 'shape=cylinder');\n addVertex('editors/images/actor.gif', 30, 40, 'shape=actor');\n toolbar.addLine();\n\n const button = mxUtils.button(\n 'Create toolbar entry from selection',\n evt => {\n if (!graph.isSelectionEmpty()) {\n // Creates a copy of the selection array to preserve its state\n const cells = graph.getSelectionCells();\n const bounds = graph.getView().getBounds(cells);\n\n // Function that is executed when the image is dropped on\n // the graph. The cell argument points to the cell under\n // the mousepointer if there is one.\n const funct = (graph, evt, cell) => {\n graph.stopEditing(false);\n\n const pt = graph.getPointForEvent(evt);\n const dx = pt.x - bounds.x;\n const dy = pt.y - bounds.y;\n\n graph.setSelectionCells(graph.importCells(cells, dx, dy, cell));\n };\n\n // Creates the image which is used as the drag icon (preview)\n const img = toolbar.addMode(\n null,\n 'editors/images/outline.gif',\n funct\n );\n mxUtils.makeDraggable(img, graph, funct);\n }\n }\n );\n\n this.el2.appendChild(button);\n }\n\n addToolbarItem(graph, toolbar, prototype, image) {\n // Function that is executed when the image is dropped on\n // the graph. The cell argument points to the cell under\n // the mousepointer if there is one.\n const funct = (graph, evt, cell) => {\n graph.stopEditing(false);\n\n const pt = graph.getPointForEvent(evt);\n const vertex = graph.getModel().cloneCell(prototype);\n vertex.geometry.x = pt.x;\n vertex.geometry.y = pt.y;\n\n graph.setSelectionCells(graph.importCells([vertex], 0, 0, cell));\n };\n\n // Creates the image which is used as the drag icon (preview)\n const img = toolbar.addMode(null, image, funct);\n mxUtils.makeDraggable(img, graph, funct);\n }\n}\n\nexport default Toolbar;\n", - "Thread": "/**\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';\n\nclass Thread extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Thread

    \n This example demonstrates setting overlays in mxGraph from within a\n timed function.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Disables basic selection and cell handling\n graph.setEnabled(false);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n let v1;\n let v2;\n let e1;\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n // Function to switch the overlay every 5 secs\n const f = () => {\n const overlays = graph.getCellOverlays(v1);\n\n if (overlays == null) {\n graph.removeCellOverlays(v2);\n graph.setCellWarning(v1, 'Tooltip');\n } else {\n graph.removeCellOverlays(v1);\n graph.setCellWarning(v2, 'Tooltip');\n }\n };\n\n window.setInterval(f, 1000);\n f();\n }\n}\n\nexport default Thread;\n", - "Animation": "/**\n * Copyright (c) 2006-2017, 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 mxPoint from '../mxgraph/util/mxPoint';\n\nclass Animation extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Animation

    \n This example demonstrates using SVG animations on edges to visualize the\n flow in a pipe.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: 'url(\"editors/images/grid.gif\")',\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n const graph = new mxGraph(this.el);\n graph.setEnabled(false);\n const parent = graph.getDefaultParent();\n\n const vertexStyle =\n 'shape=cylinder;strokeWidth=2;fillColor=#ffffff;strokeColor=black;' +\n 'gradientColor=#a0a0a0;fontColor=black;fontStyle=1;spacingTop=14;';\n\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex({\n parent,\n value: 'Pump',\n position: [20, 20],\n size: [60, 60],\n style: vertexStyle,\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'Tank',\n position: [200, 150],\n size: [60, 60],\n style: vertexStyle,\n });\n var e1 = graph.insertEdge({\n parent,\n source: v1,\n target: v2,\n style:\n 'strokeWidth=3;endArrow=block;endSize=2;endFill=1;strokeColor=black;rounded=1;',\n });\n e1.geometry.points = [new mxPoint(230, 50)];\n graph.orderCells(true, [e1]);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n // Adds animation to edge shape and makes \"pipe\" visible\n const state = graph.view.getState(e1);\n state.shape.node\n .getElementsByTagName('path')[0]\n .removeAttribute('visibility');\n state.shape.node\n .getElementsByTagName('path')[0]\n .setAttribute('stroke-width', '6');\n state.shape.node\n .getElementsByTagName('path')[0]\n .setAttribute('stroke', 'lightGray');\n state.shape.node\n .getElementsByTagName('path')[1]\n .setAttribute('class', 'flow');\n };\n}\n\nexport default Animation;\n", - "Perimeter": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxGraphView from '../mxgraph/view/mxGraphView';\n\nclass Perimeter extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Perimeter

    \n This example demonstrates how to avoid edge and label intersections.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Redirects the perimeter to the label bounds if intersection\n // between edge and label is found\n const mxGraphViewGetPerimeterPoint =\n mxGraphView.prototype.getPerimeterPoint;\n mxGraphView.prototype.getPerimeterPoint = function(\n terminal,\n next,\n orthogonal,\n border\n ) {\n let point = mxGraphViewGetPerimeterPoint.apply(this, arguments);\n\n if (point != null) {\n const perimeter = this.getPerimeterFunction(terminal);\n\n if (terminal.text != null && terminal.text.boundingBox != null) {\n // Adds a small border to the label bounds\n const b = terminal.text.boundingBox.clone();\n b.grow(3);\n\n if (mxUtils.rectangleIntersectsSegment(b, point, next)) {\n point = perimeter(b, terminal, next, orthogonal);\n }\n }\n }\n\n return point;\n };\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setVertexLabelsMovable(true);\n graph.setConnectable(true);\n\n // Uncomment the following if you want the container\n // to fit the size of the graph\n // graph.setResizeContainer(true);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(\n parent,\n null,\n 'Label',\n 20,\n 20,\n 80,\n 30,\n 'verticalLabelPosition=bottom'\n );\n const v2 = graph.insertVertex(\n parent,\n null,\n 'Label',\n 200,\n 20,\n 80,\n 30,\n 'verticalLabelPosition=bottom'\n );\n const v3 = graph.insertVertex(\n parent,\n null,\n 'Label',\n 20,\n 150,\n 80,\n 30,\n 'verticalLabelPosition=bottom'\n );\n var e1 = graph.insertEdge(parent, null, '', v1, v2);\n var e1 = graph.insertEdge(parent, null, '', v1, v3);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Perimeter;\n", - "JsonData": "/**\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 mxCodecRegistry from '../mxgraph/io/mxCodecRegistry';\nimport mxObjectCodec from '../mxgraph/io/mxObjectCodec';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxCodec from '../mxgraph/io/mxCodec';\n\nclass JsonData extends React.Component {\n // Adds an option to view the XML of the graph\n document;\n\n body;\n\n 'View XML';\n\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    JSON data

    \n This example demonstrates using JSON to encode/decode parts of the graph\n model in mxCodec.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n v1.data = new CustomData('v1');\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n v2.data = new CustomData('v2');\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n this.el2.appendChild(\n mxUtils.button(function() {\n const encoder = new mxCodec();\n const node = encoder.encode(graph.getModel());\n mxUtils.popup(mxUtils.getXml(node), true);\n })\n );\n\n function CustomData(value) {\n this.value = value;\n }\n\n const codec = new mxObjectCodec(new CustomData());\n codec.encode = function(enc, obj) {\n const node = enc.document.createElement('CustomData');\n mxUtils.setTextContent(node, JSON.stringify(obj));\n\n return node;\n };\n codec.decode = function(dec, node, into) {\n const obj = JSON.parse(mxUtils.getTextContent(node));\n obj.constructor = CustomData;\n\n return obj;\n };\n mxCodecRegistry.register(codec);\n }\n}\n\nexport default JsonData;\n", - "Wrapping": "/**\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';\n\nclass Wrapping extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Wrapping

    \n This example demonstrates using HTML markup and word-wrapping in vertex\n and edge labels.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Enables HTML labels as wrapping is only available for those\n graph.setHtmlLabels(true);\n\n // Disables in-place editing for edges\n graph.isCellEditable = function(cell) {\n return !this.model.isEdge(cell);\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n value: 'Cum Caesar vidisset, portum plenum esse, iuxta navigavit.',\n position: [20, 20],\n size: [100, 70],\n style: 'whiteSpace=wrap;',\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'Cum Caesar vidisset, portum plenum esse, iuxta navigavit.',\n position: [220, 150],\n size: [80, 70],\n style: 'whiteSpace=wrap;',\n });\n const e1 = graph.insertEdge({\n parent,\n value: 'Cum Caesar vidisset, portum plenum esse, iuxta navigavit.',\n source: v1,\n target: v2,\n style: 'whiteSpace=wrap;',\n });\n e1.geometry.width = 100;\n });\n }\n}\n\nexport default Wrapping;\n", - "Stencils": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxStencilRegistry from '../mxgraph/shape/mxStencilRegistry';\nimport mxCellRenderer from '../mxgraph/view/mxCellRenderer';\nimport mxShape from '../mxgraph/shape/mxShape';\nimport mxVertexHandler from '../mxgraph/handler/mxVertexHandler';\nimport mxCellHighlight from '../mxgraph/handler/mxCellHighlight';\nimport mxEdgeHandler from '../mxgraph/handler/mxEdgeHandler';\nimport mxConnectionHandler from '../mxgraph/handler/mxConnectionHandler';\nimport mxStencil from '../mxgraph/shape/mxStencil';\n\nclass Stencils extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Stencils

    \n This example demonstrates using an XML file to define new stencils to be\n used as shapes. See docs/stencils.xsd for the XML schema file.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '401px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n width: '601px',\n height: '150px',\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Sets the global shadow color\n mxConstants.SHADOWCOLOR = '#C0C0C0';\n mxConstants.SHADOW_OPACITY = 0.5;\n mxConstants.SHADOW_OFFSET_X = 4;\n mxConstants.SHADOW_OFFSET_Y = 4;\n mxConstants.HANDLE_FILLCOLOR = '#99ccff';\n mxConstants.HANDLE_STROKECOLOR = '#0088cf';\n mxConstants.VERTEX_SELECTION_COLOR = '#00a8ff';\n\n // Enables connections along the outline\n mxConnectionHandler.prototype.outlineConnect = true;\n mxEdgeHandler.prototype.manageLabelHandle = true;\n mxEdgeHandler.prototype.outlineConnect = true;\n mxCellHighlight.prototype.keepOnTop = true;\n\n // Enable rotation handle\n mxVertexHandler.prototype.rotationEnabled = true;\n\n // Uses the shape for resize previews\n mxVertexHandler.prototype.createSelectionShape = function(bounds) {\n const key = this.state.style[mxConstants.STYLE_SHAPE];\n const stencil = mxStencilRegistry.getStencil(key);\n let shape = null;\n\n if (stencil != null) {\n shape = new mxShape(stencil);\n shape.apply(this.state);\n } else {\n shape = new this.state.shape.constructor();\n }\n\n shape.outline = true;\n shape.bounds = bounds;\n shape.stroke = mxConstants.HANDLE_STROKECOLOR;\n shape.strokewidth = this.getSelectionStrokeWidth();\n shape.isDashed = this.isSelectionDashed();\n shape.isShadow = false;\n\n return shape;\n };\n\n // Defines a custom stencil via the canvas API as defined here:\n // http://jgraph.github.io/mxgraph/docs/js-api/files/util/mxXmlCanvas2D-js.html\n\n class CustomShape extends mxShape {\n paintBackground(c, x, y, w, h) {\n c.translate(x, y);\n\n // Head\n c.ellipse(w / 4, 0, w / 2, h / 4);\n c.fillAndStroke();\n\n c.begin();\n c.moveTo(w / 2, h / 4);\n c.lineTo(w / 2, (2 * h) / 3);\n\n // Arms\n c.moveTo(w / 2, h / 3);\n c.lineTo(0, h / 3);\n c.moveTo(w / 2, h / 3);\n c.lineTo(w, h / 3);\n\n // Legs\n c.moveTo(w / 2, (2 * h) / 3);\n c.lineTo(0, h);\n c.moveTo(w / 2, (2 * h) / 3);\n c.lineTo(w, h);\n c.end();\n\n c.stroke();\n }\n }\n\n // Replaces existing actor shape\n mxCellRenderer.registerShape('customShape', CustomShape);\n\n // Loads the stencils into the registry\n const req = mxUtils.load('stencils.xml');\n const root = req.getDocumentElement();\n let shape = root.firstChild;\n\n while (shape != null) {\n if (shape.nodeType === mxConstants.NODETYPE_ELEMENT) {\n mxStencilRegistry.addStencil(\n shape.getAttribute('name'),\n new mxStencil(shape)\n );\n }\n\n shape = shape.nextSibling;\n }\n\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setConnectable(true);\n graph.setTooltips(true);\n graph.setPanning(true);\n\n graph.getTooltipForCell = function(cell) {\n if (cell != null) {\n return cell.style;\n }\n\n return null;\n };\n\n // Changes default styles\n let style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_EDGE] = 'orthogonalEdgeStyle';\n style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_FILLCOLOR] = '#adc5ff';\n style[mxConstants.STYLE_GRADIENTCOLOR] = '#7d85df';\n style[mxConstants.STYLE_SHADOW] = '1';\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(\n parent,\n null,\n 'A1',\n 20,\n 20,\n 40,\n 80,\n 'shape=and'\n );\n const v2 = graph.insertVertex(\n parent,\n null,\n 'A2',\n 20,\n 220,\n 40,\n 80,\n 'shape=and'\n );\n const v3 = graph.insertVertex(\n parent,\n null,\n 'X1',\n 160,\n 110,\n 80,\n 80,\n 'shape=xor'\n );\n const e1 = graph.insertEdge(parent, null, '', v1, v3);\n e1.geometry.points = [new mxPoint(90, 60), new mxPoint(90, 130)];\n const e2 = graph.insertEdge(parent, null, '', v2, v3);\n e2.geometry.points = [new mxPoint(90, 260), new mxPoint(90, 170)];\n\n const v4 = graph.insertVertex(\n parent,\n null,\n 'A3',\n 520,\n 20,\n 40,\n 80,\n 'shape=customShape;flipH=1'\n );\n const v5 = graph.insertVertex(\n parent,\n null,\n 'A4',\n 520,\n 220,\n 40,\n 80,\n 'shape=and;flipH=1'\n );\n const v6 = graph.insertVertex(\n parent,\n null,\n 'X2',\n 340,\n 110,\n 80,\n 80,\n 'shape=xor;flipH=1'\n );\n const e3 = graph.insertEdge(parent, null, '', v4, v6);\n e3.geometry.points = [new mxPoint(490, 60), new mxPoint(130, 130)];\n const e4 = graph.insertEdge(parent, null, '', v5, v6);\n e4.geometry.points = [new mxPoint(490, 260), new mxPoint(130, 170)];\n\n const v7 = graph.insertVertex(\n parent,\n null,\n 'O1',\n 250,\n 260,\n 80,\n 60,\n 'shape=or;direction=south'\n );\n const e5 = graph.insertEdge(parent, null, '', v6, v7);\n e5.geometry.points = [new mxPoint(310, 150)];\n const e6 = graph.insertEdge(parent, null, '', v3, v7);\n e6.geometry.points = [new mxPoint(270, 150)];\n\n const e7 = graph.insertEdge(parent, null, '', v7, v5);\n e7.geometry.points = [new mxPoint(290, 370)];\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n this.el2.appendChild(\n mxUtils.button('FlipH', function() {\n graph.toggleCellStyles(mxConstants.STYLE_FLIPH);\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('FlipV', function() {\n graph.toggleCellStyles(mxConstants.STYLE_FLIPV);\n })\n );\n\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n\n this.el2.appendChild(\n mxUtils.button('Rotate', function() {\n const cell = graph.getSelectionCell();\n\n if (cell != null) {\n let geo = graph.getCellGeometry(cell);\n\n if (geo != null) {\n graph.getModel().beginUpdate();\n try {\n // Rotates the size and position in the geometry\n geo = geo.clone();\n geo.x += geo.width / 2 - geo.height / 2;\n geo.y += geo.height / 2 - geo.width / 2;\n const tmp = geo.width;\n geo.width = geo.height;\n geo.height = tmp;\n graph.getModel().setGeometry(cell, geo);\n\n // Reads the current direction and advances by 90 degrees\n const state = graph.view.getState(cell);\n\n if (state != null) {\n let dir =\n state.style[mxConstants.STYLE_DIRECTION] ||\n 'east'; /* default */\n\n if (dir === 'east') {\n dir = 'south';\n } else if (dir === 'south') {\n dir = 'west';\n } else if (dir === 'west') {\n dir = 'north';\n } else if (dir === 'north') {\n dir = 'east';\n }\n\n graph.setCellStyles(mxConstants.STYLE_DIRECTION, dir, [cell]);\n }\n } finally {\n graph.getModel().endUpdate();\n }\n }\n }\n })\n );\n\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n\n this.el2.appendChild(\n mxUtils.button('And', function() {\n graph.setCellStyles(mxConstants.STYLE_SHAPE, 'and');\n })\n );\n this.el2.appendChild(\n mxUtils.button('Or', function() {\n graph.setCellStyles(mxConstants.STYLE_SHAPE, 'or');\n })\n );\n this.el2.appendChild(\n mxUtils.button('Xor', function() {\n graph.setCellStyles(mxConstants.STYLE_SHAPE, 'xor');\n })\n );\n\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n this.el2.appendChild(document.createTextNode('\\u00a0'));\n\n this.el2.appendChild(\n mxUtils.button('Style', function() {\n const cell = graph.getSelectionCell();\n\n if (cell != null) {\n const style = mxUtils.prompt(\n 'Style',\n graph.getModel().getStyle(cell)\n );\n\n if (style != null) {\n graph.getModel().setStyle(cell, style);\n }\n }\n })\n );\n\n this.el2.appendChild(\n mxUtils.button('+', function() {\n graph.zoomIn();\n })\n );\n this.el2.appendChild(\n mxUtils.button('-', function() {\n graph.zoomOut();\n })\n );\n }\n}\n\nexport default Stencils;\n", - "UserObject": "/**\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 mxUtils from '../mxgraph/util/mxUtils';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxForm from '../mxgraph/util/mxForm';\nimport mxCellAttributeChange from '../mxgraph/model/atomic_changes/mxCellAttributeChange';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\nimport mxRectangle from '../mxgraph/util/mxRectangle';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\n\nclass UserObject extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    User object

    \n This example demonstrates using XML objects as values for cells.\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 \n \n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Note that these XML nodes will be enclosing the\n // mxCell nodes for the model cells in the output\n const doc = mxUtils.createXmlDocument();\n\n const person1 = doc.createElement('Person');\n person1.setAttribute('firstName', 'Daffy');\n person1.setAttribute('lastName', 'Duck');\n\n const person2 = doc.createElement('Person');\n person2.setAttribute('firstName', 'Bugs');\n person2.setAttribute('lastName', 'Bunny');\n\n const relation = doc.createElement('Knows');\n relation.setAttribute('since', '1985');\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Optional disabling of sizing\n graph.setCellsResizable(false);\n\n // Configures the graph contains to resize and\n // add a border at the bottom, right\n graph.setResizeContainer(true);\n graph.minimumContainerSize = new mxRectangle(0, 0, 500, 380);\n graph.setBorder(60);\n\n // Stops editing on enter key, handles escape\n new mxKeyHandler(graph);\n\n // Overrides method to disallow edge label editing\n graph.isCellEditable = function(cell) {\n return !this.getModel().isEdge(cell);\n };\n\n // Overrides method to provide a cell label in the display\n graph.convertValueToString = function(cell) {\n if (mxUtils.isNode(cell.value)) {\n if (cell.value.nodeName.toLowerCase() == 'person') {\n const firstName = cell.getAttribute('firstName', '');\n const lastName = cell.getAttribute('lastName', '');\n\n if (lastName != null && lastName.length > 0) {\n return `${lastName}, ${firstName}`;\n }\n\n return firstName;\n }\n if (cell.value.nodeName.toLowerCase() == 'knows') {\n return `${cell.value.nodeName} (Since ${cell.getAttribute(\n 'since',\n ''\n )})`;\n }\n }\n\n return '';\n };\n\n // Overrides method to store a cell label in the model\n const { cellLabelChanged } = graph;\n graph.cellLabelChanged = function(cell, newValue, autoSize) {\n if (\n mxUtils.isNode(cell.value) &&\n cell.value.nodeName.toLowerCase() == 'person'\n ) {\n const pos = newValue.indexOf(' ');\n\n const firstName = pos > 0 ? newValue.substring(0, pos) : newValue;\n const lastName =\n pos > 0 ? newValue.substring(pos + 1, newValue.length) : '';\n\n // Clones the value for correct undo/redo\n const elt = cell.value.cloneNode(true);\n\n elt.setAttribute('firstName', firstName);\n elt.setAttribute('lastName', lastName);\n\n newValue = elt;\n autoSize = true;\n }\n\n cellLabelChanged.apply(this, arguments);\n };\n\n // Overrides method to create the editing value\n const { getEditingValue } = graph;\n graph.getEditingValue = function(cell) {\n if (\n mxUtils.isNode(cell.value) &&\n cell.value.nodeName.toLowerCase() == 'person'\n ) {\n const firstName = cell.getAttribute('firstName', '');\n const lastName = cell.getAttribute('lastName', '');\n\n return `${firstName} ${lastName}`;\n }\n };\n\n // Adds a special tooltip for edges\n graph.setTooltips(true);\n\n const { getTooltipForCell } = graph;\n graph.getTooltipForCell = function(cell) {\n // Adds some relation details for edges\n if (graph.getModel().isEdge(cell)) {\n const src = this.getLabel(this.getModel().getTerminal(cell, true));\n const trg = this.getLabel(this.getModel().getTerminal(cell, false));\n\n return `${src} ${cell.value.nodeName} ${trg}`;\n }\n\n return getTooltipForCell.apply(this, arguments);\n };\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Adds an option to view the XML of the graph\n this.el2.appendChild(\n mxUtils.button('View XML', function() {\n const encoder = new mxCodec();\n const node = encoder.encode(graph.getModel());\n mxUtils.popup(mxUtils.getPrettyXml(node), true);\n })\n );\n\n // Changes the style for match the markup\n // Creates the default style for vertices\n let style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_STROKECOLOR] = 'gray';\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_SHADOW] = true;\n style[mxConstants.STYLE_FILLCOLOR] = '#DFDFDF';\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_FONTCOLOR] = 'black';\n style[mxConstants.STYLE_FONTSIZE] = '12';\n style[mxConstants.STYLE_SPACING] = 4;\n\n // Creates the default style for edges\n style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_STROKECOLOR] = '#0C0C0C';\n style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white';\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_FONTCOLOR] = 'black';\n style[mxConstants.STYLE_FONTSIZE] = '10';\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, person1, 40, 40, 80, 30);\n const v2 = graph.insertVertex(parent, null, person2, 200, 150, 80, 30);\n const e1 = graph.insertEdge(parent, null, relation, v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n // Implements a properties panel that uses\n // mxCellAttributeChange to change properties\n graph\n .getSelectionModel()\n .addListener(mxEvent.CHANGE, function(sender, evt) {\n this.selectionChanged(graph);\n });\n\n this.selectionChanged(graph);\n }\n\n /**\n * Updates the properties panel\n */\n selectionChanged(graph) {\n const div = this.propertiesEl;\n\n // Forces focusout in IE\n graph.container.focus();\n\n // Clears the DIV the non-DOM way\n div.innerHTML = '';\n\n // Gets the selection cell\n const cell = graph.getSelectionCell();\n\n if (cell == null) {\n mxUtils.writeln(div, 'Nothing selected.');\n } else {\n // Writes the title\n const center = document.createElement('center');\n mxUtils.writeln(center, `${cell.value.nodeName} (${cell.id})`);\n div.appendChild(center);\n mxUtils.br(div);\n\n // Creates the form from the attributes of the user object\n const form = new mxForm();\n\n const attrs = cell.value.attributes;\n\n for (let i = 0; i < attrs.length; i++) {\n this.createTextField(graph, form, cell, attrs[i]);\n }\n\n div.appendChild(form.getTable());\n mxUtils.br(div);\n }\n }\n\n /**\n * Creates the textfield for the given property.\n */\n createTextField(graph, form, cell, attribute) {\n const input = form.addText(`${attribute.nodeName}:`, attribute.nodeValue);\n\n const applyHandler = function() {\n const newValue = input.value || '';\n const oldValue = cell.getAttribute(attribute.nodeName, '');\n\n if (newValue != oldValue) {\n graph.getModel().beginUpdate();\n\n try {\n const edit = new mxCellAttributeChange(\n cell,\n attribute.nodeName,\n newValue\n );\n graph.getModel().execute(edit);\n graph.updateCellSize(cell);\n } finally {\n graph.getModel().endUpdate();\n }\n }\n };\n\n mxEvent.addListener(input, 'keypress', function(evt) {\n // Needs to take shift into account for textareas\n if (evt.keyCode == /* enter */ 13 && !mxEvent.isShiftDown(evt)) {\n input.blur();\n }\n });\n\n // Note: Known problem is the blurring of fields in\n // Firefox by changing the selection, in which case\n // no event is fired in FF and the change is lost.\n // As a workaround you should use a local variable\n // that stores the focused field and invoke blur\n // explicitely where we do the graph.focus above.\n mxEvent.addListener(input, 'blur', applyHandler);\n }\n}\n\nexport default UserObject;\n", - "Merge": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\nimport mxPerimeter from '../mxgraph/view/mxPerimeter';\n\nclass Merge extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Merge

    \n This example demonstrates using the mergeChildren function to merge two\n graphs.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '280px',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n mxConstants.SHADOWCOLOR = '#c0c0c0';\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // No size handles, please...\n graph.setCellsResizable(false);\n\n // Makes all cells round with a white, bold label\n let style = graph.stylesheet.getDefaultVertexStyle();\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter;\n style[mxConstants.STYLE_FONTCOLOR] = 'white';\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_FONTSTYLE] = mxConstants.FONT_BOLD;\n style[mxConstants.STYLE_FONTSIZE] = 14;\n style[mxConstants.STYLE_SHADOW] = true;\n\n // Makes all edge labels gray with a white background\n style = graph.stylesheet.getDefaultEdgeStyle();\n style[mxConstants.STYLE_FONTCOLOR] = 'gray';\n style[mxConstants.STYLE_FONTSTYLE] = mxConstants.FONT_BOLD;\n style[mxConstants.STYLE_FONTCOLOR] = 'black';\n style[mxConstants.STYLE_STROKEWIDTH] = 2;\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the target model in a single step\n // using custom ids for the vertices and edges\n const w = 40;\n const h = 40;\n\n graph.getModel().beginUpdate();\n try {\n const a = graph.insertVertex(\n parent,\n 'a',\n 'A',\n 20,\n 20,\n w,\n h,\n 'fillColor=blue'\n );\n const b = graph.insertVertex(\n parent,\n 'b',\n 'B',\n 20,\n 200,\n w,\n h,\n 'fillColor=blue'\n );\n const c = graph.insertVertex(\n parent,\n 'c',\n 'C',\n 200,\n 20,\n w,\n h,\n 'fillColor=red'\n );\n const d = graph.insertVertex(\n parent,\n 'd',\n 'D',\n 200,\n 200,\n w,\n h,\n 'fillColor=red'\n );\n const ac = graph.insertEdge(\n parent,\n 'ac',\n 'ac',\n a,\n c,\n 'strokeColor=blue;verticalAlign=bottom'\n );\n const ad = graph.insertEdge(\n parent,\n 'ad',\n 'ad',\n a,\n d,\n 'strokeColor=blue;align=left;verticalAlign=bottom'\n );\n const bd = graph.insertEdge(\n parent,\n 'bd',\n 'bd',\n b,\n d,\n 'strokeColor=blue;verticalAlign=bottom'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n // Creates the second graph model (without a container)\n const graph2 = new mxGraph();\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent2 = graph2.getDefaultParent();\n\n // Adds cells to the target model in a single step\n // using custom ids for the vertices\n graph2.getModel().beginUpdate();\n try {\n const c = graph2.insertVertex(\n parent2,\n 'c',\n 'C',\n 200,\n 20,\n w,\n h,\n 'fillColor=green'\n );\n const d = graph2.insertVertex(\n parent2,\n 'd',\n 'D',\n 200,\n 200,\n w,\n h,\n 'fillColor=green'\n );\n const e = graph2.insertVertex(\n parent2,\n 'e',\n 'E',\n 400,\n 20,\n w,\n h,\n 'fillColor=green'\n );\n const f = graph2.insertVertex(\n parent2,\n 'f',\n 'F',\n 400,\n 200,\n w,\n h,\n 'fillColor=green'\n );\n const ce = graph2.insertEdge(\n parent2,\n 'ce',\n 'ce',\n c,\n e,\n 'strokeColor=green;verticalAlign=bottom'\n );\n const ed = graph2.insertEdge(\n parent2,\n 'ed',\n 'ed',\n e,\n d,\n 'strokeColor=green;align=right;verticalAlign=bottom'\n );\n const fd = graph2.insertEdge(\n parent2,\n 'bd',\n 'fd',\n f,\n d,\n 'strokeColor=green;verticalAlign=bottom'\n );\n } finally {\n // Updates the display\n graph2.getModel().endUpdate();\n }\n\n // Merges the model from the second graph into the model of\n // the first graph. Note: If you add a false to the parameter\n // list then _not_ all edges will be cloned, that is, the\n // edges are assumed to have an identity, and hence the edge\n // \"bd\" will be changed to point from f to d, as specified in\n // the edge for the same id in the second graph.\n graph.getModel().mergeChildren(parent2, parent /* , false */);\n }\n}\n\nexport default Merge;\n", - "OrgChart": "/**\n * Copyright (c) 2006-2013, JGraph Ltd\n\n Orgchart. This example demonstrates using\n automatic layouts, fit to page zoom and poster print (across\n multiple pages).\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 mxPrintPreview from '../mxgraph/view/mxPrintPreview';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxCellOverlay from '../mxgraph/view/mxCellOverlay';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxWindow from '../mxgraph/util/mxWindow';\nimport mxToolbar from '../mxgraph/util/mxToolbar';\nimport mxLayoutManager from '../mxgraph/view/mxLayoutManager';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\nimport mxCompactTreeLayout from '../mxgraph/layout/mxCompactTreeLayout';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\nimport mxClient from '../mxgraph/mxClient';\nimport mxOutline from '../mxgraph/view/mxOutline';\n\nclass OrgChart extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Orgchart

    \n {\n this.el = el;\n }}\n style={{\n zIndex: 1,\n position: 'relative',\n overflow: 'hidden',\n height: '50vh',\n background: 'transparent',\n borderStyle: 'solid',\n borderColor: 'lightgray',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Makes the shadow brighter\n mxConstants.SHADOWCOLOR = '#C0C0C0';\n\n // Workaround for Internet Explorer ignoring certain styles\n const container = document.createElement('div');\n container.style.position = 'absolute';\n container.style.overflow = 'hidden';\n container.style.left = '0px';\n container.style.top = '0px';\n container.style.right = '0px';\n container.style.bottom = '0px';\n\n const outline = document.getElementById('outlineContainer');\n\n mxEvent.disableContextMenu(container);\n\n // Sets a gradient background\n if (mxClient.IS_GC || mxClient.IS_SF) {\n container.style.background =\n '-webkit-gradient(linear, 0% 0%, 0% 100%, from(#FFFFFF), to(#E7E7E7))';\n } else if (mxClient.IS_NS) {\n container.style.background =\n '-moz-linear-gradient(top, #FFFFFF, #E7E7E7)';\n }\n\n this.el.appendChild(container);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(container);\n\n // Enables automatic sizing for vertices after editing and\n // panning by using the left mouse button.\n graph.setCellsMovable(false);\n graph.setAutoSizeCells(true);\n graph.setPanning(true);\n graph.centerZoom = false;\n graph.panningHandler.useLeftButtonForPanning = true;\n\n // Displays a popupmenu when the user clicks\n // on a cell (using the left mouse button) but\n // do not select the cell when the popup menu\n // is displayed\n graph.panningHandler.popupMenuHandler = false;\n\n // Creates the outline (navigator, overview) for moving\n // around the graph in the top, right corner of the window.\n const outln = new mxOutline(graph, outline);\n\n // Disables tooltips on touch devices\n graph.setTooltips(!mxClient.IS_TOUCH);\n\n // Set some stylesheet options for the visual appearance of vertices\n let style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_SHAPE] = 'label';\n\n style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;\n style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT;\n style[mxConstants.STYLE_SPACING_LEFT] = 54;\n\n style[mxConstants.STYLE_GRADIENTCOLOR] = '#7d85df';\n style[mxConstants.STYLE_STROKECOLOR] = '#5d65df';\n style[mxConstants.STYLE_FILLCOLOR] = '#adc5ff';\n\n style[mxConstants.STYLE_FONTCOLOR] = '#1d258f';\n style[mxConstants.STYLE_FONTFAMILY] = 'Verdana';\n style[mxConstants.STYLE_FONTSIZE] = '12';\n style[mxConstants.STYLE_FONTSTYLE] = '1';\n\n style[mxConstants.STYLE_SHADOW] = '1';\n style[mxConstants.STYLE_ROUNDED] = '1';\n style[mxConstants.STYLE_GLASS] = '1';\n\n style[mxConstants.STYLE_IMAGE] = 'editors/images/dude3.png';\n style[mxConstants.STYLE_IMAGE_WIDTH] = '48';\n style[mxConstants.STYLE_IMAGE_HEIGHT] = '48';\n style[mxConstants.STYLE_SPACING] = 8;\n\n // Sets the default style for edges\n style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_STROKEWIDTH] = 3;\n style[mxConstants.STYLE_EXIT_X] = 0.5; // center\n style[mxConstants.STYLE_EXIT_Y] = 1.0; // bottom\n style[mxConstants.STYLE_EXIT_PERIMETER] = 0; // disabled\n style[mxConstants.STYLE_ENTRY_X] = 0.5; // center\n style[mxConstants.STYLE_ENTRY_Y] = 0; // top\n style[mxConstants.STYLE_ENTRY_PERIMETER] = 0; // disabled\n\n // Disable the following for straight lines\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.TopToBottom;\n\n // Stops editing on enter or escape keypress\n const keyHandler = new mxKeyHandler(graph);\n\n // Enables automatic layout on the graph and installs\n // a tree layout for all groups who's children are\n // being changed, added or removed.\n const layout = new mxCompactTreeLayout(graph, false);\n layout.useBoundingBox = false;\n layout.edgeRouting = false;\n layout.levelDistance = 60;\n layout.nodeDistance = 16;\n\n // Allows the layout to move cells even though cells\n // aren't movable in the graph\n layout.isVertexMovable = function(cell) {\n return true;\n };\n\n const layoutMgr = new mxLayoutManager(graph);\n\n layoutMgr.getLayout = function(cell) {\n if (cell.getChildCount() > 0) {\n return layout;\n }\n };\n\n // Installs a popupmenu handler using local function (see below).\n graph.popupMenuHandler.factoryMethod = function(menu, cell, evt) {\n return createPopupMenu(graph, menu, cell, evt);\n };\n\n // Fix for wrong preferred size\n const oldGetPreferredSizeForCell = graph.getPreferredSizeForCell;\n graph.getPreferredSizeForCell = function(cell) {\n const result = oldGetPreferredSizeForCell.apply(this, arguments);\n\n if (result != null) {\n result.width = Math.max(120, result.width - 40);\n }\n\n return result;\n };\n\n // Sets the maximum text scale to 1\n graph.cellRenderer.getTextScale = function(state) {\n return Math.min(1, state.view.scale);\n };\n\n // Dynamically adds text to the label as we zoom in\n // (without affecting the preferred size for new cells)\n graph.cellRenderer.getLabelValue = function(state) {\n let result = state.cell.value;\n\n if (state.view.graph.getModel().isVertex(state.cell)) {\n if (state.view.scale > 1) {\n result += '\\nDetails 1';\n }\n\n if (state.view.scale > 1.3) {\n result += '\\nDetails 2';\n }\n }\n\n return result;\n };\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds the root vertex of the tree\n graph.getModel().beginUpdate();\n try {\n const w = graph.container.offsetWidth;\n const v1 = graph.insertVertex(\n parent,\n 'treeRoot',\n 'Organization',\n w / 2 - 30,\n 20,\n 140,\n 60,\n 'image=editors/images/house.png'\n );\n graph.updateCellSize(v1);\n addOverlays(graph, v1, false);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n const content = document.createElement('div');\n content.style.padding = '4px';\n this.el2.appendChild(content);\n const tb = new mxToolbar(content);\n\n tb.addItem('Zoom In', 'images/zoom_in32.png', function(evt) {\n graph.zoomIn();\n });\n\n tb.addItem('Zoom Out', 'images/zoom_out32.png', function(evt) {\n graph.zoomOut();\n });\n\n tb.addItem('Actual Size', 'images/view_1_132.png', function(evt) {\n graph.zoomActual();\n });\n\n tb.addItem('Print', 'images/print32.png', function(evt) {\n const preview = new mxPrintPreview(graph, 1);\n preview.open();\n });\n\n tb.addItem('Poster Print', 'images/press32.png', function(evt) {\n const pageCount = mxUtils.prompt('Enter maximum page count', '1');\n\n if (pageCount != null) {\n const scale = mxUtils.getScaleForPageCount(pageCount, graph);\n const preview = new mxPrintPreview(graph, scale);\n preview.open();\n }\n });\n\n // Function to create the entries in the popupmenu\n function createPopupMenu(graph, menu, cell, evt) {\n const model = graph.getModel();\n\n if (cell != null) {\n if (model.isVertex(cell)) {\n menu.addItem(\n 'Add child',\n 'editors/images/overlays/check.png',\n function() {\n addChild(graph, cell);\n }\n );\n }\n\n menu.addItem('Edit label', 'editors/images/text.gif', function() {\n graph.startEditingAtCell(cell);\n });\n\n if (cell.id != 'treeRoot' && model.isVertex(cell)) {\n menu.addItem('Delete', 'editors/images/delete.gif', function() {\n deleteSubtree(graph, cell);\n });\n }\n\n menu.addSeparator();\n }\n\n menu.addItem('Fit', 'editors/images/zoom.gif', function() {\n graph.fit();\n });\n\n menu.addItem('Actual', 'editors/images/zoomactual.gif', function() {\n graph.zoomActual();\n });\n\n menu.addSeparator();\n\n menu.addItem('Print', 'editors/images/print.gif', function() {\n const preview = new mxPrintPreview(graph, 1);\n preview.open();\n });\n\n menu.addItem('Poster Print', 'editors/images/print.gif', function() {\n const pageCount = mxUtils.prompt('Enter maximum page count', '1');\n\n if (pageCount != null) {\n const scale = mxUtils.getScaleForPageCount(pageCount, graph);\n const preview = new mxPrintPreview(graph, scale);\n preview.open();\n }\n });\n }\n\n function addOverlays(graph, cell, addDeleteIcon) {\n let overlay = new mxCellOverlay(\n new mxImage('images/add.png', 24, 24),\n 'Add child'\n );\n overlay.cursor = 'hand';\n overlay.align = mxConstants.ALIGN_CENTER;\n overlay.addListener(\n mxEvent.CLICK,\n mxUtils.bind(this, function(sender, evt) {\n addChild(graph, cell);\n })\n );\n\n graph.addCellOverlay(cell, overlay);\n\n if (addDeleteIcon) {\n overlay = new mxCellOverlay(\n new mxImage('images/close.png', 30, 30),\n 'Delete'\n );\n overlay.cursor = 'hand';\n overlay.offset = new mxPoint(-4, 8);\n overlay.align = mxConstants.ALIGN_RIGHT;\n overlay.verticalAlign = mxConstants.ALIGN_TOP;\n overlay.addListener(\n mxEvent.CLICK,\n mxUtils.bind(this, function(sender, evt) {\n deleteSubtree(graph, cell);\n })\n );\n\n graph.addCellOverlay(cell, overlay);\n }\n }\n\n function addChild(graph, cell) {\n const model = graph.getModel();\n const parent = graph.getDefaultParent();\n let vertex;\n\n model.beginUpdate();\n try {\n vertex = graph.insertVertex(parent, null, 'Double click to set name');\n const geometry = model.getGeometry(vertex);\n\n // Updates the geometry of the vertex with the\n // preferred size computed in the graph\n const size = graph.getPreferredSizeForCell(vertex);\n geometry.width = size.width;\n geometry.height = size.height;\n\n // Adds the edge between the existing cell\n // and the new vertex and executes the\n // automatic layout on the parent\n const edge = graph.insertEdge(parent, null, '', cell, vertex);\n\n // Configures the edge label \"in-place\" to reside\n // at the end of the edge (x = 1) and with an offset\n // of 20 pixels in negative, vertical direction.\n edge.geometry.x = 1;\n edge.geometry.y = 0;\n edge.geometry.offset = new mxPoint(0, -20);\n\n addOverlays(graph, vertex, true);\n } finally {\n model.endUpdate();\n }\n\n return vertex;\n }\n\n function deleteSubtree(graph, cell) {\n // Gets the subtree from cell downwards\n const cells = [];\n graph.traverse(cell, true, function(vertex) {\n cells.push(vertex);\n\n return true;\n });\n\n graph.removeCells(cells);\n }\n }\n}\n\nexport default OrgChart;\n", - "Visibility": "/**\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';\n\nclass Visibility extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Visibility

    \n This example demonstrates using various solutions for hiding and showing\n cells.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n {\n this.el2 = el;\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n let showOne = true;\n let showTwo = true;\n let showThree = true;\n\n // Overridden to implement dynamic conditions\n graph.isCellVisible = function(cell) {\n let result = mxGraph.prototype.isCellVisible.apply(this, arguments);\n\n if (result && cell.value != null) {\n result =\n (showOne && cell.value == '1') ||\n (showTwo && cell.value == '2') ||\n (showThree && cell.value == '3');\n }\n\n return result;\n };\n\n // Adds cells to the model in a single step\n let v1;\n graph.batchUpdate(() => {\n v1 = graph.insertVertex({\n parent,\n value: '1',\n position: [20, 20],\n size: [80, 30],\n });\n const v2 = graph.insertVertex({\n parent,\n value: '2',\n position: [200, 150],\n size: [80, 30],\n });\n const e1 = graph.insertEdge({\n parent,\n value: '3',\n source: v1,\n target: v2,\n });\n });\n\n // Dynamic conditions (requires refresh)\n this.el2.appendChild(\n mxUtils.button('Cond 1', function() {\n showOne = !showOne;\n graph.refresh();\n })\n );\n this.el2.appendChild(\n mxUtils.button('Cond 2', function() {\n showTwo = !showTwo;\n graph.refresh();\n })\n );\n this.el2.appendChild(\n mxUtils.button('Cond 3', function() {\n showThree = !showThree;\n graph.refresh();\n })\n );\n\n // Explicit show/hide\n this.el2.appendChild(\n mxUtils.button('Toggle cell', function() {\n graph.toggleCells(!graph.getModel().isVisible(v1), [v1], true);\n })\n );\n\n // Explicit remove/add\n let removed = null;\n\n this.el2.appendChild(\n mxUtils.button('Add/remove cell', function() {\n if (removed != null) {\n graph.addCells(removed);\n removed = null;\n } else {\n removed = graph.removeCells([v1]);\n }\n })\n );\n }\n}\n\nexport default Visibility;\n", - "Shape": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\nimport mxCylinder from '../mxgraph/shape/mxCylinder';\nimport mxCellRenderer from '../mxgraph/view/mxCellRenderer';\n\nclass Shape extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Shape

    \n This example demonstrates how to implement and use a custom shape.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n }}\n />\n \n );\n }\n\n componentDidMount() {\n /*\n The example shape is a \"3D box\" that looks like this:\n ____\n / /|\n /___/ |\n | | /\n |___|/\n\n The code below defines the shape. The BoxShape function\n it the constructor which creates a new object instance.\n \n The next lines use an mxCylinder instance to augment the\n prototype of the shape (\"inheritance\") and reset the\n constructor to the topmost function of the c'tor chain.\n */\n\n class BoxShape extends mxCylinder {\n // Defines the extrusion of the box as a \"static class variable\"\n extrude = 10;\n\n /*\n Next, the mxCylinder's redrawPath method is \"overridden\".\n This method has a isForeground argument to separate two\n paths, one for the background (which must be closed and\n might be filled) and one for the foreground, which is\n just a stroke.\n\n Foreground: /\n _____/\n |\n |\n ____\n Background: / |\n / |\n | /\n |____/\n */\n redrawPath(path, x, y, w, h, isForeground) {\n const dy = this.extrude * this.scale;\n const dx = this.extrude * this.scale;\n\n if (isForeground) {\n path.moveTo(0, dy);\n path.lineTo(w - dx, dy);\n path.lineTo(w, 0);\n path.moveTo(w - dx, dy);\n path.lineTo(w - dx, h);\n } else {\n path.moveTo(0, dy);\n path.lineTo(dx, 0);\n path.lineTo(w, 0);\n path.lineTo(w, h - dy);\n path.lineTo(w - dx, h);\n path.lineTo(0, h);\n path.lineTo(0, dy);\n path.lineTo(dx, 0);\n path.close();\n }\n }\n }\n mxCellRenderer.registerShape('box', BoxShape);\n\n // Creates the graph inside the DOM node.\n const graph = new mxGraph(this.el);\n\n // Disables basic selection and cell handling\n graph.setEnabled(false);\n\n // Changes the default style for vertices \"in-place\"\n // to use the custom shape.\n const style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_SHAPE] = 'box';\n\n // Adds a spacing for the label that matches the\n // extrusion size\n style[mxConstants.STYLE_SPACING_TOP] = BoxShape.prototype.extrude;\n style[mxConstants.STYLE_SPACING_RIGHT] = BoxShape.prototype.extrude;\n\n // Adds a gradient and shadow to improve the user experience\n style[mxConstants.STYLE_GRADIENTCOLOR] = '#FFFFFF';\n style[mxConstants.STYLE_SHADOW] = true;\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Custom', 20, 20, 80, 60);\n const v2 = graph.insertVertex(parent, null, 'Shape', 200, 150, 80, 60);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Shape;\n", - "Images": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxRectangle from '../mxgraph/util/mxRectangle';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxPerimeter from '../mxgraph/view/mxPerimeter';\n\nclass Images extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Images

    \n This example demonstrates using background images and images for for the\n label- and image-shape.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '200px',\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Sets a background image and restricts child movement to its bounds\n graph.setBackgroundImage(\n new mxImage('images/gradient_background.jpg', 360, 200)\n );\n graph.maximumGraphBounds = new mxRectangle(0, 0, 360, 200);\n\n // Resizes the container but never make it bigger than the background\n graph.minimumContainerSize = new mxRectangle(0, 0, 360, 200);\n graph.setResizeContainer(true);\n\n // Disables basic selection and cell handling\n // graph.setEnabled(false);\n configureStylesheet(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n var v1 = graph.insertVertex(\n parent,\n null,\n 'First Line\\nSecond Line',\n 20,\n 10,\n 80,\n 100,\n 'bottom'\n );\n var v1 = graph.insertVertex(\n parent,\n null,\n 'First Line\\nSecond Line',\n 130,\n 10,\n 80,\n 100,\n 'top'\n );\n var v1 = graph.insertVertex(parent, null, '', 230, 10, 100, 100, 'image');\n var v2 = graph.insertVertex(\n parent,\n null,\n 'First Line\\nSecond Line',\n 20,\n 130,\n 140,\n 60,\n 'right'\n );\n var v2 = graph.insertVertex(\n parent,\n null,\n 'First Line\\nSecond Line',\n 180,\n 130,\n 140,\n 60,\n 'left'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n function configureStylesheet(graph) {\n let style = {};\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_IMAGE;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;\n style[mxConstants.STYLE_IMAGE] = 'images/icons48/keys.png';\n style[mxConstants.STYLE_FONTCOLOR] = '#FFFFFF';\n graph.getStylesheet().putCellStyle('image', style);\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_LABEL;\n style[mxConstants.STYLE_STROKECOLOR] = '#000000';\n style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;\n style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP;\n style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_CENTER;\n style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP;\n style[mxConstants.STYLE_IMAGE] = 'images/icons48/gear.png';\n style[mxConstants.STYLE_IMAGE_WIDTH] = '48';\n style[mxConstants.STYLE_IMAGE_HEIGHT] = '48';\n style[mxConstants.STYLE_SPACING_TOP] = '56';\n style[mxConstants.STYLE_SPACING] = '8';\n graph.getStylesheet().putCellStyle('bottom', style);\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_BOTTOM;\n style[mxConstants.STYLE_IMAGE] = 'images/icons48/server.png';\n delete style[mxConstants.STYLE_SPACING_TOP];\n graph.getStylesheet().putCellStyle('top', style);\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT;\n style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_LEFT;\n style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;\n style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;\n style[mxConstants.STYLE_IMAGE] = 'images/icons48/earth.png';\n style[mxConstants.STYLE_SPACING_LEFT] = '55';\n style[mxConstants.STYLE_SPACING] = '4';\n graph.getStylesheet().putCellStyle('right', style);\n\n style = mxUtils.clone(style);\n style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_RIGHT;\n style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_RIGHT;\n delete style[mxConstants.STYLE_SPACING_LEFT];\n style[mxConstants.STYLE_SPACING_RIGHT] = '55';\n graph.getStylesheet().putCellStyle('left', style);\n }\n }\n}\n\nexport default Images;\n", - "Stylesheet": "/**\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 mxConstants from '../mxgraph/util/mxConstants';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\nimport mxPerimeter from '../mxgraph/view/mxPerimeter';\n\nclass Stylesheet extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Stylesheet

    \n This example demonstrates using a custom stylesheet and control points\n in edges, as well as overriding the getLabel and getTooltip function to\n return dynamic information, and making a supercall in JavaScript.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '311px',\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Creates the graph inside the DOM node.\n const graph = new mxGraph(this.el);\n\n // Disables basic selection and cell handling\n graph.setEnabled(false);\n\n // Returns a special label for edges. Note: This does\n // a supercall to use the default implementation.\n graph.getLabel = function(cell) {\n const label = mxGraph.prototype.getLabel.apply(this, arguments);\n\n if (this.getModel().isEdge(cell)) {\n return `Transfer ${label}`;\n }\n return label;\n };\n\n // Installs a custom global tooltip\n graph.setTooltips(true);\n graph.getTooltip = function(state) {\n const { cell } = state;\n const model = this.getModel();\n\n if (model.isEdge(cell)) {\n const source = this.getLabel(model.getTerminal(cell, true));\n const target = this.getLabel(model.getTerminal(cell, false));\n\n return `${source} -> ${target}`;\n }\n return this.getLabel(cell);\n };\n\n // Creates the default style for vertices\n let style = [];\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;\n style[mxConstants.STYLE_STROKECOLOR] = 'gray';\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_FILLCOLOR] = '#EEEEEE';\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n style[mxConstants.STYLE_FONTCOLOR] = '#774400';\n style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;\n style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;\n style[mxConstants.STYLE_FONTSIZE] = '12';\n style[mxConstants.STYLE_FONTSTYLE] = 1;\n graph.getStylesheet().putDefaultVertexStyle(style);\n\n // Creates the default style for edges\n style = [];\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_CONNECTOR;\n style[mxConstants.STYLE_STROKECOLOR] = '#6482B9';\n style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;\n style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;\n style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC;\n style[mxConstants.STYLE_FONTSIZE] = '10';\n graph.getStylesheet().putDefaultEdgeStyle(style);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(\n parent,\n null,\n 'Interval 1',\n 20,\n 20,\n 180,\n 30\n );\n const v2 = graph.insertVertex(\n parent,\n null,\n 'Interval 2',\n 140,\n 80,\n 280,\n 30\n );\n const v3 = graph.insertVertex(\n parent,\n null,\n 'Interval 3',\n 200,\n 140,\n 360,\n 30\n );\n const v4 = graph.insertVertex(\n parent,\n null,\n 'Interval 4',\n 480,\n 200,\n 120,\n 30\n );\n const v5 = graph.insertVertex(\n parent,\n null,\n 'Interval 5',\n 60,\n 260,\n 400,\n 30\n );\n const e1 = graph.insertEdge(parent, null, '1', v1, v2);\n e1.getGeometry().points = [{ x: 160, y: 60 }];\n const e2 = graph.insertEdge(parent, null, '2', v1, v5);\n e2.getGeometry().points = [{ x: 80, y: 60 }];\n const e3 = graph.insertEdge(parent, null, '3', v2, v3);\n e3.getGeometry().points = [{ x: 280, y: 120 }];\n const e4 = graph.insertEdge(parent, null, '4', v3, v4);\n e4.getGeometry().points = [{ x: 500, y: 180 }];\n const e5 = graph.insertEdge(parent, null, '5', v3, v5);\n e5.getGeometry().points = [{ x: 380, y: 180 }];\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Stylesheet;\n", - "ExtendCanvas": "/**\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 mxRectangle from '../mxgraph/util/mxRectangle';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxPoint from '../mxgraph/util/mxPoint';\n\nclass ExtendCanvas extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Extend canvas

    \n This example demonstrates implementing an infinite canvas with\n scrollbars.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'auto',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Disables the built-in context menu\n mxEvent.disableContextMenu(this.el);\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.panningHandler.ignoreCell = true;\n graph.setPanning(true);\n\n /**\n * Specifies the size of the size for \"tiles\" to be used for a graph with\n * scrollbars but no visible background page. A good value is large\n * enough to reduce the number of repaints that is caused for auto-\n * translation, which depends on this value, and small enough to give\n * a small empty buffer around the graph. Default is 400x400.\n */\n graph.scrollTileSize = new mxRectangle(0, 0, 400, 400);\n\n /**\n * Returns the padding for pages in page view with scrollbars.\n */\n graph.getPagePadding = function() {\n return new mxPoint(\n Math.max(0, Math.round(graph.container.offsetWidth - 34)),\n Math.max(0, Math.round(graph.container.offsetHeight - 34))\n );\n };\n\n /**\n * Returns the size of the page format scaled with the page size.\n */\n graph.getPageSize = function() {\n return this.pageVisible\n ? new mxRectangle(\n 0,\n 0,\n this.pageFormat.width * this.pageScale,\n this.pageFormat.height * this.pageScale\n )\n : this.scrollTileSize;\n };\n\n /**\n * Returns a rectangle describing the position and count of the\n * background pages, where x and y are the position of the top,\n * left page and width and height are the vertical and horizontal\n * page count.\n */\n graph.getPageLayout = function() {\n const size = this.pageVisible ? this.getPageSize() : this.scrollTileSize;\n const bounds = this.getGraphBounds();\n\n if (bounds.width === 0 || bounds.height === 0) {\n return new mxRectangle(0, 0, 1, 1);\n }\n\n // Computes untransformed graph bounds\n const x = Math.ceil(bounds.x / this.view.scale - this.view.translate.x);\n const y = Math.ceil(bounds.y / this.view.scale - this.view.translate.y);\n const w = Math.floor(bounds.width / this.view.scale);\n const h = Math.floor(bounds.height / this.view.scale);\n\n const x0 = Math.floor(x / size.width);\n const y0 = Math.floor(y / size.height);\n const w0 = Math.ceil((x + w) / size.width) - x0;\n const h0 = Math.ceil((y + h) / size.height) - y0;\n\n return new mxRectangle(x0, y0, w0, h0);\n };\n\n // Fits the number of background pages to the graph\n graph.view.getBackgroundPageBounds = function() {\n const layout = this.graph.getPageLayout();\n const page = this.graph.getPageSize();\n\n return new mxRectangle(\n this.scale * (this.translate.x + layout.x * page.width),\n this.scale * (this.translate.y + layout.y * page.height),\n this.scale * layout.width * page.width,\n this.scale * layout.height * page.height\n );\n };\n\n graph.getPreferredPageSize = function(bounds, width, height) {\n const pages = this.getPageLayout();\n const size = this.getPageSize();\n\n return new mxRectangle(\n 0,\n 0,\n pages.width * size.width,\n pages.height * size.height\n );\n };\n\n /**\n * Guesses autoTranslate to avoid another repaint (see below).\n * Works if only the scale of the graph changes or if pages\n * are visible and the visible pages do not change.\n */\n const graphViewValidate = graph.view.validate;\n graph.view.validate = function() {\n if (\n this.graph.container != null &&\n mxUtils.hasScrollbars(this.graph.container)\n ) {\n const pad = this.graph.getPagePadding();\n const size = this.graph.getPageSize();\n\n // Updating scrollbars here causes flickering in quirks and is not needed\n // if zoom method is always used to set the current scale on the graph.\n const tx = this.translate.x;\n const ty = this.translate.y;\n this.translate.x = pad.x / this.scale - (this.x0 || 0) * size.width;\n this.translate.y = pad.y / this.scale - (this.y0 || 0) * size.height;\n }\n\n graphViewValidate.apply(this, arguments);\n };\n\n const graphSizeDidChange = graph.sizeDidChange;\n graph.sizeDidChange = function() {\n if (this.container != null && mxUtils.hasScrollbars(this.container)) {\n const pages = this.getPageLayout();\n const pad = this.getPagePadding();\n const size = this.getPageSize();\n\n // Updates the minimum graph size\n const minw = Math.ceil(\n (2 * pad.x) / this.view.scale + pages.width * size.width\n );\n const minh = Math.ceil(\n (2 * pad.y) / this.view.scale + pages.height * size.height\n );\n\n const min = graph.minimumGraphSize;\n\n // LATER: Fix flicker of scrollbar size in IE quirks mode\n // after delayed call in window.resize event handler\n if (min == null || min.width !== minw || min.height !== minh) {\n graph.minimumGraphSize = new mxRectangle(0, 0, minw, minh);\n }\n\n // Updates auto-translate to include padding and graph size\n const dx = pad.x / this.view.scale - pages.x * size.width;\n const dy = pad.y / this.view.scale - pages.y * size.height;\n\n if (\n !this.autoTranslate &&\n (this.view.translate.x !== dx || this.view.translate.y !== dy)\n ) {\n this.autoTranslate = true;\n this.view.x0 = pages.x;\n this.view.y0 = pages.y;\n\n // NOTE: THIS INVOKES THIS METHOD AGAIN. UNFORTUNATELY THERE IS NO WAY AROUND THIS SINCE THE\n // BOUNDS ARE KNOWN AFTER THE VALIDATION AND SETTING THE TRANSLATE TRIGGERS A REVALIDATION.\n // SHOULD MOVE TRANSLATE/SCALE TO VIEW.\n const tx = graph.view.translate.x;\n const ty = graph.view.translate.y;\n\n graph.view.setTranslate(dx, dy);\n graph.container.scrollLeft += (dx - tx) * graph.view.scale;\n graph.container.scrollTop += (dy - ty) * graph.view.scale;\n\n this.autoTranslate = false;\n return;\n }\n\n graphSizeDidChange.apply(this, arguments);\n }\n };\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n // Sets initial scrollbar positions\n window.setTimeout(function() {\n const bounds = graph.getGraphBounds();\n const width = Math.max(\n bounds.width,\n graph.scrollTileSize.width * graph.view.scale\n );\n const height = Math.max(\n bounds.height,\n graph.scrollTileSize.height * graph.view.scale\n );\n graph.container.scrollTop = Math.floor(\n Math.max(\n 0,\n bounds.y - Math.max(20, (graph.container.clientHeight - height) / 4)\n )\n );\n graph.container.scrollLeft = Math.floor(\n Math.max(\n 0,\n bounds.x - Math.max(0, (graph.container.clientWidth - width) / 2)\n )\n );\n }, 0);\n };\n}\n\nexport default ExtendCanvas;\n", - "DynamicLoading": "/**\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 mxText from '../mxgraph/shape/mxText';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxCodec from '../mxgraph/io/mxCodec';\nimport mxEffects from '../mxgraph/util/mxEffects';\nimport mxPerimeter from '../mxgraph/view/mxPerimeter';\n\nclass DynamicLoading extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Dynamic loading

    \n This example demonstrates loading graph model data dynamically to limit\n the number of cells in the model.\n {\n this.el = el;\n }}\n style={{\n overflow: 'visible',\n position: 'absolute',\n height: '100%',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n let requestId = 0;\n\n // Speedup the animation\n mxText.prototype.enableBoundingBox = false;\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Disables all built-in interactions\n graph.setEnabled(false);\n\n // Handles clicks on cells\n graph.addListener(mxEvent.CLICK, function(sender, evt) {\n const cell = evt.getProperty('cell');\n\n if (cell != null) {\n load(graph, cell);\n }\n });\n\n // Changes the default vertex style in-place\n const style = graph.getStylesheet().getDefaultVertexStyle();\n style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE;\n style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter;\n style[mxConstants.STYLE_GRADIENTCOLOR] = 'white';\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n const cx = graph.container.clientWidth / 2;\n const cy = graph.container.clientHeight / 2;\n\n const cell = graph.insertVertex(\n parent,\n '0-0',\n '0-0',\n cx - 20,\n cy - 15,\n 60,\n 40\n );\n\n // Animates the changes in the graph model\n graph.getModel().addListener(mxEvent.CHANGE, function(sender, evt) {\n const { changes } = evt.getProperty('edit');\n mxEffects.animateChanges(graph, changes);\n });\n\n // Loads the links for the given cell into the given graph\n // by requesting the respective data in the server-side\n // (implemented for this demo using the server-function)\n function load(graph, cell) {\n if (graph.getModel().isVertex(cell)) {\n const cx = graph.container.clientWidth / 2;\n const cy = graph.container.clientHeight / 2;\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const xml = server(cell.id);\n const doc = mxUtils.parseXml(xml);\n const dec = new mxCodec(doc);\n const model = dec.decode(doc.documentElement);\n\n // Removes all cells which are not in the response\n for (var key in graph.getModel().cells) {\n const tmp = graph.getModel().getCell(key);\n\n if (tmp != cell && graph.getModel().isVertex(tmp)) {\n graph.removeCells([tmp]);\n }\n }\n\n // Merges the response model with the client model\n graph.getModel().mergeChildren(model.getRoot().getChildAt(0), parent);\n\n // Moves the given cell to the center\n let geo = graph.getModel().getGeometry(cell);\n\n if (geo != null) {\n geo = geo.clone();\n geo.x = cx - geo.width / 2;\n geo.y = cy - geo.height / 2;\n\n graph.getModel().setGeometry(cell, geo);\n }\n\n // Creates a list of the new vertices, if there is more\n // than the center vertex which might have existed\n // previously, then this needs to be changed to analyze\n // the target model before calling mergeChildren above\n const vertices = [];\n\n for (var key in graph.getModel().cells) {\n const tmp = graph.getModel().getCell(key);\n\n if (tmp != cell && model.isVertex(tmp)) {\n vertices.push(tmp);\n\n // Changes the initial location \"in-place\"\n // to get a nice animation effect from the\n // center to the radius of the circle\n const geo = model.getGeometry(tmp);\n\n if (geo != null) {\n geo.x = cx - geo.width / 2;\n geo.y = cy - geo.height / 2;\n }\n }\n }\n\n // Arranges the response in a circle\n const cellCount = vertices.length;\n const phi = (2 * Math.PI) / cellCount;\n const r = Math.min(\n graph.container.clientWidth / 4,\n graph.container.clientHeight / 4\n );\n\n for (let i = 0; i < cellCount; i++) {\n let geo = graph.getModel().getGeometry(vertices[i]);\n\n if (geo != null) {\n geo = geo.clone();\n geo.x += r * Math.sin(i * phi);\n geo.y += r * Math.cos(i * phi);\n\n graph.getModel().setGeometry(vertices[i], geo);\n }\n }\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n }\n\n // Simulates the existence of a server that can crawl the\n // big graph with a certain depth and create a graph model\n // for the traversed cells, which is then sent to the client\n function server(cellId) {\n // Increments the request ID as a prefix for the cell IDs\n requestId++;\n\n // Creates a local graph with no display\n const graph = new mxGraph();\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v0 = graph.insertVertex(parent, cellId, 'Dummy', 0, 0, 60, 40);\n const cellCount = parseInt(Math.random() * 16) + 4;\n\n // Creates the random links and cells for the response\n for (let i = 0; i < cellCount; i++) {\n const id = `${requestId}-${i}`;\n const v = graph.insertVertex(parent, id, id, 0, 0, 60, 40);\n const e = graph.insertEdge(parent, null, `Link ${i}`, v0, v);\n }\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n const enc = new mxCodec();\n const node = enc.encode(graph.getModel());\n\n return mxUtils.getXml(node);\n }\n\n load(graph, cell);\n };\n}\n\nexport default DynamicLoading;\n", - "AutoLayout": "/**\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 mxClient from '../mxgraph/mxClient';\nimport mxMorphing from '../mxgraph/util/mxMorphing';\nimport mxEdgeHandler from '../mxgraph/handler/mxEdgeHandler';\nimport mxHierarchicalLayout from '../mxgraph/layout/hierarchical/mxHierarchicalLayout';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxCellOverlay from '../mxgraph/view/mxCellOverlay';\nimport mxImage from '../mxgraph/util/mxImage';\nimport mxEventObject from '../mxgraph/util/mxEventObject';\nimport mxCellRenderer from '../mxgraph/view/mxCellRenderer';\n\nclass AutoLayout extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Auto layout

    \n This example demonstrates running and animating a layout algorithm after\n every change to a graph.\n {\n this.el = el;\n }}\n style={{\n position: 'relative',\n overflow: 'hidden',\n height: '641px',\n background: 'url(\"editors/images/grid.gif\")',\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n mxEvent.disableContextMenu(this.el);\n\n class MyCustomCellRenderer extends mxCellRenderer {\n installCellOverlayListeners(state, overlay, shape) {\n super.installCellOverlayListeners(state, overlay, shape);\n\n mxEvent.addListener(\n shape.node,\n mxClient.IS_POINTER ? 'pointerdown' : 'mousedown',\n evt => {\n overlay.fireEvent(\n new mxEventObject('pointerdown', 'event', evt, 'state', state)\n );\n }\n );\n\n if (!mxClient.IS_POINTER && mxClient.IS_TOUCH) {\n mxEvent.addListener(shape.node, 'touchstart', evt => {\n overlay.fireEvent(\n new mxEventObject('pointerdown', 'event', evt, 'state', state)\n );\n });\n }\n }\n }\n\n class MyCustomEdgeHandler extends mxEdgeHandler {\n connect(edge, terminal, isSource, isClone, me) {\n super.connect(edge, terminal, isSource, isClone, me);\n executeLayout();\n }\n }\n\n class MyCustomGraph extends mxGraph {\n createEdgeHandler(state, edgeStyle) {\n return new MyCustomEdgeHandler(state, edgeStyle);\n }\n\n createCellRenderer() {\n return new MyCustomCellRenderer();\n }\n }\n\n // Creates the graph inside the given this.el\n const graph = new MyCustomGraph(this.el);\n graph.setPanning(true);\n graph.panningHandler.useLeftButtonForPanning = true;\n graph.setAllowDanglingEdges(false);\n graph.connectionHandler.select = false;\n graph.view.setTranslate(20, 20);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n const layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_WEST);\n const executeLayout = (change, post) => {\n graph.getModel().beginUpdate();\n try {\n if (change != null) {\n change();\n }\n layout.execute(graph.getDefaultParent(), v1);\n } catch (e) {\n throw e;\n } finally {\n // New API for animating graph layout results asynchronously\n const morph = new mxMorphing(graph);\n morph.addListener(mxEvent.DONE, () => {\n graph.getModel().endUpdate();\n if (post != null) {\n post();\n }\n });\n morph.startAnimation();\n }\n };\n\n const addOverlay = cell => {\n // Creates a new overlay with an image and a tooltip\n const overlay = new mxCellOverlay(\n new mxImage('images/add.png', 24, 24),\n 'Add outgoing'\n );\n overlay.cursor = 'hand';\n\n // Installs a handler for clicks on the overlay\n overlay.addListener(mxEvent.CLICK, (sender, evt2) => {\n graph.clearSelection();\n const geo = graph.getCellGeometry(cell);\n\n let v2;\n\n executeLayout(\n () => {\n v2 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [geo.x, geo.y],\n size: [80, 30],\n });\n addOverlay(v2);\n graph.view.refresh(v2);\n const e1 = graph.insertEdge({\n parent,\n source: cell,\n target: v2,\n });\n },\n () => {\n graph.scrollCellToVisible(v2);\n }\n );\n });\n\n // Special CMS event\n overlay.addListener('pointerdown', (sender, eo) => {\n const evt2 = eo.getProperty('event');\n const state = eo.getProperty('state');\n\n graph.popupMenuHandler.hideMenu();\n graph.stopEditing(false);\n\n const pt = mxUtils.convertPoint(\n graph.container,\n mxEvent.getClientX(evt2),\n mxEvent.getClientY(evt2)\n );\n graph.connectionHandler.start(state, pt.x, pt.y);\n graph.isMouseDown = true;\n graph.isMouseTrigger = mxEvent.isMouseEvent(evt2);\n mxEvent.consume(evt2);\n });\n\n // Sets the overlay for the cell in the graph\n graph.addCellOverlay(cell, overlay);\n };\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n let v1;\n try {\n v1 = graph.insertVertex({\n parent,\n value: 'Hello,',\n position: [0, 0],\n size: [80, 30],\n });\n addOverlay(v1);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n graph.resizeCell = function() {\n mxGraph.prototype.resizeCell.apply(this, arguments);\n executeLayout();\n };\n\n graph.connectionHandler.addListener(mxEvent.CONNECT, function() {\n executeLayout();\n });\n }\n}\n\nexport default AutoLayout;\n", - "FixedIcon": "/**\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';\nimport mxLabel from '../mxgraph/shape/mxLabel';\nimport mxRectangle from '../mxgraph/util/mxRectangle';\n\nclass FixedIcon extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Fixed icon

    \n This example demonstrates customizing the icon position in the mxLabel\n shape.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n };\n\n componentDidMount() {\n // Overrides the image bounds code to change the position\n mxLabel.prototype.getImageBounds = function(x, y, w, h) {\n const iw = mxUtils.getValue(\n this.style,\n mxConstants.STYLE_IMAGE_WIDTH,\n mxConstants.DEFAULT_IMAGESIZE\n );\n const ih = mxUtils.getValue(\n this.style,\n mxConstants.STYLE_IMAGE_HEIGHT,\n mxConstants.DEFAULT_IMAGESIZE\n );\n\n // Places the icon\n const ix = (w - iw) / 2;\n const iy = h - ih;\n\n return new mxRectangle(x + ix, y + iy, iw, ih);\n };\n\n // Makes the shadow brighter\n mxConstants.SHADOWCOLOR = '#C0C0C0';\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n\n // Uncomment the following if you want the container\n // to fit the size of the graph\n // graph.setResizeContainer(true);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(\n parent,\n null,\n 'Fixed icon',\n 20,\n 20,\n 80,\n 50,\n 'shape=label;image=images/plus.png;imageWidth=16;imageHeight=16;spacingBottom=10;' +\n 'fillColor=#adc5ff;gradientColor=#7d85df;glass=1;rounded=1;shadow=1;'\n );\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n };\n}\n\nexport default FixedIcon;\n", - "_app": "import '../styles/globals.css';\nimport '../public/css/common.css';\nimport './Animation.css';\n\nfunction MyApp({ Component, pageProps }) {\n return ;\n}\n\nexport default MyApp;\n", - "Guides": "/**\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 mxGraphHandler from '../mxgraph/handler/mxGraphHandler';\nimport mxEdgeHandler from '../mxgraph/handler/mxEdgeHandler';\nimport mxConstants from '../mxgraph/util/mxConstants';\nimport mxEdgeStyle from '../mxgraph/view/mxEdgeStyle';\nimport mxKeyHandler from '../mxgraph/handler/mxKeyHandler';\n\nclass Guides extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Guides

    \n This example demonstrates the guides feature which aligns the current\n selection to the existing vertices in the graph. This feature is in RFC\n state. Creating a grid using a canvas and installing a key handler for\n cursor keys is also demonstrated here, as well as snapping waypoints to\n terminals.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n height: '601px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Enables guides\n mxGraphHandler.prototype.guidesEnabled = true;\n\n // Alt disables guides\n mxGraphHandler.prototype.useGuidesForEvent = function(me) {\n return !mxEvent.isAltDown(me.getEvent());\n };\n\n // Defines the guides to be red (default)\n mxConstants.GUIDE_COLOR = '#FF0000';\n\n // Defines the guides to be 1 pixel (default)\n mxConstants.GUIDE_STROKEWIDTH = 1;\n\n // Enables snapping waypoints to terminals\n mxEdgeHandler.prototype.snapToTerminals = true;\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.setConnectable(true);\n graph.gridSize = 30;\n\n // Changes the default style for edges \"in-place\" and assigns\n // an alternate edge style which is applied in mxGraph.flip\n // when the user double clicks on the adjustment control point\n // of the edge. The ElbowConnector edge style switches to TopToBottom\n // if the horizontal style is true.\n const style = graph.getStylesheet().getDefaultEdgeStyle();\n style[mxConstants.STYLE_ROUNDED] = true;\n style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;\n graph.alternateEdgeStyle = 'elbow=vertical';\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n let v1;\n try {\n v1 = graph.insertVertex(parent, null, 'Hello,', 20, 40, 80, 70);\n const v2 = graph.insertVertex(parent, null, 'World!', 200, 140, 80, 40);\n const e1 = graph.insertEdge(parent, null, '', v1, v2);\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n\n // Handles cursor keys\n const nudge = function(keyCode) {\n if (!graph.isSelectionEmpty()) {\n let dx = 0;\n let dy = 0;\n\n if (keyCode === 37) {\n dx = -1;\n } else if (keyCode === 38) {\n dy = -1;\n } else if (keyCode === 39) {\n dx = 1;\n } else if (keyCode === 40) {\n dy = 1;\n }\n\n graph.moveCells(graph.getSelectionCells(), dx, dy);\n }\n\n // Transfer initial focus to graph container for keystroke handling\n graph.container.focus();\n\n // Handles keystroke events\n const keyHandler = new mxKeyHandler(graph);\n\n // Ignores enter keystroke. Remove this line if you want the\n // enter keystroke to stop editing\n keyHandler.enter = function() {};\n\n keyHandler.bindKey(37, function() {\n nudge(37);\n });\n\n keyHandler.bindKey(38, function() {\n nudge(38);\n });\n\n keyHandler.bindKey(39, function() {\n nudge(39);\n });\n\n keyHandler.bindKey(40, function() {\n nudge(40);\n });\n };\n }\n}\n\nexport default Guides;\n", - "DragSource": "/**\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 mxCell from '../mxgraph/model/mxCell';\nimport mxGeometry from '../mxgraph/model/mxGeometry';\nimport mxUtils from '../mxgraph/util/mxUtils';\nimport mxDragSource from '../mxgraph/util/mxDragSource';\nimport mxGraphHandler from '../mxgraph/handler/mxGraphHandler';\nimport mxGuide from '../mxgraph/util/mxGuide';\nimport mxEdgeHandler from '../mxgraph/handler/mxEdgeHandler';\n\nclass DragSource extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Dragsource

    \n This example demonstrates using one drag source for multiple graphs and\n changing the drag icon.\n {\n this.el = el;\n }}\n style={{}}\n />\n \n );\n };\n\n componentDidMount() {\n class MyCustomGuide extends mxGuide {\n isEnabledForEvent(evt) {\n // Alt disables guides\n return !mxEvent.isAltDown(evt);\n }\n }\n\n class MyCustomGraphHandler extends mxGraphHandler {\n // Enables guides\n guidesEnabled = true;\n\n createGuide() {\n return new MyCustomGuide(this.graph, this.getGuideStates());\n }\n }\n\n class MyCustomEdgeHandler extends mxEdgeHandler {\n // Enables snapping waypoints to terminals\n snapToTerminals = true;\n }\n\n class MyCustomGraph extends mxGraph {\n createGraphHandler() {\n return new MyCustomGraphHandler(this);\n }\n\n createEdgeHandler(state, edgeStyle) {\n return new MyCustomEdgeHandler(state, edgeStyle);\n }\n }\n\n const graphs = [];\n\n // Creates the graph inside the given container\n for (let i = 0; i < 2; i++) {\n const container = document.createElement('div');\n container.style.overflow = 'hidden';\n container.style.position = 'relative';\n container.style.width = '321px';\n container.style.height = '241px';\n container.style.background = \"url('editors/images/grid.gif')\";\n container.style.cursor = 'default';\n\n this.el.appendChild(container);\n\n const graph = new MyCustomGraph(container);\n graph.gridSize = 30;\n\n // Uncomment the following if you want the container\n // to fit the size of the graph\n // graph.setResizeContainer(true);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.batchUpdate(() => {\n const v1 = graph.insertVertex({\n parent,\n value: 'Hello,',\n position: [20, 20],\n size: [80, 30],\n });\n const v2 = graph.insertVertex({\n parent,\n value: 'World!',\n position: [200, 150],\n size: [80, 30],\n });\n const e1 = graph.insertEdge({\n parent,\n source: v1,\n target: v2,\n });\n });\n\n graphs.push(graph);\n }\n\n // Returns the graph under the mouse\n const graphF = evt => {\n const x = mxEvent.getClientX(evt);\n const y = mxEvent.getClientY(evt);\n const elt = document.elementFromPoint(x, y);\n\n for (const graph of graphs) {\n if (mxUtils.isAncestorNode(graph.container, elt)) {\n return graph;\n }\n }\n\n return null;\n };\n\n // Inserts a cell at the given location\n const funct = (graph, evt, target, x, y) => {\n const cell = new mxCell('Test', new mxGeometry(0, 0, 120, 40));\n cell.vertex = true;\n const cells = graph.importCells([cell], x, y, target);\n\n if (cells != null && cells.length > 0) {\n graph.scrollCellToVisible(cells[0]);\n graph.setSelectionCells(cells);\n }\n };\n\n // Creates a DOM node that acts as the drag source\n const img = mxUtils.createImage('images/icons48/gear.png');\n img.style.width = '48px';\n img.style.height = '48px';\n this.el.appendChild(img);\n\n // Creates the element that is being for the actual preview.\n const dragElt = document.createElement('div');\n dragElt.style.border = 'dashed black 1px';\n dragElt.style.width = '120px';\n dragElt.style.height = '40px';\n\n // Drag source is configured to use dragElt for preview and as drag icon\n // if scalePreview (last) argument is true. Dx and dy are null to force\n // the use of the defaults. Note that dx and dy are only used for the\n // drag icon but not for the preview.\n const ds = mxUtils.makeDraggable(\n img,\n graphF,\n funct,\n dragElt,\n null,\n null,\n graphs[0].autoscroll,\n true\n );\n\n // Redirects feature to global switch. Note that this feature should only be used\n // if the the x and y arguments are used in funct to insert the cell.\n ds.isGuidesEnabled = () => {\n return graphs[0].graphHandler.guidesEnabled;\n };\n\n // Restores original drag icon while outside of graph\n ds.createDragElement = mxDragSource.prototype.createDragElement;\n };\n\n // NOTE: To enable cross-document DnD (eg. between frames),\n // the following methods need to be overridden:\n /* mxDragSourceMouseUp = mxDragSource.prototype.mouseUp;\nmxDragSource.prototype.mouseUp = function(evt)\n{\n let doc = this.element.ownerDocument;\n\n if (doc != document)\n {\n let mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup';\n\n if (this.mouseUpHandler != null)\n {\n mxEvent.removeListener(doc, mu, this.mouseUpHandler);\n }\n }\n\n mxDragSourceMouseUp.apply(this, arguments);\n}; */\n\n /* mxDragSourceMouseDown = mxDragSource.prototype.mouseDown;\nmxDragSource.prototype.mouseDown = function(evt)\n{\n if (this.enabled && !mxEvent.isConsumed(evt))\n {\n mxDragSourceMouseDown.apply(this, arguments);\n let doc = this.element.ownerDocument;\n\n if (doc != document)\n {\n let mu = (mxClient.IS_TOUCH) ? 'touchend' : 'mouseup';\n mxEvent.addListener(doc, mu, this.mouseUpHandler);\n }\n }\n}; */\n}\n\nexport default DragSource;\n", - "Orthogonal": "/**\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 mxGraphHandler from '../mxgraph/handler/mxGraphHandler';\nimport mxGuide from '../mxgraph/util/mxGuide';\nimport mxEdgeHandler from '../mxgraph/handler/mxEdgeHandler';\nimport mxConnectionHandler from '../mxgraph/handler/mxConnectionHandler';\nimport mxGraphView from '../mxgraph/view/mxGraphView';\nimport mxPoint from '../mxgraph/util/mxPoint';\nimport mxCellState from '../mxgraph/view/mxCellState';\n\nclass Orthogonal extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n // A container for the graph\n return (\n <>\n

    Orthogonal

    \n This example demonstrates the use of port constraints and orthogonal\n edge styles and handlers.\n {\n this.el = el;\n }}\n style={{\n overflow: 'hidden',\n position: 'relative',\n height: '241px',\n background: \"url('editors/images/grid.gif')\",\n cursor: 'default',\n }}\n />\n \n );\n }\n\n componentDidMount() {\n // Enables guides\n mxGraphHandler.prototype.guidesEnabled = true;\n\n // Alt disables guides\n mxGuide.prototype.isEnabledForEvent = function(evt) {\n return !mxEvent.isAltDown(evt);\n };\n\n // Enables snapping waypoints to terminals\n mxEdgeHandler.prototype.snapToTerminals = true;\n\n // Enables orthogonal connect preview in IE\n mxConnectionHandler.prototype.movePreviewAway = false;\n\n // Creates the graph inside the given container\n const graph = new mxGraph(this.el);\n graph.disconnectOnMove = false;\n graph.foldingEnabled = false;\n graph.cellsResizable = false;\n graph.extendParents = false;\n graph.setConnectable(true);\n\n // Implements perimeter-less connection points as fixed points (computed before the edge style).\n graph.view.updateFixedTerminalPoint = function(\n edge,\n terminal,\n source,\n constraint\n ) {\n mxGraphView.prototype.updateFixedTerminalPoint.apply(this, arguments);\n\n const pts = edge.absolutePoints;\n const pt = pts[source ? 0 : pts.length - 1];\n\n if (\n terminal != null &&\n pt == null &&\n this.getPerimeterFunction(terminal) == null\n ) {\n edge.setAbsoluteTerminalPoint(\n new mxPoint(\n this.getRoutingCenterX(terminal),\n this.getRoutingCenterY(terminal)\n ),\n source\n );\n }\n };\n\n // Changes the default edge style\n graph.getStylesheet().getDefaultEdgeStyle().edgeStyle =\n 'orthogonalEdgeStyle';\n delete graph.getStylesheet().getDefaultEdgeStyle().endArrow;\n\n // Implements the connect preview\n graph.connectionHandler.createEdgeState = function(me) {\n const edge = graph.createEdge(null, null, null, null, null);\n\n return new mxCellState(\n this.graph.view,\n edge,\n this.graph.getCellStyle(edge)\n );\n };\n\n // Uncomment the following if you want the container\n // to fit the size of the graph\n // graph.setResizeContainer(true);\n\n // Enables rubberband selection\n new mxRubberband(graph);\n\n // Gets the default parent for inserting new cells. This\n // is normally the first child of the root (ie. layer 0).\n const parent = graph.getDefaultParent();\n\n // Adds cells to the model in a single step\n graph.getModel().beginUpdate();\n try {\n const v1 = graph.insertVertex(parent, null, '', 40, 40, 40, 30);\n v1.setConnectable(false);\n const v11 = graph.insertVertex(\n v1,\n null,\n '',\n 0.5,\n 0,\n 10,\n 40,\n 'portConstraint=northsouth;',\n true\n );\n v11.geometry.offset = new mxPoint(-5, -5);\n const v12 = graph.insertVertex(\n v1,\n null,\n '',\n 0,\n 0.5,\n 10,\n 10,\n 'portConstraint=west;shape=triangle;direction=west;perimeter=none;' +\n 'routingCenterX=-0.5;routingCenterY=0;',\n true\n );\n v12.geometry.offset = new mxPoint(-10, -5);\n const v13 = graph.insertVertex(\n v1,\n null,\n '',\n 1,\n 0.5,\n 10,\n 10,\n 'portConstraint=east;shape=triangle;direction=east;perimeter=none;' +\n 'routingCenterX=0.5;routingCenterY=0;',\n true\n );\n v13.geometry.offset = new mxPoint(0, -5);\n\n const v2 = graph.addCell(graph.getModel().cloneCell(v1));\n v2.geometry.x = 200;\n v2.geometry.y = 60;\n\n const v3 = graph.addCell(graph.getModel().cloneCell(v1));\n v3.geometry.x = 40;\n v3.geometry.y = 150;\n\n const v4 = graph.addCell(graph.getModel().cloneCell(v1));\n v4.geometry.x = 200;\n v4.geometry.y = 170;\n\n graph.insertEdge(parent, null, '', v1.getChildAt(2), v2.getChildAt(1));\n graph.insertEdge(parent, null, '', v2.getChildAt(2), v3.getChildAt(1));\n graph.insertEdge(parent, null, '', v3.getChildAt(2), v4.getChildAt(1));\n } finally {\n // Updates the display\n graph.getModel().endUpdate();\n }\n }\n}\n\nexport default Orthogonal;\n" -} \ No newline at end of file diff --git a/src/pages/icons_images/ContextIcons.js b/src/pages/icons_images/ContextIcons.js deleted file mode 100644 index 01c9ba2d1..000000000 --- a/src/pages/icons_images/ContextIcons.js +++ /dev/null @@ -1,210 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxVertexHandler from '../../mxgraph/handler/mxVertexHandler'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxClient from '../../mxgraph/mxClient'; - -class ContextIcons extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Context icons

    - This example demonstrates adding icons to selected vertices to carry out - special operations. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - }; - - componentDidMount() { - class mxVertexToolHandler extends mxVertexHandler { - // Defines a subclass for mxVertexHandler that adds a set of clickable - // icons to every selected vertex. - - domNode = null; - - init() { - super.init(); - - // 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); - }; - - // 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', evt => { - this.graph.removeCells([this.state.cell]); - mxEvent.consume(evt); - }); - 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, 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); - - // 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), - mxEvent.getClientY(evt) - ); - this.graph.graphHandler.cellWasClicked = true; - this.graph.isMouseDown = true; - this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt); - mxEvent.consume(evt); - }); - 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, evt => { - const pt = mxUtils.convertPoint( - this.graph.container, - mxEvent.getClientX(evt), - mxEvent.getClientY(evt) - ); - this.graph.connectionHandler.start(this.state, pt.x, pt.y); - this.graph.isMouseDown = true; - this.graph.isMouseTrigger = mxEvent.isMouseEvent(evt); - mxEvent.consume(evt); - }); - this.domNode.appendChild(img); - - this.graph.container.appendChild(this.domNode); - this.redrawTools(); - } - - redraw() { - super.redraw(); - this.redrawTools(); - } - - 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`; - } - } - - destroy(sender, me) { - super.destroy(sender, me); - - if (this.domNode != null) { - this.domNode.parentNode.removeChild(this.domNode); - this.domNode = null; - } - } - } - - class MyCustomGraph extends mxGraph { - createHandler(state) { - if (state != null && state.cell.isVertex()) { - 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, - }); - }); - }; -} - -export default ContextIcons; diff --git a/src/pages/icons_images/Control.js b/src/pages/icons_images/Control.js deleted file mode 100644 index 9a42bb5ec..000000000 --- a/src/pages/icons_images/Control.js +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; -import mxCellRenderer from '../../mxgraph/view/cell/mxCellRenderer'; -import mxImageShape from '../../mxgraph/shape/node/mxImageShape'; -import mxImage from '../../mxgraph/util/image/mxImage'; - -class Control extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Control

    - This example demonstrates adding controls to specific cells in a graph. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '441px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Specifies the URL and size of the new control - const deleteImage = new mxImage( - 'editors/images/overlays/forbidden.png', - 16, - 16 - ); - - class MyCustomCellRenderer extends mxCellRenderer { - createControl(state) { - super.createControl(state); - - const { graph } = state.view; - - if (state.cell.isVertex()) { - if (state.deleteControl == null) { - const b = new mxRectangle( - 0, - 0, - deleteImage.width, - deleteImage.height - ); - state.deleteControl = new mxImageShape(b, deleteImage.src); - state.deleteControl.dialect = graph.dialect; - state.deleteControl.preserveImageAspect = false; - - this.initControl(state, state.deleteControl, false, function(evt) { - if (graph.isEnabled()) { - graph.removeCells([state.cell]); - mxEvent.consume(evt); - } - }); - } - } else if (state.deleteControl != null) { - state.deleteControl.destroy(); - state.deleteControl = null; - } - } - - getDeleteControlBounds(state) { - // Helper function to compute the bounds of the control - if (state.deleteControl != null) { - const oldScale = state.deleteControl.scale; - const w = state.deleteControl.bounds.width / oldScale; - const h = state.deleteControl.bounds.height / oldScale; - const s = state.view.scale; - - return state.cell.isEdge() - ? new mxRectangle( - state.x + state.width / 2 - (w / 2) * s, - state.y + state.height / 2 - (h / 2) * s, - w * s, - h * s - ) - : new mxRectangle( - state.x + state.width - w * s, - state.y, - w * s, - h * s - ); - } - return null; - } - - redrawControl(state) { - // Overridden to update the scale and bounds of the control - super.redrawControl(state); - - if (state.deleteControl != null) { - const bounds = this.getDeleteControlBounds(state); - const s = state.view.scale; - - if ( - state.deleteControl.scale !== s || - !state.deleteControl.bounds.equals(bounds) - ) { - state.deleteControl.bounds = bounds; - state.deleteControl.scale = s; - state.deleteControl.redraw(); - } - } - } - - destroy(state) { - // Overridden to remove the control if the state is destroyed - super.destroy(state); - - if (state.deleteControl != null) { - state.deleteControl.destroy(); - state.deleteControl = null; - } - } - } - - class MyCustomGraph extends mxGraph { - createCellRenderer() { - return new MyCustomCellRenderer(); - } - } - - // Creates the graph inside the given container - const graph = new MyCustomGraph(this.el); - graph.setPanning(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.getModel().beginUpdate(); - try { - 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(); - } - - graph.centerZoom = false; - - this.el2.appendChild( - mxUtils.button('Zoom In', () => { - graph.zoomIn(); - }) - ); - - this.el2.appendChild( - mxUtils.button('Zoom Out', () => { - graph.zoomOut(); - }) - ); - } -} - -export default Control; diff --git a/src/pages/icons_images/FixedIcon.js b/src/pages/icons_images/FixedIcon.js deleted file mode 100644 index e1d42c9a9..000000000 --- a/src/pages/icons_images/FixedIcon.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxLabel from '../../mxgraph/shape/mxLabel'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; - -class FixedIcon extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Fixed icon

    - This example demonstrates customizing the icon position in the mxLabel - shape. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Overrides the image bounds code to change the position - mxLabel.prototype.getImageBounds = function(x, y, w, h) { - const iw = mxUtils.getValue( - this.style, - mxConstants.STYLE_IMAGE_WIDTH, - mxConstants.DEFAULT_IMAGESIZE - ); - const ih = mxUtils.getValue( - this.style, - mxConstants.STYLE_IMAGE_HEIGHT, - mxConstants.DEFAULT_IMAGESIZE - ); - - // Places the icon - const ix = (w - iw) / 2; - const iy = h - ih; - - return new mxRectangle(x + ix, y + iy, iw, ih); - }; - - // Makes the shadow brighter - mxConstants.SHADOWCOLOR = '#C0C0C0'; - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // 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, - 'Fixed icon', - 20, - 20, - 80, - 50, - 'shape=label;image=images/plus.png;imageWidth=16;imageHeight=16;spacingBottom=10;' + - 'fillColor=#adc5ff;gradientColor=#7d85df;glass=1;rounded=1;shadow=1;' - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default FixedIcon; diff --git a/src/pages/icons_images/HoverIcons.js b/src/pages/icons_images/HoverIcons.js deleted file mode 100644 index 14ee55e42..000000000 --- a/src/pages/icons_images/HoverIcons.js +++ /dev/null @@ -1,221 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; -import mxImage from '../../mxgraph/util/image/mxImage'; - -class HoverIcons extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Hover icons

    - This example demonstrates showing icons on vertices as mouse hovers over - them. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Defines an icon for creating new connections in the connection handler. - // This will automatically disable the highlighting of the source vertex. - mxConnectionHandler.prototype.connectImage = new mxImage( - 'images/connector.gif', - 16, - 16 - ); - - // Defines a new class for all icons - class mxIconSet { - constructor(state) { - this.images = []; - const { graph } = state.view; - - // Icon1 - let img = mxUtils.createImage('images/copy.png'); - img.setAttribute('title', 'Duplicate'); - Object.assign(img.style, { - cursor: 'pointer', - width: '16px', - height: '16px', - position: 'absolute', - left: `${state.x + state.width}px`, - top: `${state.y + state.height}px`, - }); - - mxEvent.addGestureListeners(img, evt => { - const s = graph.gridSize; - graph.setSelectionCells(graph.moveCells([state.cell], s, s, true)); - mxEvent.consume(evt); - this.destroy(); - }); - - state.view.graph.container.appendChild(img); - this.images.push(img); - - // Delete - img = mxUtils.createImage('images/delete2.png'); - img.setAttribute('title', 'Delete'); - Object.assign(img.style, { - cursor: 'pointer', - width: '16px', - height: '16px', - position: 'absolute', - left: `${state.x + state.width}px`, - top: `${state.y - 16}px`, - }); - - mxEvent.addGestureListeners(img, evt => { - // Disables dragging the image - mxEvent.consume(evt); - }); - - mxEvent.addListener(img, 'click', evt => { - graph.removeCells([state.cell]); - mxEvent.consume(evt); - this.destroy(); - }); - - state.view.graph.container.appendChild(img); - this.images.push(img); - } - - destroy() { - if (this.images != null) { - for (const img of this.images) { - img.parentNode.removeChild(img); - } - } - this.images = null; - } - } - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.setConnectable(true); - - // Enables rubberband selection - new mxRubberband(graph); - - // Defines the tolerance before removing the icons - const ICON_TOLERANCE = 20; - - // Shows icons if the mouse is over a cell - graph.addMouseListener({ - currentState: null, - currentIconSet: null, - - mouseDown(sender, me) { - // Hides icons on mouse down - if (this.currentState != null) { - this.dragLeave(me.getEvent(), this.currentState); - this.currentState = null; - } - }, - - mouseMove(sender, me) { - if ( - this.currentState != null && - (me.getState() === this.currentState || me.getState() == null) - ) { - const tol = ICON_TOLERANCE; - const tmp = new mxRectangle( - me.getGraphX() - tol, - me.getGraphY() - tol, - 2 * tol, - 2 * tol - ); - if (mxUtils.intersects(tmp, this.currentState)) { - return; - } - } - - let tmp = graph.view.getState(me.getCell()); - - // Ignore everything but vertices - if ( - graph.isMouseDown || - (tmp != null && !tmp.cell.isVertex()) - ) { - tmp = null; - } - - if (tmp !== this.currentState) { - if (this.currentState != null) { - this.dragLeave(me.getEvent(), this.currentState); - } - - this.currentState = tmp; - if (this.currentState != null) { - this.dragEnter(me.getEvent(), this.currentState); - } - } - }, - - mouseUp(sender, me) {}, - - dragEnter(evt, state) { - if (this.currentIconSet == null) { - this.currentIconSet = new mxIconSet(state); - } - }, - - dragLeave(evt, state) { - if (this.currentIconSet != null) { - this.currentIconSet.destroy(); - this.currentIconSet = null; - } - }, - }); - - // 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, - }); - }); - } -} - -export default HoverIcons; diff --git a/src/pages/icons_images/Images.js b/src/pages/icons_images/Images.js deleted file mode 100644 index 6e254e6c9..000000000 --- a/src/pages/icons_images/Images.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxPerimeter from '../../mxgraph/util/datatypes/style/mxPerimeter'; - -class Images extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Images

    - This example demonstrates using background images and images for for the - label- and image-shape. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '200px', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Sets a background image and restricts child movement to its bounds - graph.setBackgroundImage( - new mxImage('images/gradient_background.jpg', 360, 200) - ); - graph.maximumGraphBounds = new mxRectangle(0, 0, 360, 200); - - // Resizes the container but never make it bigger than the background - graph.minimumContainerSize = new mxRectangle(0, 0, 360, 200); - graph.setResizeContainer(true); - - // Disables basic selection and cell handling - // graph.setEnabled(false); - configureStylesheet(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 { - var v1 = graph.insertVertex( - parent, - null, - 'First Line\nSecond Line', - 20, - 10, - 80, - 100, - 'bottom' - ); - var v1 = graph.insertVertex( - parent, - null, - 'First Line\nSecond Line', - 130, - 10, - 80, - 100, - 'top' - ); - var v1 = graph.insertVertex(parent, null, '', 230, 10, 100, 100, 'image'); - var v2 = graph.insertVertex( - parent, - null, - 'First Line\nSecond Line', - 20, - 130, - 140, - 60, - 'right' - ); - var v2 = graph.insertVertex( - parent, - null, - 'First Line\nSecond Line', - 180, - 130, - 140, - 60, - 'left' - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - function configureStylesheet(graph) { - let style = {}; - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_IMAGE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - style[mxConstants.STYLE_IMAGE] = 'images/icons48/keys.png'; - style[mxConstants.STYLE_FONTCOLOR] = '#FFFFFF'; - graph.getStylesheet().putCellStyle('image', style); - - style = mxUtils.clone(style); - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_LABEL; - style[mxConstants.STYLE_STROKECOLOR] = '#000000'; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP; - style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP; - style[mxConstants.STYLE_IMAGE] = 'images/icons48/gear.png'; - style[mxConstants.STYLE_IMAGE_WIDTH] = '48'; - style[mxConstants.STYLE_IMAGE_HEIGHT] = '48'; - style[mxConstants.STYLE_SPACING_TOP] = '56'; - style[mxConstants.STYLE_SPACING] = '8'; - graph.getStylesheet().putCellStyle('bottom', style); - - style = mxUtils.clone(style); - style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_BOTTOM; - style[mxConstants.STYLE_IMAGE] = 'images/icons48/server.png'; - delete style[mxConstants.STYLE_SPACING_TOP]; - graph.getStylesheet().putCellStyle('top', style); - - style = mxUtils.clone(style); - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT; - style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_LEFT; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_IMAGE] = 'images/icons48/earth.png'; - style[mxConstants.STYLE_SPACING_LEFT] = '55'; - style[mxConstants.STYLE_SPACING] = '4'; - graph.getStylesheet().putCellStyle('right', style); - - style = mxUtils.clone(style); - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_RIGHT; - style[mxConstants.STYLE_IMAGE_ALIGN] = mxConstants.ALIGN_RIGHT; - delete style[mxConstants.STYLE_SPACING_LEFT]; - style[mxConstants.STYLE_SPACING_RIGHT] = '55'; - graph.getStylesheet().putCellStyle('left', style); - } - } -} - -export default Images; diff --git a/src/pages/icons_images/Indicators.js b/src/pages/icons_images/Indicators.js deleted file mode 100644 index 14b706d68..000000000 --- a/src/pages/icons_images/Indicators.js +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; - -class Indicators extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Indicators

    - This example demonstrates the use of indicators, which are small - subshapes inside a parent shape, typically an mxLabel. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '300ph', - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.setConnectable(true); - new mxKeyHandler(graph); - - // Enables moving of vertex labels - graph.vertexLabelsMovable = true; - - // Creates a style with an indicator - let style = graph.getStylesheet().getDefaultVertexStyle(); - - style[mxConstants.STYLE_SHAPE] = 'label'; - style[mxConstants.STYLE_VERTICAL_ALIGN] = 'bottom'; - style[mxConstants.STYLE_INDICATOR_SHAPE] = 'ellipse'; - style[mxConstants.STYLE_INDICATOR_WIDTH] = 34; - style[mxConstants.STYLE_INDICATOR_HEIGHT] = 34; - style[mxConstants.STYLE_IMAGE_VERTICAL_ALIGN] = 'top'; // indicator v-alignment - style[mxConstants.STYLE_IMAGE_ALIGN] = 'center'; - style[mxConstants.STYLE_INDICATOR_COLOR] = 'green'; - delete style[mxConstants.STYLE_STROKECOLOR]; // transparent - delete style[mxConstants.STYLE_FILLCOLOR]; // transparent - - // Creates a style with an indicator - style = graph.getStylesheet().getDefaultEdgeStyle(); - - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - style[mxConstants.STYLE_ELBOW] = mxConstants.ELBOW_VERTICAL; - style[mxConstants.STYLE_ROUNDED] = true; - - // 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 { - graph.insertVertex(parent, null, 'Bottom Label', 80, 80, 80, 60); - graph.insertVertex( - parent, - null, - 'Top Label', - 200, - 80, - 60, - 60, - 'indicatorShape=actor;indicatorWidth=28;indicatorColor=blue;imageVerticalAlign=bottom;verticalAlign=top' - ); - graph.insertVertex( - parent, - null, - 'Right Label', - 300, - 80, - 120, - 60, - 'indicatorShape=cloud;indicatorWidth=40;indicatorColor=#00FFFF;imageVerticalAlign=center;verticalAlign=middle;imageAlign=left;align=left;spacingLeft=44' - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Indicators; diff --git a/src/pages/icons_images/Markers.js b/src/pages/icons_images/Markers.js deleted file mode 100644 index a42a18d33..000000000 --- a/src/pages/icons_images/Markers.js +++ /dev/null @@ -1,232 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxCellRenderer from '../../mxgraph/view/cell/mxCellRenderer'; -import mxEdgeHandler from '../../mxgraph/handler/mxEdgeHandler'; -import mxGraphHandler from '../../mxgraph/handler/mxGraphHandler'; -import mxCylinder from '../../mxgraph/shape/node/mxCylinder'; -import mxMarker from '../../mxgraph/shape/edge/mxMarker'; -import mxArrow from '../../mxgraph/shape/edge/mxArrow'; - -class Markers extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Markers

    - This example demonstrates creating custom markers and customizing the - built-in markers. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '381px', - border: '1px solid gray', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Enables guides - mxGraphHandler.prototype.guidesEnabled = true; - mxEdgeHandler.prototype.snapToTerminals = true; - - // Registers and defines the custom marker - mxMarker.addMarker('dash', function( - canvas, - shape, - type, - pe, - unitX, - unitY, - size, - source, - sw, - filled - ) { - const nx = unitX * (size + sw + 1); - const ny = unitY * (size + sw + 1); - - return function() { - canvas.begin(); - canvas.moveTo(pe.x - nx / 2 - ny / 2, pe.y - ny / 2 + nx / 2); - canvas.lineTo( - pe.x + ny / 2 - (3 * nx) / 2, - pe.y - (3 * ny) / 2 - nx / 2 - ); - canvas.stroke(); - }; - }); - - // Defines custom message shape - class MessageShape extends mxCylinder { - redrawPath(path, x, y, w, h, isForeground) { - if (isForeground) { - path.moveTo(0, 0); - path.lineTo(w / 2, h / 2); - path.lineTo(w, 0); - } else { - path.moveTo(0, 0); - path.lineTo(w, 0); - path.lineTo(w, h); - path.lineTo(0, h); - path.close(); - } - } - } - mxCellRenderer.registerShape('message', MessageShape); - - // Defines custom edge shape - class LinkShape extends mxArrow { - paintEdgeShape(c, pts) { - const width = 10; - - // Base vector (between end points) - const p0 = pts[0]; - const pe = pts[pts.length - 1]; - - const dx = pe.x - p0.x; - const dy = pe.y - p0.y; - const dist = Math.sqrt(dx * dx + dy * dy); - const length = dist; - - // Computes the norm and the inverse norm - const nx = dx / dist; - const ny = dy / dist; - const basex = length * nx; - const basey = length * ny; - const floorx = (width * ny) / 3; - const floory = (-width * nx) / 3; - - // Computes points - const p0x = p0.x - floorx / 2; - const p0y = p0.y - floory / 2; - const p1x = p0x + floorx; - const p1y = p0y + floory; - const p2x = p1x + basex; - const p2y = p1y + basey; - const p3x = p2x + floorx; - const p3y = p2y + floory; - // p4 not necessary - const p5x = p3x - 3 * floorx; - const p5y = p3y - 3 * floory; - - c.begin(); - c.moveTo(p1x, p1y); - c.lineTo(p2x, p2y); - c.moveTo(p5x + floorx, p5y + floory); - c.lineTo(p0x, p0y); - c.stroke(); - } - } - mxCellRenderer.registerShape('link', LinkShape); - - // Creates the graph - const graph = new mxGraph(this.el); - - // Sets default styles - let style = graph.getStylesheet().getDefaultVertexStyle(); - style.fillColor = '#FFFFFF'; - style.strokeColor = '#000000'; - style.fontColor = '#000000'; - style.fontStyle = '1'; - - style = graph.getStylesheet().getDefaultEdgeStyle(); - style.strokeColor = '#000000'; - style.fontColor = '#000000'; - style.fontStyle = '0'; - style.fontStyle = '0'; - style.startSize = '8'; - style.endSize = '8'; - - // Populates the graph - const parent = graph.getDefaultParent(); - - graph.getModel().beginUpdate(); - try { - const v1 = graph.insertVertex(parent, null, 'v1', 20, 20, 80, 30); - const v2 = graph.insertVertex(parent, null, 'v2', 440, 20, 80, 30); - const e1 = graph.insertEdge( - parent, - null, - '', - v1, - v2, - 'dashed=1;' + - 'startArrow=oval;endArrow=block;sourcePerimeterSpacing=4;startFill=0;endFill=0;' - ); - const e11 = graph.insertVertex( - e1, - null, - 'Label', - 0, - 0, - 20, - 14, - 'shape=message;labelBackgroundColor=#ffffff;labelPosition=left;spacingRight=2;align=right;fontStyle=0;' - ); - e11.geometry.offset = new mxPoint(-10, -7); - e11.geometry.relative = true; - e11.connectable = false; - - const v3 = graph.insertVertex(parent, null, 'v3', 20, 120, 80, 30); - const v4 = graph.insertVertex(parent, null, 'v4', 440, 120, 80, 30); - const e2 = graph.insertEdge( - parent, - null, - 'Label', - v3, - v4, - 'startArrow=dash;startSize=12;endArrow=block;labelBackgroundColor=#FFFFFF;' - ); - - const v5 = graph.insertVertex( - parent, - null, - 'v5', - 40, - 220, - 40, - 40, - 'shape=ellipse;perimeter=ellipsePerimeter;' - ); - const v6 = graph.insertVertex( - parent, - null, - 'v6', - 460, - 220, - 40, - 40, - 'shape=doubleEllipse;perimeter=ellipsePerimeter;' - ); - const e3 = graph.insertEdge( - parent, - null, - 'Link', - v5, - v6, - 'shape=link;labelBackgroundColor=#FFFFFF;' - ); - } finally { - graph.getModel().endUpdate(); - } - } -} - -export default Markers; diff --git a/src/pages/icons_images/index.js b/src/pages/icons_images/index.js deleted file mode 100644 index 5f93f02a3..000000000 --- a/src/pages/icons_images/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import ContextIcons from './ContextIcons'; -import Preview from '../Previews'; -import Control from './Control'; -import FixedIcon from './FixedIcon'; -import HoverIcons from './HoverIcons'; -import Images from './Images'; -import Indicators from './Indicators'; -import Markers from './Markers'; -import PageTabs from '../PageTabs'; - -export default function _Backgrounds() { - return ( - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - ); -} diff --git a/src/pages/index.js b/src/pages/index.js deleted file mode 100644 index 144ef21d8..000000000 --- a/src/pages/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import Basic from './basic'; - -export default function Home() { - return ; -} diff --git a/src/pages/labels/LabelPosition.js b/src/pages/labels/LabelPosition.js deleted file mode 100644 index 1b1168cf5..000000000 --- a/src/pages/labels/LabelPosition.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; - -class LabelPosition extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Label Position

    - This example demonstrates the use of the label position styles to set - the position of vertex labels. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '300px', - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Gets the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - const parent = graph.getDefaultParent(); - - // Defines the common part of all cell styles as a string-prefix - const prefix = 'shape=image;image=images/icons48/keys.png;'; - - // Adds cells to the model in a single step and set the vertex - // label positions using the label position styles. Vertical - // and horizontal label position styles can be combined. - // Note: Alternatively, vertex labels can be set be overriding - // mxCellRenderer.getLabelBounds. - graph.getModel().beginUpdate(); - try { - graph.insertVertex( - parent, - null, - 'Bottom', - 60, - 60, - 60, - 60, - `${prefix}verticalLabelPosition=bottom;verticalAlign=top` - ); - graph.insertVertex( - parent, - null, - 'Top', - 140, - 60, - 60, - 60, - `${prefix}verticalLabelPosition=top;verticalAlign=bottom` - ); - graph.insertVertex( - parent, - null, - 'Left', - 60, - 160, - 60, - 60, - `${prefix}labelPosition=left;align=right` - ); - graph.insertVertex( - parent, - null, - 'Right', - 140, - 160, - 60, - 60, - `${prefix}labelPosition=right;align=left` - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default LabelPosition; diff --git a/src/pages/labels/Labels.js b/src/pages/labels/Labels.js deleted file mode 100644 index 09c538328..000000000 --- a/src/pages/labels/Labels.js +++ /dev/null @@ -1,194 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; - -class Labels extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Labels

    - This example demonstrates the use of wrapping and clipping for HTML - labels of vertices, truncating labels to fit the size of a vertex, and - manually placing vertex labels and relative children that act as - "sublabels". -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '300px', - background: "url('editors/images/grid.gif')", - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.setTooltips(true); - graph.htmlLabels = true; - graph.vertexLabelsMovable = true; - new mxRubberband(graph); - new mxKeyHandler(graph); - - // Do not allow removing labels from parents - graph.graphHandler.removeCellsFromParent = false; - - // Autosize labels on insert where autosize=1 - graph.autoSizeCellsOnAdd = true; - - // Allows moving of relative cells - graph.isCellLocked = function(cell) { - return this.isCellsLocked(); - }; - - graph.isCellResizable = function(cell) { - const geo = cell.getGeometry(); - - return geo == null || !geo.relative; - }; - - // Truncates the label to the size of the vertex - graph.getLabel = function(cell) { - const label = this.labelsVisible ? this.convertValueToString(cell) : ''; - const geometry = cell.getGeometry(); - - if ( - !cell.isCollapsed() && - geometry != null && - (geometry.offset == null || - (geometry.offset.x == 0 && geometry.offset.y == 0)) && - cell.isVertex() && - geometry.width >= 2 - ) { - const style = this.getCellStyle(cell); - const fontSize = - style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE; - const max = geometry.width / (fontSize * 0.625); - - if (max < label.length) { - return `${label.substring(0, max)}...`; - } - } - - return label; - }; - - // Enables wrapping for vertex labels - graph.isWrapping = function(cell) { - return cell.isCollapsed(); - }; - - // Enables clipping of vertex labels if no offset is defined - graph.isLabelClipped = function(cell) { - const geometry = cell.getGeometry(); - - return ( - geometry != null && - !geometry.relative && - (geometry.offset == null || - (geometry.offset.x == 0 && geometry.offset.y == 0)) - ); - }; - - // 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, - 'vertexLabelsMovable', - 20, - 20, - 80, - 30 - ); - - // Places sublabels inside the vertex - const label11 = graph.insertVertex( - v1, - null, - 'Label1', - 0.5, - 1, - 0, - 0, - null, - true - ); - const label12 = graph.insertVertex( - v1, - null, - 'Label2', - 0.5, - 0, - 0, - 0, - null, - true - ); - - const v2 = graph.insertVertex( - parent, - null, - 'Wrapping and clipping is enabled only if the cell is collapsed, otherwise the label is truncated if there is no manual offset.', - 200, - 150, - 80, - 30 - ); - v2.geometry.alternateBounds = new mxRectangle(0, 0, 80, 30); - const e1 = graph.insertEdge(parent, null, 'edgeLabelsMovable', v1, v2); - - // Places sublabels inside the vertex - const label21 = graph.insertVertex( - v2, - null, - 'Label1', - 0.5, - 1, - 0, - 0, - null, - true - ); - const label22 = graph.insertVertex( - v2, - null, - 'Label2', - 0.5, - 0, - 0, - 0, - null, - true - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Labels; diff --git a/src/pages/labels/Perimeter.js b/src/pages/labels/Perimeter.js deleted file mode 100644 index 48ef64cd2..000000000 --- a/src/pages/labels/Perimeter.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxGraphView from '../../mxgraph/view/graph/mxGraphView'; - -class Perimeter extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Perimeter

    - This example demonstrates how to avoid edge and label intersections. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Redirects the perimeter to the label bounds if intersection - // between edge and label is found - const mxGraphViewGetPerimeterPoint = - mxGraphView.prototype.getPerimeterPoint; - mxGraphView.prototype.getPerimeterPoint = function( - terminal, - next, - orthogonal, - border - ) { - let point = mxGraphViewGetPerimeterPoint.apply(this, arguments); - - if (point != null) { - const perimeter = this.getPerimeterFunction(terminal); - - if (terminal.text != null && terminal.text.boundingBox != null) { - // Adds a small border to the label bounds - const b = terminal.text.boundingBox.clone(); - b.grow(3); - - if (mxUtils.rectangleIntersectsSegment(b, point, next)) { - point = perimeter(b, terminal, next, orthogonal); - } - } - } - - return point; - }; - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.setVertexLabelsMovable(true); - graph.setConnectable(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.getModel().beginUpdate(); - try { - const v1 = graph.insertVertex( - parent, - null, - 'Label', - 20, - 20, - 80, - 30, - 'verticalLabelPosition=bottom' - ); - const v2 = graph.insertVertex( - parent, - null, - 'Label', - 200, - 20, - 80, - 30, - 'verticalLabelPosition=bottom' - ); - const v3 = graph.insertVertex( - parent, - null, - 'Label', - 20, - 150, - 80, - 30, - 'verticalLabelPosition=bottom' - ); - var e1 = graph.insertEdge(parent, null, '', v1, v2); - var e1 = graph.insertEdge(parent, null, '', v1, v3); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Perimeter; diff --git a/src/pages/labels/SecondLabel.js b/src/pages/labels/SecondLabel.js deleted file mode 100644 index c60096673..000000000 --- a/src/pages/labels/SecondLabel.js +++ /dev/null @@ -1,243 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxRectangleShape from '../../mxgraph/shape/node/mxRectangleShape'; -import mxText from '../../mxgraph/shape/mxText'; - -class SecondLabel extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Second label

    - This example demonstrates how to add another string label to vertices. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Simple solution to add additional text to the rectangle shape definition: - (function() { - const mxRectangleShapeIsHtmlAllowed = - mxRectangleShape.prototype.isHtmlAllowed; - mxRectangleShape.prototype.isHtmlAllowed = function() { - return ( - mxRectangleShapeIsHtmlAllowed.apply(this, arguments) && - this.state == null - ); - }; - - const mxRectangleShapePaintForeground = - mxRectangleShape.prototype.paintForeground; - mxRectangleShape.prototype.paintForeground = function(c, x, y, w, h) { - if ( - this.state != null && - this.state.cell.geometry != null && - !this.state.cell.geometry.relative - ) { - c.setFontColor('#a0a0a0'); - c.text(x + 2, y, 0, 0, this.state.cell.id, 'left', 'top'); - } - - mxRectangleShapePaintForeground.apply(this, arguments); - }; - })(); - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Disables the folding icon - graph.isCellFoldable = function(cell) { - return false; - }; - - let secondLabelVisible = true; - - // Hook for returning shape number for a given cell - graph.getSecondLabel = function(cell) { - if (!cell.isEdge()) { - // Possible to return any string here - return `The ID of this cell is ${cell.id}`; - } - - return null; - }; - - let relativeChildVerticesVisible = true; - - // Overrides method to hide relative child vertices - const isVisible = function() { - return ( - !cell.isVertex() || - cell.geometry == null || - !cell.geometry.relative || - cell.geometry.relative == relativeChildVerticesVisible - ); - }; - - // Creates the shape for the shape number and puts it into the draw pane - const { redrawShape } = graph.cellRenderer; - graph.cellRenderer.redrawShape = function(state, force, rendering) { - const result = redrawShape.apply(this, arguments); - - if ( - result && - secondLabelVisible && - state.cell.geometry != null && - !state.cell.geometry.relative - ) { - const secondLabel = graph.getSecondLabel(state.cell); - - if ( - secondLabel != null && - state.shape != null && - state.secondLabel == null - ) { - state.secondLabel = new mxText( - secondLabel, - new mxRectangle(), - mxConstants.ALIGN_LEFT, - mxConstants.ALIGN_BOTTOM - ); - - // Styles the label - state.secondLabel.color = 'black'; - state.secondLabel.family = 'Verdana'; - state.secondLabel.size = 8; - state.secondLabel.fontStyle = mxConstants.FONT_ITALIC; - state.secondLabel.background = 'yellow'; - state.secondLabel.border = 'black'; - state.secondLabel.valign = 'bottom'; - state.secondLabel.dialect = state.shape.dialect; - state.secondLabel.dialect = mxConstants.DIALECT_STRICTHTML; - state.secondLabel.wrap = true; - graph.cellRenderer.initializeLabel(state, state.secondLabel); - } - } - - if (state.secondLabel != null) { - const scale = graph.getView().getScale(); - const bounds = new mxRectangle( - state.x + state.width - 8 * scale, - state.y + 8 * scale, - 35, - 0 - ); - state.secondLabel.state = state; - state.secondLabel.value = graph.getSecondLabel(state.cell); - state.secondLabel.scale = scale; - state.secondLabel.bounds = bounds; - state.secondLabel.redraw(); - } - - return result; - }; - - // Destroys the shape number - const { destroy } = graph.cellRenderer; - graph.cellRenderer.destroy = function(state) { - destroy.apply(this, arguments); - - if (state.secondLabel != null) { - state.secondLabel.destroy(); - state.secondLabel = null; - } - }; - - graph.cellRenderer.getShapesForState = function(state) { - return [state.shape, state.text, state.secondLabel, state.control]; - }; - - // 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,', 30, 40, 80, 30); - // Alternative solution of creating a second label by creating a realtive child vertex - // with size (0, 0). This will not be selectable and only the label colors can be used - // for coloring as the actual shape will have zero size. - const v11 = graph.insertVertex( - v1, - null, - 'World', - 1, - 1, - 0, - 0, - 'align=left;verticalAlign=top;labelBackgroundColor=red;labelBorderColor=black', - true - ); - v11.geometry.offset = new mxPoint(-8, -8); - const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); - // Another alternative solution of creating a second label as a relative child vertex - // but this time with an automatic size so that the cell is actually selectable and - // the background is painted as a shape. - const v21 = graph.insertVertex( - v2, - null, - 'World', - 1, - 1, - 0, - 0, - 'align=left;verticalAlign=top;fillColor=red;rounded=1;spacingLeft=4;spacingRight=4', - true - ); - v21.geometry.offset = new mxPoint(-8, -8); - graph.updateCellSize(v21); - const e1 = graph.insertEdge(parent, null, '', v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - // Adds a button to execute the layout - this.el2.appendChild( - mxUtils.button('Toggle Child Vertices', function(evt) { - relativeChildVerticesVisible = !relativeChildVerticesVisible; - graph.refresh(); - }) - ); - - // Adds a button to execute the layout - this.el2.appendChild( - mxUtils.button('Toggle IDs', function(evt) { - secondLabelVisible = !secondLabelVisible; - graph.refresh(); - }) - ); - } -} - -export default SecondLabel; diff --git a/src/pages/labels/Wrapping.js b/src/pages/labels/Wrapping.js deleted file mode 100644 index e4ac5c77a..000000000 --- a/src/pages/labels/Wrapping.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; - -class Wrapping extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Wrapping

    - This example demonstrates using HTML markup and word-wrapping in vertex - and edge labels. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Enables HTML labels as wrapping is only available for those - graph.setHtmlLabels(true); - - // Disables in-place editing for edges - graph.isCellEditable = function(cell) { - return !cell.isEdge(); - }; - - // 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: 'Cum Caesar vidisset, portum plenum esse, iuxta navigavit.', - position: [20, 20], - size: [100, 70], - style: 'whiteSpace=wrap;', - }); - const v2 = graph.insertVertex({ - parent, - value: 'Cum Caesar vidisset, portum plenum esse, iuxta navigavit.', - position: [220, 150], - size: [80, 70], - style: 'whiteSpace=wrap;', - }); - const e1 = graph.insertEdge({ - parent, - value: 'Cum Caesar vidisset, portum plenum esse, iuxta navigavit.', - source: v1, - target: v2, - style: 'whiteSpace=wrap;', - }); - e1.geometry.width = 100; - }); - } -} - -export default Wrapping; diff --git a/src/pages/labels/index.js b/src/pages/labels/index.js deleted file mode 100644 index e6a4f9553..000000000 --- a/src/pages/labels/index.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import LabelPosition from './LabelPosition'; -import Perimeter from './Perimeter'; -import SecondLabel from './SecondLabel'; -import Wrapping from './Wrapping'; -import Labels from './Labels'; -import PageTabs from '../PageTabs'; - -export default function _Labels() { - return ( - - } /> - } /> - } /> - } /> - } /> - - ); -} diff --git a/src/pages/layout/AutoLayout.js b/src/pages/layout/AutoLayout.js deleted file mode 100644 index 5bcb7c9df..000000000 --- a/src/pages/layout/AutoLayout.js +++ /dev/null @@ -1,218 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxClient from '../../mxgraph/mxClient'; -import mxMorphing from '../../mxgraph/util/animate/mxMorphing'; -import mxEdgeHandler from '../../mxgraph/handler/mxEdgeHandler'; -import mxHierarchicalLayout from '../../mxgraph/layout/hierarchical/mxHierarchicalLayout'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxCellOverlay from '../../mxgraph/view/cell/mxCellOverlay'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxEventObject from '../../mxgraph/util/event/mxEventObject'; -import mxCellRenderer from '../../mxgraph/view/cell/mxCellRenderer'; - -class AutoLayout extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Auto layout

    - This example demonstrates running and animating a layout algorithm after - every change to a graph. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '641px', - background: 'url("editors/images/grid.gif")', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - mxEvent.disableContextMenu(this.el); - - class MyCustomCellRenderer extends mxCellRenderer { - installCellOverlayListeners(state, overlay, shape) { - super.installCellOverlayListeners(state, overlay, shape); - - mxEvent.addListener( - shape.node, - mxClient.IS_POINTER ? 'pointerdown' : 'mousedown', - evt => { - overlay.fireEvent( - new mxEventObject('pointerdown', 'event', evt, 'state', state) - ); - } - ); - - if (!mxClient.IS_POINTER && mxClient.IS_TOUCH) { - mxEvent.addListener(shape.node, 'touchstart', evt => { - overlay.fireEvent( - new mxEventObject('pointerdown', 'event', evt, 'state', state) - ); - }); - } - } - } - - class MyCustomEdgeHandler extends mxEdgeHandler { - connect(edge, terminal, isSource, isClone, me) { - super.connect(edge, terminal, isSource, isClone, me); - executeLayout(); - } - } - - class MyCustomGraph extends mxGraph { - createEdgeHandler(state, edgeStyle) { - return new MyCustomEdgeHandler(state, edgeStyle); - } - - createCellRenderer() { - return new MyCustomCellRenderer(); - } - } - - // Creates the graph inside the given this.el - const graph = new MyCustomGraph(this.el); - graph.setPanning(true); - graph.panningHandler.useLeftButtonForPanning = true; - graph.setAllowDanglingEdges(false); - graph.connectionHandler.select = false; - graph.view.setTranslate(20, 20); - - // 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(); - - const layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_WEST); - const executeLayout = (change, post) => { - graph.getModel().beginUpdate(); - try { - if (change != null) { - change(); - } - layout.execute(graph.getDefaultParent(), v1); - } catch (e) { - throw e; - } finally { - // New API for animating graph layout results asynchronously - const morph = new mxMorphing(graph); - morph.addListener(mxEvent.DONE, () => { - graph.getModel().endUpdate(); - if (post != null) { - post(); - } - }); - morph.startAnimation(); - } - }; - - const addOverlay = cell => { - // Creates a new overlay with an image and a tooltip - const overlay = new mxCellOverlay( - new mxImage('images/add.png', 24, 24), - 'Add outgoing' - ); - overlay.cursor = 'hand'; - - // Installs a handler for clicks on the overlay - overlay.addListener(mxEvent.CLICK, (sender, evt2) => { - graph.clearSelection(); - const geo = graph.getCellGeometry(cell); - - let v2; - - executeLayout( - () => { - v2 = graph.insertVertex({ - parent, - value: 'World!', - position: [geo.x, geo.y], - size: [80, 30], - }); - addOverlay(v2); - graph.view.refresh(v2); - const e1 = graph.insertEdge({ - parent, - source: cell, - target: v2, - }); - }, - () => { - graph.scrollCellToVisible(v2); - } - ); - }); - - // Special CMS event - overlay.addListener('pointerdown', (sender, eo) => { - const evt2 = eo.getProperty('event'); - const state = eo.getProperty('state'); - - graph.popupMenuHandler.hideMenu(); - graph.stopEditing(false); - - const pt = mxUtils.convertPoint( - graph.container, - mxEvent.getClientX(evt2), - mxEvent.getClientY(evt2) - ); - graph.connectionHandler.start(state, pt.x, pt.y); - graph.isMouseDown = true; - graph.isMouseTrigger = mxEvent.isMouseEvent(evt2); - mxEvent.consume(evt2); - }); - - // Sets the overlay for the cell in the graph - graph.addCellOverlay(cell, overlay); - }; - - // Adds cells to the model in a single step - graph.getModel().beginUpdate(); - let v1; - try { - v1 = graph.insertVertex({ - parent, - value: 'Hello,', - position: [0, 0], - size: [80, 30], - }); - addOverlay(v1); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - graph.resizeCell = function() { - mxGraph.prototype.resizeCell.apply(this, arguments); - executeLayout(); - }; - - graph.connectionHandler.addListener(mxEvent.CONNECT, function() { - executeLayout(); - }); - } -} - -export default AutoLayout; diff --git a/src/pages/layout/Collapse.js b/src/pages/layout/Collapse.js deleted file mode 100644 index 689d192f8..000000000 --- a/src/pages/layout/Collapse.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; -import mxGraphModel from '../../mxgraph/view/graph/mxGraphModel'; - -class Collapse extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Collapse

    - This example demonstrates changing the style of a cell based on its - collapsed state. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - }; - - componentDidMount() { - const graph = new mxGraph(this.el); - const parent = graph.getDefaultParent(); - - const getStyle = function() { - // Extends mxGraphModel.getStyle to show an image when collapsed - let style = super.getStyle(); - if (this.isCollapsed()) { - style = - `${style};shape=image;image=http://www.jgraph.com/images/mxgraph.gif;` + - `noLabel=1;imageBackground=#C3D9FF;imageBorder=#6482B9`; - } - return style; - } - - graph.batchUpdate(() => { - const v1 = graph.insertVertex({ - parent, - value: 'Container', - position: [20, 20], - size: [200, 200], - style: 'shape=swimlane;startSize=20;', - }); - v1.geometry.alternateBounds = new mxRectangle(0, 0, 110, 70); - v1.getStyle = getStyle; - - const v11 = graph.insertVertex({ - parent: v1, - value: 'Hello,', - position: [10, 40], - size: [120, 80], - }); - v11.getStyle = getStyle; - }); - }; -} - -export default Collapse; diff --git a/src/pages/layout/Constituent.js b/src/pages/layout/Constituent.js deleted file mode 100644 index ac882a4ff..000000000 --- a/src/pages/layout/Constituent.js +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxGraphHandler from '../../mxgraph/handler/mxGraphHandler'; - -class Constituent extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Constituent

    - This example demonstrates using cells as parts of other cells. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: 'url("editors/images/grid.gif")', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Disables the built-in context menu - mxEvent.disableContextMenu(this.el); - - class MyCustomGraphHandler extends mxGraphHandler { - /** - * Redirects start drag to parent. - */ - getInitialCellForEvent(me) { - let cell = super.getInitialCellForEvent(me); - if (this.graph.isPart(cell)) { - cell = this.cell.getParent(); - } - return cell; - } - } - - class MyCustomGraph extends mxGraph { - foldingEnabled = false; - - recursiveResize = true; - - isPart(cell) { - // Helper method to mark parts with constituent=1 in the style - return this.getCurrentCellStyle(cell).constituent == '1'; - } - - selectCellForEvent(cell, evt) { - // Redirects selection to parent - if (this.isPart(cell)) { - cell = cell.getParent(); - } - super.selectCellForEvent(cell, evt); - } - - createGraphHandler() { - return new MyCustomGraphHandler(this); - } - } - - // Creates the graph inside the given container - const graph = new MyCustomGraph(this.el); - - // 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, - position: [20, 20], - size: [120, 70], - }); - const v2 = graph.insertVertex({ - parent: v1, - value: 'Constituent', - position: [20, 20], - size: [80, 30], - style: 'constituent=1;', - }); - }); - } -} - -export default Constituent; diff --git a/src/pages/layout/Folding.js b/src/pages/layout/Folding.js deleted file mode 100644 index e7d670016..000000000 --- a/src/pages/layout/Folding.js +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; -import mxLayoutManager from '../../mxgraph/view/graph/mxLayoutManager'; -import mxStackLayout from '../../mxgraph/layout/mxStackLayout'; - -class Folding extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Folding

    - This example demonstrates using a layout to implement a nested group - structure. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Enables crisp rendering of rectangles in SVG - mxConstants.ENTITY_SEGMENT = 20; - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.setDropEnabled(true); - - // Disables global features - graph.collapseToPreferredSize = false; - graph.constrainChildren = false; - graph.cellsSelectable = false; - graph.extendParentsOnAdd = false; - graph.extendParents = false; - graph.border = 10; - - // Sets global styles - let style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.EntityRelation; - style[mxConstants.STYLE_ROUNDED] = true; - - style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_FILLCOLOR] = '#ffffff'; - style[mxConstants.STYLE_SHAPE] = 'swimlane'; - style[mxConstants.STYLE_STARTSIZE] = 30; - - style = []; - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; - style[mxConstants.STYLE_STROKECOLOR] = 'none'; - style[mxConstants.STYLE_FILLCOLOR] = 'none'; - style[mxConstants.STYLE_FOLDABLE] = false; - graph.getStylesheet().putCellStyle('column', style); - - // Installs auto layout for all levels - const layout = new mxStackLayout(graph, true); - layout.border = graph.border; - const layoutMgr = new mxLayoutManager(graph); - layoutMgr.getLayout = function(cell) { - if (!cell.collapsed) { - if (cell.parent !== graph.model.root) { - layout.resizeParent = true; - layout.horizontal = false; - layout.spacing = 10; - } else { - layout.resizeParent = true; - layout.horizontal = true; - layout.spacing = 40; - } - - return layout; - } - - return null; - }; - - // Resizes the container - graph.setResizeContainer(true); - - // 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 col1 = graph.insertVertex(parent, null, '', 0, 0, 120, 0, 'column'); - - const v1 = graph.insertVertex(col1, null, '1', 0, 0, 100, 30); - v1.collapsed = true; - - const v11 = graph.insertVertex(v1, null, '1.1', 0, 0, 80, 30); - v11.collapsed = true; - - const v111 = graph.insertVertex(v11, null, '1.1.1', 0, 0, 60, 30); - const v112 = graph.insertVertex(v11, null, '1.1.2', 0, 0, 60, 30); - - const v12 = graph.insertVertex(v1, null, '1.2', 0, 0, 80, 30); - - const col2 = graph.insertVertex(parent, null, '', 0, 0, 120, 0, 'column'); - - const v2 = graph.insertVertex(col2, null, '2', 0, 0, 100, 30); - v2.collapsed = true; - - const v21 = graph.insertVertex(v2, null, '2.1', 0, 0, 80, 30); - v21.collapsed = true; - - const v211 = graph.insertVertex(v21, null, '2.1.1', 0, 0, 60, 30); - const v212 = graph.insertVertex(v21, null, '2.1.2', 0, 0, 60, 30); - - const v22 = graph.insertVertex(v2, null, '2.2', 0, 0, 80, 30); - - const v3 = graph.insertVertex(col2, null, '3', 0, 0, 100, 30); - v3.collapsed = true; - - const v31 = graph.insertVertex(v3, null, '3.1', 0, 0, 80, 30); - v31.collapsed = true; - - const v311 = graph.insertVertex(v31, null, '3.1.1', 0, 0, 60, 30); - const v312 = graph.insertVertex(v31, null, '3.1.2', 0, 0, 60, 30); - - const v32 = graph.insertVertex(v3, null, '3.2', 0, 0, 80, 30); - - graph.insertEdge(parent, null, '', v111, v211); - graph.insertEdge(parent, null, '', v112, v212); - graph.insertEdge(parent, null, '', v112, v22); - - graph.insertEdge(parent, null, '', v12, v311); - graph.insertEdge(parent, null, '', v12, v312); - graph.insertEdge(parent, null, '', v12, v32); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Folding; diff --git a/src/pages/layout/Groups.js b/src/pages/layout/Groups.js deleted file mode 100644 index e7076344e..000000000 --- a/src/pages/layout/Groups.js +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxGraphHandler from '../../mxgraph/handler/mxGraphHandler'; -import mxPopupMenuHandler from '../../mxgraph/handler/mxPopupMenuHandler'; - -class Groups extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Groups

    - This example demonstrates using cells as parts of other cells. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Overrides check for valid roots - mxGraph.prototype.isValidRoot = function() { - return false; - }; - - // Don't clear selection if multiple cells selected - const graphHandlerMouseDown = mxGraphHandler.prototype.mouseDown; - mxGraphHandler.prototype.mouseDown = function(sender, me) { - graphHandlerMouseDown.apply(this, arguments); - - if ( - this.graph.isCellSelected(me.getCell()) && - this.graph.getSelectionCount() > 1 - ) { - this.delayedSelection = false; - } - }; - - // Selects descendants before children selection mode - const graphHandlerGetInitialCellForEvent = - mxGraphHandler.prototype.getInitialCellForEvent; - mxGraphHandler.prototype.getInitialCellForEvent = function(me) { - const model = this.graph.getModel(); - const psel = this.graph.getSelectionCell().getParent(); - let cell = graphHandlerGetInitialCellForEvent.apply(this, arguments); - let parent = cell.getParent(); - - if (psel == null || (psel != cell && psel != parent)) { - while ( - !this.graph.isCellSelected(cell) && - !this.graph.isCellSelected(parent) && - parent.isVertex() && - !this.graph.isValidRoot(parent) - ) { - cell = parent; - parent = this.cell.getParent(); - } - } - - return cell; - }; - - // Selection is delayed to mouseup if child selected - const graphHandlerIsDelayedSelection = - mxGraphHandler.prototype.isDelayedSelection; - mxGraphHandler.prototype.isDelayedSelection = function(cell) { - let result = graphHandlerIsDelayedSelection.apply(this, arguments); - const model = this.graph.getModel(); - const psel = this.graph.getSelectionCell().getParent(); - const parent = cell.getParent(); - - if (psel == null || (psel != cell && psel != parent)) { - if ( - !this.graph.isCellSelected(cell) && - parent.isVertex() && - !this.graph.isValidRoot(parent) - ) { - result = true; - } - } - - return result; - }; - - // Delayed selection of parent group - mxGraphHandler.prototype.selectDelayed = function(me) { - let cell = me.getCell(); - - if (cell == null) { - cell = this.cell; - } - - const model = this.graph.getModel(); - let parent = cell.getParent(); - - while ( - this.graph.isCellSelected(cell) && - parent.isVertex() && - !this.graph.isValidRoot(parent) - ) { - cell = parent; - parent = cell.getParent(); - } - - this.graph.selectCellForEvent(cell, me.getEvent()); - }; - - // Returns last selected ancestor - mxPopupMenuHandler.prototype.getCellForPopupEvent = function(me) { - let cell = me.getCell(); - const model = this.graph.getModel(); - let parent = cell.getParent(); - - while (parent.isVertex() && !this.graph.isValidRoot(parent)) { - if (this.graph.isCellSelected(parent)) { - cell = parent; - } - parent = parent.getParent(); - } - return cell; - }; - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.constrainChildren = false; - graph.extendParents = false; - graph.extendParentsOnAdd = false; - - // 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, 120, 60); - const v2 = graph.insertVertex(v1, null, 'World!', 90, 20, 60, 20); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Groups; diff --git a/src/pages/layout/Handles.js b/src/pages/layout/Handles.js deleted file mode 100644 index 6fa68174f..000000000 --- a/src/pages/layout/Handles.js +++ /dev/null @@ -1,279 +0,0 @@ -/** - * Copyright (c) 2006-2014, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxVertexHandler from '../../mxgraph/handler/mxVertexHandler'; -import mxCellRenderer from '../../mxgraph/view/cell/mxCellRenderer'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; -import mxCylinder from '../../mxgraph/shape/node/mxCylinder'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxHandle from '../../mxgraph/handler/mxHandle'; - -class Handles extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Handles

    - This example demonstrates using mxHandle to change custom styles - interactively. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '441px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - class MyShape extends mxCylinder { - defaultPos1 = 20; - - defaultPos2 = 60; - - getLabelBounds(rect) { - const pos1 = - mxUtils.getValue(this.style, 'pos1', this.defaultPos1) * this.scale; - const pos2 = - mxUtils.getValue(this.style, 'pos2', this.defaultPos2) * this.scale; - return new mxRectangle( - rect.x, - rect.y + pos1, - rect.width, - Math.min(rect.height, pos2) - Math.max(0, pos1) - ); - } - - redrawPath(path, x, y, w, h, isForeground) { - const pos1 = mxUtils.getValue(this.style, 'pos1', this.defaultPos1); - const pos2 = mxUtils.getValue(this.style, 'pos2', this.defaultPos2); - - if (isForeground) { - if (pos1 < h) { - path.moveTo(0, pos1); - path.lineTo(w, pos1); - } - - if (pos2 < h) { - path.moveTo(0, pos2); - path.lineTo(w, pos2); - } - } else { - path.rect(0, 0, w, h); - } - } - } - mxCellRenderer.registerShape('myShape', MyShape); - - class MyCustomVertexHandler extends mxVertexHandler { - livePreview = true; - - rotationEnabled = true; - - createCustomHandles() { - if (this.state.style.shape === 'myShape') { - // Implements the handle for the first divider - const firstHandle = new mxHandle(this.state); - - firstHandle.getPosition = function(bounds) { - const pos2 = Math.max( - 0, - Math.min( - bounds.height, - parseFloat( - mxUtils.getValue( - this.state.style, - 'pos2', - MyShape.prototype.defaultPos2 - ) - ) - ) - ); - const pos1 = Math.max( - 0, - Math.min( - pos2, - parseFloat( - mxUtils.getValue( - this.state.style, - 'pos1', - MyShape.prototype.defaultPos1 - ) - ) - ) - ); - - return new mxPoint(bounds.getCenterX(), bounds.y + pos1); - }; - - firstHandle.setPosition = function(bounds, pt) { - const pos2 = Math.max( - 0, - Math.min( - bounds.height, - parseFloat( - mxUtils.getValue( - this.state.style, - 'pos2', - MyShape.prototype.defaultPos2 - ) - ) - ) - ); - - this.state.style.pos1 = Math.round( - Math.max(0, Math.min(pos2, pt.y - bounds.y)) - ); - }; - - firstHandle.execute = function() { - this.copyStyle('pos1'); - }; - - firstHandle.ignoreGrid = true; - - // Implements the handle for the second divider - const secondHandle = new mxHandle(this.state); - - secondHandle.getPosition = function(bounds) { - const pos1 = Math.max( - 0, - Math.min( - bounds.height, - parseFloat( - mxUtils.getValue( - this.state.style, - 'pos1', - MyShape.prototype.defaultPos1 - ) - ) - ) - ); - const pos2 = Math.max( - pos1, - Math.min( - bounds.height, - parseFloat( - mxUtils.getValue( - this.state.style, - 'pos2', - MyShape.prototype.defaultPos2 - ) - ) - ) - ); - - return new mxPoint(bounds.getCenterX(), bounds.y + pos2); - }; - - secondHandle.setPosition = function(bounds, pt) { - const pos1 = Math.max( - 0, - Math.min( - bounds.height, - parseFloat( - mxUtils.getValue( - this.state.style, - 'pos1', - MyShape.prototype.defaultPos1 - ) - ) - ) - ); - - this.state.style.pos2 = Math.round( - Math.max(pos1, Math.min(bounds.height, pt.y - bounds.y)) - ); - }; - - secondHandle.execute = function() { - this.copyStyle('pos2'); - }; - - secondHandle.ignoreGrid = true; - - return [firstHandle, secondHandle]; - } - - return null; - } - } - - class MyCustomGraph extends mxGraph { - createVertexHandler(state) { - return new MyCustomVertexHandler(state); - } - } - - // Disables the built-in context menu - mxEvent.disableContextMenu(this.el); - - // Creates the graph inside the given container - const graph = new MyCustomGraph(this.el); - graph.setCellsCloneable(true); - graph.setHtmlLabels(true); - graph.setPanning(true); - graph.centerZoom = false; - - // 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, - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - 20, - 20, - 240, - 120, - 'shape=myShape;whiteSpace=wrap;overflow=hidden;pos1=30;pos2=80;' - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - this.el2.appendChild( - mxUtils.button('+', function() { - graph.zoomIn(); - }) - ); - this.el2.appendChild( - mxUtils.button('-', function() { - graph.zoomOut(); - }) - ); - } -} - -export default Handles; diff --git a/src/pages/layout/HierarchicalLayout.js b/src/pages/layout/HierarchicalLayout.js deleted file mode 100644 index 284645039..000000000 --- a/src/pages/layout/HierarchicalLayout.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxHierarchicalLayout from '../../mxgraph/layout/hierarchical/mxHierarchicalLayout'; -import mxFastOrganicLayout from '../../mxgraph/layout/mxFastOrganicLayout'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxPerimeter from '../../mxgraph/util/datatypes/style/mxPerimeter'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class HierarchicalLayout extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Hierarchical Layout

    - This example demonstrates the use of the hierarchical and organic - layouts. Note that the hierarchical layout requires another script tag - in the head of the page. -
    { - this.el = el; - }} - style={{ - position: 'absolute', - overflow: 'auto', - top: '36px', - bottom: '0px', - left: '0px', - right: '0px', - borderTop: 'gray 1px solid', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Adds rubberband selection - new mxRubberband(graph); - - // Changes the default vertex style in-place - let style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_PERIMETER_SPACING] = 6; - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_SHADOW] = true; - - style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_ROUNDED] = true; - - // Creates a layout algorithm to be used - // with the graph - const layout = new mxHierarchicalLayout(graph); - const organic = new mxFastOrganicLayout(graph); - organic.forceConstant = 120; - - const parent = graph.getDefaultParent(); - - // Adds a button to execute the layout - let button = document.createElement('button'); - mxUtils.write(button, 'Hierarchical'); - mxEvent.addListener(button, 'click', function(evt) { - layout.execute(parent); - }); - this.el2.appendChild(button); - - // Adds a button to execute the layout - button = document.createElement('button'); - mxUtils.write(button, 'Organic'); - - mxEvent.addListener(button, 'click', function(evt) { - organic.execute(parent); - }); - - this.el2.appendChild(button); - - // Load cells and layouts the graph - graph.getModel().beginUpdate(); - try { - const v1 = graph.insertVertex(parent, null, '1', 0, 0, 80, 30); - const v2 = graph.insertVertex(parent, null, '2', 0, 0, 80, 30); - const v3 = graph.insertVertex(parent, null, '3', 0, 0, 80, 30); - const v4 = graph.insertVertex(parent, null, '4', 0, 0, 80, 30); - const v5 = graph.insertVertex(parent, null, '5', 0, 0, 80, 30); - const v6 = graph.insertVertex(parent, null, '6', 0, 0, 80, 30); - const v7 = graph.insertVertex(parent, null, '7', 0, 0, 80, 30); - const v8 = graph.insertVertex(parent, null, '8', 0, 0, 80, 30); - const v9 = graph.insertVertex(parent, null, '9', 0, 0, 80, 30); - - const e1 = graph.insertEdge(parent, null, '', v1, v2); - const e2 = graph.insertEdge(parent, null, '', v1, v3); - const e3 = graph.insertEdge(parent, null, '', v3, v4); - const e4 = graph.insertEdge(parent, null, '', v2, v5); - const e5 = graph.insertEdge(parent, null, '', v1, v6); - const e6 = graph.insertEdge(parent, null, '', v2, v3); - const e7 = graph.insertEdge(parent, null, '', v6, v4); - const e8 = graph.insertEdge(parent, null, '', v6, v1); - const e9 = graph.insertEdge(parent, null, '', v6, v7); - const e10 = graph.insertEdge(parent, null, '', v7, v8); - const e11 = graph.insertEdge(parent, null, '', v7, v9); - const e12 = graph.insertEdge(parent, null, '', v7, v6); - const e13 = graph.insertEdge(parent, null, '', v7, v5); - - // Executes the layout - layout.execute(parent); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default HierarchicalLayout; diff --git a/src/pages/layout/Layers.js b/src/pages/layout/Layers.js deleted file mode 100644 index 645943edd..000000000 --- a/src/pages/layout/Layers.js +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxCell from '../../mxgraph/view/cell/mxCell'; -import mxGraphModel from '../../mxgraph/view/graph/mxGraphModel'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class Layers extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Layers

    - This example demonstrates using multiple layers to contain cells. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '241px', - background: "url('editors/images/grid.gif')", - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container using a model - // with a custom root and two layers. Layers can also be added - // dynamically using let layer = model.add(root, new mxCell()). - const root = new mxCell(); - const layer0 = root.insert(new mxCell()); - const layer1 = root.insert(new mxCell()); - const model = new mxGraphModel(root); - - const graph = new mxGraph(this.el, model); - - // Disables basic selection and cell handling - graph.setEnabled(false); - - // 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 - model.beginUpdate(); - try { - const v1 = graph.insertVertex( - layer1, - null, - 'Hello,', - 20, - 20, - 80, - 30, - 'fillColor=#C0C0C0' - ); - const v2 = graph.insertVertex( - layer1, - null, - 'Hello,', - 200, - 20, - 80, - 30, - 'fillColor=#C0C0C0' - ); - const v3 = graph.insertVertex(layer0, null, 'World!', 110, 150, 80, 30); - const e1 = graph.insertEdge( - layer1, - null, - '', - v1, - v3, - 'strokeColor=#0C0C0C' - ); - e1.geometry.points = [new mxPoint(60, 165)]; - const e2 = graph.insertEdge(layer0, null, '', v2, v3); - e2.geometry.points = [new mxPoint(240, 165)]; - const e3 = graph.insertEdge( - layer0, - null, - '', - v1, - v2, - 'edgeStyle=topToBottomEdgeStyle' - ); - e3.geometry.points = [new mxPoint(150, 30)]; - const e4 = graph.insertEdge( - layer1, - null, - '', - v2, - v1, - 'strokeColor=#0C0C0C;edgeStyle=topToBottomEdgeStyle' - ); - e4.geometry.points = [new mxPoint(150, 40)]; - } finally { - // Updates the display - model.endUpdate(); - } - - this.el2.appendChild( - mxUtils.button('Layer 0', function() { - model.setVisible(layer0, !layer0.isVisible()); - }) - ); - - this.el2.appendChild( - mxUtils.button('Layer 1', function() { - model.setVisible(layer1, !layer1.isVisible()); - }) - ); - } -} - -export default Layers; diff --git a/src/pages/layout/OrgChart.js b/src/pages/layout/OrgChart.js deleted file mode 100644 index 5e4a18ee9..000000000 --- a/src/pages/layout/OrgChart.js +++ /dev/null @@ -1,416 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - - Orgchart. This example demonstrates using - automatic layouts, fit to page zoom and poster print (across - multiple pages). - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxPrintPreview from '../../mxgraph/view/graph/mxPrintPreview'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxCellOverlay from '../../mxgraph/view/cell/mxCellOverlay'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxWindow from '../../mxgraph/util/gui/mxWindow'; -import mxToolbar from '../../mxgraph/util/gui/mxToolbar'; -import mxLayoutManager from '../../mxgraph/view/graph/mxLayoutManager'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; -import mxCompactTreeLayout from '../../mxgraph/layout/mxCompactTreeLayout'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; -import mxClient from '../../mxgraph/mxClient'; -import mxOutline from '../../mxgraph/view/graph/mxOutline'; - -class OrgChart extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Orgchart

    -
    { - this.el = el; - }} - style={{ - zIndex: 1, - position: 'relative', - overflow: 'hidden', - height: '50vh', - background: 'transparent', - borderStyle: 'solid', - borderColor: 'lightgray', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Makes the shadow brighter - mxConstants.SHADOWCOLOR = '#C0C0C0'; - - // Workaround for Internet Explorer ignoring certain styles - const container = document.createElement('div'); - container.style.position = 'absolute'; - container.style.overflow = 'hidden'; - container.style.left = '0px'; - container.style.top = '0px'; - container.style.right = '0px'; - container.style.bottom = '0px'; - - const outline = document.getElementById('outlineContainer'); - - mxEvent.disableContextMenu(container); - - // Sets a gradient background - if (mxClient.IS_GC || mxClient.IS_SF) { - container.style.background = - '-webkit-gradient(linear, 0% 0%, 0% 100%, from(#FFFFFF), to(#E7E7E7))'; - } else if (mxClient.IS_NS) { - container.style.background = - '-moz-linear-gradient(top, #FFFFFF, #E7E7E7)'; - } - - this.el.appendChild(container); - - // Creates the graph inside the given container - const graph = new mxGraph(container); - - // Enables automatic sizing for vertices after editing and - // panning by using the left mouse button. - graph.setCellsMovable(false); - graph.setAutoSizeCells(true); - graph.setPanning(true); - graph.centerZoom = false; - graph.panningHandler.useLeftButtonForPanning = true; - - // Displays a popupmenu when the user clicks - // on a cell (using the left mouse button) but - // do not select the cell when the popup menu - // is displayed - graph.panningHandler.popupMenuHandler = false; - - // Creates the outline (navigator, overview) for moving - // around the graph in the top, right corner of the window. - const outln = new mxOutline(graph, outline); - - // Disables tooltips on touch devices - graph.setTooltips(!mxClient.IS_TOUCH); - - // Set some stylesheet options for the visual appearance of vertices - let style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_SHAPE] = 'label'; - - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT; - style[mxConstants.STYLE_SPACING_LEFT] = 54; - - style[mxConstants.STYLE_GRADIENTCOLOR] = '#7d85df'; - style[mxConstants.STYLE_STROKECOLOR] = '#5d65df'; - style[mxConstants.STYLE_FILLCOLOR] = '#adc5ff'; - - style[mxConstants.STYLE_FONTCOLOR] = '#1d258f'; - style[mxConstants.STYLE_FONTFAMILY] = 'Verdana'; - style[mxConstants.STYLE_FONTSIZE] = '12'; - style[mxConstants.STYLE_FONTSTYLE] = '1'; - - style[mxConstants.STYLE_SHADOW] = '1'; - style[mxConstants.STYLE_ROUNDED] = '1'; - style[mxConstants.STYLE_GLASS] = '1'; - - style[mxConstants.STYLE_IMAGE] = 'editors/images/dude3.png'; - style[mxConstants.STYLE_IMAGE_WIDTH] = '48'; - style[mxConstants.STYLE_IMAGE_HEIGHT] = '48'; - style[mxConstants.STYLE_SPACING] = 8; - - // Sets the default style for edges - style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_STROKEWIDTH] = 3; - style[mxConstants.STYLE_EXIT_X] = 0.5; // center - style[mxConstants.STYLE_EXIT_Y] = 1.0; // bottom - style[mxConstants.STYLE_EXIT_PERIMETER] = 0; // disabled - style[mxConstants.STYLE_ENTRY_X] = 0.5; // center - style[mxConstants.STYLE_ENTRY_Y] = 0; // top - style[mxConstants.STYLE_ENTRY_PERIMETER] = 0; // disabled - - // Disable the following for straight lines - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.TopToBottom; - - // Stops editing on enter or escape keypress - const keyHandler = new mxKeyHandler(graph); - - // Enables automatic layout on the graph and installs - // a tree layout for all groups who's children are - // being changed, added or removed. - const layout = new mxCompactTreeLayout(graph, false); - layout.useBoundingBox = false; - layout.edgeRouting = false; - layout.levelDistance = 60; - layout.nodeDistance = 16; - - // Allows the layout to move cells even though cells - // aren't movable in the graph - layout.isVertexMovable = function(cell) { - return true; - }; - - const layoutMgr = new mxLayoutManager(graph); - - layoutMgr.getLayout = function(cell) { - if (cell.getChildCount() > 0) { - return layout; - } - }; - - // Installs a popupmenu handler using local function (see below). - graph.popupMenuHandler.factoryMethod = function(menu, cell, evt) { - return createPopupMenu(graph, menu, cell, evt); - }; - - // Fix for wrong preferred size - const oldGetPreferredSizeForCell = graph.getPreferredSizeForCell; - graph.getPreferredSizeForCell = function(cell) { - const result = oldGetPreferredSizeForCell.apply(this, arguments); - - if (result != null) { - result.width = Math.max(120, result.width - 40); - } - - return result; - }; - - // Sets the maximum text scale to 1 - graph.cellRenderer.getTextScale = function(state) { - return Math.min(1, state.view.scale); - }; - - // Dynamically adds text to the label as we zoom in - // (without affecting the preferred size for new cells) - graph.cellRenderer.getLabelValue = function(state) { - let result = state.cell.value; - - if (state.cell.isVertex()) { - if (state.view.scale > 1) { - result += '\nDetails 1'; - } - - if (state.view.scale > 1.3) { - result += '\nDetails 2'; - } - } - - return result; - }; - - // 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 the root vertex of the tree - graph.getModel().beginUpdate(); - try { - const w = graph.container.offsetWidth; - const v1 = graph.insertVertex( - parent, - 'treeRoot', - 'Organization', - w / 2 - 30, - 20, - 140, - 60, - 'image=editors/images/house.png' - ); - graph.updateCellSize(v1); - addOverlays(graph, v1, false); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - const content = document.createElement('div'); - content.style.padding = '4px'; - this.el2.appendChild(content); - const tb = new mxToolbar(content); - - tb.addItem('Zoom In', 'images/zoom_in32.png', function(evt) { - graph.zoomIn(); - }); - - tb.addItem('Zoom Out', 'images/zoom_out32.png', function(evt) { - graph.zoomOut(); - }); - - tb.addItem('Actual Size', 'images/view_1_132.png', function(evt) { - graph.zoomActual(); - }); - - tb.addItem('Print', 'images/print32.png', function(evt) { - const preview = new mxPrintPreview(graph, 1); - preview.open(); - }); - - tb.addItem('Poster Print', 'images/press32.png', function(evt) { - const pageCount = mxUtils.prompt('Enter maximum page count', '1'); - - if (pageCount != null) { - const scale = mxUtils.getScaleForPageCount(pageCount, graph); - const preview = new mxPrintPreview(graph, scale); - preview.open(); - } - }); - - // Function to create the entries in the popupmenu - function createPopupMenu(graph, menu, cell, evt) { - const model = graph.getModel(); - - if (cell != null) { - if (cell.isVertex()) { - menu.addItem( - 'Add child', - 'editors/images/overlays/check.png', - function() { - addChild(graph, cell); - } - ); - } - - menu.addItem('Edit label', 'editors/images/text.gif', function() { - graph.startEditingAtCell(cell); - }); - - if (cell.id != 'treeRoot' && cell.isVertex()) { - menu.addItem('Delete', 'editors/images/delete.gif', function() { - deleteSubtree(graph, cell); - }); - } - - menu.addSeparator(); - } - - menu.addItem('Fit', 'editors/images/zoom.gif', function() { - graph.fit(); - }); - - menu.addItem('Actual', 'editors/images/zoomactual.gif', function() { - graph.zoomActual(); - }); - - menu.addSeparator(); - - menu.addItem('Print', 'editors/images/print.gif', function() { - const preview = new mxPrintPreview(graph, 1); - preview.open(); - }); - - menu.addItem('Poster Print', 'editors/images/print.gif', function() { - const pageCount = mxUtils.prompt('Enter maximum page count', '1'); - - if (pageCount != null) { - const scale = mxUtils.getScaleForPageCount(pageCount, graph); - const preview = new mxPrintPreview(graph, scale); - preview.open(); - } - }); - } - - function addOverlays(graph, cell, addDeleteIcon) { - let overlay = new mxCellOverlay( - new mxImage('images/add.png', 24, 24), - 'Add child' - ); - overlay.cursor = 'hand'; - overlay.align = mxConstants.ALIGN_CENTER; - overlay.addListener( - mxEvent.CLICK, - mxUtils.bind(this, function(sender, evt) { - addChild(graph, cell); - }) - ); - - graph.addCellOverlay(cell, overlay); - - if (addDeleteIcon) { - overlay = new mxCellOverlay( - new mxImage('images/close.png', 30, 30), - 'Delete' - ); - overlay.cursor = 'hand'; - overlay.offset = new mxPoint(-4, 8); - overlay.align = mxConstants.ALIGN_RIGHT; - overlay.verticalAlign = mxConstants.ALIGN_TOP; - overlay.addListener( - mxEvent.CLICK, - mxUtils.bind(this, function(sender, evt) { - deleteSubtree(graph, cell); - }) - ); - - graph.addCellOverlay(cell, overlay); - } - } - - function addChild(graph, cell) { - const model = graph.getModel(); - const parent = graph.getDefaultParent(); - let vertex; - - model.beginUpdate(); - try { - vertex = graph.insertVertex(parent, null, 'Double click to set name'); - const geometry = vertex.getGeometry(); - - // Updates the geometry of the vertex with the - // preferred size computed in the graph - const size = graph.getPreferredSizeForCell(vertex); - geometry.width = size.width; - geometry.height = size.height; - - // Adds the edge between the existing cell - // and the new vertex and executes the - // automatic layout on the parent - const edge = graph.insertEdge(parent, null, '', cell, vertex); - - // Configures the edge label "in-place" to reside - // at the end of the edge (x = 1) and with an offset - // of 20 pixels in negative, vertical direction. - edge.geometry.x = 1; - edge.geometry.y = 0; - edge.geometry.offset = new mxPoint(0, -20); - - addOverlays(graph, vertex, true); - } finally { - model.endUpdate(); - } - - return vertex; - } - - function deleteSubtree(graph, cell) { - // Gets the subtree from cell downwards - const cells = []; - graph.traverse(cell, true, function(vertex) { - cells.push(vertex); - - return true; - }); - - graph.removeCells(cells); - } - } -} - -export default OrgChart; diff --git a/src/pages/layout/RadialTreeLayout.js b/src/pages/layout/RadialTreeLayout.js deleted file mode 100644 index 3e06b9312..000000000 --- a/src/pages/layout/RadialTreeLayout.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) 2006-2014, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxPerimeter from '../../mxgraph/util/datatypes/style/mxPerimeter'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxRadialTreeLayout from '../../mxgraph/layout/mxRadialTreeLayout'; - -class RadialTreeLayout extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Radial Tree (Hierarchical) Layout

    - This example demonstrates the use of the hierarchical and organic - layouts. Note that the hierarchical layout requires another script tag - in the head of the page. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'auto', - height: '800px', - borderTop: 'gray 1px solid', - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Adds rubberband selection - new mxRubberband(graph); - - // Changes the default vertex style in-place - let style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_PERIMETER_SPACING] = 6; - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_SHADOW] = true; - - style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_ROUNDED] = true; - - // Creates a layout algorithm to be used - // with the graph - const layout = new mxRadialTreeLayout(graph); - - const parent = graph.getDefaultParent(); - - // Load cells and layouts the graph - graph.getModel().beginUpdate(); - try { - const v1 = graph.insertVertex(parent, null, '1', 500, 500, 80, 30); - const v2 = graph.insertVertex(parent, null, '2.1', 0, 0, 80, 30); - const v3 = graph.insertVertex(parent, null, '2.2', 0, 0, 80, 30); - const v4 = graph.insertVertex(parent, null, '3.1', 0, 0, 80, 30); - const v4_1 = graph.insertVertex(parent, null, '3.2', 0, 0, 80, 30); - const v4_2 = graph.insertVertex(parent, null, '3.3', 0, 0, 80, 30); - const v4_3 = graph.insertVertex(parent, null, '3.6', 0, 0, 80, 30); - const v4_4 = graph.insertVertex(parent, null, '3.7', 0, 0, 80, 30); - const v5 = graph.insertVertex(parent, null, '3.4', 0, 0, 80, 30); - const v6 = graph.insertVertex(parent, null, '2.3', 0, 0, 80, 30); - const v7 = graph.insertVertex(parent, null, '4.1', 0, 0, 80, 30); - const v7_1 = graph.insertVertex(parent, null, '4.2', 0, 0, 80, 30); - const v7_2 = graph.insertVertex(parent, null, '4.3', 0, 0, 80, 30); - const v7_3 = graph.insertVertex(parent, null, '4.4', 0, 0, 80, 30); - const v7_4 = graph.insertVertex(parent, null, '4.5', 0, 0, 80, 30); - const v7_5 = graph.insertVertex(parent, null, '4.6', 0, 0, 80, 30); - const v7_6 = graph.insertVertex(parent, null, '4.7', 0, 0, 80, 30); - - const e1 = graph.insertEdge(parent, null, '', v1, v2); - const e2 = graph.insertEdge(parent, null, '', v1, v3); - const e3 = graph.insertEdge(parent, null, '', v3, v4); - const e3_1 = graph.insertEdge(parent, null, '', v3, v4_1); - const e3_2 = graph.insertEdge(parent, null, '', v3, v4_2); - const e3_3 = graph.insertEdge(parent, null, '', v3, v4_3); - const e3_4 = graph.insertEdge(parent, null, '', v3, v4_4); - const e4 = graph.insertEdge(parent, null, '', v2, v5); - const e5 = graph.insertEdge(parent, null, '', v1, v6); - const e6 = graph.insertEdge(parent, null, '', v4_3, v7); - var e6_1 = graph.insertEdge(parent, null, '', v4_4, v7_4); - var e6_2 = graph.insertEdge(parent, null, '', v4_4, v7_5); - var e6_3 = graph.insertEdge(parent, null, '', v4_4, v7_6); - var e6_1 = graph.insertEdge(parent, null, '', v4_3, v7_1); - var e6_2 = graph.insertEdge(parent, null, '', v4_3, v7_2); - var e6_3 = graph.insertEdge(parent, null, '', v4_3, v7_3); - - // Executes the layout - layout.execute(parent); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default RadialTreeLayout; diff --git a/src/pages/layout/SwimLanes.js b/src/pages/layout/SwimLanes.js deleted file mode 100644 index defa281fd..000000000 --- a/src/pages/layout/SwimLanes.js +++ /dev/null @@ -1,578 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxStackLayout from '../../mxgraph/layout/mxStackLayout'; -import mxSwimlaneManager from '../../mxgraph/view/graph/mxSwimlaneManager'; -import mxGraphModel from '../../mxgraph/view/graph/mxGraphModel'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxPerimeter from '../../mxgraph/util/datatypes/style/mxPerimeter'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxEditor from '../../mxgraph/editor/mxEditor'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxLayoutManager from '../../mxgraph/view/graph/mxLayoutManager'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; - -class SwimLanes extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Swimlanes

    - This example demonstrates using swimlanes for pools and lanes and adding - cells and edges between them. This also demonstrates using the stack - layout as an automatic layout. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '400px', - border: 'gray dotted 1px', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Defines an icon for creating new connections in the connection handler. - // This will automatically disable the highlighting of the source vertex. - mxConnectionHandler.prototype.connectImage = new mxImage( - 'images/connector.gif', - 16, - 16 - ); - - // Creates a wrapper editor around a new graph inside - // the given container using an XML config for the - // keyboard bindings - const config = mxUtils - .load('editors/config/keyhandler-commons.xml') - .getDocumentElement(); - const editor = new mxEditor(config); - editor.setGraphContainer(this.el); - const { graph } = editor; - const model = graph.getModel(); - - // Auto-resizes the container - graph.border = 80; - graph.getView().translate = new mxPoint(graph.border / 2, graph.border / 2); - graph.setResizeContainer(true); - graph.graphHandler.setRemoveCellsFromParent(false); - - // Changes the default vertex style in-place - let style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE; - style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle'; - style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white'; - style[mxConstants.STYLE_FONTSIZE] = 11; - style[mxConstants.STYLE_STARTSIZE] = 22; - style[mxConstants.STYLE_HORIZONTAL] = false; - style[mxConstants.STYLE_FONTCOLOR] = 'black'; - style[mxConstants.STYLE_STROKECOLOR] = 'black'; - delete style[mxConstants.STYLE_FILLCOLOR]; - - style = mxUtils.clone(style); - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; - style[mxConstants.STYLE_FONTSIZE] = 10; - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_HORIZONTAL] = true; - style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle'; - delete style[mxConstants.STYLE_STARTSIZE]; - style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'none'; - graph.getStylesheet().putCellStyle('process', style); - - style = mxUtils.clone(style); - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; - delete style[mxConstants.STYLE_ROUNDED]; - graph.getStylesheet().putCellStyle('state', style); - - style = mxUtils.clone(style); - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RHOMBUS; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter; - style[mxConstants.STYLE_VERTICAL_ALIGN] = 'top'; - style[mxConstants.STYLE_SPACING_TOP] = 40; - style[mxConstants.STYLE_SPACING_RIGHT] = 64; - graph.getStylesheet().putCellStyle('condition', style); - - style = mxUtils.clone(style); - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_DOUBLE_ELLIPSE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; - style[mxConstants.STYLE_SPACING_TOP] = 28; - style[mxConstants.STYLE_FONTSIZE] = 14; - style[mxConstants.STYLE_FONTSTYLE] = 1; - delete style[mxConstants.STYLE_SPACING_RIGHT]; - graph.getStylesheet().putCellStyle('end', style); - - style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_BLOCK; - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_FONTCOLOR] = 'black'; - style[mxConstants.STYLE_STROKECOLOR] = 'black'; - - style = mxUtils.clone(style); - style[mxConstants.STYLE_DASHED] = true; - style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_OPEN; - style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_OVAL; - graph.getStylesheet().putCellStyle('crossover', style); - - // Installs double click on middle control point and - // changes style of edges between empty and this value - graph.alternateEdgeStyle = 'elbow=vertical'; - - // Adds automatic layout and various switches if the - // graph is enabled - if (graph.isEnabled()) { - // Allows new connections but no dangling edges - graph.setConnectable(true); - graph.setAllowDanglingEdges(false); - - // End-states are no valid sources - const previousIsValidSource = graph.isValidSource; - - graph.isValidSource = function(cell) { - if (previousIsValidSource.apply(this, arguments)) { - const style = cell.getStyle(); - - return ( - style == null || !(style == 'end' || style.indexOf('end') == 0) - ); - } - - return false; - }; - - // Start-states are no valid targets, we do not - // perform a call to the superclass function because - // this would call isValidSource - // Note: All states are start states in - // the example below, so we use the state - // style below - graph.isValidTarget = function(cell) { - const style = cell.getStyle(); - - return ( - !cell.isEdge() && - !this.isSwimlane(cell) && - (style == null || !(style == 'state' || style.indexOf('state') == 0)) - ); - }; - - // Allows dropping cells into new lanes and - // lanes into new pools, but disallows dropping - // cells on edges to split edges - graph.setDropEnabled(true); - graph.setSplitEnabled(false); - - // Returns true for valid drop operations - graph.isValidDropTarget = function(target, cells, evt) { - if (this.isSplitEnabled() && this.isSplitTarget(target, cells, evt)) { - return true; - } - - const model = this.getModel(); - let lane = false; - let pool = false; - let cell = false; - - // Checks if any lanes or pools are selected - for (let i = 0; i < cells.length; i++) { - const tmp = cells[i].getParent(); - lane = lane || this.isPool(tmp); - pool = pool || this.isPool(cells[i]); - - cell = cell || !(lane || pool); - } - - return ( - !pool && - cell != lane && - ((lane && this.isPool(target)) || - (cell && this.isPool(target.getParent()))) - ); - }; - - // Adds new method for identifying a pool - graph.isPool = function(cell) { - const model = this.getModel(); - const parent = cell.getParent(); - - return parent != null && parent.getParent() == model.getRoot(); - }; - - // Keeps widths on collapse/expand - const foldingHandler = function(sender, evt) { - const cells = evt.getProperty('cells'); - - for (let i = 0; i < cells.length; i++) { - const geo = cells[i].getGeometry(); - - if (geo.alternateBounds != null) { - geo.width = geo.alternateBounds.width; - } - } - }; - - graph.addListener(mxEvent.FOLD_CELLS, foldingHandler); - } - - // Changes swimlane orientation while collapsed - const getStyle = function() { - let style = super.getStyle(); - if (this.isCellCollapsed()) { - if (style != null) { - style += ';'; - } else { - style = ''; - } - style += 'horizontal=1;align=left;spacingLeft=14;'; - } - return style; - }; - - // Applies size changes to siblings and parents - new mxSwimlaneManager(graph); - - // Creates a stack depending on the orientation of the swimlane - const layout = new mxStackLayout(graph, false); - - // Makes sure all children fit into the parent swimlane - layout.resizeParent = true; - - // Applies the size to children if parent size changes - layout.fill = true; - - // Only update the size of swimlanes - layout.isVertexIgnored = function(vertex) { - return !graph.isSwimlane(vertex); - }; - - // Keeps the lanes and pools stacked - const layoutMgr = new mxLayoutManager(graph); - - layoutMgr.getLayout = function(cell) { - if ( - !cell.isEdge() && - cell.getChildCount() > 0 && - (cell.getParent() == model.getRoot() || graph.isPool(cell)) - ) { - layout.fill = graph.isPool(cell); - - return layout; - } - - return null; - }; - - // Gets the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - const parent = graph.getDefaultParent(); - - const insertVertex = options => { - const v = graph.insertVertex(options); - v.getStyle = getStyle; - return v; - }; - - const insertEdge = options => { - const e = graph.insertEdge(options); - e.getStyle = getStyle; - return e; - }; - - // Adds cells to the model in a single step - model.batchUpdate(() => { - const pool1 = insertVertex({ - parent, - value: 'Pool 1', - position: [0, 0], - size: [640, 0], - }); - pool1.setConnectable(false); - - const lane1a = insertVertex({ - parent: pool1, - value: 'Lane A', - position: [0, 0], - size: [640, 110], - }); - lane1a.setConnectable(false); - - const lane1b = insertVertex({ - parent: pool1, - value: 'Lane B', - position: [0, 0], - size: [640, 110], - }); - lane1b.setConnectable(false); - - const pool2 = insertVertex({ - parent, - value: 'Pool 2', - position: [0, 0], - size: [640, 0], - }); - pool2.setConnectable(false); - - const lane2a = insertVertex({ - parent: pool2, - value: 'Lane A', - position: [0, 0], - size: [640, 140], - }); - lane2a.setConnectable(false); - - const lane2b = insertVertex({ - parent: pool2, - value: 'Lane B', - position: [0, 0], - size: [640, 110], - }); - lane2b.setConnectable(false); - - const start1 = insertVertex({ - parent: lane1a, - position: [40, 40], - size: [30, 30], - style: 'state', - }); - const end1 = insertVertex({ - parent: lane1a, - value: 'A', - position: [560, 40], - size: [30, 30], - style: 'end', - }); - - const step1 = insertVertex({ - parent: lane1a, - value: 'Contact\nProvider', - position: [90, 30], - size: [80, 50], - style: 'process', - }); - const step11 = insertVertex({ - parent: lane1a, - value: 'Complete\nAppropriate\nRequest', - position: [190, 30], - size: [80, 50], - style: 'process', - }); - const step111 = insertVertex({ - parent: lane1a, - value: 'Receive and\nAcknowledge', - position: [385, 30], - size: [80, 50], - style: 'process', - }); - - const start2 = insertVertex({ - parent: lane2b, - position: [40, 40], - size: [30, 30], - style: 'state', - }); - - const step2 = insertVertex({ - parent: lane2b, - value: 'Receive\nRequest', - position: [90, 30], - size: [80, 50], - style: 'process', - }); - const step22 = insertVertex({ - parent: lane2b, - value: 'Refer to Tap\nSystems\nCoordinator', - position: [190, 30], - size: [80, 50], - style: 'process', - }); - - const step3 = insertVertex({ - parent: lane1b, - value: 'Request 1st-\nGate\nInformation', - position: [190, 30], - size: [80, 50], - style: 'process', - }); - const step33 = insertVertex({ - parent: lane1b, - value: 'Receive 1st-\nGate\nInformation', - position: [290, 30], - size: [80, 50], - style: 'process', - }); - - const step4 = insertVertex({ - parent: lane2a, - value: 'Receive and\nAcknowledge', - position: [290, 20], - size: [80, 50], - style: 'process', - }); - const step44 = insertVertex({ - parent: lane2a, - value: 'Contract\nConstraints?', - position: [400, 20], - size: [50, 50], - style: 'condition', - }); - const step444 = insertVertex({ - parent: lane2a, - value: 'Tap for gas\ndelivery?', - position: [480, 20], - size: [50, 50], - style: 'condition', - }); - - const end2 = insertVertex({ - parent: lane2a, - value: 'B', - position: [560, 30], - size: [30, 30], - style: 'end', - }); - const end3 = insertVertex({ - parent: lane2a, - value: 'C', - position: [560, 84], - size: [30, 30], - style: 'end', - }); - - let e = null; - - insertEdge({ - parent: lane1a, - source: start1, - target: step1, - }); - insertEdge({ - parent: lane1a, - source: step1, - target: step11, - }); - insertEdge({ - parent: lane1a, - source: step11, - target: step111, - }); - - insertEdge({ - parent: lane2b, - source: start2, - target: step2, - }); - insertEdge({ - parent: lane2b, - source: step2, - target: step22, - }); - insertEdge({ - parent, - source: step22, - target: step3, - }); - - insertEdge({ - parent: lane1b, - source: step3, - target: step33, - }); - insertEdge({ - parent: lane2a, - source: step4, - target: step44, - }); - insertEdge({ - parent: lane2a, - value: 'No', - source: step44, - target: step444, - style: 'verticalAlign=bottom', - }); - insertEdge({ - parent, - value: 'Yes', - source: step44, - target: step111, - style: 'verticalAlign=bottom;horizontal=0;labelBackgroundColor=white;', - }); - - insertEdge({ - parent: lane2a, - value: 'Yes', - source: step444, - target: end2, - style: 'verticalAlign=bottom', - }); - e = insertEdge({ - parent: lane2a, - value: 'No', - source: step444, - target: end3, - style: 'verticalAlign=top', - }); - e.geometry.points = [ - new mxPoint( - step444.geometry.x + step444.geometry.width / 2, - end3.geometry.y + end3.geometry.height / 2 - ), - ]; - - insertEdge({ - parent, - source: step1, - target: step2, - style: 'crossover', - }); - insertEdge({ - parent, - source: step3, - target: step11, - style: 'crossover', - }); - e = insertEdge({ - parent: lane1a, - source: step11, - target: step33, - style: 'crossover', - }); - e.geometry.points = [ - new mxPoint( - step33.geometry.x + step33.geometry.width / 2 + 20, - step11.geometry.y + (step11.geometry.height * 4) / 5 - ), - ]; - insertEdge({ - parent, - source: step33, - target: step4, - }); - insertEdge({ - parent: lane1a, - source: step111, - target: end1, - }); - }); - } -} - -export default SwimLanes; diff --git a/src/pages/layout/Tree.js b/src/pages/layout/Tree.js deleted file mode 100644 index 8a396c5bb..000000000 --- a/src/pages/layout/Tree.js +++ /dev/null @@ -1,313 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxGraphView from '../../mxgraph/view/graph/mxGraphView'; -import mxCellRenderer from '../../mxgraph/view/cell/mxCellRenderer'; -import mxCylinder from '../../mxgraph/shape/node/mxCylinder'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; -import mxCompactTreeLayout from '../../mxgraph/layout/mxCompactTreeLayout'; -import mxLayoutManager from '../../mxgraph/view/graph/mxLayoutManager'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxClient from '../../mxgraph/mxClient'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; - -class Tree extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Tree

    - This example demonstrates folding of subtrees in a acyclic graph (tree). -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '400px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - /* - Defines a custom shape for the tree node that includes the - upper half of the outgoing edge(s). - */ - class TreeNodeShape extends mxCylinder { - // Defines the length of the upper edge segment. - segment = 20; - - constructor(bounds, fill, stroke, strokewidth) { - super(bounds, fill, stroke, strokewidth); - } - - // Needs access to the cell state for rendering - apply(state) { - super.apply(state); - this.state = state; - } - - redrawPath(path, x, y, w, h, isForeground) { - const { graph } = this.state.view; - const hasChildren = - graph.model.getOutgoingEdges(this.state.cell).length > 0; - - if (isForeground) { - if (hasChildren) { - // Painting outside of vertex bounds is used here - path.moveTo(w / 2, h + this.segment); - path.lineTo(w / 2, h); - path.end(); - } - } else { - path.moveTo(0, 0); - path.lineTo(w, 0); - path.lineTo(w, h); - path.lineTo(0, h); - path.close(); - } - } - } - mxCellRenderer.registerShape('treenode', TreeNodeShape); - - class MyCustomGraphView extends mxGraphView { - updateFloatingTerminalPoint(edge, start, end, source) { - // Defines a custom perimeter for the nodes in the tree - let pt = null; - - if (source) { - pt = new mxPoint( - start.x + start.width / 2, - start.y + start.height + TreeNodeShape.prototype.segment - ); - } else { - pt = new mxPoint(start.x + start.width / 2, start.y); - } - - edge.setAbsoluteTerminalPoint(pt, source); - } - } - - class MyCustomCellRenderer extends mxCellRenderer { - getControlBounds(state) { - // Defines the position of the folding icon - if (state.control != null) { - const oldScale = state.control.scale; - const w = state.control.bounds.width / oldScale; - const h = state.control.bounds.height / oldScale; - const s = state.view.scale; - - return new mxRectangle( - state.x + state.width / 2 - (w / 2) * s, - state.y + - state.height + - TreeNodeShape.prototype.segment * s - - (h / 2) * s, - w * s, - h * s - ); - } - return null; - } - } - - // Make the layout instance accessible by MyCustomGraph - let layout; - - class MyCustomGraph extends mxGraph { - // Sets the collapse and expand icons. The values below are the default - // values, but this is how to replace them if you need to. - collapsedImage = new mxImage( - `${mxClient.imageBasePath}/collapsed.gif`, - 9, - 9 - ); - - expandedImage = new mxImage( - `${mxClient.imageBasePath}/expanded.gif`, - 9, - 9 - ); - - isCellFoldable(cell) { - // Defines the condition for showing the folding icon - return this.model.getOutgoingEdges(cell).length > 0; - } - - createCellRenderer() { - return new MyCustomCellRenderer(); - } - - createGraphView() { - return new MyCustomGraphView(this); - } - - foldCells(collapse, recurse, cells) { - // Implements the click on a folding icon - this.model.beginUpdate(); - try { - this.toggleSubtree(this, cells[0], !collapse); - this.model.setCollapsed(cells[0], collapse); - - // Executes the layout for the new graph since - // changes to visiblity and collapsed state do - // not trigger a layout in the current manager. - layout.execute(this.getDefaultParent()); - } finally { - this.model.endUpdate(); - } - } - - toggleSubtree(cell, show) { - // Updates the visible state of a given subtree taking into - // account the collapsed state of the traversed branches - show = show != null ? show : true; - const cells = []; - - this.traverse(cell, true, function(vertex) { - if (vertex !== cell) { - cells.push(vertex); - } - - // Stops recursion if a collapsed cell is seen - return vertex === cell || !this.isCellCollapsed(vertex); - }); - - this.toggleCells(show, cells, true); - } - } - - // Creates the graph inside the given container - const graph = new MyCustomGraph(this.el); - - // Disallow any selections - graph.setCellsSelectable(false); - - // Avoids overlap of edges and collapse icons - graph.keepEdgesInBackground = true; - - // Set some stylesheet options for the visual appearance - let style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_SHAPE] = 'treenode'; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_SHADOW] = true; - - style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.TopToBottom; - style[mxConstants.STYLE_ROUNDED] = true; - - // Enables automatic sizing for vertices after editing and - // panning by using the left mouse button. - graph.setAutoSizeCells(true); - graph.setPanning(true); - graph.panningHandler.useLeftButtonForPanning = true; - - // Stops editing on enter or escape keypress - const keyHandler = new mxKeyHandler(graph); - - // Enables automatic layout on the graph and installs - // a tree layout for all groups who's children are - // being changed, added or removed. - layout = new mxCompactTreeLayout(graph, false); - layout.useBoundingBox = false; - layout.edgeRouting = false; - layout.levelDistance = 30; - layout.nodeDistance = 10; - - const layoutMgr = new mxLayoutManager(graph); - - layoutMgr.getLayout = function(cell) { - if (cell.getChildCount() > 0) { - return layout; - } - }; - - // 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 the root vertex of the tree - graph.getModel().beginUpdate(); - try { - const w = graph.container.offsetWidth; - const root = graph.insertVertex( - parent, - 'treeRoot', - 'Root', - w / 2 - 30, - 20, - 60, - 40 - ); - - const v1 = graph.insertVertex(parent, 'v1', 'Child 1', 0, 0, 60, 40); - graph.insertEdge(parent, null, '', root, v1); - - const v2 = graph.insertVertex(parent, 'v2', 'Child 2', 0, 0, 60, 40); - graph.insertEdge(parent, null, '', root, v2); - - const v3 = graph.insertVertex(parent, 'v3', 'Child 3', 0, 0, 60, 40); - graph.insertEdge(parent, null, '', root, v3); - - const v11 = graph.insertVertex(parent, 'v11', 'Child 1.1', 0, 0, 60, 40); - graph.insertEdge(parent, null, '', v1, v11); - - const v12 = graph.insertVertex(parent, 'v12', 'Child 1.2', 0, 0, 60, 40); - graph.insertEdge(parent, null, '', v1, v12); - - const v21 = graph.insertVertex(parent, 'v21', 'Child 2.1', 0, 0, 60, 40); - graph.insertEdge(parent, null, '', v2, v21); - - const v22 = graph.insertVertex(parent, 'v22', 'Child 2.2', 0, 0, 60, 40); - graph.insertEdge(parent, null, '', v2, v22); - - const v221 = graph.insertVertex( - parent, - 'v221', - 'Child 2.2.1', - 0, - 0, - 60, - 40 - ); - graph.insertEdge(parent, null, '', v22, v221); - - const v222 = graph.insertVertex( - parent, - 'v222', - 'Child 2.2.2', - 0, - 0, - 60, - 40 - ); - graph.insertEdge(parent, null, '', v22, v222); - - const v31 = graph.insertVertex(parent, 'v31', 'Child 3.1', 0, 0, 60, 40); - graph.insertEdge(parent, null, '', v3, v31); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Tree; diff --git a/src/pages/layout/index.js b/src/pages/layout/index.js deleted file mode 100644 index 2ef10c1bb..000000000 --- a/src/pages/layout/index.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import AutoLayout from './AutoLayout'; -import Collapse from './Collapse'; -import Constituent from './Constituent'; -import Folding from './Folding'; -import Groups from './Groups'; -import Handles from './Handles'; -import Layers from './Layers'; -import OrgChart from './OrgChart'; -import RadialTreeLayout from './RadialTreeLayout'; -import SwimLanes from './SwimLanes'; -import Tree from './Tree'; -import PageTabs from '../PageTabs'; - -export default function _Layout() { - return ( - - } /> - } /> - } /> - } /> - } /> - } /> - {/* } /> */} - } /> - } /> - } /> - } /> - } /> - - ); -} diff --git a/src/pages/misc/DynamicLoading.js b/src/pages/misc/DynamicLoading.js deleted file mode 100644 index 172bfb0bd..000000000 --- a/src/pages/misc/DynamicLoading.js +++ /dev/null @@ -1,228 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxText from '../../mxgraph/shape/mxText'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxCodec from '../../mxgraph/serialization/mxCodec'; -import mxEffects from '../../mxgraph/util/animate/mxEffects'; -import mxPerimeter from '../../mxgraph/util/datatypes/style/mxPerimeter'; - -class DynamicLoading extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Dynamic loading

    - This example demonstrates loading graph model data dynamically to limit - the number of cells in the model. -
    { - this.el = el; - }} - style={{ - overflow: 'visible', - position: 'absolute', - height: '100%', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - }; - - componentDidMount() { - let requestId = 0; - - // Speedup the animation - mxText.prototype.enableBoundingBox = false; - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Disables all built-in interactions - graph.setEnabled(false); - - // Handles clicks on cells - graph.addListener(mxEvent.CLICK, function(sender, evt) { - const cell = evt.getProperty('cell'); - - if (cell != null) { - load(graph, cell); - } - }); - - // Changes the default vertex style in-place - const style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - - // Gets the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - const parent = graph.getDefaultParent(); - - const cx = graph.container.clientWidth / 2; - const cy = graph.container.clientHeight / 2; - - const cell = graph.insertVertex( - parent, - '0-0', - '0-0', - cx - 20, - cy - 15, - 60, - 40 - ); - - // Animates the changes in the graph model - graph.getModel().addListener(mxEvent.CHANGE, function(sender, evt) { - const { changes } = evt.getProperty('edit'); - mxEffects.animateChanges(graph, changes); - }); - - // Loads the links for the given cell into the given graph - // by requesting the respective data in the server-side - // (implemented for this demo using the server-function) - function load(graph, cell) { - if (cell.isVertex()) { - const cx = graph.container.clientWidth / 2; - const cy = graph.container.clientHeight / 2; - - // 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 xml = server(cell.id); - const doc = mxUtils.parseXml(xml); - const dec = new mxCodec(doc); - const model = dec.decode(doc.documentElement); - - // Removes all cells which are not in the response - for (var key in graph.getModel().cells) { - const tmp = graph.getModel().getCell(key); - - if (tmp != cell && tmp.isVertex()) { - graph.removeCells([tmp]); - } - } - - // Merges the response model with the client model - graph.getModel().mergeChildren(model.getRoot().getChildAt(0), parent); - - // Moves the given cell to the center - let geo = cell.getGeometry(); - - if (geo != null) { - geo = geo.clone(); - geo.x = cx - geo.width / 2; - geo.y = cy - geo.height / 2; - - graph.getModel().setGeometry(cell, geo); - } - - // Creates a list of the new vertices, if there is more - // than the center vertex which might have existed - // previously, then this needs to be changed to analyze - // the target model before calling mergeChildren above - const vertices = []; - - for (var key in graph.getModel().cells) { - const tmp = graph.getModel().getCell(key); - - if (tmp != cell && tmp.isVertex()) { - vertices.push(tmp); - - // Changes the initial location "in-place" - // to get a nice animation effect from the - // center to the radius of the circle - const geo = tmp.getGeometry(); - - if (geo != null) { - geo.x = cx - geo.width / 2; - geo.y = cy - geo.height / 2; - } - } - } - - // Arranges the response in a circle - const cellCount = vertices.length; - const phi = (2 * Math.PI) / cellCount; - const r = Math.min( - graph.container.clientWidth / 4, - graph.container.clientHeight / 4 - ); - - for (let i = 0; i < cellCount; i++) { - let geo = vertices[i].getGeometry(); - - if (geo != null) { - geo = geo.clone(); - geo.x += r * Math.sin(i * phi); - geo.y += r * Math.cos(i * phi); - - graph.getModel().setGeometry(vertices[i], geo); - } - } - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } - } - - // Simulates the existence of a server that can crawl the - // big graph with a certain depth and create a graph model - // for the traversed cells, which is then sent to the client - function server(cellId) { - // Increments the request ID as a prefix for the cell IDs - requestId++; - - // Creates a local graph with no display - const graph = new mxGraph(); - - // 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 v0 = graph.insertVertex(parent, cellId, 'Dummy', 0, 0, 60, 40); - const cellCount = parseInt(Math.random() * 16) + 4; - - // Creates the random links and cells for the response - for (let i = 0; i < cellCount; i++) { - const id = `${requestId}-${i}`; - const v = graph.insertVertex(parent, id, id, 0, 0, 60, 40); - const e = graph.insertEdge(parent, null, `Link ${i}`, v0, v); - } - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - const enc = new mxCodec(); - const node = enc.encode(graph.getModel()); - - return mxUtils.getXml(node); - } - - load(graph, cell); - }; -} - -export default DynamicLoading; diff --git a/src/pages/misc/Guides.js b/src/pages/misc/Guides.js deleted file mode 100644 index 0d7148b56..000000000 --- a/src/pages/misc/Guides.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxGraphHandler from '../../mxgraph/handler/mxGraphHandler'; -import mxEdgeHandler from '../../mxgraph/handler/mxEdgeHandler'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; - -class Guides extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Guides

    - This example demonstrates the guides feature which aligns the current - selection to the existing vertices in the graph. This feature is in RFC - state. Creating a grid using a canvas and installing a key handler for - cursor keys is also demonstrated here, as well as snapping waypoints to - terminals. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '601px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Enables guides - mxGraphHandler.prototype.guidesEnabled = true; - - // Alt disables guides - mxGraphHandler.prototype.useGuidesForEvent = function(me) { - return !mxEvent.isAltDown(me.getEvent()); - }; - - // Defines the guides to be red (default) - mxConstants.GUIDE_COLOR = '#FF0000'; - - // Defines the guides to be 1 pixel (default) - mxConstants.GUIDE_STROKEWIDTH = 1; - - // Enables snapping waypoints to terminals - mxEdgeHandler.prototype.snapToTerminals = true; - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.setConnectable(true); - graph.gridSize = 30; - - // Changes the default style for edges "in-place" and assigns - // an alternate edge style which is applied in mxGraph.flip - // when the user double clicks on the adjustment control point - // of the edge. The ElbowConnector edge style switches to TopToBottom - // if the horizontal style is true. - const style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - graph.alternateEdgeStyle = 'elbow=vertical'; - - // 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(); - let v1; - try { - v1 = graph.insertVertex(parent, null, 'Hello,', 20, 40, 80, 70); - const v2 = graph.insertVertex(parent, null, 'World!', 200, 140, 80, 40); - const e1 = graph.insertEdge(parent, null, '', v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - // Handles cursor keys - const nudge = function(keyCode) { - if (!graph.isSelectionEmpty()) { - let dx = 0; - let dy = 0; - - if (keyCode === 37) { - dx = -1; - } else if (keyCode === 38) { - dy = -1; - } else if (keyCode === 39) { - dx = 1; - } else if (keyCode === 40) { - dy = 1; - } - - graph.moveCells(graph.getSelectionCells(), dx, dy); - } - - // Transfer initial focus to graph container for keystroke handling - graph.container.focus(); - - // Handles keystroke events - const keyHandler = new mxKeyHandler(graph); - - // Ignores enter keystroke. Remove this line if you want the - // enter keystroke to stop editing - keyHandler.enter = function() {}; - - keyHandler.bindKey(37, function() { - nudge(37); - }); - - keyHandler.bindKey(38, function() { - nudge(38); - }); - - keyHandler.bindKey(39, function() { - nudge(39); - }); - - keyHandler.bindKey(40, function() { - nudge(40); - }); - }; - } -} - -export default Guides; diff --git a/src/pages/misc/Merge.js b/src/pages/misc/Merge.js deleted file mode 100644 index d883e58a4..000000000 --- a/src/pages/misc/Merge.js +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxPerimeter from '../../mxgraph/util/datatypes/style/mxPerimeter'; - -class Merge extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Merge

    - This example demonstrates using the mergeChildren function to merge two - graphs. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '280px', - }} - /> - - ); - } - - componentDidMount() { - mxConstants.SHADOWCOLOR = '#c0c0c0'; - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // No size handles, please... - graph.setCellsResizable(false); - - // Makes all cells round with a white, bold label - let style = graph.stylesheet.getDefaultVertexStyle(); - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; - style[mxConstants.STYLE_FONTCOLOR] = 'white'; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_FONTSTYLE] = mxConstants.FONT_BOLD; - style[mxConstants.STYLE_FONTSIZE] = 14; - style[mxConstants.STYLE_SHADOW] = true; - - // Makes all edge labels gray with a white background - style = graph.stylesheet.getDefaultEdgeStyle(); - style[mxConstants.STYLE_FONTCOLOR] = 'gray'; - style[mxConstants.STYLE_FONTSTYLE] = mxConstants.FONT_BOLD; - style[mxConstants.STYLE_FONTCOLOR] = 'black'; - style[mxConstants.STYLE_STROKEWIDTH] = 2; - - // 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 target model in a single step - // using custom ids for the vertices and edges - const w = 40; - const h = 40; - - graph.getModel().beginUpdate(); - try { - const a = graph.insertVertex( - parent, - 'a', - 'A', - 20, - 20, - w, - h, - 'fillColor=blue' - ); - const b = graph.insertVertex( - parent, - 'b', - 'B', - 20, - 200, - w, - h, - 'fillColor=blue' - ); - const c = graph.insertVertex( - parent, - 'c', - 'C', - 200, - 20, - w, - h, - 'fillColor=red' - ); - const d = graph.insertVertex( - parent, - 'd', - 'D', - 200, - 200, - w, - h, - 'fillColor=red' - ); - const ac = graph.insertEdge( - parent, - 'ac', - 'ac', - a, - c, - 'strokeColor=blue;verticalAlign=bottom' - ); - const ad = graph.insertEdge( - parent, - 'ad', - 'ad', - a, - d, - 'strokeColor=blue;align=left;verticalAlign=bottom' - ); - const bd = graph.insertEdge( - parent, - 'bd', - 'bd', - b, - d, - 'strokeColor=blue;verticalAlign=bottom' - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - // Creates the second graph model (without a container) - const graph2 = new mxGraph(); - - // Gets the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - const parent2 = graph2.getDefaultParent(); - - // Adds cells to the target model in a single step - // using custom ids for the vertices - graph2.getModel().beginUpdate(); - try { - const c = graph2.insertVertex( - parent2, - 'c', - 'C', - 200, - 20, - w, - h, - 'fillColor=green' - ); - const d = graph2.insertVertex( - parent2, - 'd', - 'D', - 200, - 200, - w, - h, - 'fillColor=green' - ); - const e = graph2.insertVertex( - parent2, - 'e', - 'E', - 400, - 20, - w, - h, - 'fillColor=green' - ); - const f = graph2.insertVertex( - parent2, - 'f', - 'F', - 400, - 200, - w, - h, - 'fillColor=green' - ); - const ce = graph2.insertEdge( - parent2, - 'ce', - 'ce', - c, - e, - 'strokeColor=green;verticalAlign=bottom' - ); - const ed = graph2.insertEdge( - parent2, - 'ed', - 'ed', - e, - d, - 'strokeColor=green;align=right;verticalAlign=bottom' - ); - const fd = graph2.insertEdge( - parent2, - 'bd', - 'fd', - f, - d, - 'strokeColor=green;verticalAlign=bottom' - ); - } finally { - // Updates the display - graph2.getModel().endUpdate(); - } - - // Merges the model from the second graph into the model of - // the first graph. Note: If you add a false to the parameter - // list then _not_ all edges will be cloned, that is, the - // edges are assumed to have an identity, and hence the edge - // "bd" will be changed to point from f to d, as specified in - // the edge for the same id in the second graph. - graph.getModel().mergeChildren(parent2, parent /* , false */); - } -} - -export default Merge; diff --git a/src/pages/misc/Monitor.js b/src/pages/misc/Monitor.js deleted file mode 100644 index df3ebadda..000000000 --- a/src/pages/misc/Monitor.js +++ /dev/null @@ -1,296 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxCellOverlay from '../../mxgraph/view/cell/mxCellOverlay'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxCodec from '../../mxgraph/serialization/mxCodec'; -import mxPerimeter from '../../mxgraph/util/datatypes/style/mxPerimeter'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; - -class Monitor extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Workflow Monitor

    - This example demonstrates using a graph to display the current state of - a workflow. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '406px', - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - mxConstants.SHADOWCOLOR = '#e0e0e0'; - - // Creates the graph inside the given container - const graph = createGraph(this.el); - - // Creates a process display using the activity names as IDs to refer to the elements - const xml = - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - ''; - const doc = mxUtils.parseXml(xml); - const codec = new mxCodec(doc); - codec.decode(doc.documentElement, graph.getModel()); - - // Creates a button to invoke the refresh function - this.el2.appendChild( - mxUtils.button('Update', function(evt) { - // XML is normally fetched from URL at server using mxUtils.get - this is a client-side - // string with randomized states to demonstrate the idea of the workflow monitor - const xml = - `` + - `` + - ``; - update(graph, xml); - }) - ); - - /** - * Updates the display of the given graph using the XML data - */ - function update(graph, xml) { - if (xml != null && xml.length > 0) { - const doc = mxUtils.parseXml(xml); - - if (doc != null && doc.documentElement != null) { - const model = graph.getModel(); - const nodes = doc.documentElement.getElementsByTagName('update'); - - if (nodes != null && nodes.length > 0) { - model.beginUpdate(); - - try { - for (let i = 0; i < nodes.length; i++) { - // Processes the activity nodes inside the process node - const id = nodes[i].getAttribute('id'); - const state = nodes[i].getAttribute('state'); - - // Gets the cell for the given activity name from the model - const cell = model.getCell(id); - - // Updates the cell color and adds some tooltip information - if (cell != null) { - // Resets the fillcolor and the overlay - graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, 'white', [ - cell, - ]); - graph.removeCellOverlays(cell); - - // Changes the cell color for the known states - if (state == 'Running') { - graph.setCellStyles( - mxConstants.STYLE_FILLCOLOR, - '#f8cecc', - [cell] - ); - } else if (state == 'Waiting') { - graph.setCellStyles( - mxConstants.STYLE_FILLCOLOR, - '#fff2cc', - [cell] - ); - } else if (state == 'Completed') { - graph.setCellStyles( - mxConstants.STYLE_FILLCOLOR, - '#d4e1f5', - [cell] - ); - } - - // Adds tooltip information using an overlay icon - if (state != 'Init') { - // Sets the overlay for the cell in the graph - graph.addCellOverlay( - cell, - createOverlay(graph.warningImage, `State: ${state}`) - ); - } - } - } // for - } finally { - model.endUpdate(); - } - } - } - } - } - - /** - * Creates an overlay object using the given tooltip and text for the alert window - * which is being displayed on click. - */ - function createOverlay(image, tooltip) { - const overlay = new mxCellOverlay(image, tooltip); - - // Installs a handler for clicks on the overlay - overlay.addListener(mxEvent.CLICK, function(sender, evt) { - mxUtils.alert(`${tooltip}\nLast update: ${new Date()}`); - }); - - return overlay; - } - - /** - * Creates and returns an empty graph inside the given container. - */ - function createGraph(container) { - const graph = new mxGraph(container); - graph.setTooltips(true); - graph.setEnabled(false); - - // Disables folding - graph.isCellFoldable = function(cell, collapse) { - return false; - }; - - // Creates the stylesheet for the process display - let style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_FONTSIZE] = 11; - style[mxConstants.STYLE_FONTCOLOR] = 'black'; - style[mxConstants.STYLE_STROKECOLOR] = '#808080'; - style[mxConstants.STYLE_FILLCOLOR] = 'white'; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_GRADIENT_DIRECTION] = mxConstants.DIRECTION_EAST; - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_SHADOW] = true; - style[mxConstants.STYLE_FONTSTYLE] = 1; - - style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - style[mxConstants.STYLE_STROKECOLOR] = '#808080'; - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_SHADOW] = true; - - style = []; - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - style[mxConstants.STYLE_STROKECOLOR] = '#a0a0a0'; - style[mxConstants.STYLE_FONTCOLOR] = '#606060'; - style[mxConstants.STYLE_FILLCOLOR] = '#E0E0DF'; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_STARTSIZE] = 30; - style[mxConstants.STYLE_ROUNDED] = false; - style[mxConstants.STYLE_FONTSIZE] = 12; - style[mxConstants.STYLE_FONTSTYLE] = 0; - style[mxConstants.STYLE_HORIZONTAL] = false; - // To improve text quality for vertical labels in some old IE versions... - style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = '#efefef'; - - graph.getStylesheet().putCellStyle('swimlane', style); - - style = []; - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RHOMBUS; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter; - style[mxConstants.STYLE_STROKECOLOR] = '#91BCC0'; - style[mxConstants.STYLE_FONTCOLOR] = 'gray'; - style[mxConstants.STYLE_FILLCOLOR] = '#91BCC0'; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_FONTSIZE] = 16; - graph.getStylesheet().putCellStyle('step', style); - - style = []; - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; - style[mxConstants.STYLE_FONTCOLOR] = 'gray'; - style[mxConstants.STYLE_FILLCOLOR] = '#A0C88F'; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_STROKECOLOR] = '#A0C88F'; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_FONTSIZE] = 16; - graph.getStylesheet().putCellStyle('start', style); - - style = mxUtils.clone(style); - style[mxConstants.STYLE_FILLCOLOR] = '#DACCBC'; - style[mxConstants.STYLE_STROKECOLOR] = '#AF7F73'; - graph.getStylesheet().putCellStyle('end', style); - - return graph; - } - - /** - * Returns a random state. - */ - function getState() { - let state = 'Init'; - const rnd = Math.random() * 4; - - if (rnd > 3) { - state = 'Completed'; - } else if (rnd > 2) { - state = 'Running'; - } else if (rnd > 1) { - state = 'Waiting'; - } - - return state; - } - } -} - -export default Monitor; diff --git a/src/pages/misc/Permissions.js b/src/pages/misc/Permissions.js deleted file mode 100644 index 5ceec34a8..000000000 --- a/src/pages/misc/Permissions.js +++ /dev/null @@ -1,243 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class Permission { - constructor(locked, createEdges, editEdges, editVertices, cloneCells) { - this.locked = locked != null ? locked : false; - this.createEdges = createEdges != null ? createEdges : true; - this.editEdges = editEdges != null ? editEdges : true; - this.editVertices = editVertices != null ? editVertices : true; - this.cloneCells = cloneCells != null ? cloneCells : true; - } - - apply(graph) { - graph.setConnectable(this.createEdges); - graph.setCellsLocked(this.locked); - } -} - -class Permissions extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Permissions

    - This example demonstrates creating permissions to define the available - operations a the graph. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '300px', - // background: "url('editors/images/grid.gif')", - }} - /> - - ); - } - - componentDidMount() { - // Defines an icon for creating new connections in the connection handler. - // This will automatically disable the highlighting of the source vertex. - mxConnectionHandler.prototype.connectImage = new mxImage( - 'images/connector.gif', - 16, - 16 - ); - - // Creates the div for the graph - const container = document.createElement('div'); - container.style.position = 'absolute'; - container.style.overflow = 'hidden'; - container.style.left = '00px'; - container.style.top = '40px'; - container.style.right = '0px'; - container.style.bottom = '0px'; - container.style.background = 'url("editors/images/grid.gif")'; - - this.el.appendChild(container); - - // Creates the graph inside the given container - const graph = new mxGraph(container); - - // Enable tooltips, disables mutligraphs, enable loops - graph.setMultigraph(false); - graph.setAllowLoops(true); - - // Enables rubberband selection and key handling - const rubberband = new mxRubberband(graph); - const keyHandler = new mxKeyHandler(graph); - - // Assigns the delete key - keyHandler.bindKey(46, function(evt) { - if (graph.isEnabled()) { - graph.removeCells(); - } - }); - - // Shared variable between child function scopes - // aka "private" variable - let currentPermission = null; - - const apply = function(permission) { - graph.clearSelection(); - permission.apply(graph); - graph.setEnabled(true); - graph.setTooltips(true); - - // Updates the icons on the shapes - rarely - // needed and very slow for large graphs - graph.refresh(); - currentPermission = permission; - }; - - apply(new Permission()); - - let button = mxUtils.button('Allow All', function(evt) { - apply(new Permission()); - }); - this.el.appendChild(button); - - button = mxUtils.button('Connect Only', function(evt) { - apply(new Permission(false, true, false, false, true)); - }); - this.el.appendChild(button); - - button = mxUtils.button('Edges Only', function(evt) { - apply(new Permission(false, false, true, false, false)); - }); - this.el.appendChild(button); - - button = mxUtils.button('Vertices Only', function(evt) { - apply(new Permission(false, false, false, true, false)); - }); - this.el.appendChild(button); - - button = mxUtils.button('Select Only', function(evt) { - apply(new Permission(false, false, false, false, false)); - }); - this.el.appendChild(button); - - button = mxUtils.button('Locked', function(evt) { - apply(new Permission(true, false)); - }); - this.el.appendChild(button); - - button = mxUtils.button('Disabled', function(evt) { - graph.clearSelection(); - graph.setEnabled(false); - graph.setTooltips(false); - }); - this.el.appendChild(button); - - // Extends hook functions to use permission object. This could - // be done by assigning the respective switches (eg. - // setMovable), but this approach is more flexible, doesn't - // override any existing behaviour or settings, and allows for - // dynamic conditions to be used in the functions. See the - // specification for more functions to extend (eg. - // isSelectable). - const oldDisconnectable = graph.isCellDisconnectable; - graph.isCellDisconnectable = function(cell, terminal, source) { - return ( - oldDisconnectable.apply(this, arguments) && currentPermission.editEdges - ); - }; - - const oldTerminalPointMovable = graph.isTerminalPointMovable; - graph.isTerminalPointMovable = function(cell) { - return ( - oldTerminalPointMovable.apply(this, arguments) && - currentPermission.editEdges - ); - }; - - const oldBendable = graph.isCellBendable; - graph.isCellBendable = function(cell) { - return oldBendable.apply(this, arguments) && currentPermission.editEdges; - }; - - const oldLabelMovable = graph.isLabelMovable; - graph.isLabelMovable = function(cell) { - return ( - oldLabelMovable.apply(this, arguments) && currentPermission.editEdges - ); - }; - - const oldMovable = graph.isCellMovable; - graph.isCellMovable = function(cell) { - return ( - oldMovable.apply(this, arguments) && currentPermission.editVertices - ); - }; - - const oldResizable = graph.isCellResizable; - graph.isCellResizable = function(cell) { - return ( - oldResizable.apply(this, arguments) && currentPermission.editVertices - ); - }; - - const oldEditable = graph.isCellEditable; - graph.isCellEditable = function(cell) { - return ( - (oldEditable.apply(this, arguments) && - cell.isVertex() && - currentPermission.editVertices) || - (cell.isEdge() && currentPermission.editEdges) - ); - }; - - const oldDeletable = graph.isCellDeletable; - graph.isCellDeletable = function(cell) { - return ( - (oldDeletable.apply(this, arguments) && - cell.isVertex() && - currentPermission.editVertices) || - (cell.isEdge() && currentPermission.editEdges) - ); - }; - - const oldCloneable = graph.isCellCloneable; - graph.isCellCloneable = function(cell) { - return ( - oldCloneable.apply(this, arguments) && currentPermission.cloneCells - ); - }; - - // 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, 'Hello,', 200, 20, 80, 30); - const v3 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); - const e1 = graph.insertEdge(parent, null, 'Connection', v1, v3); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Permissions; diff --git a/src/pages/misc/Thread.js b/src/pages/misc/Thread.js deleted file mode 100644 index 107ded3f3..000000000 --- a/src/pages/misc/Thread.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; - -class Thread extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Thread

    - This example demonstrates setting overlays in mxGraph from within a - timed function. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Disables basic selection and cell handling - graph.setEnabled(false); - - // Gets the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - const parent = graph.getDefaultParent(); - let v1; - let v2; - let e1; - - // Adds cells to the model in a single step - graph.getModel().beginUpdate(); - try { - v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30); - v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); - e1 = graph.insertEdge(parent, null, '', v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - // Function to switch the overlay every 5 secs - const f = () => { - const overlays = graph.getCellOverlays(v1); - - if (overlays == null) { - graph.removeCellOverlays(v2); - graph.setCellWarning(v1, 'Tooltip'); - } else { - graph.removeCellOverlays(v1); - graph.setCellWarning(v2, 'Tooltip'); - } - }; - - window.setInterval(f, 1000); - f(); - } -} - -export default Thread; diff --git a/src/pages/misc/Validation.js b/src/pages/misc/Validation.js deleted file mode 100644 index 8471ed34b..000000000 --- a/src/pages/misc/Validation.js +++ /dev/null @@ -1,173 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxClient from '../../mxgraph/mxClient'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxMultiplicity from '../../mxgraph/view/connection/mxMultiplicity'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; - -class Validation extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Validation

    - This example demonstrates using multiplicities for automatically - validating a graph. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '281px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - const xmlDocument = mxUtils.createXmlDocument(); - const sourceNode = xmlDocument.createElement('Source'); - const targetNode = xmlDocument.createElement('Target'); - const subtargetNode = xmlDocument.createElement('Subtarget'); - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.setConnectable(true); - graph.setTooltips(true); - graph.setAllowDanglingEdges(false); - graph.setMultigraph(false); - - // Source nodes needs 1..2 connected Targets - graph.multiplicities.push( - new mxMultiplicity( - true, - 'Source', - null, - null, - 1, - 2, - ['Target'], - 'Source Must Have 1 or 2 Targets', - 'Source Must Connect to Target' - ) - ); - - // Source node does not want any incoming connections - graph.multiplicities.push( - new mxMultiplicity( - false, - 'Source', - null, - null, - 0, - 0, - null, - 'Source Must Have No Incoming Edge', - null - ) - ); // Type does not matter - - // Target needs exactly one incoming connection from Source - graph.multiplicities.push( - new mxMultiplicity( - false, - 'Target', - null, - null, - 1, - 1, - ['Source'], - 'Target Must Have 1 Source', - 'Target Must Connect From Source' - ) - ); - - // Enables rubberband selection - new mxRubberband(graph); - - // Removes cells when [DELETE] is pressed - const keyHandler = new mxKeyHandler(graph); - keyHandler.bindKey(46, function(evt) { - if (graph.isEnabled()) { - graph.removeCells(); - } - }); - - // Installs automatic validation (use editor.validation = true - // if you are using an mxEditor instance) - const listener = function(sender, evt) { - graph.validateGraph(); - }; - - graph.getModel().addListener(mxEvent.CHANGE, listener); - - // 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, sourceNode, 20, 20, 80, 30); - const v2 = graph.insertVertex(parent, null, targetNode, 200, 20, 80, 30); - const v3 = graph.insertVertex({ - parent, - value: targetNode.cloneNode(true), - position: [200, 80], - size: [80, 30], - }); - const v4 = graph.insertVertex( - parent, - null, - targetNode.cloneNode(true), - 200, - 140, - 80, - 30 - ); - const v5 = graph.insertVertex( - parent, - null, - subtargetNode, - 200, - 200, - 80, - 30 - ); - const v6 = graph.insertVertex( - parent, - null, - sourceNode.cloneNode(true), - 20, - 140, - 80, - 30 - ); - const e1 = graph.insertEdge(parent, null, '', v1, v2); - const e2 = graph.insertEdge(parent, null, '', v1, v3); - const e3 = graph.insertEdge(parent, null, '', v6, v4); - // var e4 = graph.insertEdge(parent, null, '', v1, v4); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Validation; diff --git a/src/pages/misc/Visibility.js b/src/pages/misc/Visibility.js deleted file mode 100644 index dfc3a4492..000000000 --- a/src/pages/misc/Visibility.js +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class Visibility extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Visibility

    - This example demonstrates using various solutions for hiding and showing - cells. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // 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(); - - let showOne = true; - let showTwo = true; - let showThree = true; - - // Overridden to implement dynamic conditions - const isVisible = function() { - let result = super.isVisible(); - if (result && this.value != null) { - result = - (showOne && this.value == '1') || - (showTwo && this.value == '2') || - (showThree && this.value == '3'); - } - return result; - }; - - // Adds cells to the model in a single step - let v1; - graph.batchUpdate(() => { - v1 = graph.insertVertex({ - parent, - value: '1', - position: [20, 20], - size: [80, 30], - }); - v1.isVisible = isVisible; - - const v2 = graph.insertVertex({ - parent, - value: '2', - position: [200, 150], - size: [80, 30], - }); - v2.isVisible = isVisible; - - const e1 = graph.insertEdge({ - parent, - value: '3', - source: v1, - target: v2, - }); - e1.isVisible = isVisible; - }); - - // Dynamic conditions (requires refresh) - this.el2.appendChild( - mxUtils.button('Cond 1', function() { - showOne = !showOne; - graph.refresh(); - }) - ); - this.el2.appendChild( - mxUtils.button('Cond 2', function() { - showTwo = !showTwo; - graph.refresh(); - }) - ); - this.el2.appendChild( - mxUtils.button('Cond 3', function() { - showThree = !showThree; - graph.refresh(); - }) - ); - - // Explicit show/hide - this.el2.appendChild( - mxUtils.button('Toggle cell', function() { - graph.toggleCells(!v1.isVisible(), [v1], true); - }) - ); - - // Explicit remove/add - let removed = null; - - this.el2.appendChild( - mxUtils.button('Add/remove cell', function() { - if (removed != null) { - graph.addCells(removed); - removed = null; - } else { - removed = graph.removeCells([v1]); - } - }) - ); - } -} - -export default Visibility; diff --git a/src/pages/misc/index.js b/src/pages/misc/index.js deleted file mode 100644 index 18a73312b..000000000 --- a/src/pages/misc/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import Guides from './Guides'; -import Merge from './Merge'; -import Monitor from './Monitor'; -import Permissions from './Permissions'; -import Thread from './Thread'; -import Validation from './Validation'; -import Visibility from './Visibility'; -import PageTabs from '../PageTabs'; - -export default function _Misc() { - return ( - - {/* } /> */} - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - ); -} diff --git a/src/pages/printing/PageBreaks.js b/src/pages/printing/PageBreaks.js deleted file mode 100644 index 97b7b6fef..000000000 --- a/src/pages/printing/PageBreaks.js +++ /dev/null @@ -1,185 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxPrintPreview from '../../mxgraph/view/graph/mxPrintPreview'; - -class PageBreaks extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Pagebreaks

    - This example demonstrates using the pageBreaksVisible and preferPageSize - switches and adding headers and footers to print output. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '481px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - mxEvent.disableContextMenu(this.el); - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.view.setScale(0.15); - graph.pageBreaksVisible = true; - graph.pageBreakDashed = true; - graph.preferPageSize = true; - graph.centerZoom = false; - graph.setPanning(true); - - // Account for the header and footer size in the page format - const headerSize = 100; - const footerSize = 100; - - // Removes header and footer from page height - graph.pageFormat.height -= headerSize + footerSize; - - // Takes zoom into account for moving cells - graph.graphHandler.scaleGrid = 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,', 10, 10, 280, 330); - const v2 = graph.insertVertex( - parent, - null, - 'World!', - graph.pageFormat.width * graph.pageScale - 280 - 10, - graph.pageFormat.height * graph.pageScale - 330 - 10, - 280, - 330 - ); - const e1 = graph.insertEdge(parent, null, '', v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - this.el2.appendChild( - mxUtils.button('Toggle Page Breaks', function(evt) { - graph.pageBreaksVisible = !graph.pageBreaksVisible; - graph.sizeDidChange(); - }) - ); - - this.el2.appendChild( - mxUtils.button('Zoom In', function(evt) { - graph.zoomIn(); - }) - ); - - this.el2.appendChild( - mxUtils.button('Zoom Out', function(evt) { - graph.zoomOut(); - }) - ); - - this.el2.appendChild( - mxUtils.button('Print', function(evt) { - // Matches actual printer paper size and avoids blank pages - const scale = 0.5; - - // Applies scale to page - const pf = mxRectangle.fromRectangle( - graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT - ); - pf.width = Math.round(pf.width * scale * graph.pageScale); - pf.height = Math.round(pf.height * scale * graph.pageScale); - - // Finds top left corner of top left page - const bounds = mxRectangle.fromRectangle(graph.getGraphBounds()); - bounds.x -= graph.view.translate.x * graph.view.scale; - bounds.y -= graph.view.translate.y * graph.view.scale; - - const x0 = Math.floor(bounds.x / pf.width) * pf.width; - const y0 = Math.floor(bounds.y / pf.height) * pf.height; - - const preview = new mxPrintPreview(graph, scale, pf, 0, -x0, -y0); - preview.marginTop = headerSize * scale * graph.pageScale; - preview.marginBottom = footerSize * scale * graph.pageScale; - preview.autoOrigin = false; - - const oldRenderPage = preview.renderPage; - preview.renderPage = function(w, h, x, y, content, pageNumber) { - const div = oldRenderPage.apply(this, arguments); - - const header = document.createElement('div'); - header.style.position = 'absolute'; - header.style.boxSizing = 'border-box'; - header.style.fontFamily = 'Arial,Helvetica'; - header.style.height = `${this.marginTop - 10}px`; - header.style.textAlign = 'center'; - header.style.verticalAlign = 'middle'; - header.style.marginTop = 'auto'; - header.style.fontSize = '12px'; - header.style.width = '100%'; - - // Vertical centering for text in header/footer - header.style.lineHeight = `${this.marginTop - 10}px`; - - const footer = header.cloneNode(true); - - mxUtils.write(header, `Page ${pageNumber} - Header`); - header.style.borderBottom = '1px solid gray'; - header.style.top = '0px'; - - mxUtils.write(footer, `Page ${pageNumber} - Footer`); - footer.style.borderTop = '1px solid gray'; - footer.style.bottom = '0px'; - - div.firstChild.appendChild(footer); - div.firstChild.appendChild(header); - - return div; - }; - - preview.open(); - }) - ); - - this.el2.appendChild( - mxUtils.button('Reset View', function(evt) { - graph.view.scaleAndTranslate(0.15, 0, 0); - }) - ); - } -} - -export default PageBreaks; diff --git a/src/pages/printing/index.js b/src/pages/printing/index.js deleted file mode 100644 index f807e673a..000000000 --- a/src/pages/printing/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import PageTabs from '../PageTabs'; - -export default function _Printing() { - return ( - - {/* } /> */} - - ); -} diff --git a/src/pages/shapes_stencils/Shape.js b/src/pages/shapes_stencils/Shape.js deleted file mode 100644 index c5e283a73..000000000 --- a/src/pages/shapes_stencils/Shape.js +++ /dev/null @@ -1,137 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxCylinder from '../../mxgraph/shape/node/mxCylinder'; -import mxCellRenderer from '../../mxgraph/view/cell/mxCellRenderer'; - -class Shape extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Shape

    - This example demonstrates how to implement and use a custom shape. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - }} - /> - - ); - } - - componentDidMount() { - /* - The example shape is a "3D box" that looks like this: - ____ - / /| - /___/ | - | | / - |___|/ - - The code below defines the shape. The BoxShape function - it the constructor which creates a new object instance. - - The next lines use an mxCylinder instance to augment the - prototype of the shape ("inheritance") and reset the - constructor to the topmost function of the c'tor chain. - */ - - class BoxShape extends mxCylinder { - // Defines the extrusion of the box as a "static class variable" - extrude = 10; - - /* - Next, the mxCylinder's redrawPath method is "overridden". - This method has a isForeground argument to separate two - paths, one for the background (which must be closed and - might be filled) and one for the foreground, which is - just a stroke. - - Foreground: / - _____/ - | - | - ____ - Background: / | - / | - | / - |____/ - */ - redrawPath(path, x, y, w, h, isForeground) { - const dy = this.extrude * this.scale; - const dx = this.extrude * this.scale; - - if (isForeground) { - path.moveTo(0, dy); - path.lineTo(w - dx, dy); - path.lineTo(w, 0); - path.moveTo(w - dx, dy); - path.lineTo(w - dx, h); - } else { - path.moveTo(0, dy); - path.lineTo(dx, 0); - path.lineTo(w, 0); - path.lineTo(w, h - dy); - path.lineTo(w - dx, h); - path.lineTo(0, h); - path.lineTo(0, dy); - path.lineTo(dx, 0); - path.close(); - } - } - } - mxCellRenderer.registerShape('box', BoxShape); - - // Creates the graph inside the DOM node. - const graph = new mxGraph(this.el); - - // Disables basic selection and cell handling - graph.setEnabled(false); - - // Changes the default style for vertices "in-place" - // to use the custom shape. - const style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_SHAPE] = 'box'; - - // Adds a spacing for the label that matches the - // extrusion size - style[mxConstants.STYLE_SPACING_TOP] = BoxShape.prototype.extrude; - style[mxConstants.STYLE_SPACING_RIGHT] = BoxShape.prototype.extrude; - - // Adds a gradient and shadow to improve the user experience - style[mxConstants.STYLE_GRADIENTCOLOR] = '#FFFFFF'; - style[mxConstants.STYLE_SHADOW] = true; - - // 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, 'Custom', 20, 20, 80, 60); - const v2 = graph.insertVertex(parent, null, 'Shape', 200, 150, 80, 60); - const e1 = graph.insertEdge(parent, null, '', v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Shape; diff --git a/src/pages/shapes_stencils/Stencils.js b/src/pages/shapes_stencils/Stencils.js deleted file mode 100644 index 5527df733..000000000 --- a/src/pages/shapes_stencils/Stencils.js +++ /dev/null @@ -1,401 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxPoint from '../../mxgraph/util/datatypes/mxPoint'; -import mxStencilRegistry from '../../mxgraph/shape/node/mxStencilRegistry'; -import mxCellRenderer from '../../mxgraph/view/cell/mxCellRenderer'; -import mxShape from '../../mxgraph/shape/mxShape'; -import mxVertexHandler from '../../mxgraph/handler/mxVertexHandler'; -import mxCellHighlight from '../../mxgraph/handler/mxCellHighlight'; -import mxEdgeHandler from '../../mxgraph/handler/mxEdgeHandler'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; -import mxStencil from '../../mxgraph/shape/node/mxStencil'; - -class Stencils extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Stencils

    - This example demonstrates using an XML file to define new stencils to be - used as shapes. See docs/stencils.xsd for the XML schema file. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '401px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - width: '601px', - height: '150px', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Sets the global shadow color - mxConstants.SHADOWCOLOR = '#C0C0C0'; - mxConstants.SHADOW_OPACITY = 0.5; - mxConstants.SHADOW_OFFSET_X = 4; - mxConstants.SHADOW_OFFSET_Y = 4; - mxConstants.HANDLE_FILLCOLOR = '#99ccff'; - mxConstants.HANDLE_STROKECOLOR = '#0088cf'; - mxConstants.VERTEX_SELECTION_COLOR = '#00a8ff'; - - // Enables connections along the outline - mxConnectionHandler.prototype.outlineConnect = true; - mxEdgeHandler.prototype.manageLabelHandle = true; - mxEdgeHandler.prototype.outlineConnect = true; - mxCellHighlight.prototype.keepOnTop = true; - - // Enable rotation handle - mxVertexHandler.prototype.rotationEnabled = true; - - // Uses the shape for resize previews - mxVertexHandler.prototype.createSelectionShape = function(bounds) { - const key = this.state.style[mxConstants.STYLE_SHAPE]; - const stencil = mxStencilRegistry.getStencil(key); - let shape = null; - - if (stencil != null) { - shape = new mxShape(stencil); - shape.apply(this.state); - } else { - shape = new this.state.shape.constructor(); - } - - shape.outline = true; - shape.bounds = bounds; - shape.stroke = mxConstants.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 CustomShape extends mxShape { - paintBackground(c, x, y, w, h) { - c.translate(x, y); - - // Head - c.ellipse(w / 4, 0, w / 2, h / 4); - c.fillAndStroke(); - - c.begin(); - c.moveTo(w / 2, h / 4); - c.lineTo(w / 2, (2 * h) / 3); - - // Arms - c.moveTo(w / 2, h / 3); - c.lineTo(0, h / 3); - c.moveTo(w / 2, h / 3); - c.lineTo(w, h / 3); - - // Legs - c.moveTo(w / 2, (2 * h) / 3); - c.lineTo(0, h); - c.moveTo(w / 2, (2 * h) / 3); - c.lineTo(w, h); - c.end(); - - c.stroke(); - } - } - - // Replaces existing actor shape - mxCellRenderer.registerShape('customShape', CustomShape); - - // Loads the stencils into the registry - const req = mxUtils.load('stencils.xml'); - const root = req.getDocumentElement(); - let shape = root.firstChild; - - while (shape != null) { - if (shape.nodeType === mxConstants.NODETYPE_ELEMENT) { - mxStencilRegistry.addStencil( - shape.getAttribute('name'), - new mxStencil(shape) - ); - } - - shape = shape.nextSibling; - } - - mxEvent.disableContextMenu(this.el); - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.setConnectable(true); - graph.setTooltips(true); - graph.setPanning(true); - - graph.getTooltipForCell = function(cell) { - if (cell != null) { - return cell.style; - } - - return null; - }; - - // Changes default styles - let style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_EDGE] = 'orthogonalEdgeStyle'; - style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_FILLCOLOR] = '#adc5ff'; - style[mxConstants.STYLE_GRADIENTCOLOR] = '#7d85df'; - style[mxConstants.STYLE_SHADOW] = '1'; - - // 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, - 'A1', - 20, - 20, - 40, - 80, - 'shape=and' - ); - 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 mxPoint(90, 60), new mxPoint(90, 130)]; - const e2 = graph.insertEdge(parent, null, '', v2, v3); - e2.geometry.points = [new mxPoint(90, 260), new mxPoint(90, 170)]; - - const v4 = graph.insertVertex( - parent, - null, - 'A3', - 520, - 20, - 40, - 80, - 'shape=customShape;flipH=1' - ); - const v5 = graph.insertVertex( - parent, - null, - 'A4', - 520, - 220, - 40, - 80, - 'shape=and;flipH=1' - ); - const v6 = graph.insertVertex( - parent, - null, - 'X2', - 340, - 110, - 80, - 80, - 'shape=xor;flipH=1' - ); - const e3 = graph.insertEdge(parent, null, '', v4, v6); - e3.geometry.points = [new mxPoint(490, 60), new mxPoint(130, 130)]; - const e4 = graph.insertEdge(parent, null, '', v5, v6); - e4.geometry.points = [new mxPoint(490, 260), new mxPoint(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 mxPoint(310, 150)]; - const e6 = graph.insertEdge(parent, null, '', v3, v7); - e6.geometry.points = [new mxPoint(270, 150)]; - - const e7 = graph.insertEdge(parent, null, '', v7, v5); - e7.geometry.points = [new mxPoint(290, 370)]; - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - this.el2.appendChild( - mxUtils.button('FlipH', function() { - graph.toggleCellStyles(mxConstants.STYLE_FLIPH); - }) - ); - - this.el2.appendChild( - mxUtils.button('FlipV', function() { - graph.toggleCellStyles(mxConstants.STYLE_FLIPV); - }) - ); - - this.el2.appendChild(document.createTextNode('\u00a0')); - this.el2.appendChild(document.createTextNode('\u00a0')); - this.el2.appendChild(document.createTextNode('\u00a0')); - this.el2.appendChild(document.createTextNode('\u00a0')); - - this.el2.appendChild( - mxUtils.button('Rotate', function() { - const cell = graph.getSelectionCell(); - - if (cell != null) { - let geo = graph.getCellGeometry(cell); - - if (geo != null) { - graph.getModel().beginUpdate(); - try { - // Rotates the size and position in the geometry - geo = geo.clone(); - geo.x += geo.width / 2 - geo.height / 2; - geo.y += geo.height / 2 - geo.width / 2; - const tmp = geo.width; - geo.width = geo.height; - geo.height = tmp; - graph.getModel().setGeometry(cell, geo); - - // Reads the current direction and advances by 90 degrees - const state = graph.view.getState(cell); - - if (state != null) { - let dir = - state.style[mxConstants.STYLE_DIRECTION] || - 'east'; /* default */ - - if (dir === 'east') { - dir = 'south'; - } else if (dir === 'south') { - dir = 'west'; - } else if (dir === 'west') { - dir = 'north'; - } else if (dir === 'north') { - dir = 'east'; - } - - graph.setCellStyles(mxConstants.STYLE_DIRECTION, dir, [cell]); - } - } finally { - graph.getModel().endUpdate(); - } - } - } - }) - ); - - this.el2.appendChild(document.createTextNode('\u00a0')); - this.el2.appendChild(document.createTextNode('\u00a0')); - this.el2.appendChild(document.createTextNode('\u00a0')); - this.el2.appendChild(document.createTextNode('\u00a0')); - - this.el2.appendChild( - mxUtils.button('And', function() { - graph.setCellStyles(mxConstants.STYLE_SHAPE, 'and'); - }) - ); - this.el2.appendChild( - mxUtils.button('Or', function() { - graph.setCellStyles(mxConstants.STYLE_SHAPE, 'or'); - }) - ); - this.el2.appendChild( - mxUtils.button('Xor', function() { - graph.setCellStyles(mxConstants.STYLE_SHAPE, 'xor'); - }) - ); - - this.el2.appendChild(document.createTextNode('\u00a0')); - this.el2.appendChild(document.createTextNode('\u00a0')); - this.el2.appendChild(document.createTextNode('\u00a0')); - this.el2.appendChild(document.createTextNode('\u00a0')); - - this.el2.appendChild( - mxUtils.button('Style', function() { - const cell = graph.getSelectionCell(); - - if (cell != null) { - const style = mxUtils.prompt( - 'Style', - cell.getStyle() - ); - - if (style != null) { - graph.getModel().setStyle(cell, style); - } - } - }) - ); - - this.el2.appendChild( - mxUtils.button('+', function() { - graph.zoomIn(); - }) - ); - this.el2.appendChild( - mxUtils.button('-', function() { - graph.zoomOut(); - }) - ); - } -} - -export default Stencils; diff --git a/src/pages/shapes_stencils/index.js b/src/pages/shapes_stencils/index.js deleted file mode 100644 index db0ded617..000000000 --- a/src/pages/shapes_stencils/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import Shape from './Shape'; -import Stencils from './Stencils'; -import PageTabs from '../PageTabs'; - -export default function _ShapesStencils() { - return ( - - } /> - {/* } /> */} - - ); -} diff --git a/src/pages/styles/DynamicStyle.js b/src/pages/styles/DynamicStyle.js deleted file mode 100644 index f40da1cee..000000000 --- a/src/pages/styles/DynamicStyle.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxConstants from '../../mxgraph/util/mxConstants'; - -class DynamicStyle extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Dynamic Style

    - This example demonstrates changing the style of a cell dynamically by - overriding mxGraphModel.getStyle. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - }} - /> - - ); - }; - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Disables moving of edge labels in this examples - graph.edgeLabelsMovable = false; - - // Enables rubberband selection - new mxRubberband(graph); - - // Needs to set a flag to check for dynamic style changes, - // that is, changes to styles on cells where the style was - // not explicitely changed using mxStyleChange - graph.getView().updateStyle = true; - - // Overrides mxCell.getStyle to return a specific style - // for edges that reflects their target terminal (in this case - // the strokeColor will be equal to the target's fillColor). - - const getStyle = function() { - let style = super.getStyle(); - - if (this.isEdge()) { - const target = this.getTerminal(false); - - if (target != null) { - const targetStyle = graph.getCurrentCellStyle(target); - const fill = mxUtils.getValue( - targetStyle, - mxConstants.STYLE_FILLCOLOR - ); - - if (fill != null) { - style += `;strokeColor=${fill}`; - } - } - } else if (this.isVertex()) { - const geometry = this.getGeometry(); - if (geometry != null && geometry.width > 80) { - style += ';fillColor=green'; - } - } - return style; - }; - - // 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], - style: 'fillColor=green', - }); - v1.getStyle = getStyle; - - const v2 = graph.insertVertex({ - parent, - value: 'World!', - position: [200, 150], - size: [80, 30], - style: 'fillColor=blue', - }); - v2.getStyle = getStyle; - - const v3 = graph.insertVertex({ - parent, - value: 'World!', - position: [20, 150], - size: [80, 30], - style: 'fillColor=red', - }); - v3.getStyle = getStyle; - - const e1 = graph.insertEdge({ - parent, - value: 'Connect', - source: v1, - target: v2, - style: 'perimeterSpacing=4;strokeWidth=4;labelBackgroundColor=white;fontStyle=1', - }); - e1.getStyle = getStyle; - }); - }; -} - -export default DynamicStyle; diff --git a/src/pages/styles/HoverStyle.js b/src/pages/styles/HoverStyle.js deleted file mode 100644 index d0eca3ff1..000000000 --- a/src/pages/styles/HoverStyle.js +++ /dev/null @@ -1,145 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class HoverStyle extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Hoverstyle

    - This example shows hot to change the style of a vertex on mouseover. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - function updateStyle(state, hover) { - if (hover) { - state.style[mxConstants.STYLE_FILLCOLOR] = '#ff0000'; - } - - // Sets rounded style for both cases since the rounded style - // is not set in the default style and is therefore inherited - // once it is set, whereas the above overrides the default value - state.style[mxConstants.STYLE_ROUNDED] = hover ? '1' : '0'; - state.style[mxConstants.STYLE_STROKEWIDTH] = hover ? '4' : '1'; - state.style[mxConstants.STYLE_FONTSTYLE] = hover - ? mxConstants.FONT_BOLD - : '0'; - } - - // Changes fill color to red on mouseover - graph.addMouseListener({ - currentState: null, - previousStyle: null, - mouseDown(sender, me) { - if (this.currentState != null) { - this.dragLeave(me.getEvent(), this.currentState); - this.currentState = null; - } - }, - mouseMove(sender, me) { - if (this.currentState != null && me.getState() == this.currentState) { - return; - } - - let tmp = graph.view.getState(me.getCell()); - - // Ignores everything but vertices - if ( - graph.isMouseDown || - (tmp != null && !tmp.cell.isVertex()) - ) { - tmp = null; - } - - if (tmp != this.currentState) { - if (this.currentState != null) { - this.dragLeave(me.getEvent(), this.currentState); - } - - this.currentState = tmp; - - if (this.currentState != null) { - this.dragEnter(me.getEvent(), this.currentState); - } - } - }, - mouseUp(sender, me) {}, - dragEnter(evt, state) { - if (state != null) { - this.previousStyle = state.style; - state.style = mxUtils.clone(state.style); - updateStyle(state, true); - state.shape.apply(state); - state.shape.redraw(); - - if (state.text != null) { - state.text.apply(state); - state.text.redraw(); - } - } - }, - dragLeave(evt, state) { - if (state != null) { - state.style = this.previousStyle; - updateStyle(state, false); - state.shape.apply(state); - state.shape.redraw(); - - if (state.text != null) { - state.text.apply(state); - state.text.redraw(); - } - } - }, - }); - - // 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(); - } - } -} - -export default HoverStyle; diff --git a/src/pages/styles/Stylesheet.js b/src/pages/styles/Stylesheet.js deleted file mode 100644 index 3018c898b..000000000 --- a/src/pages/styles/Stylesheet.js +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; -import mxPerimeter from '../../mxgraph/util/datatypes/style/mxPerimeter'; - -class Stylesheet extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Stylesheet

    - This example demonstrates using a custom stylesheet and control points - in edges, as well as overriding the getLabel and getTooltip function to - return dynamic information, and making a supercall in JavaScript. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - position: 'relative', - height: '311px', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the DOM node. - const graph = new mxGraph(this.el); - - // Disables basic selection and cell handling - graph.setEnabled(false); - - // Returns a special label for edges. Note: This does - // a supercall to use the default implementation. - graph.getLabel = function(cell) { - const label = mxGraph.prototype.getLabel.apply(this, arguments); - - if (cell.isEdge()) { - return `Transfer ${label}`; - } - return label; - }; - - // Installs a custom global tooltip - graph.setTooltips(true); - graph.getTooltip = function(state) { - const { cell } = state; - const model = this.getModel(); - - if (modcellel.isEdge()) { - const source = this.getLabel(cell.getTerminal(true)); - const target = this.getLabel(cell.getTerminal(false)); - - return `${source} -> ${target}`; - } - return this.getLabel(cell); - }; - - // Creates the default style for vertices - let style = []; - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - style[mxConstants.STYLE_STROKECOLOR] = 'gray'; - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_FILLCOLOR] = '#EEEEEE'; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_FONTCOLOR] = '#774400'; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_FONTSIZE] = '12'; - style[mxConstants.STYLE_FONTSTYLE] = 1; - graph.getStylesheet().putDefaultVertexStyle(style); - - // Creates the default style for edges - style = []; - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_CONNECTOR; - style[mxConstants.STYLE_STROKECOLOR] = '#6482B9'; - style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; - style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC; - style[mxConstants.STYLE_FONTSIZE] = '10'; - graph.getStylesheet().putDefaultEdgeStyle(style); - - // 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, - 'Interval 1', - 20, - 20, - 180, - 30 - ); - const v2 = graph.insertVertex( - parent, - null, - 'Interval 2', - 140, - 80, - 280, - 30 - ); - const v3 = graph.insertVertex( - parent, - null, - 'Interval 3', - 200, - 140, - 360, - 30 - ); - const v4 = graph.insertVertex( - parent, - null, - 'Interval 4', - 480, - 200, - 120, - 30 - ); - const v5 = graph.insertVertex( - parent, - null, - 'Interval 5', - 60, - 260, - 400, - 30 - ); - const e1 = graph.insertEdge(parent, null, '1', v1, v2); - e1.getGeometry().points = [{ x: 160, y: 60 }]; - const e2 = graph.insertEdge(parent, null, '2', v1, v5); - e2.getGeometry().points = [{ x: 80, y: 60 }]; - const e3 = graph.insertEdge(parent, null, '3', v2, v3); - e3.getGeometry().points = [{ x: 280, y: 120 }]; - const e4 = graph.insertEdge(parent, null, '4', v3, v4); - e4.getGeometry().points = [{ x: 500, y: 180 }]; - const e5 = graph.insertEdge(parent, null, '5', v3, v5); - e5.getGeometry().points = [{ x: 380, y: 180 }]; - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - } -} - -export default Stylesheet; diff --git a/src/pages/styles/index.js b/src/pages/styles/index.js deleted file mode 100644 index a1fbf6ca1..000000000 --- a/src/pages/styles/index.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import DynamicStyle from './DynamicStyle'; -import HoverStyle from './HoverStyle'; -import Stylesheet from './Stylesheet'; -import PageTabs from '../PageTabs'; - -export default function _Styles() { - return ( - - } /> - } /> - } /> - - ); -} diff --git a/src/pages/toolbars/DynamicToolbar.js b/src/pages/toolbars/DynamicToolbar.js deleted file mode 100644 index 5ef31b34a..000000000 --- a/src/pages/toolbars/DynamicToolbar.js +++ /dev/null @@ -1,159 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxToolbar from '../../mxgraph/util/gui/mxToolbar'; -import mxGraphModel from '../../mxgraph/view/graph/mxGraphModel'; -import mxCell from '../../mxgraph/view/cell/mxCell'; -import mxGeometry from '../../mxgraph/util/datatypes/mxGeometry'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; - -class DynamicToolbar extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Dynamic Toolbar

    - This example demonstrates changing the state of the toolbar at runtime. -
    { - this.el = el; - }} - style={{ - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - position: 'relative', - }} - /> - - ); - } - - componentDidMount() { - // Defines an icon for creating new connections in the connection handler. - // This will automatically disable the highlighting of the source vertex. - mxConnectionHandler.prototype.connectImage = new mxImage( - 'images/connector.gif', - 16, - 16 - ); - - // Creates the div for the toolbar - const tbContainer = document.createElement('div'); - tbContainer.style.position = 'absolute'; - tbContainer.style.overflow = 'hidden'; - tbContainer.style.padding = '2px'; - tbContainer.style.left = '0px'; - tbContainer.style.top = '0px'; - tbContainer.style.width = '24px'; - tbContainer.style.bottom = '0px'; - - this.el.appendChild(tbContainer); - - // Creates new toolbar without event processing - const toolbar = (this.toolbar = new mxToolbar(tbContainer)); - toolbar.enabled = false; - - // Creates the div for the graph - const container = document.createElement('div'); - container.style.position = 'absolute'; - container.style.overflow = 'hidden'; - container.style.left = '24px'; - container.style.top = '0px'; - container.style.right = '0px'; - container.style.bottom = '0px'; - container.style.background = 'url("editors/images/grid.gif")'; - - this.el.appendChild(container); - - // Creates the model and the graph inside the container - // using the fastest rendering available on the browser - const model = new mxGraphModel(); - const graph = (this.graph = new mxGraph(container, model)); - - // Enables new connections in the graph - graph.setConnectable(true); - graph.setMultigraph(false); - - // Stops editing on enter or escape keypress - const keyHandler = new mxKeyHandler(graph); - const rubberband = new mxRubberband(graph); - - this.addVertex('editors/images/rectangle.gif', 100, 40, ''); - this.addVertex('editors/images/rounded.gif', 100, 40, 'shape=rounded'); - this.addVertex('editors/images/ellipse.gif', 40, 40, 'shape=ellipse'); - this.addVertex('editors/images/rhombus.gif', 40, 40, 'shape=rhombus'); - this.addVertex('editors/images/triangle.gif', 40, 40, 'shape=triangle'); - this.addVertex('editors/images/cylinder.gif', 40, 40, 'shape=cylinder'); - this.addVertex('editors/images/actor.gif', 30, 40, 'shape=actor'); - } - - addVertex(icon, w, h, style) { - const vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style); - vertex.setVertex(true); - - const img = this.addToolbarItem(this.graph, this.toolbar, vertex, icon); - img.enabled = true; - - this.graph.getSelectionModel().addListener(mxEvent.CHANGE, () => { - const tmp = this.graph.isSelectionEmpty(); - mxUtils.setOpacity(img, tmp ? 100 : 20); - img.enabled = tmp; - }); - } - - addToolbarItem(graph, toolbar, prototype, image) { - // Function that is executed when the image is dropped on - // the graph. The cell argument points to the cell under - // the mousepointer if there is one. - const funct = (graph, evt, cell, x, y) => { - graph.stopEditing(false); - - const vertex = graph.getModel().cloneCell(prototype); - vertex.geometry.x = x; - vertex.geometry.y = y; - - graph.addCell(vertex); - graph.setSelectionCell(vertex); - }; - - // Creates the image which is used as the drag icon (preview) - const img = toolbar.addMode(null, image, (evt, cell) => { - const pt = this.graph.getPointForEvent(evt); - funct(graph, evt, cell, pt.x, pt.y); - }); - - // Disables dragging if element is disabled. This is a workaround - // for wrong event order in IE. Following is a dummy listener that - // is invoked as the last listener in IE. - mxEvent.addListener(img, 'mousedown', evt => { - // do nothing - }); - - // This listener is always called first before any other listener - // in all browsers. - mxEvent.addListener(img, 'mousedown', evt => { - if (img.enabled == false) { - mxEvent.consume(evt); - } - }); - - mxUtils.makeDraggable(img, graph, funct); - return img; - } -} - -export default DynamicToolbar; diff --git a/src/pages/toolbars/Toolbar.js b/src/pages/toolbars/Toolbar.js deleted file mode 100644 index b5aed2c1b..000000000 --- a/src/pages/toolbars/Toolbar.js +++ /dev/null @@ -1,190 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxDragSource from '../../mxgraph/util/drag_pan/mxDragSource'; -import mxGraphModel from '../../mxgraph/view/graph/mxGraphModel'; -import mxToolbar from '../../mxgraph/util/gui/mxToolbar'; -import mxConnectionHandler from '../../mxgraph/handler/mxConnectionHandler'; -import mxImage from '../../mxgraph/util/image/mxImage'; -import mxGeometry from '../../mxgraph/util/datatypes/mxGeometry'; -import mxCell from '../../mxgraph/view/cell/mxCell'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; - -class Toolbar extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Toolbar

    - This example demonstrates using existing cells as templates for creating - new cells. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '400px', - border: 'gray dotted 1px', - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Defines an icon for creating new connections in the connection handler. - // This will automatically disable the highlighting of the source vertex. - mxConnectionHandler.prototype.connectImage = new mxImage( - 'images/connector.gif', - 16, - 16 - ); - - // Creates the div for the toolbar - const tbContainer = document.createElement('div'); - tbContainer.style.position = 'absolute'; - tbContainer.style.overflow = 'hidden'; - tbContainer.style.padding = '2px'; - tbContainer.style.left = '0px'; - tbContainer.style.top = '26px'; - tbContainer.style.width = '24px'; - tbContainer.style.bottom = '0px'; - - this.el.appendChild(tbContainer); - - // Creates new toolbar without event processing - const toolbar = new mxToolbar(tbContainer); - toolbar.enabled = false; - - // Creates the div for the graph - const container = document.createElement('div'); - container.style.position = 'absolute'; - container.style.overflow = 'hidden'; - container.style.left = '24px'; - container.style.top = '26px'; - container.style.right = '0px'; - container.style.bottom = '0px'; - container.style.background = 'url("editors/images/grid.gif")'; - - this.el.appendChild(container); - - // Creates the model and the graph inside the container - // using the fastest rendering available on the browser - const model = new mxGraphModel(); - const graph = new mxGraph(container, model); - graph.dropEnabled = true; - - // Matches DnD inside the graph - mxDragSource.prototype.getDropTarget = function(graph, x, y) { - let cell = graph.getCellAt(x, y); - if (!graph.isValidDropTarget(cell)) { - cell = null; - } - return cell; - }; - - // Enables new connections in the graph - graph.setConnectable(true); - graph.setMultigraph(false); - - // Stops editing on enter or escape keypress - const keyHandler = new mxKeyHandler(graph); - const rubberband = new mxRubberband(graph); - - const addVertex = (icon, w, h, style) => { - const vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style); - vertex.setVertex(true); - - this.addToolbarItem(graph, toolbar, vertex, icon); - }; - - addVertex( - 'editors/images/swimlane.gif', - 120, - 160, - 'shape=swimlane;startSize=20;' - ); - addVertex('editors/images/rectangle.gif', 100, 40, ''); - addVertex('editors/images/rounded.gif', 100, 40, 'shape=rounded'); - addVertex('editors/images/ellipse.gif', 40, 40, 'shape=ellipse'); - addVertex('editors/images/rhombus.gif', 40, 40, 'shape=rhombus'); - addVertex('editors/images/triangle.gif', 40, 40, 'shape=triangle'); - addVertex('editors/images/cylinder.gif', 40, 40, 'shape=cylinder'); - addVertex('editors/images/actor.gif', 30, 40, 'shape=actor'); - toolbar.addLine(); - - const button = mxUtils.button( - 'Create toolbar entry from selection', - evt => { - if (!graph.isSelectionEmpty()) { - // Creates a copy of the selection array to preserve its state - const cells = graph.getSelectionCells(); - const bounds = graph.getView().getBounds(cells); - - // Function that is executed when the image is dropped on - // the graph. The cell argument points to the cell under - // the mousepointer if there is one. - const funct = (graph, evt, cell) => { - graph.stopEditing(false); - - const pt = graph.getPointForEvent(evt); - const dx = pt.x - bounds.x; - const dy = pt.y - bounds.y; - - graph.setSelectionCells(graph.importCells(cells, dx, dy, cell)); - }; - - // Creates the image which is used as the drag icon (preview) - const img = toolbar.addMode( - null, - 'editors/images/outline.gif', - funct - ); - mxUtils.makeDraggable(img, graph, funct); - } - } - ); - - this.el2.appendChild(button); - } - - addToolbarItem(graph, toolbar, prototype, image) { - // Function that is executed when the image is dropped on - // the graph. The cell argument points to the cell under - // the mousepointer if there is one. - const funct = (graph, evt, cell) => { - graph.stopEditing(false); - - const pt = graph.getPointForEvent(evt); - const vertex = graph.getModel().cloneCell(prototype); - vertex.geometry.x = pt.x; - vertex.geometry.y = pt.y; - - graph.setSelectionCells(graph.importCells([vertex], 0, 0, cell)); - }; - - // Creates the image which is used as the drag icon (preview) - const img = toolbar.addMode(null, image, funct); - mxUtils.makeDraggable(img, graph, funct); - } -} - -export default Toolbar; diff --git a/src/pages/toolbars/index.js b/src/pages/toolbars/index.js deleted file mode 100644 index b6893a2ae..000000000 --- a/src/pages/toolbars/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import DynamicToolbar from './DynamicToolbar'; -import Toolbar from './Toolbar'; -import PageTabs from '../PageTabs'; - -export default function _Toolbars() { - return ( - - } /> - } /> - - ); -} diff --git a/src/pages/uiconfig.xml b/src/pages/uiconfig.xml deleted file mode 100644 index 7cf140e92..000000000 --- a/src/pages/uiconfig.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - -

    - - -
    - - - - - -
    diff --git a/src/pages/windows/Windows.js b/src/pages/windows/Windows.js deleted file mode 100644 index 774973f70..000000000 --- a/src/pages/windows/Windows.js +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxLog from '../../mxgraph/util/gui/mxLog'; -import mxWindow from '../../mxgraph/util/gui/mxWindow'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; - -class Windows extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Windows

    - This example demonstrates using the mxWindow class for displaying - windows. -
    { - this.el = el; - }} - style={{ - overflow: 'auto', - position: 'relative', - height: '500px', - background: 'lightyellow', - cursor: 'default', - }} - /> - - ); - } - - componentDidMount() { - // Note that we're using the container scrollbars for the graph so that the - // container extends to the parent div inside the window - let wnd = new mxWindow( - 'Scrollable, resizable, given height', - this.el, - 50, - 50, - 220, - 224, - true, - true - ); - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Adds rubberband selection and keystrokes - graph.setTooltips(true); - graph.setPanning(true); - const rubberband = new mxRubberband(graph); - new mxKeyHandler(graph); - - mxEvent.disableContextMenu(this.el); - - // 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(); - } - - wnd.setMaximizable(true); - wnd.setResizable(true); - wnd.setVisible(true); - - const lorem = - 'Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. '; - let content = document.createElement('div'); - mxUtils.write(content, lorem + lorem + lorem); - - wnd = new mxWindow( - 'Scrollable, resizable, auto height', - content, - 300, - 50, - 200, - null, - true, - true - ); - wnd.setMaximizable(true); - wnd.setScrollable(true); - wnd.setResizable(true); - wnd.setVisible(true); - - content = content.cloneNode(true); - content.style.width = '400px'; - - wnd = new mxWindow( - 'Scrollable, resizable, fixed content', - content, - 520, - 50, - 220, - 200, - true, - true - ); - wnd.setMaximizable(true); - wnd.setScrollable(true); - wnd.setResizable(true); - wnd.setVisible(true); - - mxLog.show(); - } -} - -export default Windows; diff --git a/src/pages/windows/index.js b/src/pages/windows/index.js deleted file mode 100644 index 594d77b99..000000000 --- a/src/pages/windows/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import Windows from './Windows'; -import Preview from '../Previews'; -import PageTabs from '../PageTabs'; - -export default function _Windows() { - return ( - - } /> - - ); -} diff --git a/src/pages/xml_json/FileIO.js b/src/pages/xml_json/FileIO.js deleted file mode 100644 index d0d77090f..000000000 --- a/src/pages/xml_json/FileIO.js +++ /dev/null @@ -1,226 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxCellTracker from '../../mxgraph/handler/mxCellTracker'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxFastOrganicLayout from '../../mxgraph/layout/mxFastOrganicLayout'; -import mxEventObject from '../../mxgraph/util/event/mxEventObject'; -import mxCodec from '../../mxgraph/serialization/mxCodec'; -import mxPerimeter from '../../mxgraph/util/datatypes/style/mxPerimeter'; -import mxClient from '../../mxgraph/mxClient'; - -class FileIO extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    File I/O

    - This example demonstrates reading an XML file, writing a custom parser, - applying an automatic layout and defining a 2-way edge. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'auto', - height: '80vh', - borderTop: 'gray 1px solid', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - }; - - componentDidMount() { - // 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 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.setEnabled(false); - graph.setPanning(true); - graph.setTooltips(true); - graph.panningHandler.useLeftButtonForPanning = true; - - // Adds a highlight on the cell under the mousepointer - new mxCellTracker(graph); - - // Changes the default vertex style in-place - let style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ROUNDED; - style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_PERIMETER_SPACING] = 4; - style[mxConstants.STYLE_SHADOW] = true; - - style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white'; - - style = mxUtils.clone(style); - style[mxConstants.STYLE_STARTARROW] = mxConstants.ARROW_CLASSIC; - graph.getStylesheet().putCellStyle('2way', style); - - graph.isHtmlLabel = function(cell) { - return true; - }; - - // Larger grid size yields cleaner layout result - graph.gridSize = 20; - - // Creates a layout algorithm to be used - // with the graph - const layout = new mxFastOrganicLayout(graph); - - // Moves stuff wider apart than usual - layout.forceConstant = 140; - - // Adds a button to execute the layout - this.el2.appendChild( - mxUtils.button('Arrange', function(evt) { - const parent = graph.getDefaultParent(); - layout.execute(parent); - }) - ); - - // Load cells and layouts the graph - graph.getModel().beginUpdate(); - try { - // Loads the custom file format (TXT file) - parse(graph, 'fileio.txt'); - - // Loads the mxGraph file format (XML file) - // read(graph, 'fileio.xml'); - - // Gets the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - const parent = graph.getDefaultParent(); - - // Executes the layout - layout.execute(parent); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - graph.dblClick = function(evt, cell) { - const mxe = new mxEventObject( - mxEvent.DOUBLE_CLICK, - 'event', - evt, - 'cell', - cell - ); - this.fireEvent(mxe); - - if ( - this.isEnabled() && - !mxEvent.isConsumed(evt) && - !mxe.isConsumed() && - cell != null - ) { - mxUtils.alert( - `Show properties for cell ${cell.customId || cell.getId()}` - ); - } - }; - } - } - - // Custom parser for simple file format - function parse(graph, filename) { - const model = graph.getModel(); - - // Gets the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - const parent = graph.getDefaultParent(); - - const req = mxUtils.load(filename); - const text = req.getText(); - - const lines = text.split('\n'); - - // Creates the lookup table for the vertices - const vertices = []; - - // Parses all lines (vertices must be first in the file) - graph.getModel().beginUpdate(); - try { - for (let i = 0; i < lines.length; i++) { - // Ignores comments (starting with #) - const colon = lines[i].indexOf(':'); - - if (lines[i].substring(0, 1) != '#' || colon == -1) { - const comma = lines[i].indexOf(','); - const value = lines[i].substring(colon + 2, lines[i].length); - - if (comma == -1 || comma > colon) { - const key = lines[i].substring(0, colon); - - if (key.length > 0) { - vertices[key] = graph.insertVertex( - parent, - null, - value, - 0, - 0, - 80, - 70 - ); - } - } else if (comma < colon) { - // Looks up the vertices in the lookup table - const source = vertices[lines[i].substring(0, comma)]; - const target = vertices[lines[i].substring(comma + 1, colon)]; - - if (source != null && target != null) { - const e = graph.insertEdge(parent, null, value, source, target); - - // Uses the special 2-way style for 2-way labels - if (value.indexOf('2-Way') >= 0) { - e.style = '2way'; - } - } - } - } - } - } finally { - graph.getModel().endUpdate(); - } - } - - // Parses the mxGraph XML file format - function read(graph, filename) { - const req = mxUtils.load(filename); - const root = req.getDocumentElement(); - const dec = new mxCodec(root.ownerDocument); - - dec.decode(root, graph.getModel()); - } - }; -} - -export default FileIO; diff --git a/src/pages/xml_json/JsonData.js b/src/pages/xml_json/JsonData.js deleted file mode 100644 index 82cc6e635..000000000 --- a/src/pages/xml_json/JsonData.js +++ /dev/null @@ -1,110 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxCodecRegistry from '../../mxgraph/serialization/mxCodecRegistry'; -import mxObjectCodec from '../../mxgraph/serialization/mxObjectCodec'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxCodec from '../../mxgraph/serialization/mxCodec'; - -class JsonData extends React.Component { - // Adds an option to view the XML of the graph - document; - - body; - - 'View XML'; - - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    JSON data

    - This example demonstrates using JSON to encode/decode parts of the graph - model in mxCodec. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '241px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Register a new codec - function CustomData(value) { - this.value = value; - } - const codec = new mxObjectCodec(new CustomData()); - codec.encode = function(enc, obj) { - const node = enc.document.createElement('CustomData'); - mxUtils.setTextContent(node, JSON.stringify(obj)); - return node; - }; - codec.decode = function(dec, node, into) { - const obj = JSON.parse(mxUtils.getTextContent(node)); - obj.constructor = CustomData; - - return obj; - }; - mxCodecRegistry.register(codec); - - // Disables the built-in context menu - mxEvent.disableContextMenu(this.el); - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // 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); - v1.data = new CustomData('v1'); - const v2 = graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30); - v2.data = new CustomData('v2'); - const e1 = graph.insertEdge(parent, null, '', v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - this.el2.appendChild( - mxUtils.button('Show JSON', function() { - const encoder = new mxCodec(); - const node = encoder.encode(graph.getModel()); - mxUtils.popup(mxUtils.getXml(node), true); - }) - ); - } -} - -export default JsonData; diff --git a/src/pages/xml_json/UserObject.js b/src/pages/xml_json/UserObject.js deleted file mode 100644 index 81326762e..000000000 --- a/src/pages/xml_json/UserObject.js +++ /dev/null @@ -1,328 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxUtils from '../../mxgraph/util/mxUtils'; -import mxConstants from '../../mxgraph/util/mxConstants'; -import mxForm from '../../mxgraph/util/gui/mxForm'; -import mxCellAttributeChange from '../../mxgraph/atomic_changes/mxCellAttributeChange'; -import mxKeyHandler from '../../mxgraph/handler/mxKeyHandler'; -import mxRectangle from '../../mxgraph/util/datatypes/mxRectangle'; -import mxEdgeStyle from '../../mxgraph/util/datatypes/style/mxEdgeStyle'; -import mxCodec from "../../mxgraph/serialization/mxCodec"; - -class UserObject extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    User object

    - This example demonstrates using XML objects as values for cells. - - - - - -
    -
    { - this.el = el; - }} - style={{ - border: 'solid 1px black', - overflow: 'hidden', - height: '241px', - cursor: 'default', - }} - /> -
    -
    { - this.propertiesEl = el; - }} - style={{ - border: 'solid 1px black', - padding: '10px', - }} - /> -
    -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Note that these XML nodes will be enclosing the - // mxCell nodes for the model cells in the output - const doc = mxUtils.createXmlDocument(); - - const person1 = doc.createElement('Person'); - person1.setAttribute('firstName', 'Daffy'); - person1.setAttribute('lastName', 'Duck'); - - const person2 = doc.createElement('Person'); - person2.setAttribute('firstName', 'Bugs'); - person2.setAttribute('lastName', 'Bunny'); - - const relation = doc.createElement('Knows'); - relation.setAttribute('since', '1985'); - - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - - // Optional disabling of sizing - graph.setCellsResizable(false); - - // Configures the graph contains to resize and - // add a border at the bottom, right - graph.setResizeContainer(true); - graph.minimumContainerSize = new mxRectangle(0, 0, 500, 380); - graph.setBorder(60); - - // Stops editing on enter key, handles escape - new mxKeyHandler(graph); - - // Overrides method to disallow edge label editing - graph.isCellEditable = function(cell) { - return !cell.isEdge(); - }; - - // Overrides method to provide a cell label in the display - graph.convertValueToString = function(cell) { - if (mxUtils.isNode(cell.value)) { - if (cell.value.nodeName.toLowerCase() == 'person') { - const firstName = cell.getAttribute('firstName', ''); - const lastName = cell.getAttribute('lastName', ''); - - if (lastName != null && lastName.length > 0) { - return `${lastName}, ${firstName}`; - } - - return firstName; - } - if (cell.value.nodeName.toLowerCase() == 'knows') { - return `${cell.value.nodeName} (Since ${cell.getAttribute( - 'since', - '' - )})`; - } - } - - return ''; - }; - - // Overrides method to store a cell label in the model - const { cellLabelChanged } = graph; - graph.cellLabelChanged = function(cell, newValue, autoSize) { - if ( - mxUtils.isNode(cell.value) && - cell.value.nodeName.toLowerCase() == 'person' - ) { - const pos = newValue.indexOf(' '); - - const firstName = pos > 0 ? newValue.substring(0, pos) : newValue; - const lastName = - pos > 0 ? newValue.substring(pos + 1, newValue.length) : ''; - - // Clones the value for correct undo/redo - const elt = cell.value.cloneNode(true); - - elt.setAttribute('firstName', firstName); - elt.setAttribute('lastName', lastName); - - newValue = elt; - autoSize = true; - } - - cellLabelChanged.apply(this, arguments); - }; - - // Overrides method to create the editing value - const { getEditingValue } = graph; - graph.getEditingValue = function(cell) { - if ( - mxUtils.isNode(cell.value) && - cell.value.nodeName.toLowerCase() == 'person' - ) { - const firstName = cell.getAttribute('firstName', ''); - const lastName = cell.getAttribute('lastName', ''); - - return `${firstName} ${lastName}`; - } - }; - - // Adds a special tooltip for edges - graph.setTooltips(true); - - const { getTooltipForCell } = graph; - graph.getTooltipForCell = function(cell) { - // Adds some relation details for edges - if (cell.isEdge()) { - const src = this.getLabel(cell.getTerminal(true)); - const trg = this.getLabel(cell.getTerminal(false)); - - return `${src} ${cell.value.nodeName} ${trg}`; - } - - return getTooltipForCell.apply(this, arguments); - }; - - // Enables rubberband selection - new mxRubberband(graph); - - // Adds an option to view the XML of the graph - this.el2.appendChild( - mxUtils.button('View XML', function() { - const encoder = new mxCodec(); - const node = encoder.encode(graph.getModel()); - mxUtils.popup(mxUtils.getPrettyXml(node), true); - }) - ); - - // Changes the style for match the markup - // Creates the default style for vertices - let style = graph.getStylesheet().getDefaultVertexStyle(); - style[mxConstants.STYLE_STROKECOLOR] = 'gray'; - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_SHADOW] = true; - style[mxConstants.STYLE_FILLCOLOR] = '#DFDFDF'; - style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; - style[mxConstants.STYLE_FONTCOLOR] = 'black'; - style[mxConstants.STYLE_FONTSIZE] = '12'; - style[mxConstants.STYLE_SPACING] = 4; - - // Creates the default style for edges - style = graph.getStylesheet().getDefaultEdgeStyle(); - style[mxConstants.STYLE_STROKECOLOR] = '#0C0C0C'; - style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white'; - style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; - style[mxConstants.STYLE_ROUNDED] = true; - style[mxConstants.STYLE_FONTCOLOR] = 'black'; - style[mxConstants.STYLE_FONTSIZE] = '10'; - - // 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, person1, 40, 40, 80, 30); - const v2 = graph.insertVertex(parent, null, person2, 200, 150, 80, 30); - const e1 = graph.insertEdge(parent, null, relation, v1, v2); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - - // Implements a properties panel that uses - // mxCellAttributeChange to change properties - graph - .getSelectionModel() - .addListener(mxEvent.CHANGE, function(sender, evt) { - this.selectionChanged(graph); - }); - - this.selectionChanged(graph); - } - - /** - * Updates the properties panel - */ - selectionChanged(graph) { - const div = this.propertiesEl; - - // Forces focusout in IE - graph.container.focus(); - - // Clears the DIV the non-DOM way - div.innerHTML = ''; - - // Gets the selection cell - const cell = graph.getSelectionCell(); - - if (cell == null) { - mxUtils.writeln(div, 'Nothing selected.'); - } else { - // Writes the title - const center = document.createElement('center'); - mxUtils.writeln(center, `${cell.value.nodeName} (${cell.id})`); - div.appendChild(center); - mxUtils.br(div); - - // Creates the form from the attributes of the user object - const form = new mxForm(); - - const attrs = cell.value.attributes; - - for (let i = 0; i < attrs.length; i++) { - this.createTextField(graph, form, cell, attrs[i]); - } - - div.appendChild(form.getTable()); - mxUtils.br(div); - } - } - - /** - * Creates the textfield for the given property. - */ - createTextField(graph, form, cell, attribute) { - const input = form.addText(`${attribute.nodeName}:`, attribute.nodeValue); - - const applyHandler = function() { - const newValue = input.value || ''; - const oldValue = cell.getAttribute(attribute.nodeName, ''); - - if (newValue != oldValue) { - graph.getModel().beginUpdate(); - - try { - const edit = new mxCellAttributeChange( - cell, - attribute.nodeName, - newValue - ); - graph.getModel().execute(edit); - graph.updateCellSize(cell); - } finally { - graph.getModel().endUpdate(); - } - } - }; - - mxEvent.addListener(input, 'keypress', function(evt) { - // Needs to take shift into account for textareas - if (evt.keyCode == /* enter */ 13 && !mxEvent.isShiftDown(evt)) { - input.blur(); - } - }); - - // Note: Known problem is the blurring of fields in - // Firefox by changing the selection, in which case - // no event is fired in FF and the change is lost. - // As a workaround you should use a local variable - // that stores the focused field and invoke blur - // explicitely where we do the graph.focus above. - mxEvent.addListener(input, 'blur', applyHandler); - } -} - -export default UserObject; diff --git a/src/pages/xml_json/index.js b/src/pages/xml_json/index.js deleted file mode 100644 index 10989af2b..000000000 --- a/src/pages/xml_json/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import JsonData from './JsonData'; -import UserObject from './UserObject'; -import PageTabs from '../PageTabs'; - -export default function _XMLJSON() { - return ( - - } /> - } /> - - ); -} diff --git a/src/pages/zoom_offpage/LOD.js b/src/pages/zoom_offpage/LOD.js deleted file mode 100644 index 3fcc5e7aa..000000000 --- a/src/pages/zoom_offpage/LOD.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxUtils from '../../mxgraph/util/mxUtils'; - -class LOD extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Level of detail

    - This example demonstrates implementing a level of detail per cell. -
    { - this.el = el; - }} - style={{ - position: 'relative', - overflow: 'hidden', - height: '441px', - background: "url('editors/images/grid.gif')", - cursor: 'default', - }} - /> -
    { - this.el2 = el; - }} - /> - - ); - } - - componentDidMount() { - // Creates the graph inside the given container - const graph = new mxGraph(this.el); - graph.centerZoom = false; - - // Links level of detail to zoom level but can be independent of zoom - const isVisible = function(cell) { - return cell.lod == null || cell.lod / 2 < this.view.scale; - }; - - // 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, null, '1', 20, 20, 80, 30); - v1.lod = 1; - v1.isVisible = isVisible; - - const v2 = graph.insertVertex(parent, null, '1', 200, 150, 80, 30); - v2.lod = 1; - v2.isVisible = isVisible; - - const v3 = graph.insertVertex(parent, null, '2', 20, 150, 40, 20); - v3.lod = 2; - v3.isVisible = isVisible; - - const v4 = graph.insertVertex(parent, null, '3', 200, 10, 20, 20); - v4.lod = 3; - v4.isVisible = isVisible; - - const e1 = graph.insertEdge(parent, null, '2', v1, v2, 'strokeWidth=2'); - e1.lod = 2; - e1.isVisible = isVisible; - - const e2 = graph.insertEdge(parent, null, '2', v3, v4, 'strokeWidth=2'); - e2.lod = 2; - e2.isVisible = isVisible; - - const e3 = graph.insertEdge(parent, null, '3', v1, v4, 'strokeWidth=1'); - e3.lod = 3; - e3.isVisible = isVisible; - }); - - this.el2.appendChild( - mxUtils.button('+', function() { - graph.zoomIn(); - }) - ); - - this.el2.appendChild( - mxUtils.button('-', function() { - graph.zoomOut(); - }) - ); - } -} - -export default LOD; diff --git a/src/pages/zoom_offpage/OffPage.js b/src/pages/zoom_offpage/OffPage.js deleted file mode 100644 index 2f5800e7e..000000000 --- a/src/pages/zoom_offpage/OffPage.js +++ /dev/null @@ -1,217 +0,0 @@ -/** - * Copyright (c) 2006-2013, JGraph Ltd - * Converted to ES9 syntax/React by David Morrissey 2021 - */ - -import React from 'react'; -import mxEvent from '../../mxgraph/util/event/mxEvent'; -import mxGraph from '../../mxgraph/view/graph/mxGraph'; -import mxRubberband from '../../mxgraph/handler/mxRubberband'; -import mxCellTracker from '../../mxgraph/handler/mxCellTracker'; -import mxConstants from '../../mxgraph/util/mxConstants'; - -class OffPage extends React.Component { - constructor(props) { - super(props); - } - - render() { - // A container for the graph - return ( - <> -

    Offpage connector

    - This example demonstrates creating offpage connectors in a graph and - loading a new diagram on a single click. -
    { - this.el = el; - }} - style={{}} - /> - - ); - } - - componentDidMount() { - // Use complete cell as highlight region - mxConstants.ACTIVE_REGION = 1; - - const container = document.createElement('div'); - container.style.position = 'relative'; - container.style.overflow = 'hidden'; - container.style.height = '80vhpx'; - container.style.background = 'url("editors/images/grid.gif")'; - - this.el.appendChild(container); - - // Creates the graph inside the given container - const graph = new mxGraph(container); - graph.setEnabled(false); - - // Highlights offpage connectors - const highlight = new mxCellTracker(graph, null, function(me) { - const cell = me.getCell(); - - if ( - cell != null && - cell.value != null && - typeof cell.value.create === 'function' - ) { - return cell; - } - - return null; - }); - - // Handles clicks on offpage connectors and - // executes function in user object - graph.addListener(mxEvent.CLICK, function(source, evt) { - const cell = evt.getProperty('cell'); - - if ( - cell != null && - cell.value != null && - typeof cell.value.create === 'function' - ) { - cell.value.create(); - } - }); - - // Handles clicks on offpage connectors and - // executes function in user object - graph.getCursorForCell = function(cell) { - if ( - cell != null && - cell.value != null && - typeof cell.value.create === 'function' - ) { - return 'pointer'; - } - }; - - // Gets the default parent for inserting new cells. This - // is normally the first child of the root (ie. layer 0). - let first = null; - let second = null; - - first = function() { - const value = { - toString() { - return 'Next'; - }, - create: second, - }; - - // Adds cells to the model in a single step - graph.getModel().beginUpdate(); - try { - graph.getModel().setRoot(graph.getModel().createRoot()); - const parent = graph.getDefaultParent(); - - const v1 = graph.insertVertex( - parent, - null, - 'Click', - 30, - 20, - 80, - 30, - 'fillColor=#FFFF88;strokeColor=#FF1A00' - ); - const v2 = graph.insertVertex( - parent, - null, - 'Next', - 20, - 150, - 100, - 30, - 'fillColor=#FFFF88;strokeColor=#FF1A00' - ); - const v3 = graph.insertVertex( - parent, - null, - value, - 200, - 150, - 40, - 40, - 'shape=triangle;align=left;fillColor=#C3D9FF;strokeColor=#4096EE' - ); - const e1 = graph.insertEdge( - parent, - null, - null, - v1, - v2, - 'strokeColor=#FF1A00' - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - }; - - second = function() { - const value = { - toString() { - return 'Prev'; - }, - create: first, - }; - - // Adds cells to the model in a single step - graph.getModel().beginUpdate(); - try { - graph.getModel().setRoot(graph.getModel().createRoot()); - const parent = graph.getDefaultParent(); - - const v1 = graph.insertVertex( - parent, - null, - 'Click', - 30, - 20, - 80, - 30, - 'fillColor=#CDEB8B;strokeColor=#008C00' - ); - const v2 = graph.insertVertex( - parent, - null, - 'Prev', - 220, - 20, - 100, - 30, - 'fillColor=#CDEB8B;strokeColor=#008C00' - ); - const v3 = graph.insertVertex( - parent, - null, - value, - 30, - 150, - 40, - 40, - 'shape=triangle;align=right;fillColor=#C3D9FF;strokeColor=#4096EE;direction=west' - ); - const e1 = graph.insertEdge( - parent, - null, - null, - v1, - v2, - 'strokeColor=#008C00' - ); - } finally { - // Updates the display - graph.getModel().endUpdate(); - } - }; - - first(); - } -} - -export default OffPage; diff --git a/src/pages/zoom_offpage/index.js b/src/pages/zoom_offpage/index.js deleted file mode 100644 index 02f63d223..000000000 --- a/src/pages/zoom_offpage/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import Preview from '../Previews'; -import LOD from './LOD'; -import OffPage from './OffPage'; -import PageTabs from '../PageTabs'; - -export default function _ZoomOffpage() { - return ( - - } /> - } /> - - ); -} diff --git a/src/public/editors/config/diagrameditor.xml b/src/public/editors/config/diagrameditor.xml deleted file mode 100644 index f9576bfcb..000000000 --- a/src/public/editors/config/diagrameditor.xml +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ' + label + - ' (' + cell.getId() + ')
    ') : '') + - ((style != null) ? ('
    Style: ' + style + '
    ') : '') + - 'Connections: ' + cell.getEdgeCount()+ - '
    Children: ' + cell.getChildCount(); - } - ]]>
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - null - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - -

    - - - - - - - - - - - - - - -
    -
    diff --git a/src/public/editors/config/editor-commons.xml b/src/public/editors/config/editor-commons.xml deleted file mode 100644 index 5d7069847..000000000 --- a/src/public/editors/config/editor-commons.xml +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0) - { - window.open(href); - } - else - { - mxUtils.alert('No URL defined. Showing properties...'); - editor.execute('showProperties', cell); - } - } - } - ]]> - - - - - - 0) - { - editor.graph.setCellStyles("fontFamily", family); - } - } - ]]> - 0 && size < 999) - { - editor.graph.setCellStyles("fontSize", size); - } - } - ]]> - - = 0 && opacity <= 100) - { - editor.graph.setCellStyles("opacity", opacity); - } - } - ]]> - - - - - - - - - - diff --git a/src/public/editors/config/keyhandler-commons.xml b/src/public/editors/config/keyhandler-commons.xml deleted file mode 100644 index 1e2c159c8..000000000 --- a/src/public/editors/config/keyhandler-commons.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/public/editors/config/keyhandler-minimal.xml b/src/public/editors/config/keyhandler-minimal.xml deleted file mode 100644 index 7f4ce3cb4..000000000 --- a/src/public/editors/config/keyhandler-minimal.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/public/editors/config/layouteditor.xml b/src/public/editors/config/layouteditor.xml deleted file mode 100644 index 09f3a097a..000000000 --- a/src/public/editors/config/layouteditor.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/public/editors/config/processeditor.xml b/src/public/editors/config/processeditor.xml deleted file mode 100644 index 3e057d7b1..000000000 --- a/src/public/editors/config/processeditor.xml +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0; - } - ]]> - - function (cell) - { - return mxUtils.isNode(this.model.getValue(cell), 'swimlane'); - } - - - function(cell) - { - return !this.isSwimlane(cell.parent); - } - - '+cell.getAttribute('label')+ - ' ('+cell.getId()+')'+ - '
    Style: '+cell.getStyle()+ - '
    Edges: '+cell.getEdgeCount()+ - '
    Children: '+cell.getChildCount(); - } - ]]>
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    diff --git a/src/public/editors/config/wfeditor-commons.xml b/src/public/editors/config/wfeditor-commons.xml deleted file mode 100644 index 7cfb41b0d..000000000 --- a/src/public/editors/config/wfeditor-commons.xml +++ /dev/null @@ -1,184 +0,0 @@ - - - - function () - { - this.showTasks(); - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0) || this.graph.isSwimlane(cell)) - { - mxUtils.para(div, mxResources.get('layout')); - mxUtils.linkAction(div, mxResources.get('verticalTree'), - this, 'verticalTree', off); - mxUtils.br(div); - mxUtils.linkAction(div, mxResources.get('horizontalTree'), - this, 'horizontalTree', off); - mxUtils.br(div); - } - - mxUtils.para(div, mxResources.get('format')); - - if (mxUtils.isNode(cell.value, 'Symbol')) - { - mxUtils.linkAction(div, mxResources.get('image'), - this, 'image', off); - mxUtils.br(div); - } - else - { - mxUtils.linkAction(div, mxResources.get('opacity'), - this, 'opacity', off); - mxUtils.br(div); - if (this.graph.model.isVertex(cell) || - (cell.style != null && - cell.style.indexOf("arrowEdge") >= 0)) - { - mxUtils.linkAction(div, mxResources.get('gradientColor'), - this, 'gradientColor', off); - mxUtils.br(div); - } - if (this.graph.model.isEdge(cell)) - { - mxUtils.linkAction(div, 'Straight Connector', this, 'straightConnector', off); - mxUtils.br(div); - mxUtils.linkAction(div, 'Elbow Connector', this, 'elbowConnector', off); - mxUtils.br(div); - mxUtils.linkAction(div, 'Arrow Connector', this, 'arrowConnector', off); - mxUtils.br(div); - } - } - - mxUtils.linkAction(div, mxResources.get('toggleRounded'), this, 'toggleRounded', off); - mxUtils.br(div); - if (this.graph.isSwimlane(cell) || this.graph.model.isEdge(cell)) - { - mxUtils.linkAction(div, mxResources.get('toggleOrientation'), this, 'toggleOrientation', off); - mxUtils.br(div); - } - - if (this.graph.getSelectionCount() > 1) - { - mxUtils.para(div, mxResources.get('align')); - mxUtils.linkAction(div, mxResources.get('left'), - this, 'alignCellsLeft', off); - mxUtils.br(div); - mxUtils.linkAction(div, mxResources.get('center'), - this, 'alignCellsCenter', off); - mxUtils.br(div); - mxUtils.linkAction(div, mxResources.get('right'), - this, 'alignCellsRight', off); - mxUtils.br(div); - mxUtils.linkAction(div, mxResources.get('top'), - this, 'alignCellsTop', off); - mxUtils.br(div); - mxUtils.linkAction(div, mxResources.get('middle'), - this, 'alignCellsMiddle', off); - mxUtils.br(div); - mxUtils.linkAction(div, mxResources.get('bottom'), - this, 'alignCellsBottom', off); - mxUtils.br(div); - } - - mxUtils.para(div, mxResources.get('selection')); - mxUtils.linkAction(div, mxResources.get('clearSelection'), - this, 'selectNone', off); - mxUtils.br(div); - } - else if (layer.getChildCount() > 0) - { - mxUtils.para(div, mxResources.get('selection')); - mxUtils.linkAction(div, mxResources.get('selectAll'), - this, 'selectAll', off); - mxUtils.br(div); - } - - mxUtils.br(div); - } - } - ]]> - diff --git a/src/public/editors/config/wfgraph-commons.xml b/src/public/editors/config/wfgraph-commons.xml deleted file mode 100644 index 218068029..000000000 --- a/src/public/editors/config/wfgraph-commons.xml +++ /dev/null @@ -1,152 +0,0 @@ - - - - - 0) ? - '
    '+href : ''; - let maxlen = 30; - let desc = cell.getAttribute('description'); - if (desc == null || desc.length == 0) - { - desc = ''; - } - else if (desc.length < maxlen) - { - desc = '
    '+desc; - } - else - { - desc = '
    '+desc.substring(0, maxlen)+'...'; - } - return ''+cell.getAttribute('label')+ - ' ('+cell.getId()+')'+href+desc+ - '
    Edges: '+cell.getEdgeCount()+ - '
    Children: '+cell.getChildCount(); - } - ]]>
    - - function(cell) - { - return cell.getAttribute('label'); - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    diff --git a/src/public/editors/config/wftoolbar-commons.xml b/src/public/editors/config/wftoolbar-commons.xml deleted file mode 100644 index ca91e1e57..000000000 --- a/src/public/editors/config/wftoolbar-commons.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - -

    - - - - -

    - - -

    - - - - -

    - - -

    - - - - - - -

    - - - - - - - - - - - - - - - - - -

    - - - - - -

    - - - - -
    diff --git a/src/public/editors/config/workfloweditor.xml b/src/public/editors/config/workfloweditor.xml deleted file mode 100644 index 846e7f358..000000000 --- a/src/public/editors/config/workfloweditor.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/public/editors/css/process.css b/src/public/editors/css/process.css deleted file mode 100644 index e5d01c064..000000000 --- a/src/public/editors/css/process.css +++ /dev/null @@ -1,3 +0,0 @@ -img.mxToolbarMode { - margin-right: 7px; -} diff --git a/src/public/editors/css/wordpress.css b/src/public/editors/css/wordpress.css deleted file mode 100644 index c6d4971f1..000000000 --- a/src/public/editors/css/wordpress.css +++ /dev/null @@ -1,599 +0,0 @@ -/* Begin Typography & Colors */ -body { - font-size: 62.5%; /* Resets 1em to 10px */ - font-family: 'Lucida Grande', Verdana, Arial, Sans-Serif; - background: #d5d6d7 url('../images/draw/drawbgcolor.jpg'); - color: #333; - text-align: center; - } - -#page { - background-color: white; - border: 1px solid #959596; - text-align: left; - } - -#header { - background: #73a0c5 url('../images/draw/drawheader.jpg') no-repeat bottom center; - } - -#headerimg { - margin: 7px 9px 0; - height: 62px; - width: 740px; - } - -#content { - font-size: 1.2em - } - -.widecolumn .entry p { - font-size: 1.05em; - } - -.narrowcolumn .entry, .widecolumn .entry { - line-height: 1.4em; - } - -.widecolumn { - line-height: 1.6em; - } - -.narrowcolumn .postmetadata { - text-align: center; - } - -.alt { - background-color: #f8f8f8; - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - } - -pre { - background: #f8f8f8; - font-size: 12px; - padding: 8px; -} - -#footer { - background: #eee url('../images/draw/drawfooter.jpg') no-repeat top; - border: none; - } - -small { - font-family: Arial, Helvetica, Sans-Serif; - font-size: 0.9em; - line-height: 1.5em; - } - -h1, h2, h3 { - font-family: 'Trebuchet MS', 'Lucida Grande', Verdana, Arial, Sans-Serif; - font-weight: bold; - } - -h1 { - font-size: 2em; - text-align: center; - } - -#headerimg .description { - font-size: 1.2em; - text-align: center; - } - -h2 { - font-size: 1.6em; - } - -h2.pagetitle { - font-size: 1.6em; - } - -#sidebar h2 { - font-family: 'Lucida Grande', Verdana, Sans-Serif; - font-size: 1.2em; - } - -h3 { - font-size: 1.3em; - } - -h1, h1 a, h1 a:hover, h1 a:visited, #headerimg .description { - text-decoration: none; - color: white; - } - -h2, h2 a, h2 a:visited, h3, h3 a, h3 a:visited { - color: #333; - } - -h2, h2 a, h2 a:hover, h2 a:visited, h3, h3 a, h3 a:hover, h3 a:visited, #sidebar h2, #wp-calendar caption, cite { - text-decoration: none; - } - -.entry p a:visited { - color: #b85b5a; - } - -.commentlist li, #commentform input, #commentform textarea { - font: 0.9em 'Lucida Grande', Verdana, Arial, Sans-Serif; - } - -.commentlist li { - font-weight: bold; - } - -.commentlist cite, .commentlist cite a { - font-weight: bold; - font-style: normal; - font-size: 1.1em; - } - -.commentlist p { - font-weight: normal; - line-height: 1.5em; - text-transform: none; - } - -#commentform p { - font-family: 'Lucida Grande', Verdana, Arial, Sans-Serif; - } - -.commentmetadata { - font-weight: normal; - } - -#sidebar { - font: 1em 'Lucida Grande', Verdana, Arial, Sans-Serif; - } - -small, #sidebar ul ul li, #sidebar ul ol li, .nocomments, .postmetadata, blockquote, strike { - color: #777; - } - -code { - font: 1.1em 'Courier New', Courier, Fixed; - } - -acronym, abbr, span.caps -{ - font-size: 0.9em; - letter-spacing: .07em; - } - -a, h2 a:hover, h3 a:hover { - color: #06c; - text-decoration: none; - } - -a:hover { - color: #147; - text-decoration: underline; - } - -#wp-calendar #prev a { - font-size: 9pt; - } - -#wp-calendar a { - text-decoration: none; - } - -#wp-calendar caption { - font: bold 1.3em 'Lucida Grande', Verdana, Arial, Sans-Serif; - text-align: center; - } - -#wp-calendar th { - font-style: normal; - text-transform: capitalize; - } -/* End Typography & Colors */ - - - -/* Begin Structure */ -body { - margin: 0 0 20px 0; - padding: 0; - } - -#page { - background-color: white; - margin: 20px auto; - padding: 0; - width: 760px; - border: 1px solid #959596; - } - -#header { - background-color: #73a0c5; - margin: 0 0 0 1px; - padding: 0; - height: 70px; - width: 758px; - } - -#headerimg { - margin: 0; - height: 70px; - width: 100%; - } - -.narrowcolumn { - float: left; - padding: 0 0 20px 45px; - margin: 0px 0 0; - width: 450px; - } - -.widecolumn { - padding: 10px 0 20px 0; - margin: 5px 0 0 150px; - width: 450px; - } - -.post { - margin: 0 0 40px; -/* text-align: justify; */ - } - -.widecolumn .post { - margin: 0; - } - -.narrowcolumn .postmetadata { - padding-top: 5px; - } - -.widecolumn .postmetadata { - margin: 30px 0; - } - -.widecolumn .smallattachment { - text-align: center; - float: left; - width: 128px; - margin: 5px 5px 5px 0px; -} - -.widecolumn .attachment { - text-align: center; - margin: 5px 0px; -} - -.postmetadata { - clear: left; -} - -#footer { - padding: 0; - margin: 0 auto; - width: 760px; - clear: both; - } - -#footer p { - margin: 0; - padding: 20px 0; - text-align: center; - } -/* End Structure */ - - - -/* Begin Headers */ -h1 { - padding-top: 30px; - margin: 0; - } - -h2 { - margin: 30px 0 0; - } - -h2.pagetitle { - margin-top: 30px; - text-align: center; -} - -#sidebar h2 { - margin: 5px 0 0; - padding: 0; - } - -h3 { - padding: 0; - margin: 30px 0 0; - } - -h3.comments { - padding: 0; - margin: 40px auto 20px ; - } -/* End Headers */ - - - -/* Begin Images */ -p img { - padding: 0; - max-width: 100%; - } - -/* Using 'class="alignright"' on an image will (who would've - thought?!) align the image to the right. And using 'class="centered', - will of course center the image. This is much better than using - align="center", being much more futureproof (and valid) */ - -img.centered { - display: block; - margin-left: auto; - margin-right: auto; - } - -img.alignright { - padding: 4px; - margin: 0 0 2px 7px; - display: inline; - } - -img.alignleft { - padding: 4px; - margin: 0 7px 2px 0; - display: inline; - } - -.alignright { - float: right; - } - -.alignleft { - float: left - } -/* End Images */ - - - -/* Begin Lists - - Special stylized non-IE bullets - Do not work in Internet Explorer, which merely default to normal bullets. */ - -html>body .entry ul { - margin-left: 0px; - padding: 0 0 0 30px; - list-style: none; - padding-left: 10px; - text-indent: -10px; - } - -html>body .entry li { - margin: 7px 0 8px 10px; - } - -.entry ul li:before, #sidebar ul ul li:before { - content: "\00BB \0020"; - } - -.entry ol { - padding: 0 0 0 35px; - margin: 0; - } - -.entry ol li { - margin: 0; - padding: 0; - } - -.postmetadata ul, .postmetadata li { - display: inline; - list-style-type: none; - list-style-image: none; - } - -#sidebar ul, #sidebar ul ol { - margin: 0; - padding: 0; - } - -#sidebar ul li { - list-style-type: none; - list-style-image: none; - margin-bottom: 15px; - } - -#sidebar ul p, #sidebar ul select { - margin: 5px 0 8px; - } - -#sidebar ul ul, #sidebar ul ol { - margin: 5px 0 0 10px; - } - -#sidebar ul ul ul, #sidebar ul ol { - margin: 0 0 0 10px; - } - -ol li, #sidebar ul ol li { - list-style: decimal outside; - } - -#sidebar ul ul li, #sidebar ul ol li { - margin: 3px 0 0; - padding: 0; - } -/* End Entry Lists */ - - - -/* Begin Form Elements */ -#searchform { - margin: 10px auto; - padding: 5px 3px; - text-align: center; - } - -#sidebar #searchform #s { - width: 108px; - padding: 2px; - } - -#sidebar #searchsubmit { - padding: 1px; - } - -.entry form { /* This is mainly for password protected posts, makes them look better. */ - text-align:center; - } - -select { - width: 130px; - } - -#commentform input { - width: 170px; - padding: 2px; - margin: 5px 5px 1px 0; - } - -#commentform textarea { - width: 100%; - padding: 2px; - } - -#commentform #submit { - margin: 0; - float: right; - } -/* End Form Elements */ - - - -/* Begin Comments*/ -.alt { - margin: 0; - padding: 10px; - } - -.commentlist { - padding: 0; -/* text-align: justify; */ - } - -.commentlist li { - margin: 15px 0 3px; - padding: 5px 10px 3px; - list-style: none; - } - -.commentlist p { - margin: 10px 5px 10px 0; - } - -#commentform p { - margin: 5px 0; - } - -.nocomments { - text-align: center; - margin: 0; - padding: 0; - } - -.commentmetadata { - margin: 0; - display: block; - } -/* End Comments */ - - - -/* Begin Sidebar */ -#sidebar -{ - padding: 20px 0 10px 0; - margin-left: 545px; - width: 190px; - } - -#sidebar form { - margin: 0; - } -/* End Sidebar */ - - - -/* Begin Calendar */ -#wp-calendar { - empty-cells: show; - margin: 10px auto 0; - width: 155px; - } - -#wp-calendar #next a { - padding-right: 10px; - text-align: right; - } - -#wp-calendar #prev a { - padding-left: 10px; - text-align: left; - } - -#wp-calendar a { - display: block; - } - -#wp-calendar caption { - text-align: center; - width: 100%; - } - -#wp-calendar td { - padding: 3px 0; - text-align: center; - } - -#wp-calendar td.pad:hover { /* Doesn't work in IE */ - background-color: #fff; } -/* End Calendar */ - - - -/* Begin Various Tags & Classes */ -acronym, abbr, span.caps { - cursor: help; - } - -acronym, abbr { - border-bottom: 1px dashed #999; - } - -blockquote { - margin: 15px 30px 0 10px; - padding-left: 20px; - border-left: 5px solid #ddd; - } - -blockquote cite { - margin: 5px 0 0; - display: block; - } - -.center { - text-align: center; - } - -a img { - border: none; - } - -.navigation { - display: block; - text-align: center; - margin-top: 10px; - margin-bottom: 60px; - } -/* End Various Tags & Classes*/ - diff --git a/src/public/editors/diagrameditor.html b/src/public/editors/diagrameditor.html deleted file mode 100644 index 9f55627e5..000000000 --- a/src/public/editors/diagrameditor.html +++ /dev/null @@ -1,340 +0,0 @@ - - - mxDraw Example - - - - - - - - - -
    - -
    -
    -
    -
    - - - - - -
    - - -
    - -
    - -
    -
    - -
    - - Source - -
    -
    - -
    - - diff --git a/src/public/editors/diagrams/empty.xml b/src/public/editors/diagrams/empty.xml deleted file mode 100644 index 4d02c0696..000000000 --- a/src/public/editors/diagrams/empty.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/public/editors/diagrams/swimlanes.xml b/src/public/editors/diagrams/swimlanes.xml deleted file mode 100644 index 0b38f4dc4..000000000 --- a/src/public/editors/diagrams/swimlanes.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/public/editors/diagrams/travel-booking.xml b/src/public/editors/diagrams/travel-booking.xml deleted file mode 100644 index b408aca63..000000000 --- a/src/public/editors/diagrams/travel-booking.xml +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/public/editors/diagrams/withdrawal.xml b/src/public/editors/diagrams/withdrawal.xml deleted file mode 100644 index 42b0bbc95..000000000 --- a/src/public/editors/diagrams/withdrawal.xml +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/public/editors/grapheditor.html b/src/public/editors/grapheditor.html deleted file mode 100644 index 551ae496b..000000000 --- a/src/public/editors/grapheditor.html +++ /dev/null @@ -1,9 +0,0 @@ - - - Deprecation Warning - - -This example has been deprecated. A new implementation is available here. -A copy of the old example is here. - - diff --git a/src/public/editors/help/index-all.html b/src/public/editors/help/index-all.html deleted file mode 100644 index 3f03c1d7d..000000000 --- a/src/public/editors/help/index-all.html +++ /dev/null @@ -1,45 +0,0 @@ - - - mxGraph Workflow Editor Help Index - - - -

    Help Index

    -

    Help Index

    -
    - Lorem Ipsum
    - Lorem Ipsum
    - Lorem Ipsum
    -
    - Lorem Ipsum
    - Lorem Ipsum
    - Lorem Ipsum
    - Lorem Ipsum
    -
    - Lorem Ipsum
    - Lorem Ipsum
    - Lorem Ipsum
    - Lorem Ipsum
    - - diff --git a/src/public/editors/help/index.html b/src/public/editors/help/index.html deleted file mode 100644 index cb0e7207b..000000000 --- a/src/public/editors/help/index.html +++ /dev/null @@ -1,41 +0,0 @@ - - - mxGraph Workflow Editor Help - - - -

    mxGraph Online Help

    -

    -Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et -dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip -ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu -fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt -mollit anim id est laborum. -

    - See Help Index - - diff --git a/src/public/editors/js/app.js b/src/public/editors/js/app.js deleted file mode 100644 index 940162290..000000000 --- a/src/public/editors/js/app.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2006-2013, JGraph Ltd - * - * Defines the startup sequence of the application. - */ -{ - /** - * Constructs a new application (returns an mxEditor instance) - */ - function createEditor(config) { - let editor = null; - - const hideSplash = function() { - // Fades-out the splash screen - const splash = document.getElementById('splash'); - - if (splash != null) { - try { - mxEvent.release(splash); - mxEffects.fadeOut(splash, 100, true); - } catch (e) { - splash.parentNode.removeChild(splash); - } - } - }; - - try { - if (!mxClient.isBrowserSupported()) { - mxUtils.error('Browser is not supported!', 200, false); - } else { - mxObjectCodec.allowEval = true; - const node = mxUtils.load(config).getDocumentElement(); - editor = new mxEditor(node); - mxObjectCodec.allowEval = false; - - // Adds active border for panning inside the container - editor.graph.createPanningManager = function() { - const pm = new mxPanningManager(this); - pm.border = 30; - - return pm; - }; - - editor.graph.allowAutoPanning = true; - editor.graph.timerAutoScroll = true; - - // Updates the window title after opening new files - const { title } = document; - const funct = function(sender) { - document.title = `${title} - ${sender.getTitle()}`; - }; - - editor.addListener(mxEvent.OPEN, funct); - - // Prints the current root in the window title if the - // current root of the graph changes (drilling). - editor.addListener(mxEvent.ROOT, funct); - funct(editor); - - // Displays version in statusbar - editor.setStatus(`mxGraph ${mxClient.VERSION}`); - - // Shows the application - hideSplash(); - } - } catch (e) { - hideSplash(); - - // Shows an error message if the editor cannot start - mxUtils.alert(`Cannot start application: ${e.message}`); - throw e; // for debugging - } - - return editor; - } -} diff --git a/src/public/editors/layouteditor.html b/src/public/editors/layouteditor.html deleted file mode 100644 index 35a1695e6..000000000 --- a/src/public/editors/layouteditor.html +++ /dev/null @@ -1,34 +0,0 @@ - - - mxGraph Workflow Designer - - - - - - - -
    - -
    -
    - Done -
    - - diff --git a/src/public/editors/processeditor.html b/src/public/editors/processeditor.html deleted file mode 100644 index 6393d284f..000000000 --- a/src/public/editors/processeditor.html +++ /dev/null @@ -1,63 +0,0 @@ - - - mxGraph Process Example - - - - - - - - -
    - -
    -
    - -
    -
    - Done -
    - - diff --git a/src/public/editors/resources/app.txt b/src/public/editors/resources/app.txt deleted file mode 100644 index 6e3f29d36..000000000 --- a/src/public/editors/resources/app.txt +++ /dev/null @@ -1,75 +0,0 @@ -urlHelp=help/index.html -lastSaved=Last Saved -currentFile=Current File -toolbar=Tools -save=Save -print=Print -cut=Cut -copy=Copy -paste=Paste -delete=Delete -undo=Undo -redo=Redo -select=Select -connect=Connect -pan=Pan -zoomIn=Zoom In -zoomOut=Zoom Out -zoom=Zoom -fit=Fit -actualSize=Actual Size -selectAll=Select All -clearSelection=Clear Selection -shape=Shape -format=Format -font=Font -group=Group -ungroup=Ungroup -removeFromParent=Orphan -align=Align -left=Left -right=Right -center=Center -top=Top -middle=Middle -bottom=Bottom -collapse=Collapse -expand=Expand -toBack=Send to back -toFront=Bring to front -enterGroup=Enter group -exitGroup=Exit group -layout=Layout -horizontalTree=Horizontal Tree -verticalTree=Vertical Tree -fillColor=Fill Color -strokeColor=Line Color -gradientColor=Gradient Color -bold=Bold -italic=Italic -fontColor=Font Color -fontSize=Font Size -fontFamily=Font Family -examples=Examples -newDiagram=New Diagram -image=Image -opacity=Opacity -selection=Selection -editStyle=Edit Style -enterStyle=Enter Style -enterColorname=Enter Colorname -enterImageUrl=Enter Image URL -enterOpacity=Enter Opacity (%) -enterFontsize=Enter Fontsize (pt) -enterFontfamily=Enter Fontfamily -toggleRounded=Rounded -toggleShadow=Shadow -toggleOrientation=Orientation -openHref=Open URL -show=Show -exportImage=Export Image -exportSvg=Export SVG -changesLost=All changes will be lost! -swimlanes=Swimlanes -travelBooking=Travel Booking -notAvailable=Not available diff --git a/src/public/editors/resources/app_de.txt b/src/public/editors/resources/app_de.txt deleted file mode 100644 index 921ad78cd..000000000 --- a/src/public/editors/resources/app_de.txt +++ /dev/null @@ -1,73 +0,0 @@ -urlHelp=help/index.html -lastSaved=Zuletzt Gespeichert -currentFile=Aktuelle Datei -toolbar=Tools -save=Speichern -print=Drucken -cut=Ausschneiden -copy=Kopieren -paste=Einfügen -delete=Löschen -undo=Rückgängig -redo=Wiederherstellen -select=Markieren -connect=Verbinden -pan=Verschieben -zoomIn=Hineinzoomen -zoomOut=Herauszoomen -zoom=Zoom -fit=Anpassen -actualSize=Aktuelle Grösse -selectAll=Alle Markieren -clearSelection=Markierung aufheben -shape=Element -format=Format -font=Schrift -group=Gruppieren -ungroup=Gruppe aufheben -removeFromParent=Herauslösen -align=Ausrichten -left=Links -right=Rechts -center=Zentriert -top=Oben -middle=Mitte -bottom=Unten -collapse=Zusammenziehen -expand=Expandieren -toBack=Nach hinten -toFront=Nach vorne -enterGroup=In Gruppe hinein -exitGroup=Aus Gruppe heraus -layout=Anordnen -horizontalTree=Horizontaler Baum -verticalTree=Vertikaler Baum -fillColor=Füllfarbe -strokeColor=Linienfarbe -gradientColor=Farbverlauf -bold=Fett -italic=Kursiv -fontColor=Schriftfarbe -fontSize=Schriftgrösse -fontFamily=Schriftart -examples=Beispiele -newDiagram=Neues Diagramm -image=Bild -opacity=Transparenz -selection=Markierung -editStyle=Style bearbeiten -enterStyle=Style eingeben -enterColorname=Farbname eingeben -enterImageUrl=Bild URL eingeben -enterOpacity=Deckkraft eingeben (%) -enterFontsize=Schriftgrösse eingeben (pt) -enterFontfamily=Schriftart eingeben -toggleRounded=Abgerundet -toggleShadow=Schatten -toggleOrientation=Orientierung -openHref=URL öffnen -show=Anzeigen -exportImage=Exportiere Bild -exportSvg=Exportiere SVG -changesLost=Alle Aenderungen gehen verloren! -notAvailable=Nicht verfügbar diff --git a/src/public/editors/resources/app_zh.txt b/src/public/editors/resources/app_zh.txt deleted file mode 100644 index bd1f18e64..000000000 --- a/src/public/editors/resources/app_zh.txt +++ /dev/null @@ -1,75 +0,0 @@ -urlHelp=help/index.html -lastSaved=上次保存 -currentFile=当前文件 -toolbar=工具栏 -save=保存 -print=打印 -cut=剪切 -copy=复制 -paste=粘贴 -delete=删除 -undo=撤销 -redo=重做 -select=选中 -connect=连接 -pan=平移 -zoomIn=放大 -zoomOut=缩小 -zoom=缩放 -fit=适合大小 -actualSize=实际大小 -selectAll=选中全部 -clearSelection=清空选中 -shape=形状 -format=格式 -font=字体 -group=分组 -ungroup=取消分组 -removeFromParent=从父级移除 -align=对齐 -left=左对齐 -right=右对齐 -center=水平居中 -top=顶端对齐 -middle=垂直居中 -bottom=底端对齐 -collapse=折叠 -expand=展开 -toBack=向后 -toFront=向前 -enterGroup=进入分组 -exitGroup=退出分组 -layout=布局 -horizontalTree=水平树状布局 -verticalTree=垂直树状布局 -fillColor=填充颜色 -strokeColor=线条颜色 -gradientColor=渐变色 -bold=粗体 -italic=斜体 -fontColor=字体颜色 -fontSize=字体大小 -fontFamily=字体 -examples=示例 -newDiagram=新图像 -image=图片 -opacity=不透明度 -selection=已选中 -editStyle=编辑样式 -enterStyle=输入样式 -enterColorname=输入颜色名 -enterImageUrl=输入图片URL -enterOpacity=输入不透明度(%) -enterFontsize=输入字体大小(pt) -enterFontfamily=输入字体 -toggleRounded=圆角 -toggleShadow=阴影 -toggleOrientation=方向 -openHref=打开URL -show=显示 -exportImage=导出图片 -exportSvg=导出SVG -changesLost=所有更改都将丢失! -swimlanes=泳道 -travelBooking=旅游预订 -notAvailable=不可用 diff --git a/src/public/editors/workfloweditor.html b/src/public/editors/workfloweditor.html deleted file mode 100644 index 9185ad64b..000000000 --- a/src/public/editors/workfloweditor.html +++ /dev/null @@ -1,65 +0,0 @@ - - - mxGraph Workflow Example - - - - - - - - - - - - -
    - -
    -
    - -
    -
    - -
    - - diff --git a/src/public/favicon.ico b/src/public/favicon.ico deleted file mode 100644 index 4965832f2..000000000 Binary files a/src/public/favicon.ico and /dev/null differ diff --git a/src/public/images/connector.gif b/src/public/images/connector.gif deleted file mode 100644 index 326e061ea..000000000 Binary files a/src/public/images/connector.gif and /dev/null differ diff --git a/src/public/images/loading.gif b/src/public/images/loading.gif deleted file mode 100644 index 118f4b0df..000000000 Binary files a/src/public/images/loading.gif and /dev/null differ diff --git a/src/public/images/printer.png b/src/public/images/printer.png deleted file mode 100644 index 6004816bc..000000000 Binary files a/src/public/images/printer.png and /dev/null differ diff --git a/src/public/map-background/images/layers-2x.png b/src/public/map-background/images/layers-2x.png deleted file mode 100644 index 200c333dc..000000000 Binary files a/src/public/map-background/images/layers-2x.png and /dev/null differ diff --git a/src/public/map-background/images/layers.png b/src/public/map-background/images/layers.png deleted file mode 100644 index 1a72e5784..000000000 Binary files a/src/public/map-background/images/layers.png and /dev/null differ diff --git a/src/public/map-background/images/marker-icon-2x.png b/src/public/map-background/images/marker-icon-2x.png deleted file mode 100644 index 88f9e5018..000000000 Binary files a/src/public/map-background/images/marker-icon-2x.png and /dev/null differ diff --git a/src/public/map-background/images/marker-icon.png b/src/public/map-background/images/marker-icon.png deleted file mode 100644 index 950edf246..000000000 Binary files a/src/public/map-background/images/marker-icon.png and /dev/null differ diff --git a/src/public/map-background/images/marker-shadow.png b/src/public/map-background/images/marker-shadow.png deleted file mode 100644 index 9fd297953..000000000 Binary files a/src/public/map-background/images/marker-shadow.png and /dev/null differ diff --git a/src/public/map-background/leaflet-src.js b/src/public/map-background/leaflet-src.js deleted file mode 100644 index 87981794f..000000000 --- a/src/public/map-background/leaflet-src.js +++ /dev/null @@ -1,13802 +0,0 @@ -/* @preserve - * Leaflet 1.3.1+Detached: ba6f97fff8647e724e4dfe66d2ed7da11f908989.ba6f97f, a JS library for interactive maps. http://leafletjs.com - * (c) 2010-2017 Vladimir Agafonkin, (c) 2010-2011 CloudMade - */ - -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (factory((global.L = {}))); -}(this, (function (exports) { 'use strict'; - -let version = "1.3.1+HEAD.ba6f97f"; - -/* - * @namespace Util - * - * Various utility functions, used by Leaflet internally. - */ - -let freeze = Object.freeze; -Object.freeze = (obj) => { return obj; }; - -// @function extend(dest: Object, src?: Object): Object -// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut. -function extend(dest) { - var i, j, len, src; - - for (j = 1, len = arguments.length; j < len; j++) { - src = arguments[j]; - for (i in src) { - dest[i] = src[i]; - } - } - return dest; -} - -// @function create(proto: Object, properties?: Object): Object -// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create) -let create = Object.create || (function () { - function F() {} - return function (proto) { - F.prototype = proto; - return new F(); - }; -})(); - -// @function bind(fn: Function, …): Function -// Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). -// Has a `L.bind()` shortcut. -function bind(fn, obj) { - let slice = Array.prototype.slice; - - if (fn.bind) { - return fn.bind.apply(fn, slice.call(arguments, 1)); - } - - let args = slice.call(arguments, 2); - - return function () { - return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments); - }; -} - -// @property lastId: Number -// Last unique ID used by [`stamp()`](#util-stamp) -let lastId = 0; - -// @function stamp(obj: Object): Number -// Returns the unique ID of an object, assigning it one if it doesn't have it. -function stamp(obj) { - /*eslint-disable */ - obj._leaflet_id = obj._leaflet_id || ++lastId; - return obj._leaflet_id; - /* eslint-enable */ -} - -// @function throttle(fn: Function, time: Number, context: Object): Function -// Returns a function which executes function `fn` with the given scope `context` -// (so that the `this` keyword refers to `context` inside `fn`'s code). The function -// `fn` will be called no more than one time per given amount of `time`. The arguments -// received by the bound function will be any arguments passed when binding the -// function, followed by any arguments passed when invoking the bound function. -// Has an `L.throttle` shortcut. -function throttle(fn, time, context) { - var lock, args, wrapperFn, later; - - later = () => { - // reset lock and call if queued - lock = false; - if (args) { - wrapperFn.apply(context, args); - args = false; - } - }; - - wrapperFn = () => { - if (lock) { - // called too soon, queue to call later - args = arguments; - - } else { - // call and lock until later - fn.apply(context, arguments); - setTimeout(later, time); - lock = true; - } - }; - - return wrapperFn; -} - -// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number -// Returns the number `num` modulo `range` in such a way so it lies within -// `range[0]` and `range[1]`. The returned value will be always smaller than -// `range[1]` unless `includeMax` is set to `true`. -function wrapNum(x, range, includeMax) { - let max = range[1], - min = range[0], - d = max - min; - return x === max && includeMax ? x : ((x - min) % d + d) % d + min; -} - -// @function falseFn(): Function -// Returns a function which always returns `false`. -function falseFn() { return false; } - -// @function formatNum(num: Number, digits?: Number): Number -// Returns the number `num` rounded to `digits` decimals, or to 6 decimals by default. -function formatNum(num, digits) { - let pow = Math.pow(10, (digits === undefined ? 6 : digits)); - return Math.round(num * pow) / pow; -} - -// @function trim(str: String): String -// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) -function trim(str) { - return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); -} - -// @function splitWords(str: String): String[] -// Trims and splits the string on whitespace and returns the array of parts. -function splitWords(str) { - return trim(str).split(/\s+/); -} - -// @function setOptions(obj: Object, options: Object): Object -// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut. -function setOptions(obj, options) { - if (!obj.hasOwnProperty('options')) { - obj.options = obj.options ? create(obj.options) : {}; - } - for (var i in options) { - obj.options[i] = options[i]; - } - return obj.options; -} - -// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String -// Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}` -// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will -// be appended at the end. If `uppercase` is `true`, the parameter names will -// be uppercased (e.g. `'?A=foo&B=bar'`) -function getParamString(obj, existingUrl, uppercase) { - let params = []; - for (var i in obj) { - params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); - } - return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); -} - -let templateRe = /\{ *([\w_-]+) *\}/g; - -// @function template(str: String, data: Object): String -// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'` -// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string -// `('Hello foo, bar')`. You can also specify functions instead of strings for -// data values — they will be evaluated passing `data` as an argument. -function template(str, data) { - return str.replace(templateRe, function (str, key) { - let value = data[key]; - - if (value === undefined) { - throw new Error('No value provided for variable ' + str); - - } else if (typeof value === 'function') { - value = value(data); - } - return value; - }); -} - -// @function isArray(obj): Boolean -// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) -let isArray = Array.isArray || function (obj) { - return (Object.prototype.toString.call(obj) === '[object Array]'); -}; - -// @function indexOf(array: Array, el: Object): Number -// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) -function indexOf(array, el) { - for (let i = 0; i < array.length; i++) { - if (array[i] === el) { return i; } - } - return -1; -} - -// @property emptyImageUrl: String -// Data URI string containing a base64-encoded empty GIF image. -// Used as a hack to free memory from unused images on WebKit-powered -// mobile devices (by setting image `src` to this string). -let emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; - -// inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - -function getPrefixed(name) { - return window['webkit' + name] || window['moz' + name] || window['ms' + name]; -} - -let lastTime = 0; - -// fallback for IE 7-8 -function timeoutDefer(fn) { - let time = +new Date(), - timeToCall = Math.max(0, 16 - (time - lastTime)); - - lastTime = time + timeToCall; - return window.setTimeout(fn, timeToCall); -} - -let requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer; -let cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') || - getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); }; - -// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number -// Schedules `fn` to be executed when the browser repaints. `fn` is bound to -// `context` if given. When `immediate` is set, `fn` is called immediately if -// the browser doesn't have native support for -// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame), -// otherwise it's delayed. Returns a request ID that can be used to cancel the request. -function requestAnimFrame(fn, context, immediate) { - if (immediate && requestFn === timeoutDefer) { - fn.call(context); - } else { - return requestFn.call(window, bind(fn, context)); - } -} - -// @function cancelAnimFrame(id: Number): undefined -// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame). -function cancelAnimFrame(id) { - if (id) { - cancelFn.call(window, id); - } -} - - -let Util = (Object.freeze || Object)({ - freeze: freeze, - extend: extend, - create: create, - bind: bind, - lastId: lastId, - stamp: stamp, - throttle: throttle, - wrapNum: wrapNum, - falseFn: falseFn, - formatNum: formatNum, - trim: trim, - splitWords: splitWords, - setOptions: setOptions, - getParamString: getParamString, - template: template, - isArray: isArray, - indexOf: indexOf, - emptyImageUrl: emptyImageUrl, - requestFn: requestFn, - cancelFn: cancelFn, - requestAnimFrame: requestAnimFrame, - cancelAnimFrame: cancelAnimFrame -}); - -// @class Class -// @aka L.Class - -// @section -// @uninheritable - -// Thanks to John Resig and Dean Edwards for inspiration! - -function Class() {} - -Class.extend = (props) => { - - // @function extend(props: Object): Function - // [Extends the current class](#class-inheritance) given the properties to be included. - // Returns a Javascript function that is a class constructor (to be called with `new`). - let NewClass = () => { - - // call the constructor - if (this.initialize) { - this.initialize.apply(this, arguments); - } - - // call all constructor hooks - this.callInitHooks(); - }; - - let parentProto = NewClass.__super__ = this.prototype; - - let proto = create(parentProto); - proto.constructor = NewClass; - - NewClass.prototype = proto; - - // inherit parent's statics - for (var i in this) { - if (this.hasOwnProperty(i) && i !== 'prototype' && i !== '__super__') { - NewClass[i] = this[i]; - } - } - - // mix static properties into the class - if (props.statics) { - extend(NewClass, props.statics); - delete props.statics; - } - - // mix includes into the prototype - if (props.includes) { - checkDeprecatedMixinEvents(props.includes); - extend.apply(null, [proto].concat(props.includes)); - delete props.includes; - } - - // merge options - if (proto.options) { - props.options = extend(create(proto.options), props.options); - } - - // mix given properties into the prototype - extend(proto, props); - - proto._initHooks = []; - - // add method for calling all hooks - proto.callInitHooks = () => { - - if (this._initHooksCalled) { return; } - - if (parentProto.callInitHooks) { - parentProto.callInitHooks.call(this); - } - - this._initHooksCalled = true; - - for (let i = 0, len = proto._initHooks.length; i < len; i++) { - proto._initHooks[i].call(this); - } - }; - - return NewClass; -}; - - -// @function include(properties: Object): this -// [Includes a mixin](#class-includes) into the current class. -Class.include = (props) => { - extend(this.prototype, props); - return this; -}; - -// @function mergeOptions(options: Object): this -// [Merges `options`](#class-options) into the defaults of the class. -Class.mergeOptions = (options) => { - extend(this.prototype.options, options); - return this; -}; - -// @function addInitHook(fn: Function): this -// Adds a [constructor hook](#class-constructor-hooks) to the class. -Class.addInitHook = (fn) => { // (Function) || (String, args...) - let args = Array.prototype.slice.call(arguments, 1); - - let init = typeof fn === 'function' ? fn : function () { - this[fn].apply(this, args); - }; - - this.prototype._initHooks = this.prototype._initHooks || []; - this.prototype._initHooks.push(init); - return this; -}; - -function checkDeprecatedMixinEvents(includes) { - if (typeof L === 'undefined' || !L || !L.Mixin) { return; } - - includes = isArray(includes) ? includes : [includes]; - - for (let i = 0; i < includes.length; i++) { - if (includes[i] === L.Mixin.Events) { - console.warn('Deprecated include of L.Mixin.Events: ' + - 'this property will be removed in future releases, ' + - 'please inherit from L.Evented instead.', new Error().stack); - } - } -} - -/* - * @class Evented - * @aka L.Evented - * @inherits Class - * - * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event). - * - * @example - * - * ```js - * map.on('click', function(e) { - * alert(e.latlng); - * } ); - * ``` - * - * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function: - * - * ```js - * function onClick(e) { ... } - * - * map.on('click', onClick); - * map.off('click', onClick); - * ``` - */ - -let Events = { - /* @method on(type: String, fn: Function, context?: Object): this - * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`). - * - * @alternative - * @method on(eventMap: Object): this - * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` - */ - on: function (types, fn, context) { - - // types can be a map of types/handlers - if (typeof types === 'object') { - for (var type in types) { - // we don't process space-separated events here for performance; - // it's a hot path since Layer uses the on(obj) syntax - this._on(type, types[type], fn); - } - - } else { - // types can be a string of space-separated words - types = splitWords(types); - - for (let i = 0, len = types.length; i < len; i++) { - this._on(types[i], fn, context); - } - } - - return this; - }, - - /* @method off(type: String, fn?: Function, context?: Object): this - * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener. - * - * @alternative - * @method off(eventMap: Object): this - * Removes a set of type/listener pairs. - * - * @alternative - * @method off: this - * Removes all listeners to all events on the object. - */ - off: function (types, fn, context) { - - if (!types) { - // clear all listeners if called without arguments - delete this._events; - - } else if (typeof types === 'object') { - for (var type in types) { - this._off(type, types[type], fn); - } - - } else { - types = splitWords(types); - - for (let i = 0, len = types.length; i < len; i++) { - this._off(types[i], fn, context); - } - } - - return this; - }, - - // attach listener (without syntactic sugar now) - _on: function (type, fn, context) { - this._events = this._events || {}; - - /* get/init listeners for type */ - let typeListeners = this._events[type]; - if (!typeListeners) { - typeListeners = []; - this._events[type] = typeListeners; - } - - if (context === this) { - // Less memory footprint. - context = undefined; - } - let newListener = {fn: fn, ctx: context}, - listeners = typeListeners; - - // check if fn already there - for (let i = 0, len = listeners.length; i < len; i++) { - if (listeners[i].fn === fn && listeners[i].ctx === context) { - return; - } - } - - listeners.push(newListener); - }, - - _off: function (type, fn, context) { - var listeners, - i, - len; - - if (!this._events) { return; } - - listeners = this._events[type]; - - if (!listeners) { - return; - } - - if (!fn) { - // Set all removed listeners to noop so they are not called if remove happens in fire - for (i = 0, len = listeners.length; i < len; i++) { - listeners[i].fn = falseFn; - } - // clear all listeners for a type if function isn't specified - delete this._events[type]; - return; - } - - if (context === this) { - context = undefined; - } - - if (listeners) { - - // find fn and remove it - for (i = 0, len = listeners.length; i < len; i++) { - let l = listeners[i]; - if (l.ctx !== context) { continue; } - if (l.fn === fn) { - - // set the removed listener to noop so that's not called if remove happens in fire - l.fn = falseFn; - - if (this._firingCount) { - /* copy array in case events are being fired */ - this._events[type] = listeners = listeners.slice(); - } - listeners.splice(i, 1); - - return; - } - } - } - }, - - // @method fire(type: String, data?: Object, propagate?: Boolean): this - // Fires an event of the specified type. You can optionally provide an data - // object — the first argument of the listener function will contain its - // properties. The event can optionally be propagated to event parents. - fire: function (type, data, propagate) { - if (!this.listens(type, propagate)) { return this; } - - let event = extend({}, data, { - type: type, - target: this, - sourceTarget: data && data.sourceTarget || this - }); - - if (this._events) { - let listeners = this._events[type]; - - if (listeners) { - this._firingCount = (this._firingCount + 1) || 1; - for (let i = 0, len = listeners.length; i < len; i++) { - let l = listeners[i]; - l.fn.call(l.ctx || this, event); - } - - this._firingCount--; - } - } - - if (propagate) { - // propagate the event to parents (set with addEventParent) - this._propagateEvent(event); - } - - return this; - }, - - // @method listens(type: String): Boolean - // Returns `true` if a particular event type has any listeners attached to it. - listens: function (type, propagate) { - let listeners = this._events && this._events[type]; - if (listeners && listeners.length) { return true; } - - if (propagate) { - // also check parents for listeners if event propagates - for (var id in this._eventParents) { - if (this._eventParents[id].listens(type, propagate)) { return true; } - } - } - return false; - }, - - // @method once(…): this - // Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed. - once: function (types, fn, context) { - - if (typeof types === 'object') { - for (var type in types) { - this.once(type, types[type], fn); - } - return this; - } - - let handler = bind(function () { - this - .off(types, fn, context) - .off(types, handler, context); - }, this); - - // add a listener that's executed once and removed after that - return this - .on(types, fn, context) - .on(types, handler, context); - }, - - // @method addEventParent(obj: Evented): this - // Adds an event parent - an `Evented` that will receive propagated events - addEventParent: function (obj) { - this._eventParents = this._eventParents || {}; - this._eventParents[stamp(obj)] = obj; - return this; - }, - - // @method removeEventParent(obj: Evented): this - // Removes an event parent, so it will stop receiving propagated events - removeEventParent: function (obj) { - if (this._eventParents) { - delete this._eventParents[stamp(obj)]; - } - return this; - }, - - _propagateEvent: function (e) { - for (var id in this._eventParents) { - this._eventParents[id].fire(e.type, extend({ - layer: e.target, - propagatedFrom: e.target - }, e), true); - } - } -}; - -// aliases; we should ditch those eventually - -// @method addEventListener(…): this -// Alias to [`on(…)`](#evented-on) -Events.addEventListener = Events.on; - -// @method removeEventListener(…): this -// Alias to [`off(…)`](#evented-off) - -// @method clearAllEventListeners(…): this -// Alias to [`off()`](#evented-off) -Events.removeEventListener = Events.clearAllEventListeners = Events.off; - -// @method addOneTimeEventListener(…): this -// Alias to [`once(…)`](#evented-once) -Events.addOneTimeEventListener = Events.once; - -// @method fireEvent(…): this -// Alias to [`fire(…)`](#evented-fire) -Events.fireEvent = Events.fire; - -// @method hasEventListeners(…): Boolean -// Alias to [`listens(…)`](#evented-listens) -Events.hasEventListeners = Events.listens; - -let Evented = Class.extend(Events); - -/* - * @class Point - * @aka L.Point - * - * Represents a point with `x` and `y` coordinates in pixels. - * - * @example - * - * ```js - * let point = L.point(200, 300); - * ``` - * - * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent: - * - * ```js - * map.panBy([200, 300]); - * map.panBy(L.point(200, 300)); - * ``` - * - * Note that `Point` does not inherit from Leafet's `Class` object, - * which means new classes can't inherit from it, and new methods - * can't be added to it with the `include` function. - */ - -function Point(x, y, round) { - // @property x: Number; The `x` coordinate of the point - this.x = (round ? Math.round(x) : x); - // @property y: Number; The `y` coordinate of the point - this.y = (round ? Math.round(y) : y); -} - -let trunc = Math.trunc || function (v) { - return v > 0 ? Math.floor(v) : Math.ceil(v); -}; - -Point.prototype = { - - // @method clone(): Point - // Returns a copy of the current point. - clone: function () { - return new Point(this.x, this.y); - }, - - // @method add(otherPoint: Point): Point - // Returns the result of addition of the current and the given points. - add: function (point) { - // non-destructive, returns a new point - return this.clone()._add(toPoint(point)); - }, - - _add: function (point) { - // destructive, used directly for performance in situations where it's safe to modify existing point - this.x += point.x; - this.y += point.y; - return this; - }, - - // @method subtract(otherPoint: Point): Point - // Returns the result of subtraction of the given point from the current. - subtract: function (point) { - return this.clone()._subtract(toPoint(point)); - }, - - _subtract: function (point) { - this.x -= point.x; - this.y -= point.y; - return this; - }, - - // @method divideBy(num: Number): Point - // Returns the result of division of the current point by the given number. - divideBy: function (num) { - return this.clone()._divideBy(num); - }, - - _divideBy: function (num) { - this.x /= num; - this.y /= num; - return this; - }, - - // @method multiplyBy(num: Number): Point - // Returns the result of multiplication of the current point by the given number. - multiplyBy: function (num) { - return this.clone()._multiplyBy(num); - }, - - _multiplyBy: function (num) { - this.x *= num; - this.y *= num; - return this; - }, - - // @method scaleBy(scale: Point): Point - // Multiply each coordinate of the current point by each coordinate of - // `scale`. In linear algebra terms, multiply the point by the - // [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation) - // defined by `scale`. - scaleBy: function (point) { - return new Point(this.x * point.x, this.y * point.y); - }, - - // @method unscaleBy(scale: Point): Point - // Inverse of `scaleBy`. Divide each coordinate of the current point by - // each coordinate of `scale`. - unscaleBy: function (point) { - return new Point(this.x / point.x, this.y / point.y); - }, - - // @method round(): Point - // Returns a copy of the current point with rounded coordinates. - round: function () { - return this.clone()._round(); - }, - - _round: function () { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; - }, - - // @method floor(): Point - // Returns a copy of the current point with floored coordinates (rounded down). - floor: function () { - return this.clone()._floor(); - }, - - _floor: function () { - this.x = Math.floor(this.x); - this.y = Math.floor(this.y); - return this; - }, - - // @method ceil(): Point - // Returns a copy of the current point with ceiled coordinates (rounded up). - ceil: function () { - return this.clone()._ceil(); - }, - - _ceil: function () { - this.x = Math.ceil(this.x); - this.y = Math.ceil(this.y); - return this; - }, - - // @method trunc(): Point - // Returns a copy of the current point with truncated coordinates (rounded towards zero). - trunc: function () { - return this.clone()._trunc(); - }, - - _trunc: function () { - this.x = trunc(this.x); - this.y = trunc(this.y); - return this; - }, - - // @method distanceTo(otherPoint: Point): Number - // Returns the cartesian distance between the current and the given points. - distanceTo: function (point) { - point = toPoint(point); - - let x = point.x - this.x, - y = point.y - this.y; - - return Math.sqrt(x * x + y * y); - }, - - // @method equals(otherPoint: Point): Boolean - // Returns `true` if the given point has the same coordinates. - equals: function (point) { - point = toPoint(point); - - return point.x === this.x && - point.y === this.y; - }, - - // @method contains(otherPoint: Point): Boolean - // Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values). - contains: function (point) { - point = toPoint(point); - - return Math.abs(point.x) <= Math.abs(this.x) && - Math.abs(point.y) <= Math.abs(this.y); - }, - - // @method toString(): String - // Returns a string representation of the point for debugging purposes. - toString: function () { - return 'Point(' + - formatNum(this.x) + ', ' + - formatNum(this.y) + ')'; - } -}; - -// @factory L.point(x: Number, y: Number, round?: Boolean) -// Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values. - -// @alternative -// @factory L.point(coords: Number[]) -// Expects an array of the form `[x, y]` instead. - -// @alternative -// @factory L.point(coords: Object) -// Expects a plain object of the form `{x: Number, y: Number}` instead. -function toPoint(x, y, round) { - if (x instanceof Point) { - return x; - } - if (isArray(x)) { - return new Point(x[0], x[1]); - } - if (x === undefined || x === null) { - return x; - } - if (typeof x === 'object' && 'x' in x && 'y' in x) { - return new Point(x.x, x.y); - } - return new Point(x, y, round); -} - -/* - * @class Bounds - * @aka L.Bounds - * - * Represents a rectangular area in pixel coordinates. - * - * @example - * - * ```js - * var p1 = L.point(10, 10), - * p2 = L.point(40, 60), - * bounds = L.bounds(p1, p2); - * ``` - * - * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this: - * - * ```js - * otherBounds.intersects([[10, 10], [40, 60]]); - * ``` - * - * Note that `Bounds` does not inherit from Leafet's `Class` object, - * which means new classes can't inherit from it, and new methods - * can't be added to it with the `include` function. - */ - -function Bounds(a, b) { - if (!a) { return; } - - let points = b ? [a, b] : a; - - for (let i = 0, len = points.length; i < len; i++) { - this.extend(points[i]); - } -} - -Bounds.prototype = { - // @method extend(point: Point): this - // Extends the bounds to contain the given point. - extend: function (point) { // (Point) - point = toPoint(point); - - // @property min: Point - // The top left corner of the rectangle. - // @property max: Point - // The bottom right corner of the rectangle. - if (!this.min && !this.max) { - this.min = point.clone(); - this.max = point.clone(); - } else { - this.min.x = Math.min(point.x, this.min.x); - this.max.x = Math.max(point.x, this.max.x); - this.min.y = Math.min(point.y, this.min.y); - this.max.y = Math.max(point.y, this.max.y); - } - return this; - }, - - // @method getCenter(round?: Boolean): Point - // Returns the center point of the bounds. - getCenter: function (round) { - return new Point( - (this.min.x + this.max.x) / 2, - (this.min.y + this.max.y) / 2, round); - }, - - // @method getBottomLeft(): Point - // Returns the bottom-left point of the bounds. - getBottomLeft: function () { - return new Point(this.min.x, this.max.y); - }, - - // @method getTopRight(): Point - // Returns the top-right point of the bounds. - getTopRight: function () { // -> Point - return new Point(this.max.x, this.min.y); - }, - - // @method getTopLeft(): Point - // Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)). - getTopLeft: function () { - return this.min; // left, top - }, - - // @method getBottomRight(): Point - // Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)). - getBottomRight: function () { - return this.max; // right, bottom - }, - - // @method getSize(): Point - // Returns the size of the given bounds - getSize: function () { - return this.max.subtract(this.min); - }, - - // @method contains(otherBounds: Bounds): Boolean - // Returns `true` if the rectangle contains the given one. - // @alternative - // @method contains(point: Point): Boolean - // Returns `true` if the rectangle contains the given point. - contains: function (obj) { - var min, max; - - if (typeof obj[0] === 'number' || obj instanceof Point) { - obj = toPoint(obj); - } else { - obj = toBounds(obj); - } - - if (obj instanceof Bounds) { - min = obj.min; - max = obj.max; - } else { - min = max = obj; - } - - return (min.x >= this.min.x) && - (max.x <= this.max.x) && - (min.y >= this.min.y) && - (max.y <= this.max.y); - }, - - // @method intersects(otherBounds: Bounds): Boolean - // Returns `true` if the rectangle intersects the given bounds. Two bounds - // intersect if they have at least one point in common. - intersects: function (bounds) { // (Bounds) -> Boolean - bounds = toBounds(bounds); - - let min = this.min, - max = this.max, - min2 = bounds.min, - max2 = bounds.max, - xIntersects = (max2.x >= min.x) && (min2.x <= max.x), - yIntersects = (max2.y >= min.y) && (min2.y <= max.y); - - return xIntersects && yIntersects; - }, - - // @method overlaps(otherBounds: Bounds): Boolean - // Returns `true` if the rectangle overlaps the given bounds. Two bounds - // overlap if their intersection is an area. - overlaps: function (bounds) { // (Bounds) -> Boolean - bounds = toBounds(bounds); - - let min = this.min, - max = this.max, - min2 = bounds.min, - max2 = bounds.max, - xOverlaps = (max2.x > min.x) && (min2.x < max.x), - yOverlaps = (max2.y > min.y) && (min2.y < max.y); - - return xOverlaps && yOverlaps; - }, - - isValid: function () { - return !!(this.min && this.max); - } -}; - - -// @factory L.bounds(corner1: Point, corner2: Point) -// Creates a Bounds object from two corners coordinate pairs. -// @alternative -// @factory L.bounds(points: Point[]) -// Creates a Bounds object from the given array of points. -function toBounds(a, b) { - if (!a || a instanceof Bounds) { - return a; - } - return new Bounds(a, b); -} - -/* - * @class LatLngBounds - * @aka L.LatLngBounds - * - * Represents a rectangular geographical area on a map. - * - * @example - * - * ```js - * var corner1 = L.latLng(40.712, -74.227), - * corner2 = L.latLng(40.774, -74.125), - * bounds = L.latLngBounds(corner1, corner2); - * ``` - * - * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this: - * - * ```js - * map.fitBounds([ - * [40.712, -74.227], - * [40.774, -74.125] - * ]); - * ``` - * - * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range. - * - * Note that `LatLngBounds` does not inherit from Leafet's `Class` object, - * which means new classes can't inherit from it, and new methods - * can't be added to it with the `include` function. - */ - -function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[]) - if (!corner1) { return; } - - let latlngs = corner2 ? [corner1, corner2] : corner1; - - for (let i = 0, len = latlngs.length; i < len; i++) { - this.extend(latlngs[i]); - } -} - -LatLngBounds.prototype = { - - // @method extend(latlng: LatLng): this - // Extend the bounds to contain the given point - - // @alternative - // @method extend(otherBounds: LatLngBounds): this - // Extend the bounds to contain the given bounds - extend: function (obj) { - let sw = this._southWest, - ne = this._northEast, - sw2, ne2; - - if (obj instanceof LatLng) { - sw2 = obj; - ne2 = obj; - - } else if (obj instanceof LatLngBounds) { - sw2 = obj._southWest; - ne2 = obj._northEast; - - if (!sw2 || !ne2) { return this; } - - } else { - return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this; - } - - if (!sw && !ne) { - this._southWest = new LatLng(sw2.lat, sw2.lng); - this._northEast = new LatLng(ne2.lat, ne2.lng); - } else { - sw.lat = Math.min(sw2.lat, sw.lat); - sw.lng = Math.min(sw2.lng, sw.lng); - ne.lat = Math.max(ne2.lat, ne.lat); - ne.lng = Math.max(ne2.lng, ne.lng); - } - - return this; - }, - - // @method pad(bufferRatio: Number): LatLngBounds - // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction. - // For example, a ratio of 0.5 extends the bounds by 50% in each direction. - // Negative values will retract the bounds. - pad: function (bufferRatio) { - let sw = this._southWest, - ne = this._northEast, - heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, - widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio; - - return new LatLngBounds( - new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer), - new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)); - }, - - // @method getCenter(): LatLng - // Returns the center point of the bounds. - getCenter: function () { - return new LatLng( - (this._southWest.lat + this._northEast.lat) / 2, - (this._southWest.lng + this._northEast.lng) / 2); - }, - - // @method getSouthWest(): LatLng - // Returns the south-west point of the bounds. - getSouthWest: function () { - return this._southWest; - }, - - // @method getNorthEast(): LatLng - // Returns the north-east point of the bounds. - getNorthEast: function () { - return this._northEast; - }, - - // @method getNorthWest(): LatLng - // Returns the north-west point of the bounds. - getNorthWest: function () { - return new LatLng(this.getNorth(), this.getWest()); - }, - - // @method getSouthEast(): LatLng - // Returns the south-east point of the bounds. - getSouthEast: function () { - return new LatLng(this.getSouth(), this.getEast()); - }, - - // @method getWest(): Number - // Returns the west longitude of the bounds - getWest: function () { - return this._southWest.lng; - }, - - // @method getSouth(): Number - // Returns the south latitude of the bounds - getSouth: function () { - return this._southWest.lat; - }, - - // @method getEast(): Number - // Returns the east longitude of the bounds - getEast: function () { - return this._northEast.lng; - }, - - // @method getNorth(): Number - // Returns the north latitude of the bounds - getNorth: function () { - return this._northEast.lat; - }, - - // @method contains(otherBounds: LatLngBounds): Boolean - // Returns `true` if the rectangle contains the given one. - - // @alternative - // @method contains (latlng: LatLng): Boolean - // Returns `true` if the rectangle contains the given point. - contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean - if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) { - obj = toLatLng(obj); - } else { - obj = toLatLngBounds(obj); - } - - let sw = this._southWest, - ne = this._northEast, - sw2, ne2; - - if (obj instanceof LatLngBounds) { - sw2 = obj.getSouthWest(); - ne2 = obj.getNorthEast(); - } else { - sw2 = ne2 = obj; - } - - return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && - (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); - }, - - // @method intersects(otherBounds: LatLngBounds): Boolean - // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common. - intersects: function (bounds) { - bounds = toLatLngBounds(bounds); - - let sw = this._southWest, - ne = this._northEast, - sw2 = bounds.getSouthWest(), - ne2 = bounds.getNorthEast(), - - latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), - lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); - - return latIntersects && lngIntersects; - }, - - // @method overlaps(otherBounds: Bounds): Boolean - // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area. - overlaps: function (bounds) { - bounds = toLatLngBounds(bounds); - - let sw = this._southWest, - ne = this._northEast, - sw2 = bounds.getSouthWest(), - ne2 = bounds.getNorthEast(), - - latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat), - lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng); - - return latOverlaps && lngOverlaps; - }, - - // @method toBBoxString(): String - // Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data. - toBBoxString: function () { - return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(','); - }, - - // @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean - // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number. - equals: function (bounds, maxMargin) { - if (!bounds) { return false; } - - bounds = toLatLngBounds(bounds); - - return this._southWest.equals(bounds.getSouthWest(), maxMargin) && - this._northEast.equals(bounds.getNorthEast(), maxMargin); - }, - - // @method isValid(): Boolean - // Returns `true` if the bounds are properly initialized. - isValid: function () { - return !!(this._southWest && this._northEast); - } -}; - -// TODO International date line? - -// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng) -// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle. - -// @alternative -// @factory L.latLngBounds(latlngs: LatLng[]) -// Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds). -function toLatLngBounds(a, b) { - if (a instanceof LatLngBounds) { - return a; - } - return new LatLngBounds(a, b); -} - -/* @class LatLng - * @aka L.LatLng - * - * Represents a geographical point with a certain latitude and longitude. - * - * @example - * - * ``` - * let latlng = L.latLng(50.5, 30.5); - * ``` - * - * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent: - * - * ``` - * map.panTo([50, 30]); - * map.panTo({lon: 30, lat: 50}); - * map.panTo({lat: 50, lng: 30}); - * map.panTo(L.latLng(50, 30)); - * ``` - * - * Note that `LatLng` does not inherit from Leafet's `Class` object, - * which means new classes can't inherit from it, and new methods - * can't be added to it with the `include` function. - */ - -function LatLng(lat, lng, alt) { - if (isNaN(lat) || isNaN(lng)) { - throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')'); - } - - // @property lat: Number - // Latitude in degrees - this.lat = +lat; - - // @property lng: Number - // Longitude in degrees - this.lng = +lng; - - // @property alt: Number - // Altitude in meters (optional) - if (alt !== undefined) { - this.alt = +alt; - } -} - -LatLng.prototype = { - // @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean - // Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number. - equals: function (obj, maxMargin) { - if (!obj) { return false; } - - obj = toLatLng(obj); - - let margin = Math.max( - Math.abs(this.lat - obj.lat), - Math.abs(this.lng - obj.lng)); - - return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin); - }, - - // @method toString(): String - // Returns a string representation of the point (for debugging purposes). - toString: function (precision) { - return 'LatLng(' + - formatNum(this.lat, precision) + ', ' + - formatNum(this.lng, precision) + ')'; - }, - - // @method distanceTo(otherLatLng: LatLng): Number - // Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines). - distanceTo: function (other) { - return Earth.distance(this, toLatLng(other)); - }, - - // @method wrap(): LatLng - // Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees. - wrap: function () { - return Earth.wrapLatLng(this); - }, - - // @method toBounds(sizeInMeters: Number): LatLngBounds - // Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`. - toBounds: function (sizeInMeters) { - let latAccuracy = 180 * sizeInMeters / 40075017, - lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat); - - return toLatLngBounds( - [this.lat - latAccuracy, this.lng - lngAccuracy], - [this.lat + latAccuracy, this.lng + lngAccuracy]); - }, - - clone: function () { - return new LatLng(this.lat, this.lng, this.alt); - } -}; - - - -// @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng -// Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude). - -// @alternative -// @factory L.latLng(coords: Array): LatLng -// Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead. - -// @alternative -// @factory L.latLng(coords: Object): LatLng -// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead. - -function toLatLng(a, b, c) { - if (a instanceof LatLng) { - return a; - } - if (isArray(a) && typeof a[0] !== 'object') { - if (a.length === 3) { - return new LatLng(a[0], a[1], a[2]); - } - if (a.length === 2) { - return new LatLng(a[0], a[1]); - } - return null; - } - if (a === undefined || a === null) { - return a; - } - if (typeof a === 'object' && 'lat' in a) { - return new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt); - } - if (b === undefined) { - return null; - } - return new LatLng(a, b, c); -} - -/* - * @namespace CRS - * @crs L.CRS.Base - * Object that defines coordinate reference systems for projecting - * geographical points into pixel (screen) coordinates and back (and to - * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See - * [spatial reference system](http://en.wikipedia.org/wiki/Coordinate_reference_system). - * - * Leaflet defines the most usual CRSs by default. If you want to use a - * CRS not defined by default, take a look at the - * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin. - * - * Note that the CRS instances do not inherit from Leafet's `Class` object, - * and can't be instantiated. Also, new classes can't inherit from them, - * and methods can't be added to them with the `include` function. - */ - -let CRS = { - // @method latLngToPoint(latlng: LatLng, zoom: Number): Point - // Projects geographical coordinates into pixel coordinates for a given zoom. - latLngToPoint: function (latlng, zoom) { - let projectedPoint = this.projection.project(latlng), - scale = this.scale(zoom); - - return this.transformation._transform(projectedPoint, scale); - }, - - // @method pointToLatLng(point: Point, zoom: Number): LatLng - // The inverse of `latLngToPoint`. Projects pixel coordinates on a given - // zoom into geographical coordinates. - pointToLatLng: function (point, zoom) { - let scale = this.scale(zoom), - untransformedPoint = this.transformation.untransform(point, scale); - - return this.projection.unproject(untransformedPoint); - }, - - // @method project(latlng: LatLng): Point - // Projects geographical coordinates into coordinates in units accepted for - // this CRS (e.g. meters for EPSG:3857, for passing it to WMS services). - project: function (latlng) { - return this.projection.project(latlng); - }, - - // @method unproject(point: Point): LatLng - // Given a projected coordinate returns the corresponding LatLng. - // The inverse of `project`. - unproject: function (point) { - return this.projection.unproject(point); - }, - - // @method scale(zoom: Number): Number - // Returns the scale used when transforming projected coordinates into - // pixel coordinates for a particular zoom. For example, it returns - // `256 * 2^zoom` for Mercator-based CRS. - scale: function (zoom) { - return 256 * Math.pow(2, zoom); - }, - - // @method zoom(scale: Number): Number - // Inverse of `scale()`, returns the zoom level corresponding to a scale - // factor of `scale`. - zoom: function (scale) { - return Math.log(scale / 256) / Math.LN2; - }, - - // @method getProjectedBounds(zoom: Number): Bounds - // Returns the projection's bounds scaled and transformed for the provided `zoom`. - getProjectedBounds: function (zoom) { - if (this.infinite) { return null; } - - let b = this.projection.bounds, - s = this.scale(zoom), - min = this.transformation.transform(b.min, s), - max = this.transformation.transform(b.max, s); - - return new Bounds(min, max); - }, - - // @method distance(latlng1: LatLng, latlng2: LatLng): Number - // Returns the distance between two geographical coordinates. - - // @property code: String - // Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`) - // - // @property wrapLng: Number[] - // An array of two numbers defining whether the longitude (horizontal) coordinate - // axis wraps around a given range and how. Defaults to `[-180, 180]` in most - // geographical CRSs. If `undefined`, the longitude axis does not wrap around. - // - // @property wrapLat: Number[] - // Like `wrapLng`, but for the latitude (vertical) axis. - - // wrapLng: [min, max], - // wrapLat: [min, max], - - // @property infinite: Boolean - // If true, the coordinate space will be unbounded (infinite in both axes) - infinite: false, - - // @method wrapLatLng(latlng: LatLng): LatLng - // Returns a `LatLng` where lat and lng has been wrapped according to the - // CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds. - wrapLatLng: function (latlng) { - let lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng, - lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat, - alt = latlng.alt; - - return new LatLng(lat, lng, alt); - }, - - // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds - // Returns a `LatLngBounds` with the same size as the given one, ensuring - // that its center is within the CRS's bounds. - // Only accepts actual `L.LatLngBounds` instances, not arrays. - wrapLatLngBounds: function (bounds) { - let center = bounds.getCenter(), - newCenter = this.wrapLatLng(center), - latShift = center.lat - newCenter.lat, - lngShift = center.lng - newCenter.lng; - - if (latShift === 0 && lngShift === 0) { - return bounds; - } - - let sw = bounds.getSouthWest(), - ne = bounds.getNorthEast(), - newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift), - newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift); - - return new LatLngBounds(newSw, newNe); - } -}; - -/* - * @namespace CRS - * @crs L.CRS.Earth - * - * Serves as the base for CRS that are global such that they cover the earth. - * Can only be used as the base for other CRS and cannot be used directly, - * since it does not have a `code`, `projection` or `transformation`. `distance()` returns - * meters. - */ - -let Earth = extend({}, CRS, { - wrapLng: [-180, 180], - - // Mean Earth Radius, as recommended for use by - // the International Union of Geodesy and Geophysics, - // see http://rosettacode.org/wiki/Haversine_formula - R: 6371000, - - // distance between two geographical points using spherical law of cosines approximation - distance: function (latlng1, latlng2) { - let rad = Math.PI / 180, - lat1 = latlng1.lat * rad, - lat2 = latlng2.lat * rad, - sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2), - sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2), - a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon, - c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - return this.R * c; - } -}); - -/* - * @namespace Projection - * @projection L.Projection.SphericalMercator - * - * Spherical Mercator projection — the most common projection for online maps, - * used by almost all free and commercial tile providers. Assumes that Earth is - * a sphere. Used by the `EPSG:3857` CRS. - */ - -let SphericalMercator = { - - R: 6378137, - MAX_LATITUDE: 85.0511287798, - - project: function (latlng) { - let d = Math.PI / 180, - max = this.MAX_LATITUDE, - lat = Math.max(Math.min(max, latlng.lat), -max), - sin = Math.sin(lat * d); - - return new Point( - this.R * latlng.lng * d, - this.R * Math.log((1 + sin) / (1 - sin)) / 2); - }, - - unproject: function (point) { - let d = 180 / Math.PI; - - return new LatLng( - (2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d, - point.x * d / this.R); - }, - - bounds: (function () { - let d = 6378137 * Math.PI; - return new Bounds([-d, -d], [d, d]); - })() -}; - -/* - * @class Transformation - * @aka L.Transformation - * - * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d` - * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing - * the reverse. Used by Leaflet in its projections code. - * - * @example - * - * ```js - * let transformation = L.transformation(2, 5, -1, 10), - * p = L.point(1, 2), - * p2 = transformation.transform(p), // L.point(7, 8) - * p3 = transformation.untransform(p2); // L.point(1, 2) - * ``` - */ - - -// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number) -// Creates a `Transformation` object with the given coefficients. -function Transformation(a, b, c, d) { - if (isArray(a)) { - // use array properties - this._a = a[0]; - this._b = a[1]; - this._c = a[2]; - this._d = a[3]; - return; - } - this._a = a; - this._b = b; - this._c = c; - this._d = d; -} - -Transformation.prototype = { - // @method transform(point: Point, scale?: Number): Point - // Returns a transformed point, optionally multiplied by the given scale. - // Only accepts actual `L.Point` instances, not arrays. - transform: function (point, scale) { // (Point, Number) -> Point - return this._transform(point.clone(), scale); - }, - - // destructive transform (faster) - _transform: function (point, scale) { - scale = scale || 1; - point.x = scale * (this._a * point.x + this._b); - point.y = scale * (this._c * point.y + this._d); - return point; - }, - - // @method untransform(point: Point, scale?: Number): Point - // Returns the reverse transformation of the given point, optionally divided - // by the given scale. Only accepts actual `L.Point` instances, not arrays. - untransform: function (point, scale) { - scale = scale || 1; - return new Point( - (point.x / scale - this._b) / this._a, - (point.y / scale - this._d) / this._c); - } -}; - -// factory L.transformation(a: Number, b: Number, c: Number, d: Number) - -// @factory L.transformation(a: Number, b: Number, c: Number, d: Number) -// Instantiates a Transformation object with the given coefficients. - -// @alternative -// @factory L.transformation(coefficients: Array): Transformation -// Expects an coefficients array of the form -// `[a: Number, b: Number, c: Number, d: Number]`. - -function toTransformation(a, b, c, d) { - return new Transformation(a, b, c, d); -} - -/* - * @namespace CRS - * @crs L.CRS.EPSG3857 - * - * The most common CRS for online maps, used by almost all free and commercial - * tile providers. Uses Spherical Mercator projection. Set in by default in - * Map's `crs` option. - */ - -var EPSG3857 = extend({}, Earth, { - code: 'EPSG:3857', - projection: SphericalMercator, - - transformation: (function () { - let scale = 0.5 / (Math.PI * SphericalMercator.R); - return toTransformation(scale, 0.5, -scale, 0.5); - }()) -}); - -var EPSG900913 = extend({}, EPSG3857, { - code: 'EPSG:900913' -}); - -// @namespace SVG; @section -// There are several static functions which can be called without instantiating L.SVG: - -// @function create(name: String): SVGElement -// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement), -// corresponding to the class name passed. For example, using 'line' will return -// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement). -function svgCreate(name) { - return document.createElementNS('http://www.w3.org/2000/svg', name); -} - -// @function pointsToPath(rings: Point[], closed: Boolean): String -// Generates a SVG path string for multiple rings, with each ring turning -// into "M..L..L.." instructions -function pointsToPath(rings, closed) { - let str = '', - i, j, len, len2, points, p; - - for (i = 0, len = rings.length; i < len; i++) { - points = rings[i]; - - for (j = 0, len2 = points.length; j < len2; j++) { - p = points[j]; - str += (j ? 'L' : 'M') + p.x + ' ' + p.y; - } - - // closes the ring for polygons; "x" is VML syntax - str += closed ? (svg ? 'z' : 'x') : ''; - } - - // SVG complains about empty path strings - return str || 'M0 0'; -} - -/* - * @namespace Browser - * @aka L.Browser - * - * A namespace with static properties for browser/feature detection used by Leaflet internally. - * - * @example - * - * ```js - * if (L.Browser.ielt9) { - * alert('Upgrade your browser, dude!'); - * } - * ``` - */ - -var style$1 = document.documentElement.style; - -// @property ie: Boolean; `true` for all Internet Explorer versions (not Edge). -let ie = 'ActiveXObject' in window; - -// @property ielt9: Boolean; `true` for Internet Explorer versions less than 9. -var ielt9 = ie && !document.addEventListener; - -// @property edge: Boolean; `true` for the Edge web browser. -let edge = 'msLaunchUri' in navigator && !('documentMode' in document); - -// @property webkit: Boolean; -// `true` for webkit-based browsers like Chrome and Safari (including mobile versions). -let webkit = userAgentContains('webkit'); - -// @property android: Boolean -// `true` for any browser running on an Android platform. -let android = userAgentContains('android'); - -// @property android23: Boolean; `true` for browsers running on Android 2 or Android 3. -var android23 = userAgentContains('android 2') || userAgentContains('android 3'); - -/* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */ -let webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit -// @property androidStock: Boolean; `true` for the Android stock browser (i.e. not Chrome) -let androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window); - -// @property opera: Boolean; `true` for the Opera browser -let opera = !!window.opera; - -// @property chrome: Boolean; `true` for the Chrome browser. -let chrome = userAgentContains('chrome'); - -// @property gecko: Boolean; `true` for gecko-based browsers like Firefox. -let gecko = userAgentContains('gecko') && !webkit && !opera && !ie; - -// @property safari: Boolean; `true` for the Safari browser. -let safari = !chrome && userAgentContains('safari'); - -let phantom = userAgentContains('phantom'); - -// @property opera12: Boolean -// `true` for the Opera browser supporting CSS transforms (version 12 or later). -var opera12 = 'OTransition' in style$1; - -// @property win: Boolean; `true` when the browser is running in a Windows platform -let win = navigator.platform.indexOf('Win') === 0; - -// @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms. -var ie3d = ie && ('transition' in style$1); - -// @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms. -var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23; - -// @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms. -var gecko3d = 'MozPerspective' in style$1; - -// @property any3d: Boolean -// `true` for all browsers supporting CSS transforms. -var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom; - -// @property mobile: Boolean; `true` for all browsers running in a mobile device. -let mobile = typeof orientation !== 'undefined' || userAgentContains('mobile'); - -// @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device. -let mobileWebkit = mobile && webkit; - -// @property mobileWebkit3d: Boolean -// `true` for all webkit-based browsers in a mobile device supporting CSS transforms. -var mobileWebkit3d = mobile && webkit3d; - -// @property msPointer: Boolean -// `true` for browsers implementing the Microsoft touch events model (notably IE10). -let msPointer = !window.PointerEvent && window.MSPointerEvent; - -// @property pointer: Boolean -// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx). -let pointer = !!(window.PointerEvent || msPointer); - -// @property touch: Boolean -// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events). -// This does not necessarily mean that the browser is running in a computer with -// a touchscreen, it only means that the browser is capable of understanding -// touch events. -let touch = !window.L_NO_TOUCH && (pointer || 'ontouchstart' in window || - (window.DocumentTouch && document instanceof window.DocumentTouch)); - -// @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device. -let mobileOpera = mobile && opera; - -// @property mobileGecko: Boolean -// `true` for gecko-based browsers running in a mobile device. -let mobileGecko = mobile && gecko; - -// @property retina: Boolean -// `true` for browsers on a high-resolution "retina" screen. -let retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1; - - -// @property canvas: Boolean -// `true` when the browser supports [``](https://developer.mozilla.org/docs/Web/API/Canvas_API). -let canvas = (function () { - return !!document.createElement('canvas').getContext; -}()); - -// @property svg: Boolean -// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG). -let svg = !!(document.createElementNS && svgCreate('svg').createSVGRect); - -// @property vml: Boolean -// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language). -let vml = !svg && (function () { - try { - let div = document.createElement('div'); - div.innerHTML = ''; - - let shape = div.firstChild; - shape.style.behavior = 'url(#default#VML)'; - - return shape && (typeof shape.adj === 'object'); - - } catch (e) { - return false; - } -}()); - - -function userAgentContains(str) { - return navigator.userAgent.toLowerCase().indexOf(str) >= 0; -} - - -let Browser = (Object.freeze || Object)({ - ie: ie, - ielt9: ielt9, - edge: edge, - webkit: webkit, - android: android, - android23: android23, - androidStock: androidStock, - opera: opera, - chrome: chrome, - gecko: gecko, - safari: safari, - phantom: phantom, - opera12: opera12, - win: win, - ie3d: ie3d, - webkit3d: webkit3d, - gecko3d: gecko3d, - any3d: any3d, - mobile: mobile, - mobileWebkit: mobileWebkit, - mobileWebkit3d: mobileWebkit3d, - msPointer: msPointer, - pointer: pointer, - touch: touch, - mobileOpera: mobileOpera, - mobileGecko: mobileGecko, - retina: retina, - canvas: canvas, - svg: svg, - vml: vml -}); - -/* - * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices. - */ - - -let POINTER_DOWN = msPointer ? 'MSPointerDown' : 'pointerdown'; -let POINTER_MOVE = msPointer ? 'MSPointerMove' : 'pointermove'; -let POINTER_UP = msPointer ? 'MSPointerUp' : 'pointerup'; -let POINTER_CANCEL = msPointer ? 'MSPointerCancel' : 'pointercancel'; -let TAG_WHITE_LIST = ['INPUT', 'SELECT', 'OPTION']; - -let _pointers = {}; -let _pointerDocListener = false; - -// DomEvent.DoubleTap needs to know about this -let _pointersCount = 0; - -// Provides a touch events wrapper for (ms)pointer events. -// ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890 - -function addPointerListener(obj, type, handler, id) { - if (type === 'touchstart') { - _addPointerStart(obj, handler, id); - - } else if (type === 'touchmove') { - _addPointerMove(obj, handler, id); - - } else if (type === 'touchend') { - _addPointerEnd(obj, handler, id); - } - - return this; -} - -function removePointerListener(obj, type, id) { - let handler = obj['_leaflet_' + type + id]; - - if (type === 'touchstart') { - obj.removeEventListener(POINTER_DOWN, handler, false); - - } else if (type === 'touchmove') { - obj.removeEventListener(POINTER_MOVE, handler, false); - - } else if (type === 'touchend') { - obj.removeEventListener(POINTER_UP, handler, false); - obj.removeEventListener(POINTER_CANCEL, handler, false); - } - - return this; -} - -function _addPointerStart(obj, handler, id) { - let onDown = bind(function (e) { - if (e.pointerType !== 'mouse' && e.MSPOINTER_TYPE_MOUSE && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) { - // In IE11, some touch events needs to fire for form controls, or - // the controls will stop working. We keep a whitelist of tag names that - // need these events. For other target tags, we prevent default on the event. - if (TAG_WHITE_LIST.indexOf(e.target.tagName) < 0) { - preventDefault(e); - } else { - return; - } - } - - _handlePointer(e, handler); - }); - - obj['_leaflet_touchstart' + id] = onDown; - obj.addEventListener(POINTER_DOWN, onDown, false); - - // need to keep track of what pointers and how many are active to provide e.touches emulation - if (!_pointerDocListener) { - // we listen documentElement as any drags that end by moving the touch off the screen get fired there - document.documentElement.addEventListener(POINTER_DOWN, _globalPointerDown, true); - document.documentElement.addEventListener(POINTER_MOVE, _globalPointerMove, true); - document.documentElement.addEventListener(POINTER_UP, _globalPointerUp, true); - document.documentElement.addEventListener(POINTER_CANCEL, _globalPointerUp, true); - - _pointerDocListener = true; - } -} - -function _globalPointerDown(e) { - _pointers[e.pointerId] = e; - _pointersCount++; -} - -function _globalPointerMove(e) { - if (_pointers[e.pointerId]) { - _pointers[e.pointerId] = e; - } -} - -function _globalPointerUp(e) { - delete _pointers[e.pointerId]; - _pointersCount--; -} - -function _handlePointer(e, handler) { - e.touches = []; - for (var i in _pointers) { - e.touches.push(_pointers[i]); - } - e.changedTouches = [e]; - - handler(e); -} - -function _addPointerMove(obj, handler, id) { - let onMove = (e) => { - // don't fire touch moves when mouse isn't down - if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; } - - _handlePointer(e, handler); - }; - - obj['_leaflet_touchmove' + id] = onMove; - obj.addEventListener(POINTER_MOVE, onMove, false); -} - -function _addPointerEnd(obj, handler, id) { - let onUp = (e) => { - _handlePointer(e, handler); - }; - - obj['_leaflet_touchend' + id] = onUp; - obj.addEventListener(POINTER_UP, onUp, false); - obj.addEventListener(POINTER_CANCEL, onUp, false); -} - -/* - * Extends the event handling code with double tap support for mobile browsers. - */ - -let _touchstart = msPointer ? 'MSPointerDown' : pointer ? 'pointerdown' : 'touchstart'; -let _touchend = msPointer ? 'MSPointerUp' : pointer ? 'pointerup' : 'touchend'; -let _pre = '_leaflet_'; - -// inspired by Zepto touch code by Thomas Fuchs -function addDoubleTapListener(obj, handler, id) { - var last, touch$$1, - doubleTap = false, - delay = 250; - - function onTouchStart(e) { - var count; - - if (pointer) { - if ((!edge) || e.pointerType === 'mouse') { return; } - count = _pointersCount; - } else { - count = e.touches.length; - } - - if (count > 1) { return; } - - let now = Date.now(), - delta = now - (last || now); - - touch$$1 = e.touches ? e.touches[0] : e; - doubleTap = (delta > 0 && delta <= delay); - last = now; - } - - function onTouchEnd(e) { - if (doubleTap && !touch$$1.cancelBubble) { - if (pointer) { - if ((!edge) || e.pointerType === 'mouse') { return; } - // work around .type being readonly with MSPointer* events - let newTouch = {}, - prop, i; - - for (i in touch$$1) { - prop = touch$$1[i]; - newTouch[i] = prop && prop.bind ? prop.bind(touch$$1) : prop; - } - touch$$1 = newTouch; - } - touch$$1.type = 'dblclick'; - handler(touch$$1); - last = null; - } - } - - obj[_pre + _touchstart + id] = onTouchStart; - obj[_pre + _touchend + id] = onTouchEnd; - obj[_pre + 'dblclick' + id] = handler; - - obj.addEventListener(_touchstart, onTouchStart, false); - obj.addEventListener(_touchend, onTouchEnd, false); - - // On some platforms (notably, chrome<55 on win10 + touchscreen + mouse), - // the browser doesn't fire touchend/pointerup events but does fire - // native dblclicks. See #4127. - // Edge 14 also fires native dblclicks, but only for pointerType mouse, see #5180. - obj.addEventListener('dblclick', handler, false); - - return this; -} - -function removeDoubleTapListener(obj, id) { - let touchstart = obj[_pre + _touchstart + id], - touchend = obj[_pre + _touchend + id], - dblclick = obj[_pre + 'dblclick' + id]; - - obj.removeEventListener(_touchstart, touchstart, false); - obj.removeEventListener(_touchend, touchend, false); - if (!edge) { - obj.removeEventListener('dblclick', dblclick, false); - } - - return this; -} - -/* - * @namespace DomEvent - * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally. - */ - -// Inspired by John Resig, Dean Edwards and YUI addEvent implementations. - -// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this -// Adds a listener function (`fn`) to a particular DOM event type of the -// element `el`. You can optionally specify the context of the listener -// (object the `this` keyword will point to). You can also pass several -// space-separated types (e.g. `'click dblclick'`). - -// @alternative -// @function on(el: HTMLElement, eventMap: Object, context?: Object): this -// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` -function on(obj, types, fn, context) { - - if (typeof types === 'object') { - for (var type in types) { - addOne(obj, type, types[type], fn); - } - } else { - types = splitWords(types); - - for (let i = 0, len = types.length; i < len; i++) { - addOne(obj, types[i], fn, context); - } - } - - return this; -} - -let eventsKey = '_leaflet_events'; - -// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this -// Removes a previously added listener function. -// Note that if you passed a custom context to on, you must pass the same -// context to `off` in order to remove the listener. - -// @alternative -// @function off(el: HTMLElement, eventMap: Object, context?: Object): this -// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` -function off(obj, types, fn, context) { - - if (typeof types === 'object') { - for (var type in types) { - removeOne(obj, type, types[type], fn); - } - } else if (types) { - types = splitWords(types); - - for (let i = 0, len = types.length; i < len; i++) { - removeOne(obj, types[i], fn, context); - } - } else { - for (var j in obj[eventsKey]) { - removeOne(obj, j, obj[eventsKey][j]); - } - delete obj[eventsKey]; - } - - return this; -} - -function addOne(obj, type, fn, context) { - let id = type + stamp(fn) + (context ? '_' + stamp(context) : ''); - - if (obj[eventsKey] && obj[eventsKey][id]) { return this; } - - let handler = (e) => { - return fn.call(context || obj, e || window.event); - }; - - let originalHandler = handler; - - if (pointer && type.indexOf('touch') === 0) { - // Needs DomEvent.Pointer.js - addPointerListener(obj, type, handler, id); - - } else if (touch && (type === 'dblclick') && addDoubleTapListener && - !(pointer && chrome)) { - // Chrome >55 does not need the synthetic dblclicks from addDoubleTapListener - // See #5180 - addDoubleTapListener(obj, handler, id); - - } else if ('addEventListener' in obj) { - - if (type === 'mousewheel') { - obj.addEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false); - - } else if ((type === 'mouseenter') || (type === 'mouseleave')) { - handler = (e) => { - e = e || window.event; - if (isExternalTarget(obj, e)) { - originalHandler(e); - } - }; - obj.addEventListener(type === 'mouseenter' ? 'mouseover' : 'mouseout', handler, false); - - } else { - if (type === 'click' && android) { - handler = (e) => { - filterClick(e, originalHandler); - }; - } - obj.addEventListener(type, handler, false); - } - - } else if ('attachEvent' in obj) { - obj.attachEvent('on' + type, handler); - } - - obj[eventsKey] = obj[eventsKey] || {}; - obj[eventsKey][id] = handler; -} - -function removeOne(obj, type, fn, context) { - - let id = type + stamp(fn) + (context ? '_' + stamp(context) : ''), - handler = obj[eventsKey] && obj[eventsKey][id]; - - if (!handler) { return this; } - - if (pointer && type.indexOf('touch') === 0) { - removePointerListener(obj, type, id); - - } else if (touch && (type === 'dblclick') && removeDoubleTapListener && - !(pointer && chrome)) { - removeDoubleTapListener(obj, id); - - } else if ('removeEventListener' in obj) { - - if (type === 'mousewheel') { - obj.removeEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false); - - } else { - obj.removeEventListener( - type === 'mouseenter' ? 'mouseover' : - type === 'mouseleave' ? 'mouseout' : type, handler, false); - } - - } else if ('detachEvent' in obj) { - obj.detachEvent('on' + type, handler); - } - - obj[eventsKey][id] = null; -} - -// @function stopPropagation(ev: DOMEvent): this -// Stop the given event from propagation to parent elements. Used inside the listener functions: -// ```js -// L.DomEvent.on(div, 'click', function (ev) { -// L.DomEvent.stopPropagation(ev); -// }); -// ``` -function stopPropagation(e) { - - if (e.stopPropagation) { - e.stopPropagation(); - } else if (e.originalEvent) { // In case of Leaflet event. - e.originalEvent._stopped = true; - } else { - e.cancelBubble = true; - } - skipped(e); - - return this; -} - -// @function disableScrollPropagation(el: HTMLElement): this -// Adds `stopPropagation` to the element's `'mousewheel'` events (plus browser variants). -function disableScrollPropagation(el) { - addOne(el, 'mousewheel', stopPropagation); - return this; -} - -// @function disableClickPropagation(el: HTMLElement): this -// Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`, -// `'mousedown'` and `'touchstart'` events (plus browser variants). -function disableClickPropagation(el) { - on(el, 'mousedown touchstart dblclick', stopPropagation); - addOne(el, 'click', fakeStop); - return this; -} - -// @function preventDefault(ev: DOMEvent): this -// Prevents the default action of the DOM Event `ev` from happening (such as -// following a link in the href of the a element, or doing a POST request -// with page reload when a `
    ` is submitted). -// Use it inside listener functions. -function preventDefault(e) { - if (e.preventDefault) { - e.preventDefault(); - } else { - e.returnValue = false; - } - return this; -} - -// @function stop(ev: DOMEvent): this -// Does `stopPropagation` and `preventDefault` at the same time. -function stop(e) { - preventDefault(e); - stopPropagation(e); - return this; -} - -// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point -// Gets normalized mouse position from a DOM event relative to the -// `container` or to the whole page if not specified. -function getMousePosition(e, container) { - if (!container) { - return new Point(e.clientX, e.clientY); - } - - let rect = container.getBoundingClientRect(); - - let scaleX = rect.width / container.offsetWidth || 1; - let scaleY = rect.height / container.offsetHeight || 1; - return new Point( - e.clientX / scaleX - rect.left - container.clientLeft, - e.clientY / scaleY - rect.top - container.clientTop); -} - -// Chrome on Win scrolls double the pixels as in other platforms (see #4538), -// and Firefox scrolls device pixels, not CSS pixels -let wheelPxFactor = - (win && chrome) ? 2 * window.devicePixelRatio : - gecko ? window.devicePixelRatio : 1; - -// @function getWheelDelta(ev: DOMEvent): Number -// Gets normalized wheel delta from a mousewheel DOM event, in vertical -// pixels scrolled (negative if scrolling down). -// Events from pointing devices without precise scrolling are mapped to -// a best guess of 60 pixels. -function getWheelDelta(e) { - return (edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta - (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels - (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines - (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages - (e.deltaX || e.deltaZ) ? 0 : // Skip horizontal/depth wheel events - e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels - (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines - e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages - 0; -} - -let skipEvents = {}; - -function fakeStop(e) { - // fakes stopPropagation by setting a special event flag, checked/reset with skipped(e) - skipEvents[e.type] = true; -} - -function skipped(e) { - let events = skipEvents[e.type]; - // reset when checking, as it's only used in map container and propagates outside of the map - skipEvents[e.type] = false; - return events; -} - -// check if element really left/entered the event target (for mouseenter/mouseleave) -function isExternalTarget(el, e) { - - let related = e.relatedTarget; - - if (!related) { return true; } - - try { - while (related && (related !== el)) { - related = related.parentNode; - } - } catch (err) { - return false; - } - return (related !== el); -} - -var lastClick; - -// this is a horrible workaround for a bug in Android where a single touch triggers two click events -function filterClick(e, handler) { - let timeStamp = (e.timeStamp || (e.originalEvent && e.originalEvent.timeStamp)), - elapsed = lastClick && (timeStamp - lastClick); - - // are they closer together than 500ms yet more than 100ms? - // Android typically triggers them ~300ms apart while multiple listeners - // on the same event should be triggered far faster; - // or check if click is simulated on the element, and if it is, reject any non-simulated events - - if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) { - stop(e); - return; - } - lastClick = timeStamp; - - handler(e); -} - - - - -let DomEvent = (Object.freeze || Object)({ - on: on, - off: off, - stopPropagation: stopPropagation, - disableScrollPropagation: disableScrollPropagation, - disableClickPropagation: disableClickPropagation, - preventDefault: preventDefault, - stop: stop, - getMousePosition: getMousePosition, - getWheelDelta: getWheelDelta, - fakeStop: fakeStop, - skipped: skipped, - isExternalTarget: isExternalTarget, - addListener: on, - removeListener: off -}); - -/* - * @namespace DomUtil - * - * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model) - * tree, used by Leaflet internally. - * - * Most functions expecting or returning a `HTMLElement` also work for - * SVG elements. The only difference is that classes refer to CSS classes - * in HTML and SVG classes in SVG. - */ - - -// @property TRANSFORM: String -// Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit). -let TRANSFORM = testProp( - ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); - -// webkitTransition comes first because some browser versions that drop vendor prefix don't do -// the same for the transitionend event, in particular the Android 4.1 stock browser - -// @property TRANSITION: String -// Vendor-prefixed transition style name. -let TRANSITION = testProp( - ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); - -// @property TRANSITION_END: String -// Vendor-prefixed transitionend event name. -let TRANSITION_END = - TRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend'; - - -// @function get(id: String|HTMLElement): HTMLElement -// Returns an element given its DOM id, or returns the element itself -// if it was passed directly. -function get(id) { - return typeof id === 'string' ? document.getElementById(id) : id; -} - -// @function getStyle(el: HTMLElement, styleAttrib: String): String -// Returns the value for a certain style attribute on an element, -// including computed values or values set through CSS. -function getStyle(el, style) { - let value = el.style[style] || (el.currentStyle && el.currentStyle[style]); - - if ((!value || value === 'auto') && document.defaultView) { - let css = document.defaultView.getComputedStyle(el, null); - value = css ? css[style] : null; - } - return value === 'auto' ? null : value; -} - -// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement -// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element. -function create$1(tagName, className, container) { - let el = document.createElement(tagName); - el.className = className || ''; - - if (container) { - container.appendChild(el); - } - return el; -} - -// @function remove(el: HTMLElement) -// Removes `el` from its parent element -function remove(el) { - let parent = el.parentNode; - if (parent) { - parent.removeChild(el); - } -} - -// @function empty(el: HTMLElement) -// Removes all of `el`'s children elements from `el` -function empty(el) { - while (el.firstChild) { - el.removeChild(el.firstChild); - } -} - -// @function toFront(el: HTMLElement) -// Makes `el` the last child of its parent, so it renders in front of the other children. -function toFront(el) { - let parent = el.parentNode; - if (parent.lastChild !== el) { - parent.appendChild(el); - } -} - -// @function toBack(el: HTMLElement) -// Makes `el` the first child of its parent, so it renders behind the other children. -function toBack(el) { - let parent = el.parentNode; - if (parent.firstChild !== el) { - parent.insertBefore(el, parent.firstChild); - } -} - -// @function hasClass(el: HTMLElement, name: String): Boolean -// Returns `true` if the element's class attribute contains `name`. -function hasClass(el, name) { - if (el.classList !== undefined) { - return el.classList.contains(name); - } - let className = getClass(el); - return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className); -} - -// @function addClass(el: HTMLElement, name: String) -// Adds `name` to the element's class attribute. -function addClass(el, name) { - if (el.classList !== undefined) { - let classes = splitWords(name); - for (let i = 0, len = classes.length; i < len; i++) { - el.classList.add(classes[i]); - } - } else if (!hasClass(el, name)) { - let className = getClass(el); - setClass(el, (className ? className + ' ' : '') + name); - } -} - -// @function removeClass(el: HTMLElement, name: String) -// Removes `name` from the element's class attribute. -function removeClass(el, name) { - if (el.classList !== undefined) { - el.classList.remove(name); - } else { - setClass(el, trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' '))); - } -} - -// @function setClass(el: HTMLElement, name: String) -// Sets the element's class. -function setClass(el, name) { - if (el.className.baseVal === undefined) { - el.className = name; - } else { - // in case of SVG element - el.className.baseVal = name; - } -} - -// @function getClass(el: HTMLElement): String -// Returns the element's class. -function getClass(el) { - return el.className.baseVal === undefined ? el.className : el.className.baseVal; -} - -// @function setOpacity(el: HTMLElement, opacity: Number) -// Set the opacity of an element (including old IE support). -// `opacity` must be a number from `0` to `1`. -function setOpacity(el, value) { - if ('opacity' in el.style) { - el.style.opacity = value; - } else if ('filter' in el.style) { - _setOpacityIE(el, value); - } -} - -function _setOpacityIE(el, value) { - let filter = false, - filterName = 'DXImageTransform.Microsoft.Alpha'; - - // filters collection throws an error if we try to retrieve a filter that doesn't exist - try { - filter = el.filters.item(filterName); - } catch (e) { - // don't set opacity to 1 if we haven't already set an opacity, - // it isn't needed and breaks transparent pngs. - if (value === 1) { return; } - } - - value = Math.round(value * 100); - - if (filter) { - filter.Enabled = (value !== 100); - filter.Opacity = value; - } else { - el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; - } -} - -// @function testProp(props: String[]): String|false -// Goes through the array of style names and returns the first name -// that is a valid style name for an element. If no such name is found, -// it returns false. Useful for vendor-prefixed styles like `transform`. -function testProp(props) { - let style = document.documentElement.style; - - for (let i = 0; i < props.length; i++) { - if (props[i] in style) { - return props[i]; - } - } - return false; -} - -// @function setTransform(el: HTMLElement, offset: Point, scale?: Number) -// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels -// and optionally scaled by `scale`. Does not have an effect if the -// browser doesn't support 3D CSS transforms. -function setTransform(el, offset, scale) { - let pos = offset || new Point(0, 0); - - el.style[TRANSFORM] = - (ie3d ? - 'translate(' + pos.x + 'px,' + pos.y + 'px)' : - 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') + - (scale ? ' scale(' + scale + ')' : ''); -} - -// @function setPosition(el: HTMLElement, position: Point) -// Sets the position of `el` to coordinates specified by `position`, -// using CSS translate or top/left positioning depending on the browser -// (used by Leaflet internally to position its layers). -function setPosition(el, point) { - - /*eslint-disable */ - el._leaflet_pos = point; - /* eslint-enable */ - - if (any3d) { - setTransform(el, point); - } else { - el.style.left = point.x + 'px'; - el.style.top = point.y + 'px'; - } -} - -// @function getPosition(el: HTMLElement): Point -// Returns the coordinates of an element previously positioned with setPosition. -function getPosition(el) { - // this method is only used for elements previously positioned using setPosition, - // so it's safe to cache the position for performance - - return el._leaflet_pos || new Point(0, 0); -} - -// @function disableTextSelection() -// Prevents the user from generating `selectstart` DOM events, usually generated -// when the user drags the mouse through a page with text. Used internally -// by Leaflet to override the behaviour of any click-and-drag interaction on -// the map. Affects drag interactions on the whole document. - -// @function enableTextSelection() -// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection). -var disableTextSelection; -var enableTextSelection; -var _userSelect; -if ('onselectstart' in document) { - disableTextSelection = () => { - on(window, 'selectstart', preventDefault); - }; - enableTextSelection = () => { - off(window, 'selectstart', preventDefault); - }; -} else { - let userSelectProperty = testProp( - ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); - - disableTextSelection = () => { - if (userSelectProperty) { - let style = document.documentElement.style; - _userSelect = style[userSelectProperty]; - style[userSelectProperty] = 'none'; - } - }; - enableTextSelection = () => { - if (userSelectProperty) { - document.documentElement.style[userSelectProperty] = _userSelect; - _userSelect = undefined; - } - }; -} - -// @function disableImageDrag() -// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but -// for `dragstart` DOM events, usually generated when the user drags an image. -function disableImageDrag() { - on(window, 'dragstart', preventDefault); -} - -// @function enableImageDrag() -// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection). -function enableImageDrag() { - off(window, 'dragstart', preventDefault); -} - -var _outlineElement; -var _outlineStyle; -// @function preventOutline(el: HTMLElement) -// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline) -// of the element `el` invisible. Used internally by Leaflet to prevent -// focusable elements from displaying an outline when the user performs a -// drag interaction on them. -function preventOutline(element) { - while (element.tabIndex === -1) { - element = element.parentNode; - } - if (!element.style) { return; } - restoreOutline(); - _outlineElement = element; - _outlineStyle = element.style.outline; - element.style.outline = 'none'; - on(window, 'keydown', restoreOutline); -} - -// @function restoreOutline() -// Cancels the effects of a previous [`L.DomUtil.preventOutline`](). -function restoreOutline() { - if (!_outlineElement) { return; } - _outlineElement.style.outline = _outlineStyle; - _outlineElement = undefined; - _outlineStyle = undefined; - off(window, 'keydown', restoreOutline); -} - - -let DomUtil = (Object.freeze || Object)({ - TRANSFORM: TRANSFORM, - TRANSITION: TRANSITION, - TRANSITION_END: TRANSITION_END, - get: get, - getStyle: getStyle, - create: create$1, - remove: remove, - empty: empty, - toFront: toFront, - toBack: toBack, - hasClass: hasClass, - addClass: addClass, - removeClass: removeClass, - setClass: setClass, - getClass: getClass, - setOpacity: setOpacity, - testProp: testProp, - setTransform: setTransform, - setPosition: setPosition, - getPosition: getPosition, - disableTextSelection: disableTextSelection, - enableTextSelection: enableTextSelection, - disableImageDrag: disableImageDrag, - enableImageDrag: enableImageDrag, - preventOutline: preventOutline, - restoreOutline: restoreOutline -}); - -/* - * @class PosAnimation - * @aka L.PosAnimation - * @inherits Evented - * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9. - * - * @example - * ```js - * let fx = new L.PosAnimation(); - * fx.run(el, [300, 500], 0.5); - * ``` - * - * @constructor L.PosAnimation() - * Creates a `PosAnimation` object. - * - */ - -let PosAnimation = Evented.extend({ - - // @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number) - // Run an animation of a given element to a new position, optionally setting - // duration in seconds (`0.25` by default) and easing linearity factor (3rd - // argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1), - // `0.5` by default). - run: function (el, newPos, duration, easeLinearity) { - this.stop(); - - this._el = el; - this._inProgress = true; - this._duration = duration || 0.25; - this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2); - - this._startPos = getPosition(el); - this._offset = newPos.subtract(this._startPos); - this._startTime = +new Date(); - - // @event start: Event - // Fired when the animation starts - this.fire('start'); - - this._animate(); - }, - - // @method stop() - // Stops the animation (if currently running). - stop: function () { - if (!this._inProgress) { return; } - - this._step(true); - this._complete(); - }, - - _animate: function () { - // animation loop - this._animId = requestAnimFrame(this._animate, this); - this._step(); - }, - - _step: function (round) { - let elapsed = (+new Date()) - this._startTime, - duration = this._duration * 1000; - - if (elapsed < duration) { - this._runFrame(this._easeOut(elapsed / duration), round); - } else { - this._runFrame(1); - this._complete(); - } - }, - - _runFrame: function (progress, round) { - let pos = this._startPos.add(this._offset.multiplyBy(progress)); - if (round) { - pos._round(); - } - setPosition(this._el, pos); - - // @event step: Event - // Fired continuously during the animation. - this.fire('step'); - }, - - _complete: function () { - cancelAnimFrame(this._animId); - - this._inProgress = false; - // @event end: Event - // Fired when the animation ends. - this.fire('end'); - }, - - _easeOut: function (t) { - return 1 - Math.pow(1 - t, this._easeOutPower); - } -}); - -/* - * @class Map - * @aka L.Map - * @inherits Evented - * - * The central class of the API — it is used to create a map on a page and manipulate it. - * - * @example - * - * ```js - * // initialize the map on the "map" div with a given center and zoom - * let map = L.map('map', { - * center: [51.505, -0.09], - * zoom: 13 - * }); - * ``` - * - */ - -let Map = Evented.extend({ - - options: { - // @section Map State Options - // @option crs: CRS = L.CRS.EPSG3857 - // The [Coordinate Reference System](#crs) to use. Don't change this if you're not - // sure what it means. - crs: EPSG3857, - - // @option center: LatLng = undefined - // Initial geographic center of the map - center: undefined, - - // @option zoom: Number = undefined - // Initial map zoom level - zoom: undefined, - - // @option minZoom: Number = * - // Minimum zoom level of the map. - // If not specified and at least one `GridLayer` or `TileLayer` is in the map, - // the lowest of their `minZoom` options will be used instead. - minZoom: undefined, - - // @option maxZoom: Number = * - // Maximum zoom level of the map. - // If not specified and at least one `GridLayer` or `TileLayer` is in the map, - // the highest of their `maxZoom` options will be used instead. - maxZoom: undefined, - - // @option layers: Layer[] = [] - // Array of layers that will be added to the map initially - layers: [], - - // @option maxBounds: LatLngBounds = null - // When this option is set, the map restricts the view to the given - // geographical bounds, bouncing the user back if the user tries to pan - // outside the view. To set the restriction dynamically, use - // [`setMaxBounds`](#map-setmaxbounds) method. - maxBounds: undefined, - - // @option renderer: Renderer = * - // The default method for drawing vector layers on the map. `L.SVG` - // or `L.Canvas` by default depending on browser support. - renderer: undefined, - - - // @section Animation Options - // @option zoomAnimation: Boolean = true - // Whether the map zoom animation is enabled. By default it's enabled - // in all browsers that support CSS3 Transitions except Android. - zoomAnimation: true, - - // @option zoomAnimationThreshold: Number = 4 - // Won't animate zoom if the zoom difference exceeds this value. - zoomAnimationThreshold: 4, - - // @option fadeAnimation: Boolean = true - // Whether the tile fade animation is enabled. By default it's enabled - // in all browsers that support CSS3 Transitions except Android. - fadeAnimation: true, - - // @option markerZoomAnimation: Boolean = true - // Whether markers animate their zoom with the zoom animation, if disabled - // they will disappear for the length of the animation. By default it's - // enabled in all browsers that support CSS3 Transitions except Android. - markerZoomAnimation: true, - - // @option transform3DLimit: Number = 2^23 - // Defines the maximum size of a CSS translation transform. The default - // value should not be changed unless a web browser positions layers in - // the wrong place after doing a large `panBy`. - transform3DLimit: 8388608, // Precision limit of a 32-bit float - - // @section Interaction Options - // @option zoomSnap: Number = 1 - // Forces the map's zoom level to always be a multiple of this, particularly - // right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom. - // By default, the zoom level snaps to the nearest integer; lower values - // (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0` - // means the zoom level will not be snapped after `fitBounds` or a pinch-zoom. - zoomSnap: 1, - - // @option zoomDelta: Number = 1 - // Controls how much the map's zoom level will change after a - // [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+` - // or `-` on the keyboard, or using the [zoom controls](#control-zoom). - // Values smaller than `1` (e.g. `0.5`) allow for greater granularity. - zoomDelta: 1, - - // @option trackResize: Boolean = true - // Whether the map automatically handles browser window resize to update itself. - trackResize: true - }, - - initialize: function (id, options) { // (HTMLElement or String, Object) - options = setOptions(this, options); - - this._initContainer(id); - this._initLayout(); - - // hack for https://github.com/Leaflet/Leaflet/issues/1980 - this._onResize = bind(this._onResize, this); - - this._initEvents(); - - if (options.maxBounds) { - this.setMaxBounds(options.maxBounds); - } - - if (options.zoom !== undefined) { - this._zoom = this._limitZoom(options.zoom); - } - - if (options.center && options.zoom !== undefined) { - this.setView(toLatLng(options.center), options.zoom, {reset: true}); - } - - this._handlers = []; - this._layers = {}; - this._zoomBoundLayers = {}; - this._sizeChanged = true; - - this.callInitHooks(); - - // don't animate on browsers without hardware-accelerated transitions or old Android/Opera - this._zoomAnimated = TRANSITION && any3d && !mobileOpera && - this.options.zoomAnimation; - - // zoom transitions run with the same duration for all layers, so if one of transitionend events - // happens after starting zoom animation (propagating to the map pane), we know that it ended globally - if (this._zoomAnimated) { - this._createAnimProxy(); - on(this._proxy, TRANSITION_END, this._catchTransitionEnd, this); - } - - this._addLayers(this.options.layers); - }, - - - // @section Methods for modifying map state - - // @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this - // Sets the view of the map (geographical center and zoom) with the given - // animation options. - setView: function (center, zoom, options) { - - zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom); - center = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds); - options = options || {}; - - this._stop(); - - if (this._loaded && !options.reset && options !== true) { - - if (options.animate !== undefined) { - options.zoom = extend({animate: options.animate}, options.zoom); - options.pan = extend({animate: options.animate, duration: options.duration}, options.pan); - } - - // try animating pan or zoom - let moved = (this._zoom !== zoom) ? - this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) : - this._tryAnimatedPan(center, options.pan); - - if (moved) { - // prevent resize handler call, the view will refresh after animation anyway - clearTimeout(this._sizeTimer); - return this; - } - } - - // animation didn't start, just reset the map view - this._resetView(center, zoom); - - return this; - }, - - // @method setZoom(zoom: Number, options?: Zoom/pan options): this - // Sets the zoom of the map. - setZoom: function (zoom, options) { - if (!this._loaded) { - this._zoom = zoom; - return this; - } - return this.setView(this.getCenter(), zoom, {zoom: options}); - }, - - // @method zoomIn(delta?: Number, options?: Zoom options): this - // Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default). - zoomIn: function (delta, options) { - delta = delta || (any3d ? this.options.zoomDelta : 1); - return this.setZoom(this._zoom + delta, options); - }, - - // @method zoomOut(delta?: Number, options?: Zoom options): this - // Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default). - zoomOut: function (delta, options) { - delta = delta || (any3d ? this.options.zoomDelta : 1); - return this.setZoom(this._zoom - delta, options); - }, - - // @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this - // Zooms the map while keeping a specified geographical point on the map - // stationary (e.g. used internally for scroll zoom and double-click zoom). - // @alternative - // @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this - // Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary. - setZoomAround: function (latlng, zoom, options) { - let scale = this.getZoomScale(zoom), - viewHalf = this.getSize().divideBy(2), - containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng), - - centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale), - newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset)); - - return this.setView(newCenter, zoom, {zoom: options}); - }, - - _getBoundsCenterZoom: function (bounds, options) { - - options = options || {}; - bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds); - - let paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]), - paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]), - - zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR)); - - zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom; - - if (zoom === Infinity) { - return { - center: bounds.getCenter(), - zoom: zoom - }; - } - - let paddingOffset = paddingBR.subtract(paddingTL).divideBy(2), - - swPoint = this.project(bounds.getSouthWest(), zoom), - nePoint = this.project(bounds.getNorthEast(), zoom), - center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom); - - return { - center: center, - zoom: zoom - }; - }, - - // @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this - // Sets a map view that contains the given geographical bounds with the - // maximum zoom level possible. - fitBounds: function (bounds, options) { - - bounds = toLatLngBounds(bounds); - - if (!bounds.isValid()) { - throw new Error('Bounds are not valid.'); - } - - let target = this._getBoundsCenterZoom(bounds, options); - return this.setView(target.center, target.zoom, options); - }, - - // @method fitWorld(options?: fitBounds options): this - // Sets a map view that mostly contains the whole world with the maximum - // zoom level possible. - fitWorld: function (options) { - return this.fitBounds([[-90, -180], [90, 180]], options); - }, - - // @method panTo(latlng: LatLng, options?: Pan options): this - // Pans the map to a given center. - panTo: function (center, options) { // (LatLng) - return this.setView(center, this._zoom, {pan: options}); - }, - - // @method panBy(offset: Point, options?: Pan options): this - // Pans the map by a given number of pixels (animated). - panBy: function (offset, options) { - offset = toPoint(offset).round(); - options = options || {}; - - if (!offset.x && !offset.y) { - return this.fire('moveend'); - } - // If we pan too far, Chrome gets issues with tiles - // and makes them disappear or appear in the wrong place (slightly offset) #2602 - if (options.animate !== true && !this.getSize().contains(offset)) { - this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom()); - return this; - } - - if (!this._panAnim) { - this._panAnim = new PosAnimation(); - - this._panAnim.on({ - 'step': this._onPanTransitionStep, - 'end': this._onPanTransitionEnd - }, this); - } - - // don't fire movestart if animating inertia - if (!options.noMoveStart) { - this.fire('movestart'); - } - - // animate pan unless animate: false specified - if (options.animate !== false) { - addClass(this._mapPane, 'leaflet-pan-anim'); - - let newPos = this._getMapPanePos().subtract(offset).round(); - this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity); - } else { - this._rawPanBy(offset); - this.fire('move').fire('moveend'); - } - - return this; - }, - - // @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this - // Sets the view of the map (geographical center and zoom) performing a smooth - // pan-zoom animation. - flyTo: function (targetCenter, targetZoom, options) { - - options = options || {}; - if (options.animate === false || !any3d) { - return this.setView(targetCenter, targetZoom, options); - } - - this._stop(); - - let from = this.project(this.getCenter()), - to = this.project(targetCenter), - size = this.getSize(), - startZoom = this._zoom; - - targetCenter = toLatLng(targetCenter); - targetZoom = targetZoom === undefined ? startZoom : targetZoom; - - var w0 = Math.max(size.x, size.y), - w1 = w0 * this.getZoomScale(startZoom, targetZoom), - u1 = (to.distanceTo(from)) || 1, - rho = 1.42, - rho2 = rho * rho; - - function r(i) { - var s1 = i ? -1 : 1, - s2 = i ? w1 : w0, - t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1, - b1 = 2 * s2 * rho2 * u1, - b = t1 / b1, - sq = Math.sqrt(b * b + 1) - b; - - // workaround for floating point precision bug when sq = 0, log = -Infinite, - // thus triggering an infinite loop in flyTo - let log = sq < 0.000000001 ? -18 : Math.log(sq); - - return log; - } - - function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; } - function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; } - function tanh(n) { return sinh(n) / cosh(n); } - - var r0 = r(0); - - function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); } - function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; } - - function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); } - - let start = Date.now(), - S = (r(1) - r0) / rho, - duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8; - - function frame() { - let t = (Date.now() - start) / duration, - s = easeOut(t) * S; - - if (t <= 1) { - this._flyToFrame = requestAnimFrame(frame, this); - - this._move( - this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom), - this.getScaleZoom(w0 / w(s), startZoom), - {flyTo: true}); - - } else { - this - ._move(targetCenter, targetZoom) - ._moveEnd(true); - } - } - - this._moveStart(true, options.noMoveStart); - - frame.call(this); - return this; - }, - - // @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this - // Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto), - // but takes a bounds parameter like [`fitBounds`](#map-fitbounds). - flyToBounds: function (bounds, options) { - let target = this._getBoundsCenterZoom(bounds, options); - return this.flyTo(target.center, target.zoom, options); - }, - - // @method setMaxBounds(bounds: Bounds): this - // Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option). - setMaxBounds: function (bounds) { - bounds = toLatLngBounds(bounds); - - if (!bounds.isValid()) { - this.options.maxBounds = null; - return this.off('moveend', this._panInsideMaxBounds); - } else if (this.options.maxBounds) { - this.off('moveend', this._panInsideMaxBounds); - } - - this.options.maxBounds = bounds; - - if (this._loaded) { - this._panInsideMaxBounds(); - } - - return this.on('moveend', this._panInsideMaxBounds); - }, - - // @method setMinZoom(zoom: Number): this - // Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option). - setMinZoom: function (zoom) { - let oldZoom = this.options.minZoom; - this.options.minZoom = zoom; - - if (this._loaded && oldZoom !== zoom) { - this.fire('zoomlevelschange'); - - if (this.getZoom() < this.options.minZoom) { - return this.setZoom(zoom); - } - } - - return this; - }, - - // @method setMaxZoom(zoom: Number): this - // Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option). - setMaxZoom: function (zoom) { - let oldZoom = this.options.maxZoom; - this.options.maxZoom = zoom; - - if (this._loaded && oldZoom !== zoom) { - this.fire('zoomlevelschange'); - - if (this.getZoom() > this.options.maxZoom) { - return this.setZoom(zoom); - } - } - - return this; - }, - - // @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this - // Pans the map to the closest view that would lie inside the given bounds (if it's not already), controlling the animation using the options specific, if any. - panInsideBounds: function (bounds, options) { - this._enforcingBounds = true; - let center = this.getCenter(), - newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds)); - - if (!center.equals(newCenter)) { - this.panTo(newCenter, options); - } - - this._enforcingBounds = false; - return this; - }, - - // @method invalidateSize(options: Zoom/pan options): this - // Checks if the map container size changed and updates the map if so — - // call it after you've changed the map size dynamically, also animating - // pan by default. If `options.pan` is `false`, panning will not occur. - // If `options.debounceMoveend` is `true`, it will delay `moveend` event so - // that it doesn't happen often even if the method is called many - // times in a row. - - // @alternative - // @method invalidateSize(animate: Boolean): this - // Checks if the map container size changed and updates the map if so — - // call it after you've changed the map size dynamically, also animating - // pan by default. - invalidateSize: function (options) { - if (!this._loaded) { return this; } - - options = extend({ - animate: false, - pan: true - }, options === true ? {animate: true} : options); - - let oldSize = this.getSize(); - this._sizeChanged = true; - this._lastCenter = null; - - let newSize = this.getSize(), - oldCenter = oldSize.divideBy(2).round(), - newCenter = newSize.divideBy(2).round(), - offset = oldCenter.subtract(newCenter); - - if (!offset.x && !offset.y) { return this; } - - if (options.animate && options.pan) { - this.panBy(offset); - - } else { - if (options.pan) { - this._rawPanBy(offset); - } - - this.fire('move'); - - if (options.debounceMoveend) { - clearTimeout(this._sizeTimer); - this._sizeTimer = setTimeout(bind(this.fire, this, 'moveend'), 200); - } else { - this.fire('moveend'); - } - } - - // @section Map state change events - // @event resize: ResizeEvent - // Fired when the map is resized. - return this.fire('resize', { - oldSize: oldSize, - newSize: newSize - }); - }, - - // @section Methods for modifying map state - // @method stop(): this - // Stops the currently running `panTo` or `flyTo` animation, if any. - stop: function () { - this.setZoom(this._limitZoom(this._zoom)); - if (!this.options.zoomSnap) { - this.fire('viewreset'); - } - return this._stop(); - }, - - // @section Geolocation methods - // @method locate(options?: Locate options): this - // Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound) - // event with location data on success or a [`locationerror`](#map-locationerror) event on failure, - // and optionally sets the map view to the user's location with respect to - // detection accuracy (or to the world view if geolocation failed). - // Note that, if your page doesn't use HTTPS, this method will fail in - // modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins)) - // See `Locate options` for more details. - locate: function (options) { - - options = this._locateOptions = extend({ - timeout: 10000, - watch: false - // setView: false - // maxZoom: - // maximumAge: 0 - // enableHighAccuracy: false - }, options); - - if (!('geolocation' in navigator)) { - this._handleGeolocationError({ - code: 0, - message: 'Geolocation not supported.' - }); - return this; - } - - let onResponse = bind(this._handleGeolocationResponse, this), - onError = bind(this._handleGeolocationError, this); - - if (options.watch) { - this._locationWatchId = - navigator.geolocation.watchPosition(onResponse, onError, options); - } else { - navigator.geolocation.getCurrentPosition(onResponse, onError, options); - } - return this; - }, - - // @method stopLocate(): this - // Stops watching location previously initiated by `map.locate({watch: true})` - // and aborts resetting the map view if map.locate was called with - // `{setView: true}`. - stopLocate: function () { - if (navigator.geolocation && navigator.geolocation.clearWatch) { - navigator.geolocation.clearWatch(this._locationWatchId); - } - if (this._locateOptions) { - this._locateOptions.setView = false; - } - return this; - }, - - _handleGeolocationError: function (error) { - let c = error.code, - message = error.message || - (c === 1 ? 'permission denied' : - (c === 2 ? 'position unavailable' : 'timeout')); - - if (this._locateOptions.setView && !this._loaded) { - this.fitWorld(); - } - - // @section Location events - // @event locationerror: ErrorEvent - // Fired when geolocation (using the [`locate`](#map-locate) method) failed. - this.fire('locationerror', { - code: c, - message: 'Geolocation error: ' + message + '.' - }); - }, - - _handleGeolocationResponse: function (pos) { - let lat = pos.coords.latitude, - lng = pos.coords.longitude, - latlng = new LatLng(lat, lng), - bounds = latlng.toBounds(pos.coords.accuracy), - options = this._locateOptions; - - if (options.setView) { - let zoom = this.getBoundsZoom(bounds); - this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom); - } - - let data = { - latlng: latlng, - bounds: bounds, - timestamp: pos.timestamp - }; - - for (var i in pos.coords) { - if (typeof pos.coords[i] === 'number') { - data[i] = pos.coords[i]; - } - } - - // @event locationfound: LocationEvent - // Fired when geolocation (using the [`locate`](#map-locate) method) - // went successfully. - this.fire('locationfound', data); - }, - - // TODO Appropriate docs section? - // @section Other Methods - // @method addHandler(name: String, HandlerClass: Function): this - // Adds a new `Handler` to the map, given its name and constructor function. - addHandler: function (name, HandlerClass) { - if (!HandlerClass) { return this; } - - let handler = this[name] = new HandlerClass(this); - - this._handlers.push(handler); - - if (this.options[name]) { - handler.enable(); - } - - return this; - }, - - // @method remove(): this - // Destroys the map and clears all related event listeners. - remove: function () { - - this._initEvents(true); - - if (this._containerId !== this._container._leaflet_id) { - throw new Error('Map container is being reused by another instance'); - } - - try { - // throws error in IE6-8 - delete this._container._leaflet_id; - delete this._containerId; - } catch (e) { - /*eslint-disable */ - this._container._leaflet_id = undefined; - /* eslint-enable */ - this._containerId = undefined; - } - - if (this._locationWatchId !== undefined) { - this.stopLocate(); - } - - this._stop(); - - remove(this._mapPane); - - if (this._clearControlPos) { - this._clearControlPos(); - } - - this._clearHandlers(); - - if (this._loaded) { - // @section Map state change events - // @event unload: Event - // Fired when the map is destroyed with [remove](#map-remove) method. - this.fire('unload'); - } - - var i; - for (i in this._layers) { - this._layers[i].remove(); - } - for (i in this._panes) { - remove(this._panes[i]); - } - - this._layers = []; - this._panes = []; - delete this._mapPane; - delete this._renderer; - - return this; - }, - - // @section Other Methods - // @method createPane(name: String, container?: HTMLElement): HTMLElement - // Creates a new [map pane](#map-pane) with the given name if it doesn't exist already, - // then returns it. The pane is created as a child of `container`, or - // as a child of the main map pane if not set. - createPane: function (name, container) { - let className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''), - pane = create$1('div', className, container || this._mapPane); - - if (name) { - this._panes[name] = pane; - } - return pane; - }, - - // @section Methods for Getting Map State - - // @method getCenter(): LatLng - // Returns the geographical center of the map view - getCenter: function () { - this._checkIfLoaded(); - - if (this._lastCenter && !this._moved()) { - return this._lastCenter; - } - return this.layerPointToLatLng(this._getCenterLayerPoint()); - }, - - // @method getZoom(): Number - // Returns the current zoom level of the map view - getZoom: function () { - return this._zoom; - }, - - // @method getBounds(): LatLngBounds - // Returns the geographical bounds visible in the current map view - getBounds: function () { - let bounds = this.getPixelBounds(), - sw = this.unproject(bounds.getBottomLeft()), - ne = this.unproject(bounds.getTopRight()); - - return new LatLngBounds(sw, ne); - }, - - // @method getMinZoom(): Number - // Returns the minimum zoom level of the map (if set in the `minZoom` option of the map or of any layers), or `0` by default. - getMinZoom: function () { - return this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom; - }, - - // @method getMaxZoom(): Number - // Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers). - getMaxZoom: function () { - return this.options.maxZoom === undefined ? - (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) : - this.options.maxZoom; - }, - - // @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean): Number - // Returns the maximum zoom level on which the given bounds fit to the map - // view in its entirety. If `inside` (optional) is set to `true`, the method - // instead returns the minimum zoom level on which the map view fits into - // the given bounds in its entirety. - getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number - bounds = toLatLngBounds(bounds); - padding = toPoint(padding || [0, 0]); - - let zoom = this.getZoom() || 0, - min = this.getMinZoom(), - max = this.getMaxZoom(), - nw = bounds.getNorthWest(), - se = bounds.getSouthEast(), - size = this.getSize().subtract(padding), - boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(), - snap = any3d ? this.options.zoomSnap : 1, - scalex = size.x / boundsSize.x, - scaley = size.y / boundsSize.y, - scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley); - - zoom = this.getScaleZoom(scale, zoom); - - if (snap) { - zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level - zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap; - } - - return Math.max(min, Math.min(max, zoom)); - }, - - // @method getSize(): Point - // Returns the current size of the map container (in pixels). - getSize: function () { - if (!this._size || this._sizeChanged) { - this._size = new Point( - this._container.clientWidth || 0, - this._container.clientHeight || 0); - - this._sizeChanged = false; - } - return this._size.clone(); - }, - - // @method getPixelBounds(): Bounds - // Returns the bounds of the current map view in projected pixel - // coordinates (sometimes useful in layer and overlay implementations). - getPixelBounds: function (center, zoom) { - let topLeftPoint = this._getTopLeftPoint(center, zoom); - return new Bounds(topLeftPoint, topLeftPoint.add(this.getSize())); - }, - - // TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to - // the map pane? "left point of the map layer" can be confusing, specially - // since there can be negative offsets. - // @method getPixelOrigin(): Point - // Returns the projected pixel coordinates of the top left point of - // the map layer (useful in custom layer and overlay implementations). - getPixelOrigin: function () { - this._checkIfLoaded(); - return this._pixelOrigin; - }, - - // @method getPixelWorldBounds(zoom?: Number): Bounds - // Returns the world's bounds in pixel coordinates for zoom level `zoom`. - // If `zoom` is omitted, the map's current zoom level is used. - getPixelWorldBounds: function (zoom) { - return this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom); - }, - - // @section Other Methods - - // @method getPane(pane: String|HTMLElement): HTMLElement - // Returns a [map pane](#map-pane), given its name or its HTML element (its identity). - getPane: function (pane) { - return typeof pane === 'string' ? this._panes[pane] : pane; - }, - - // @method getPanes(): Object - // Returns a plain object containing the names of all [panes](#map-pane) as keys and - // the panes as values. - getPanes: function () { - return this._panes; - }, - - // @method getContainer: HTMLElement - // Returns the HTML element that contains the map. - getContainer: function () { - return this._container; - }, - - - // @section Conversion Methods - - // @method getZoomScale(toZoom: Number, fromZoom: Number): Number - // Returns the scale factor to be applied to a map transition from zoom level - // `fromZoom` to `toZoom`. Used internally to help with zoom animations. - getZoomScale: function (toZoom, fromZoom) { - // TODO replace with universal implementation after refactoring projections - let crs = this.options.crs; - fromZoom = fromZoom === undefined ? this._zoom : fromZoom; - return crs.scale(toZoom) / crs.scale(fromZoom); - }, - - // @method getScaleZoom(scale: Number, fromZoom: Number): Number - // Returns the zoom level that the map would end up at, if it is at `fromZoom` - // level and everything is scaled by a factor of `scale`. Inverse of - // [`getZoomScale`](#map-getZoomScale). - getScaleZoom: function (scale, fromZoom) { - let crs = this.options.crs; - fromZoom = fromZoom === undefined ? this._zoom : fromZoom; - let zoom = crs.zoom(scale * crs.scale(fromZoom)); - return isNaN(zoom) ? Infinity : zoom; - }, - - // @method project(latlng: LatLng, zoom: Number): Point - // Projects a geographical coordinate `LatLng` according to the projection - // of the map's CRS, then scales it according to `zoom` and the CRS's - // `Transformation`. The result is pixel coordinate relative to - // the CRS origin. - project: function (latlng, zoom) { - zoom = zoom === undefined ? this._zoom : zoom; - return this.options.crs.latLngToPoint(toLatLng(latlng), zoom); - }, - - // @method unproject(point: Point, zoom: Number): LatLng - // Inverse of [`project`](#map-project). - unproject: function (point, zoom) { - zoom = zoom === undefined ? this._zoom : zoom; - return this.options.crs.pointToLatLng(toPoint(point), zoom); - }, - - // @method layerPointToLatLng(point: Point): LatLng - // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin), - // returns the corresponding geographical coordinate (for the current zoom level). - layerPointToLatLng: function (point) { - let projectedPoint = toPoint(point).add(this.getPixelOrigin()); - return this.unproject(projectedPoint); - }, - - // @method latLngToLayerPoint(latlng: LatLng): Point - // Given a geographical coordinate, returns the corresponding pixel coordinate - // relative to the [origin pixel](#map-getpixelorigin). - latLngToLayerPoint: function (latlng) { - let projectedPoint = this.project(toLatLng(latlng))._round(); - return projectedPoint._subtract(this.getPixelOrigin()); - }, - - // @method wrapLatLng(latlng: LatLng): LatLng - // Returns a `LatLng` where `lat` and `lng` has been wrapped according to the - // map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the - // CRS's bounds. - // By default this means longitude is wrapped around the dateline so its - // value is between -180 and +180 degrees. - wrapLatLng: function (latlng) { - return this.options.crs.wrapLatLng(toLatLng(latlng)); - }, - - // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds - // Returns a `LatLngBounds` with the same size as the given one, ensuring that - // its center is within the CRS's bounds. - // By default this means the center longitude is wrapped around the dateline so its - // value is between -180 and +180 degrees, and the majority of the bounds - // overlaps the CRS's bounds. - wrapLatLngBounds: function (latlng) { - return this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng)); - }, - - // @method distance(latlng1: LatLng, latlng2: LatLng): Number - // Returns the distance between two geographical coordinates according to - // the map's CRS. By default this measures distance in meters. - distance: function (latlng1, latlng2) { - return this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2)); - }, - - // @method containerPointToLayerPoint(point: Point): Point - // Given a pixel coordinate relative to the map container, returns the corresponding - // pixel coordinate relative to the [origin pixel](#map-getpixelorigin). - containerPointToLayerPoint: function (point) { // (Point) - return toPoint(point).subtract(this._getMapPanePos()); - }, - - // @method layerPointToContainerPoint(point: Point): Point - // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin), - // returns the corresponding pixel coordinate relative to the map container. - layerPointToContainerPoint: function (point) { // (Point) - return toPoint(point).add(this._getMapPanePos()); - }, - - // @method containerPointToLatLng(point: Point): LatLng - // Given a pixel coordinate relative to the map container, returns - // the corresponding geographical coordinate (for the current zoom level). - containerPointToLatLng: function (point) { - let layerPoint = this.containerPointToLayerPoint(toPoint(point)); - return this.layerPointToLatLng(layerPoint); - }, - - // @method latLngToContainerPoint(latlng: LatLng): Point - // Given a geographical coordinate, returns the corresponding pixel coordinate - // relative to the map container. - latLngToContainerPoint: function (latlng) { - return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng))); - }, - - // @method mouseEventToContainerPoint(ev: MouseEvent): Point - // Given a MouseEvent object, returns the pixel coordinate relative to the - // map container where the event took place. - mouseEventToContainerPoint: function (e) { - return getMousePosition(e, this._container); - }, - - // @method mouseEventToLayerPoint(ev: MouseEvent): Point - // Given a MouseEvent object, returns the pixel coordinate relative to - // the [origin pixel](#map-getpixelorigin) where the event took place. - mouseEventToLayerPoint: function (e) { - return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e)); - }, - - // @method mouseEventToLatLng(ev: MouseEvent): LatLng - // Given a MouseEvent object, returns geographical coordinate where the - // event took place. - mouseEventToLatLng: function (e) { // (MouseEvent) - return this.layerPointToLatLng(this.mouseEventToLayerPoint(e)); - }, - - - // map initialization methods - - _initContainer: function (id) { - let container = this._container = get(id); - - if (!container) { - throw new Error('Map container not found.'); - } else if (container._leaflet_id) { - throw new Error('Map container is already initialized.'); - } - - on(container, 'scroll', this._onScroll, this); - this._containerId = stamp(container); - }, - - _initLayout: function () { - let container = this._container; - - this._fadeAnimated = this.options.fadeAnimation && any3d; - - addClass(container, 'leaflet-container' + - (touch ? ' leaflet-touch' : '') + - (retina ? ' leaflet-retina' : '') + - (ielt9 ? ' leaflet-oldie' : '') + - (safari ? ' leaflet-safari' : '') + - (this._fadeAnimated ? ' leaflet-fade-anim' : '')); - - let position = getStyle(container, 'position'); - - if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') { - container.style.position = 'relative'; - } - - this._initPanes(); - - if (this._initControlPos) { - this._initControlPos(); - } - }, - - _initPanes: function () { - let panes = this._panes = {}; - this._paneRenderers = {}; - - // @section - // - // Panes are DOM elements used to control the ordering of layers on the map. You - // can access panes with [`map.getPane`](#map-getpane) or - // [`map.getPanes`](#map-getpanes) methods. New panes can be created with the - // [`map.createPane`](#map-createpane) method. - // - // Every map has the following default panes that differ only in zIndex. - // - // @pane mapPane: HTMLElement = 'auto' - // Pane that contains all other map panes - - this._mapPane = this.createPane('mapPane', this._container); - setPosition(this._mapPane, new Point(0, 0)); - - // @pane tilePane: HTMLElement = 200 - // Pane for `GridLayer`s and `TileLayer`s - this.createPane('tilePane'); - // @pane overlayPane: HTMLElement = 400 - // Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s - this.createPane('shadowPane'); - // @pane shadowPane: HTMLElement = 500 - // Pane for overlay shadows (e.g. `Marker` shadows) - this.createPane('overlayPane'); - // @pane markerPane: HTMLElement = 600 - // Pane for `Icon`s of `Marker`s - this.createPane('markerPane'); - // @pane tooltipPane: HTMLElement = 650 - // Pane for `Tooltip`s. - this.createPane('tooltipPane'); - // @pane popupPane: HTMLElement = 700 - // Pane for `Popup`s. - this.createPane('popupPane'); - - if (!this.options.markerZoomAnimation) { - addClass(panes.markerPane, 'leaflet-zoom-hide'); - addClass(panes.shadowPane, 'leaflet-zoom-hide'); - } - }, - - - // private methods that modify map state - - // @section Map state change events - _resetView: function (center, zoom) { - setPosition(this._mapPane, new Point(0, 0)); - - let loading = !this._loaded; - this._loaded = true; - zoom = this._limitZoom(zoom); - - this.fire('viewprereset'); - - let zoomChanged = this._zoom !== zoom; - this - ._moveStart(zoomChanged, false) - ._move(center, zoom) - ._moveEnd(zoomChanged); - - // @event viewreset: Event - // Fired when the map needs to redraw its content (this usually happens - // on map zoom or load). Very useful for creating custom overlays. - this.fire('viewreset'); - - // @event load: Event - // Fired when the map is initialized (when its center and zoom are set - // for the first time). - if (loading) { - this.fire('load'); - } - }, - - _moveStart: function (zoomChanged, noMoveStart) { - // @event zoomstart: Event - // Fired when the map zoom is about to change (e.g. before zoom animation). - // @event movestart: Event - // Fired when the view of the map starts changing (e.g. user starts dragging the map). - if (zoomChanged) { - this.fire('zoomstart'); - } - if (!noMoveStart) { - this.fire('movestart'); - } - return this; - }, - - _move: function (center, zoom, data) { - if (zoom === undefined) { - zoom = this._zoom; - } - let zoomChanged = this._zoom !== zoom; - - this._zoom = zoom; - this._lastCenter = center; - this._pixelOrigin = this._getNewPixelOrigin(center); - - // @event zoom: Event - // Fired repeatedly during any change in zoom level, including zoom - // and fly animations. - if (zoomChanged || (data && data.pinch)) { // Always fire 'zoom' if pinching because #3530 - this.fire('zoom', data); - } - - // @event move: Event - // Fired repeatedly during any movement of the map, including pan and - // fly animations. - return this.fire('move', data); - }, - - _moveEnd: function (zoomChanged) { - // @event zoomend: Event - // Fired when the map has changed, after any animations. - if (zoomChanged) { - this.fire('zoomend'); - } - - // @event moveend: Event - // Fired when the center of the map stops changing (e.g. user stopped - // dragging the map). - return this.fire('moveend'); - }, - - _stop: function () { - cancelAnimFrame(this._flyToFrame); - if (this._panAnim) { - this._panAnim.stop(); - } - return this; - }, - - _rawPanBy: function (offset) { - setPosition(this._mapPane, this._getMapPanePos().subtract(offset)); - }, - - _getZoomSpan: function () { - return this.getMaxZoom() - this.getMinZoom(); - }, - - _panInsideMaxBounds: function () { - if (!this._enforcingBounds) { - this.panInsideBounds(this.options.maxBounds); - } - }, - - _checkIfLoaded: function () { - if (!this._loaded) { - throw new Error('Set map center and zoom first.'); - } - }, - - // DOM event handling - - // @section Interaction events - _initEvents: function (remove$$1) { - this._targets = {}; - this._targets[stamp(this._container)] = this; - - let onOff = remove$$1 ? off : on; - - // @event click: MouseEvent - // Fired when the user clicks (or taps) the map. - // @event dblclick: MouseEvent - // Fired when the user double-clicks (or double-taps) the map. - // @event mousedown: MouseEvent - // Fired when the user pushes the mouse button on the map. - // @event mouseup: MouseEvent - // Fired when the user releases the mouse button on the map. - // @event mouseover: MouseEvent - // Fired when the mouse enters the map. - // @event mouseout: MouseEvent - // Fired when the mouse leaves the map. - // @event mousemove: MouseEvent - // Fired while the mouse moves over the map. - // @event contextmenu: MouseEvent - // Fired when the user pushes the right mouse button on the map, prevents - // default browser context menu from showing if there are listeners on - // this event. Also fired on mobile when the user holds a single touch - // for a second (also called long press). - // @event keypress: KeyboardEvent - // Fired when the user presses a key from the keyboard while the map is focused. - onOff(this._container, 'click dblclick mousedown mouseup ' + - 'mouseover mouseout mousemove contextmenu keypress', this._handleDOMEvent, this); - - if (this.options.trackResize) { - onOff(window, 'resize', this._onResize, this); - } - - if (any3d && this.options.transform3DLimit) { - (remove$$1 ? this.off : this.on).call(this, 'moveend', this._onMoveEnd); - } - }, - - _onResize: function () { - cancelAnimFrame(this._resizeRequest); - this._resizeRequest = requestAnimFrame( - function () { this.invalidateSize({debounceMoveend: true}); }, this); - }, - - _onScroll: function () { - this._container.scrollTop = 0; - this._container.scrollLeft = 0; - }, - - _onMoveEnd: function () { - let pos = this._getMapPanePos(); - if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) { - // https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have - // a pixel offset on very high values, see: http://jsfiddle.net/dg6r5hhb/ - this._resetView(this.getCenter(), this.getZoom()); - } - }, - - _findEventTargets: function (e, type) { - let targets = [], - target, - isHover = type === 'mouseout' || type === 'mouseover', - src = e.target || e.srcElement, - dragging = false; - - while (src) { - target = this._targets[stamp(src)]; - if (target && (type === 'click' || type === 'preclick') && !e._simulated && this._draggableMoved(target)) { - // Prevent firing click after you just dragged an object. - dragging = true; - break; - } - if (target && target.listens(type, true)) { - if (isHover && !isExternalTarget(src, e)) { break; } - targets.push(target); - if (isHover) { break; } - } - if (src === this._container) { break; } - src = src.parentNode; - } - if (!targets.length && !dragging && !isHover && isExternalTarget(src, e)) { - targets = [this]; - } - return targets; - }, - - _handleDOMEvent: function (e) { - if (!this._loaded || skipped(e)) { return; } - - let type = e.type; - - if (type === 'mousedown' || type === 'keypress') { - // prevents outline when clicking on keyboard-focusable element - preventOutline(e.target || e.srcElement); - } - - this._fireDOMEvent(e, type); - }, - - _mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'], - - _fireDOMEvent: function (e, type, targets) { - - if (e.type === 'click') { - // Fire a synthetic 'preclick' event which propagates up (mainly for closing popups). - // @event preclick: MouseEvent - // Fired before mouse click on the map (sometimes useful when you - // want something to happen on click before any existing click - // handlers start running). - let synth = extend({}, e); - synth.type = 'preclick'; - this._fireDOMEvent(synth, synth.type, targets); - } - - if (e._stopped) { return; } - - // Find the layer the event is propagating from and its parents. - targets = (targets || []).concat(this._findEventTargets(e, type)); - - if (!targets.length) { return; } - - let target = targets[0]; - if (type === 'contextmenu' && target.listens(type, true)) { - preventDefault(e); - } - - let data = { - originalEvent: e - }; - - if (e.type !== 'keypress') { - let isMarker = target.getLatLng && (!target._radius || target._radius <= 10); - data.containerPoint = isMarker ? - this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e); - data.layerPoint = this.containerPointToLayerPoint(data.containerPoint); - data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint); - } - - for (let i = 0; i < targets.length; i++) { - targets[i].fire(type, data, true); - if (data.originalEvent._stopped || - (targets[i].options.bubblingMouseEvents === false && indexOf(this._mouseEvents, type) !== -1)) { return; } - } - }, - - _draggableMoved: function (obj) { - obj = obj.dragging && obj.dragging.enabled() ? obj : this; - return (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved()); - }, - - _clearHandlers: function () { - for (let i = 0, len = this._handlers.length; i < len; i++) { - this._handlers[i].disable(); - } - }, - - // @section Other Methods - - // @method whenReady(fn: Function, context?: Object): this - // Runs the given function `fn` when the map gets initialized with - // a view (center and zoom) and at least one layer, or immediately - // if it's already initialized, optionally passing a function context. - whenReady: function (callback, context) { - if (this._loaded) { - callback.call(context || this, {target: this}); - } else { - this.on('load', callback, context); - } - return this; - }, - - - // private methods for getting map state - - _getMapPanePos: function () { - return getPosition(this._mapPane) || new Point(0, 0); - }, - - _moved: function () { - let pos = this._getMapPanePos(); - return pos && !pos.equals([0, 0]); - }, - - _getTopLeftPoint: function (center, zoom) { - let pixelOrigin = center && zoom !== undefined ? - this._getNewPixelOrigin(center, zoom) : - this.getPixelOrigin(); - return pixelOrigin.subtract(this._getMapPanePos()); - }, - - _getNewPixelOrigin: function (center, zoom) { - let viewHalf = this.getSize()._divideBy(2); - return this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round(); - }, - - _latLngToNewLayerPoint: function (latlng, zoom, center) { - let topLeft = this._getNewPixelOrigin(center, zoom); - return this.project(latlng, zoom)._subtract(topLeft); - }, - - _latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) { - let topLeft = this._getNewPixelOrigin(center, zoom); - return toBounds([ - this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft), - this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft), - this.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft), - this.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft) - ]); - }, - - // layer point of the current center - _getCenterLayerPoint: function () { - return this.containerPointToLayerPoint(this.getSize()._divideBy(2)); - }, - - // offset of the specified place to the current center in pixels - _getCenterOffset: function (latlng) { - return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint()); - }, - - // adjust center for view to get inside bounds - _limitCenter: function (center, zoom, bounds) { - - if (!bounds) { return center; } - - let centerPoint = this.project(center, zoom), - viewHalf = this.getSize().divideBy(2), - viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)), - offset = this._getBoundsOffset(viewBounds, bounds, zoom); - - // If offset is less than a pixel, ignore. - // This prevents unstable projections from getting into - // an infinite loop of tiny offsets. - if (offset.round().equals([0, 0])) { - return center; - } - - return this.unproject(centerPoint.add(offset), zoom); - }, - - // adjust offset for view to get inside bounds - _limitOffset: function (offset, bounds) { - if (!bounds) { return offset; } - - let viewBounds = this.getPixelBounds(), - newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset)); - - return offset.add(this._getBoundsOffset(newBounds, bounds)); - }, - - // returns offset needed for pxBounds to get inside maxBounds at a specified zoom - _getBoundsOffset: function (pxBounds, maxBounds, zoom) { - let projectedMaxBounds = toBounds( - this.project(maxBounds.getNorthEast(), zoom), - this.project(maxBounds.getSouthWest(), zoom) - ), - minOffset = projectedMaxBounds.min.subtract(pxBounds.min), - maxOffset = projectedMaxBounds.max.subtract(pxBounds.max), - - dx = this._rebound(minOffset.x, -maxOffset.x), - dy = this._rebound(minOffset.y, -maxOffset.y); - - return new Point(dx, dy); - }, - - _rebound: function (left, right) { - return left + right > 0 ? - Math.round(left - right) / 2 : - Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right)); - }, - - _limitZoom: function (zoom) { - let min = this.getMinZoom(), - max = this.getMaxZoom(), - snap = any3d ? this.options.zoomSnap : 1; - if (snap) { - zoom = Math.round(zoom / snap) * snap; - } - return Math.max(min, Math.min(max, zoom)); - }, - - _onPanTransitionStep: function () { - this.fire('move'); - }, - - _onPanTransitionEnd: function () { - removeClass(this._mapPane, 'leaflet-pan-anim'); - this.fire('moveend'); - }, - - _tryAnimatedPan: function (center, options) { - // difference between the new and current centers in pixels - let offset = this._getCenterOffset(center)._trunc(); - - // don't animate too far unless animate: true specified in options - if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; } - - this.panBy(offset, options); - - return true; - }, - - _createAnimProxy: function () { - - let proxy = this._proxy = create$1('div', 'leaflet-proxy leaflet-zoom-animated'); - this._panes.mapPane.appendChild(proxy); - - this.on('zoomanim', function (e) { - let prop = TRANSFORM, - transform = this._proxy.style[prop]; - - setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1)); - - // workaround for case when transform is the same and so transitionend event is not fired - if (transform === this._proxy.style[prop] && this._animatingZoom) { - this._onZoomTransitionEnd(); - } - }, this); - - this.on('load moveend', function () { - let c = this.getCenter(), - z = this.getZoom(); - setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1)); - }, this); - - this._on('unload', this._destroyAnimProxy, this); - }, - - _destroyAnimProxy: function () { - remove(this._proxy); - delete this._proxy; - }, - - _catchTransitionEnd: function (e) { - if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) { - this._onZoomTransitionEnd(); - } - }, - - _nothingToAnimate: function () { - return !this._container.getElementsByClassName('leaflet-zoom-animated').length; - }, - - _tryAnimatedZoom: function (center, zoom, options) { - - if (this._animatingZoom) { return true; } - - options = options || {}; - - // don't animate if disabled, not supported or zoom difference is too large - if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() || - Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; } - - // offset is the pixel coords of the zoom origin relative to the current center - let scale = this.getZoomScale(zoom), - offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale); - - // don't animate if the zoom origin isn't within one screen from the current center, unless forced - if (options.animate !== true && !this.getSize().contains(offset)) { return false; } - - requestAnimFrame(function () { - this - ._moveStart(true, false) - ._animateZoom(center, zoom, true); - }, this); - - return true; - }, - - _animateZoom: function (center, zoom, startAnim, noUpdate) { - if (!this._mapPane) { return; } - - if (startAnim) { - this._animatingZoom = true; - - // remember what center/zoom to set after animation - this._animateToCenter = center; - this._animateToZoom = zoom; - - addClass(this._mapPane, 'leaflet-zoom-anim'); - } - - // @event zoomanim: ZoomAnimEvent - // Fired on every frame of a zoom animation - this.fire('zoomanim', { - center: center, - zoom: zoom, - noUpdate: noUpdate - }); - - // Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693 - setTimeout(bind(this._onZoomTransitionEnd, this), 250); - }, - - _onZoomTransitionEnd: function () { - if (!this._animatingZoom) { return; } - - if (this._mapPane) { - removeClass(this._mapPane, 'leaflet-zoom-anim'); - } - - this._animatingZoom = false; - - this._move(this._animateToCenter, this._animateToZoom); - - // This anim frame should prevent an obscure iOS webkit tile loading race condition. - requestAnimFrame(function () { - this._moveEnd(true); - }, this); - } -}); - -// @section - -// @factory L.map(id: String, options?: Map options) -// Instantiates a map object given the DOM ID of a `
    ` element -// and optionally an object literal with `Map options`. -// -// @alternative -// @factory L.map(el: HTMLElement, options?: Map options) -// Instantiates a map object given an instance of a `
    ` HTML element -// and optionally an object literal with `Map options`. -function createMap(id, options) { - return new Map(id, options); -} - -/* - * @class Control - * @aka L.Control - * @inherits Class - * - * L.Control is a base class for implementing map controls. Handles positioning. - * All other controls extend from this class. - */ - -let Control = Class.extend({ - // @section - // @aka Control options - options: { - // @option position: String = 'topright' - // The position of the control (one of the map corners). Possible values are `'topleft'`, - // `'topright'`, `'bottomleft'` or `'bottomright'` - position: 'topright' - }, - - initialize: function (options) { - setOptions(this, options); - }, - - /* @section - * Classes extending L.Control will inherit the following methods: - * - * @method getPosition: string - * Returns the position of the control. - */ - getPosition: function () { - return this.options.position; - }, - - // @method setPosition(position: string): this - // Sets the position of the control. - setPosition: function (position) { - let map = this._map; - - if (map) { - map.removeControl(this); - } - - this.options.position = position; - - if (map) { - map.addControl(this); - } - - return this; - }, - - // @method getContainer: HTMLElement - // Returns the HTMLElement that contains the control. - getContainer: function () { - return this._container; - }, - - // @method addTo(map: Map): this - // Adds the control to the given map. - addTo: function (map) { - this.remove(); - this._map = map; - - let container = this._container = this.onAdd(map), - pos = this.getPosition(), - corner = map._controlCorners[pos]; - - addClass(container, 'leaflet-control'); - - if (pos.indexOf('bottom') !== -1) { - corner.insertBefore(container, corner.firstChild); - } else { - corner.appendChild(container); - } - - return this; - }, - - // @method remove: this - // Removes the control from the map it is currently active on. - remove: function () { - if (!this._map) { - return this; - } - - remove(this._container); - - if (this.onRemove) { - this.onRemove(this._map); - } - - this._map = null; - - return this; - }, - - _refocusOnMap: function (e) { - // if map exists and event is not a keyboard event - if (this._map && e && e.screenX > 0 && e.screenY > 0) { - this._map.getContainer().focus(); - } - } -}); - -let control = (options) => { - return new Control(options); -}; - -/* @section Extension methods - * @uninheritable - * - * Every control should extend from `L.Control` and (re-)implement the following methods. - * - * @method onAdd(map: Map): HTMLElement - * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo). - * - * @method onRemove(map: Map) - * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove). - */ - -/* @namespace Map - * @section Methods for Layers and Controls - */ -Map.include({ - // @method addControl(control: Control): this - // Adds the given control to the map - addControl: function (control) { - control.addTo(this); - return this; - }, - - // @method removeControl(control: Control): this - // Removes the given control from the map - removeControl: function (control) { - control.remove(); - return this; - }, - - _initControlPos: function () { - let corners = this._controlCorners = {}, - l = 'leaflet-', - container = this._controlContainer = - create$1('div', l + 'control-container', this._container); - - function createCorner(vSide, hSide) { - let className = l + vSide + ' ' + l + hSide; - - corners[vSide + hSide] = create$1('div', className, container); - } - - createCorner('top', 'left'); - createCorner('top', 'right'); - createCorner('bottom', 'left'); - createCorner('bottom', 'right'); - }, - - _clearControlPos: function () { - for (var i in this._controlCorners) { - remove(this._controlCorners[i]); - } - remove(this._controlContainer); - delete this._controlCorners; - delete this._controlContainer; - } -}); - -/* - * @class Control.Layers - * @aka L.Control.Layers - * @inherits Control - * - * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](http://leafletjs.com/examples/layers-control/)). Extends `Control`. - * - * @example - * - * ```js - * let baseLayers = { - * "Mapbox": mapbox, - * "OpenStreetMap": osm - * }; - * - * let overlays = { - * "Marker": marker, - * "Roads": roadsLayer - * }; - * - * L.control.layers(baseLayers, overlays).addTo(map); - * ``` - * - * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values: - * - * ```js - * { - * "": layer1, - * "": layer2 - * } - * ``` - * - * The layer names can contain HTML, which allows you to add additional styling to the items: - * - * ```js - * {" My Layer": myLayer} - * ``` - */ - -let Layers = Control.extend({ - // @section - // @aka Control.Layers options - options: { - // @option collapsed: Boolean = true - // If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch. - collapsed: true, - position: 'topright', - - // @option autoZIndex: Boolean = true - // If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off. - autoZIndex: true, - - // @option hideSingleBase: Boolean = false - // If `true`, the base layers in the control will be hidden when there is only one. - hideSingleBase: false, - - // @option sortLayers: Boolean = false - // Whether to sort the layers. When `false`, layers will keep the order - // in which they were added to the control. - sortLayers: false, - - // @option sortFunction: Function = * - // A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) - // that will be used for sorting the layers, when `sortLayers` is `true`. - // The function receives both the `L.Layer` instances and their names, as in - // `sortFunction(layerA, layerB, nameA, nameB)`. - // By default, it sorts layers alphabetically by their name. - sortFunction: function (layerA, layerB, nameA, nameB) { - return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0); - } - }, - - initialize: function (baseLayers, overlays, options) { - setOptions(this, options); - - this._layerControlInputs = []; - this._layers = []; - this._lastZIndex = 0; - this._handlingClick = false; - - for (var i in baseLayers) { - this._addLayer(baseLayers[i], i); - } - - for (i in overlays) { - this._addLayer(overlays[i], i, true); - } - }, - - onAdd: function (map) { - this._initLayout(); - this._update(); - - this._map = map; - map.on('zoomend', this._checkDisabledLayers, this); - - for (let i = 0; i < this._layers.length; i++) { - this._layers[i].layer.on('add remove', this._onLayerChange, this); - } - - return this._container; - }, - - addTo: function (map) { - Control.prototype.addTo.call(this, map); - // Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height. - return this._expandIfNotCollapsed(); - }, - - onRemove: function () { - this._map.off('zoomend', this._checkDisabledLayers, this); - - for (let i = 0; i < this._layers.length; i++) { - this._layers[i].layer.off('add remove', this._onLayerChange, this); - } - }, - - // @method addBaseLayer(layer: Layer, name: String): this - // Adds a base layer (radio button entry) with the given name to the control. - addBaseLayer: function (layer, name) { - this._addLayer(layer, name); - return (this._map) ? this._update() : this; - }, - - // @method addOverlay(layer: Layer, name: String): this - // Adds an overlay (checkbox entry) with the given name to the control. - addOverlay: function (layer, name) { - this._addLayer(layer, name, true); - return (this._map) ? this._update() : this; - }, - - // @method removeLayer(layer: Layer): this - // Remove the given layer from the control. - removeLayer: function (layer) { - layer.off('add remove', this._onLayerChange, this); - - let obj = this._getLayer(stamp(layer)); - if (obj) { - this._layers.splice(this._layers.indexOf(obj), 1); - } - return (this._map) ? this._update() : this; - }, - - // @method expand(): this - // Expand the control container if collapsed. - expand: function () { - addClass(this._container, 'leaflet-control-layers-expanded'); - this._form.style.height = null; - let acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50); - if (acceptableHeight < this._form.clientHeight) { - addClass(this._form, 'leaflet-control-layers-scrollbar'); - this._form.style.height = acceptableHeight + 'px'; - } else { - removeClass(this._form, 'leaflet-control-layers-scrollbar'); - } - this._checkDisabledLayers(); - return this; - }, - - // @method collapse(): this - // Collapse the control container if expanded. - collapse: function () { - removeClass(this._container, 'leaflet-control-layers-expanded'); - return this; - }, - - _initLayout: function () { - let className = 'leaflet-control-layers', - container = this._container = create$1('div', className), - collapsed = this.options.collapsed; - - // makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released - container.setAttribute('aria-haspopup', true); - - disableClickPropagation(container); - disableScrollPropagation(container); - - let form = this._form = create$1('form', className + '-list'); - - if (collapsed) { - this._map.on('click', this.collapse, this); - - if (!android) { - on(container, { - mouseenter: this.expand, - mouseleave: this.collapse - }, this); - } - } - - let link = this._layersLink = create$1('a', className + '-toggle', container); - link.href = '#'; - link.title = 'Layers'; - - if (touch) { - on(link, 'click', stop); - on(link, 'click', this.expand, this); - } else { - on(link, 'focus', this.expand, this); - } - - if (!collapsed) { - this.expand(); - } - - this._baseLayersList = create$1('div', className + '-base', form); - this._separator = create$1('div', className + '-separator', form); - this._overlaysList = create$1('div', className + '-overlays', form); - - container.appendChild(form); - }, - - _getLayer: function (id) { - for (let i = 0; i < this._layers.length; i++) { - - if (this._layers[i] && stamp(this._layers[i].layer) === id) { - return this._layers[i]; - } - } - }, - - _addLayer: function (layer, name, overlay) { - if (this._map) { - layer.on('add remove', this._onLayerChange, this); - } - - this._layers.push({ - layer: layer, - name: name, - overlay: overlay - }); - - if (this.options.sortLayers) { - this._layers.sort(bind(function (a, b) { - return this.options.sortFunction(a.layer, b.layer, a.name, b.name); - }, this)); - } - - if (this.options.autoZIndex && layer.setZIndex) { - this._lastZIndex++; - layer.setZIndex(this._lastZIndex); - } - - this._expandIfNotCollapsed(); - }, - - _update: function () { - if (!this._container) { return this; } - - empty(this._baseLayersList); - empty(this._overlaysList); - - this._layerControlInputs = []; - var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0; - - for (i = 0; i < this._layers.length; i++) { - obj = this._layers[i]; - this._addItem(obj); - overlaysPresent = overlaysPresent || obj.overlay; - baseLayersPresent = baseLayersPresent || !obj.overlay; - baseLayersCount += !obj.overlay ? 1 : 0; - } - - // Hide base layers section if there's only one layer. - if (this.options.hideSingleBase) { - baseLayersPresent = baseLayersPresent && baseLayersCount > 1; - this._baseLayersList.style.display = baseLayersPresent ? '' : 'none'; - } - - this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none'; - - return this; - }, - - _onLayerChange: function (e) { - if (!this._handlingClick) { - this._update(); - } - - let obj = this._getLayer(stamp(e.target)); - - // @namespace Map - // @section Layer events - // @event baselayerchange: LayersControlEvent - // Fired when the base layer is changed through the [layer control](#control-layers). - // @event overlayadd: LayersControlEvent - // Fired when an overlay is selected through the [layer control](#control-layers). - // @event overlayremove: LayersControlEvent - // Fired when an overlay is deselected through the [layer control](#control-layers). - // @namespace Control.Layers - let type = obj.overlay ? - (e.type === 'add' ? 'overlayadd' : 'overlayremove') : - (e.type === 'add' ? 'baselayerchange' : null); - - if (type) { - this._map.fire(type, obj); - } - }, - - // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe) - _createRadioElement: function (name, checked) { - - let radioHtml = ''; - - let radioFragment = document.createElement('div'); - radioFragment.innerHTML = radioHtml; - - return radioFragment.firstChild; - }, - - _addItem: function (obj) { - let label = document.createElement('label'), - checked = this._map.hasLayer(obj.layer), - input; - - if (obj.overlay) { - input = document.createElement('input'); - input.type = 'checkbox'; - input.className = 'leaflet-control-layers-selector'; - input.defaultChecked = checked; - } else { - input = this._createRadioElement('leaflet-base-layers', checked); - } - - this._layerControlInputs.push(input); - input.layerId = stamp(obj.layer); - - on(input, 'click', this._onInputClick, this); - - let name = document.createElement('span'); - name.innerHTML = ' ' + obj.name; - - // Helps from preventing layer control flicker when checkboxes are disabled - // https://github.com/Leaflet/Leaflet/issues/2771 - let holder = document.createElement('div'); - - label.appendChild(holder); - holder.appendChild(input); - holder.appendChild(name); - - let container = obj.overlay ? this._overlaysList : this._baseLayersList; - container.appendChild(label); - - this._checkDisabledLayers(); - return label; - }, - - _onInputClick: function () { - let inputs = this._layerControlInputs, - input, layer; - let addedLayers = [], - removedLayers = []; - - this._handlingClick = true; - - for (let i = inputs.length - 1; i >= 0; i--) { - input = inputs[i]; - layer = this._getLayer(input.layerId).layer; - - if (input.checked) { - addedLayers.push(layer); - } else if (!input.checked) { - removedLayers.push(layer); - } - } - - // Bugfix issue 2318: Should remove all old layers before readding new ones - for (i = 0; i < removedLayers.length; i++) { - if (this._map.hasLayer(removedLayers[i])) { - this._map.removeLayer(removedLayers[i]); - } - } - for (i = 0; i < addedLayers.length; i++) { - if (!this._map.hasLayer(addedLayers[i])) { - this._map.addLayer(addedLayers[i]); - } - } - - this._handlingClick = false; - - this._refocusOnMap(); - }, - - _checkDisabledLayers: function () { - let inputs = this._layerControlInputs, - input, - layer, - zoom = this._map.getZoom(); - - for (let i = inputs.length - 1; i >= 0; i--) { - input = inputs[i]; - layer = this._getLayer(input.layerId).layer; - input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) || - (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom); - - } - }, - - _expandIfNotCollapsed: function () { - if (this._map && !this.options.collapsed) { - this.expand(); - } - return this; - }, - - _expand: function () { - // Backward compatibility, remove me in 1.1. - return this.expand(); - }, - - _collapse: function () { - // Backward compatibility, remove me in 1.1. - return this.collapse(); - } - -}); - - -// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options) -// Creates an attribution control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation. -let layers = (baseLayers, overlays, options) => { - return new Layers(baseLayers, overlays, options); -}; - -/* - * @class Control.Zoom - * @aka L.Control.Zoom - * @inherits Control - * - * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`. - */ - -let Zoom = Control.extend({ - // @section - // @aka Control.Zoom options - options: { - position: 'topleft', - - // @option zoomInText: String = '+' - // The text set on the 'zoom in' button. - zoomInText: '+', - - // @option zoomInTitle: String = 'Zoom in' - // The title set on the 'zoom in' button. - zoomInTitle: 'Zoom in', - - // @option zoomOutText: String = '−' - // The text set on the 'zoom out' button. - zoomOutText: '−', - - // @option zoomOutTitle: String = 'Zoom out' - // The title set on the 'zoom out' button. - zoomOutTitle: 'Zoom out' - }, - - onAdd: function (map) { - let zoomName = 'leaflet-control-zoom', - container = create$1('div', zoomName + ' leaflet-bar'), - options = this.options; - - this._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle, - zoomName + '-in', container, this._zoomIn); - this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle, - zoomName + '-out', container, this._zoomOut); - - this._updateDisabled(); - map.on('zoomend zoomlevelschange', this._updateDisabled, this); - - return container; - }, - - onRemove: function (map) { - map.off('zoomend zoomlevelschange', this._updateDisabled, this); - }, - - disable: function () { - this._disabled = true; - this._updateDisabled(); - return this; - }, - - enable: function () { - this._disabled = false; - this._updateDisabled(); - return this; - }, - - _zoomIn: function (e) { - if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) { - this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1)); - } - }, - - _zoomOut: function (e) { - if (!this._disabled && this._map._zoom > this._map.getMinZoom()) { - this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1)); - } - }, - - _createButton: function (html, title, className, container, fn) { - let link = create$1('a', className, container); - link.innerHTML = html; - link.href = '#'; - link.title = title; - - /* - * Will force screen readers like VoiceOver to read this as "Zoom in - button" - */ - link.setAttribute('role', 'button'); - link.setAttribute('aria-label', title); - - disableClickPropagation(link); - on(link, 'click', stop); - on(link, 'click', fn, this); - on(link, 'click', this._refocusOnMap, this); - - return link; - }, - - _updateDisabled: function () { - let map = this._map, - className = 'leaflet-disabled'; - - removeClass(this._zoomInButton, className); - removeClass(this._zoomOutButton, className); - - if (this._disabled || map._zoom === map.getMinZoom()) { - addClass(this._zoomOutButton, className); - } - if (this._disabled || map._zoom === map.getMaxZoom()) { - addClass(this._zoomInButton, className); - } - } -}); - -// @namespace Map -// @section Control options -// @option zoomControl: Boolean = true -// Whether a [zoom control](#control-zoom) is added to the map by default. -Map.mergeOptions({ - zoomControl: true -}); - -Map.addInitHook(function () { - if (this.options.zoomControl) { - this.zoomControl = new Zoom(); - this.addControl(this.zoomControl); - } -}); - -// @namespace Control.Zoom -// @factory L.control.zoom(options: Control.Zoom options) -// Creates a zoom control -let zoom = (options) => { - return new Zoom(options); -}; - -/* - * @class Control.Scale - * @aka L.Control.Scale - * @inherits Control - * - * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`. - * - * @example - * - * ```js - * L.control.scale().addTo(map); - * ``` - */ - -let Scale = Control.extend({ - // @section - // @aka Control.Scale options - options: { - position: 'bottomleft', - - // @option maxWidth: Number = 100 - // Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500). - maxWidth: 100, - - // @option metric: Boolean = True - // Whether to show the metric scale line (m/km). - metric: true, - - // @option imperial: Boolean = True - // Whether to show the imperial scale line (mi/ft). - imperial: true - - // @option updateWhenIdle: Boolean = false - // If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)). - }, - - onAdd: function (map) { - let className = 'leaflet-control-scale', - container = create$1('div', className), - options = this.options; - - this._addScales(options, className + '-line', container); - - map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this); - map.whenReady(this._update, this); - - return container; - }, - - onRemove: function (map) { - map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this); - }, - - _addScales: function (options, className, container) { - if (options.metric) { - this._mScale = create$1('div', className, container); - } - if (options.imperial) { - this._iScale = create$1('div', className, container); - } - }, - - _update: function () { - let map = this._map, - y = map.getSize().y / 2; - - let maxMeters = map.distance( - map.containerPointToLatLng([0, y]), - map.containerPointToLatLng([this.options.maxWidth, y])); - - this._updateScales(maxMeters); - }, - - _updateScales: function (maxMeters) { - if (this.options.metric && maxMeters) { - this._updateMetric(maxMeters); - } - if (this.options.imperial && maxMeters) { - this._updateImperial(maxMeters); - } - }, - - _updateMetric: function (maxMeters) { - let meters = this._getRoundNum(maxMeters), - label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km'; - - this._updateScale(this._mScale, label, meters / maxMeters); - }, - - _updateImperial: function (maxMeters) { - let maxFeet = maxMeters * 3.2808399, - maxMiles, miles, feet; - - if (maxFeet > 5280) { - maxMiles = maxFeet / 5280; - miles = this._getRoundNum(maxMiles); - this._updateScale(this._iScale, miles + ' mi', miles / maxMiles); - - } else { - feet = this._getRoundNum(maxFeet); - this._updateScale(this._iScale, feet + ' ft', feet / maxFeet); - } - }, - - _updateScale: function (scale, text, ratio) { - scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px'; - scale.innerHTML = text; - }, - - _getRoundNum: function (num) { - var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1), - d = num / pow10; - - d = d >= 10 ? 10 : - d >= 5 ? 5 : - d >= 3 ? 3 : - d >= 2 ? 2 : 1; - - return pow10 * d; - } -}); - - -// @factory L.control.scale(options?: Control.Scale options) -// Creates an scale control with the given options. -let scale = (options) => { - return new Scale(options); -}; - -/* - * @class Control.Attribution - * @aka L.Control.Attribution - * @inherits Control - * - * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control. - */ - -let Attribution = Control.extend({ - // @section - // @aka Control.Attribution options - options: { - position: 'bottomright', - - // @option prefix: String = 'Leaflet' - // The HTML text shown before the attributions. Pass `false` to disable. - prefix: 'Leaflet' - }, - - initialize: function (options) { - setOptions(this, options); - - this._attributions = {}; - }, - - onAdd: function (map) { - map.attributionControl = this; - this._container = create$1('div', 'leaflet-control-attribution'); - disableClickPropagation(this._container); - - // TODO ugly, refactor - for (var i in map._layers) { - if (map._layers[i].getAttribution) { - this.addAttribution(map._layers[i].getAttribution()); - } - } - - this._update(); - - return this._container; - }, - - // @method setPrefix(prefix: String): this - // Sets the text before the attributions. - setPrefix: function (prefix) { - this.options.prefix = prefix; - this._update(); - return this; - }, - - // @method addAttribution(text: String): this - // Adds an attribution text (e.g. `'Vector data © Mapbox'`). - addAttribution: function (text) { - if (!text) { return this; } - - if (!this._attributions[text]) { - this._attributions[text] = 0; - } - this._attributions[text]++; - - this._update(); - - return this; - }, - - // @method removeAttribution(text: String): this - // Removes an attribution text. - removeAttribution: function (text) { - if (!text) { return this; } - - if (this._attributions[text]) { - this._attributions[text]--; - this._update(); - } - - return this; - }, - - _update: function () { - if (!this._map) { return; } - - let attribs = []; - - for (var i in this._attributions) { - if (this._attributions[i]) { - attribs.push(i); - } - } - - let prefixAndAttribs = []; - - if (this.options.prefix) { - prefixAndAttribs.push(this.options.prefix); - } - if (attribs.length) { - prefixAndAttribs.push(attribs.join(', ')); - } - - this._container.innerHTML = prefixAndAttribs.join(' | '); - } -}); - -// @namespace Map -// @section Control options -// @option attributionControl: Boolean = true -// Whether a [attribution control](#control-attribution) is added to the map by default. -Map.mergeOptions({ - attributionControl: true -}); - -Map.addInitHook(function () { - if (this.options.attributionControl) { - new Attribution().addTo(this); - } -}); - -// @namespace Control.Attribution -// @factory L.control.attribution(options: Control.Attribution options) -// Creates an attribution control. -let attribution = (options) => { - return new Attribution(options); -}; - -Control.Layers = Layers; -Control.Zoom = Zoom; -Control.Scale = Scale; -Control.Attribution = Attribution; - -control.layers = layers; -control.zoom = zoom; -control.scale = scale; -control.attribution = attribution; - -/* - L.Handler is a base class for handler classes that are used internally to inject - interaction features like dragging to classes like Map and Marker. -*/ - -// @class Handler -// @aka L.Handler -// Abstract class for map interaction handlers - -let Handler = Class.extend({ - initialize: function (map) { - this._map = map; - }, - - // @method enable(): this - // Enables the handler - enable: function () { - if (this._enabled) { return this; } - - this._enabled = true; - this.addHooks(); - return this; - }, - - // @method disable(): this - // Disables the handler - disable: function () { - if (!this._enabled) { return this; } - - this._enabled = false; - this.removeHooks(); - return this; - }, - - // @method enabled(): Boolean - // Returns `true` if the handler is enabled - enabled: function () { - return !!this._enabled; - } - - // @section Extension methods - // Classes inheriting from `Handler` must implement the two following methods: - // @method addHooks() - // Called when the handler is enabled, should add event hooks. - // @method removeHooks() - // Called when the handler is disabled, should remove the event hooks added previously. -}); - -// @section There is static function which can be called without instantiating L.Handler: -// @function addTo(map: Map, name: String): this -// Adds a new Handler to the given map with the given name. -Handler.addTo = (map, name) => { - map.addHandler(name, this); - return this; -}; - -let Mixin = {Events: Events}; - -/* - * @class Draggable - * @aka L.Draggable - * @inherits Evented - * - * A class for making DOM elements draggable (including touch support). - * Used internally for map and marker dragging. Only works for elements - * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition). - * - * @example - * ```js - * let draggable = new L.Draggable(elementToDrag); - * draggable.enable(); - * ``` - */ - -let START = touch ? 'touchstart mousedown' : 'mousedown'; -let END = { - mousedown: 'mouseup', - touchstart: 'touchend', - pointerdown: 'touchend', - MSPointerDown: 'touchend' -}; -let MOVE = { - mousedown: 'mousemove', - touchstart: 'touchmove', - pointerdown: 'touchmove', - MSPointerDown: 'touchmove' -}; - - -let Draggable = Evented.extend({ - - options: { - // @section - // @aka Draggable options - // @option clickTolerance: Number = 3 - // The max number of pixels a user can shift the mouse pointer during a click - // for it to be considered a valid click (as opposed to a mouse drag). - clickTolerance: 3 - }, - - // @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options) - // Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default). - initialize: function (element, dragStartTarget, preventOutline$$1, options) { - setOptions(this, options); - - this._element = element; - this._dragStartTarget = dragStartTarget || element; - this._preventOutline = preventOutline$$1; - }, - - // @method enable() - // Enables the dragging ability - enable: function () { - if (this._enabled) { return; } - - on(this._dragStartTarget, START, this._onDown, this); - - this._enabled = true; - }, - - // @method disable() - // Disables the dragging ability - disable: function () { - if (!this._enabled) { return; } - - // If we're currently dragging this draggable, - // disabling it counts as first ending the drag. - if (Draggable._dragging === this) { - this.finishDrag(); - } - - off(this._dragStartTarget, START, this._onDown, this); - - this._enabled = false; - this._moved = false; - }, - - _onDown: function (e) { - // Ignore simulated events, since we handle both touch and - // mouse explicitly; otherwise we risk getting duplicates of - // touch events, see #4315. - // Also ignore the event if disabled; this happens in IE11 - // under some circumstances, see #3666. - if (e._simulated || !this._enabled) { return; } - - this._moved = false; - - if (hasClass(this._element, 'leaflet-zoom-anim')) { return; } - - if (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; } - Draggable._dragging = this; // Prevent dragging multiple objects at once. - - if (this._preventOutline) { - preventOutline(this._element); - } - - disableImageDrag(); - disableTextSelection(); - - if (this._moving) { return; } - - // @event down: Event - // Fired when a drag is about to start. - this.fire('down'); - - let first = e.touches ? e.touches[0] : e; - - this._startPoint = new Point(first.clientX, first.clientY); - - on(document, MOVE[e.type], this._onMove, this); - on(document, END[e.type], this._onUp, this); - }, - - _onMove: function (e) { - // Ignore simulated events, since we handle both touch and - // mouse explicitly; otherwise we risk getting duplicates of - // touch events, see #4315. - // Also ignore the event if disabled; this happens in IE11 - // under some circumstances, see #3666. - if (e._simulated || !this._enabled) { return; } - - if (e.touches && e.touches.length > 1) { - this._moved = true; - return; - } - - let first = (e.touches && e.touches.length === 1 ? e.touches[0] : e), - newPoint = new Point(first.clientX, first.clientY), - offset = newPoint.subtract(this._startPoint); - - if (!offset.x && !offset.y) { return; } - if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; } - - preventDefault(e); - - if (!this._moved) { - // @event dragstart: Event - // Fired when a drag starts - this.fire('dragstart'); - - this._moved = true; - this._startPos = getPosition(this._element).subtract(offset); - - addClass(document.body, 'leaflet-dragging'); - - this._lastTarget = e.target || e.srcElement; - // IE and Edge do not give the element, so fetch it - // if necessary - if ((window.SVGElementInstance) && (this._lastTarget instanceof SVGElementInstance)) { - this._lastTarget = this._lastTarget.correspondingUseElement; - } - addClass(this._lastTarget, 'leaflet-drag-target'); - } - - this._newPos = this._startPos.add(offset); - this._moving = true; - - cancelAnimFrame(this._animRequest); - this._lastEvent = e; - this._animRequest = requestAnimFrame(this._updatePosition, this, true); - }, - - _updatePosition: function () { - let e = {originalEvent: this._lastEvent}; - - // @event predrag: Event - // Fired continuously during dragging *before* each corresponding - // update of the element's position. - this.fire('predrag', e); - setPosition(this._element, this._newPos); - - // @event drag: Event - // Fired continuously during dragging. - this.fire('drag', e); - }, - - _onUp: function (e) { - // Ignore simulated events, since we handle both touch and - // mouse explicitly; otherwise we risk getting duplicates of - // touch events, see #4315. - // Also ignore the event if disabled; this happens in IE11 - // under some circumstances, see #3666. - if (e._simulated || !this._enabled) { return; } - this.finishDrag(); - }, - - finishDrag: function () { - removeClass(document.body, 'leaflet-dragging'); - - if (this._lastTarget) { - removeClass(this._lastTarget, 'leaflet-drag-target'); - this._lastTarget = null; - } - - for (var i in MOVE) { - off(document, MOVE[i], this._onMove, this); - off(document, END[i], this._onUp, this); - } - - enableImageDrag(); - enableTextSelection(); - - if (this._moved && this._moving) { - // ensure drag is not fired after dragend - cancelAnimFrame(this._animRequest); - - // @event dragend: DragEndEvent - // Fired when the drag ends. - this.fire('dragend', { - distance: this._newPos.distanceTo(this._startPos) - }); - } - - this._moving = false; - Draggable._dragging = false; - } - -}); - -/* - * @namespace LineUtil - * - * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast. - */ - -// Simplify polyline with vertex reduction and Douglas-Peucker simplification. -// Improves rendering performance dramatically by lessening the number of points to draw. - -// @function simplify(points: Point[], tolerance: Number): Point[] -// Dramatically reduces the number of points in a polyline while retaining -// its shape and returns a new array of simplified points, using the -// [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm). -// Used for a huge performance boost when processing/displaying Leaflet polylines for -// each zoom level and also reducing visual noise. tolerance affects the amount of -// simplification (lesser value means higher quality but slower and with more points). -// Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/). -function simplify(points, tolerance) { - if (!tolerance || !points.length) { - return points.slice(); - } - - let sqTolerance = tolerance * tolerance; - - // stage 1: vertex reduction - points = _reducePoints(points, sqTolerance); - - // stage 2: Douglas-Peucker simplification - points = _simplifyDP(points, sqTolerance); - - return points; -} - -// @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number -// Returns the distance between point `p` and segment `p1` to `p2`. -function pointToSegmentDistance(p, p1, p2) { - return Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true)); -} - -// @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number -// Returns the closest point from a point `p` on a segment `p1` to `p2`. -function closestPointOnSegment(p, p1, p2) { - return _sqClosestPointOnSegment(p, p1, p2); -} - -// Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm -function _simplifyDP(points, sqTolerance) { - - let len = points.length, - ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array, - markers = new ArrayConstructor(len); - - markers[0] = markers[len - 1] = 1; - - _simplifyDPStep(points, markers, sqTolerance, 0, len - 1); - - var i, - newPoints = []; - - for (i = 0; i < len; i++) { - if (markers[i]) { - newPoints.push(points[i]); - } - } - - return newPoints; -} - -function _simplifyDPStep(points, markers, sqTolerance, first, last) { - - let maxSqDist = 0, - index, i, sqDist; - - for (i = first + 1; i <= last - 1; i++) { - sqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true); - - if (sqDist > maxSqDist) { - index = i; - maxSqDist = sqDist; - } - } - - if (maxSqDist > sqTolerance) { - markers[index] = 1; - - _simplifyDPStep(points, markers, sqTolerance, first, index); - _simplifyDPStep(points, markers, sqTolerance, index, last); - } -} - -// reduce points that are too close to each other to a single point -function _reducePoints(points, sqTolerance) { - let reducedPoints = [points[0]]; - - for (let i = 1, prev = 0, len = points.length; i < len; i++) { - if (_sqDist(points[i], points[prev]) > sqTolerance) { - reducedPoints.push(points[i]); - prev = i; - } - } - if (prev < len - 1) { - reducedPoints.push(points[len - 1]); - } - return reducedPoints; -} - -var _lastCode; - -// @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean -// Clips the segment a to b by rectangular bounds with the -// [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm) -// (modifying the segment points directly!). Used by Leaflet to only show polyline -// points that are on the screen or near, increasing performance. -function clipSegment(a, b, bounds, useLastCode, round) { - let codeA = useLastCode ? _lastCode : _getBitCode(a, bounds), - codeB = _getBitCode(b, bounds), - - codeOut, p, newCode; - - // save 2nd code to avoid calculating it on the next segment - _lastCode = codeB; - - while (true) { - // if a,b is inside the clip window (trivial accept) - if (!(codeA | codeB)) { - return [a, b]; - } - - // if a,b is outside the clip window (trivial reject) - if (codeA & codeB) { - return false; - } - - // other cases - codeOut = codeA || codeB; - p = _getEdgeIntersection(a, b, codeOut, bounds, round); - newCode = _getBitCode(p, bounds); - - if (codeOut === codeA) { - a = p; - codeA = newCode; - } else { - b = p; - codeB = newCode; - } - } -} - -function _getEdgeIntersection(a, b, code, bounds, round) { - let dx = b.x - a.x, - dy = b.y - a.y, - min = bounds.min, - max = bounds.max, - x, y; - - if (code & 8) { // top - x = a.x + dx * (max.y - a.y) / dy; - y = max.y; - - } else if (code & 4) { // bottom - x = a.x + dx * (min.y - a.y) / dy; - y = min.y; - - } else if (code & 2) { // right - x = max.x; - y = a.y + dy * (max.x - a.x) / dx; - - } else if (code & 1) { // left - x = min.x; - y = a.y + dy * (min.x - a.x) / dx; - } - - return new Point(x, y, round); -} - -function _getBitCode(p, bounds) { - let code = 0; - - if (p.x < bounds.min.x) { // left - code |= 1; - } else if (p.x > bounds.max.x) { // right - code |= 2; - } - - if (p.y < bounds.min.y) { // bottom - code |= 4; - } else if (p.y > bounds.max.y) { // top - code |= 8; - } - - return code; -} - -// square distance (to avoid unnecessary Math.sqrt calls) -function _sqDist(p1, p2) { - let dx = p2.x - p1.x, - dy = p2.y - p1.y; - return dx * dx + dy * dy; -} - -// return closest point on segment or distance to that point -function _sqClosestPointOnSegment(p, p1, p2, sqDist) { - let x = p1.x, - y = p1.y, - dx = p2.x - x, - dy = p2.y - y, - dot = dx * dx + dy * dy, - t; - - if (dot > 0) { - t = ((p.x - x) * dx + (p.y - y) * dy) / dot; - - if (t > 1) { - x = p2.x; - y = p2.y; - } else if (t > 0) { - x += dx * t; - y += dy * t; - } - } - - dx = p.x - x; - dy = p.y - y; - - return sqDist ? dx * dx + dy * dy : new Point(x, y); -} - - -// @function isFlat(latlngs: LatLng[]): Boolean -// Returns true if `latlngs` is a flat array, false is nested. -function isFlat(latlngs) { - return !isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined'); -} - -function _flat(latlngs) { - console.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.'); - return isFlat(latlngs); -} - - -let LineUtil = (Object.freeze || Object)({ - simplify: simplify, - pointToSegmentDistance: pointToSegmentDistance, - closestPointOnSegment: closestPointOnSegment, - clipSegment: clipSegment, - _getEdgeIntersection: _getEdgeIntersection, - _getBitCode: _getBitCode, - _sqClosestPointOnSegment: _sqClosestPointOnSegment, - isFlat: isFlat, - _flat: _flat -}); - -/* - * @namespace PolyUtil - * Various utility functions for polygon geometries. - */ - -/* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[] - * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)). - * Used by Leaflet to only show polygon points that are on the screen or near, increasing - * performance. Note that polygon points needs different algorithm for clipping - * than polyline, so there's a separate method for it. - */ -function clipPolygon(points, bounds, round) { - var clippedPoints, - edges = [1, 4, 2, 8], - i, j, k, - a, b, - len, edge, p; - - for (i = 0, len = points.length; i < len; i++) { - points[i]._code = _getBitCode(points[i], bounds); - } - - // for each edge (left, bottom, right, top) - for (k = 0; k < 4; k++) { - edge = edges[k]; - clippedPoints = []; - - for (i = 0, len = points.length, j = len - 1; i < len; j = i++) { - a = points[i]; - b = points[j]; - - // if a is inside the clip window - if (!(a._code & edge)) { - // if b is outside the clip window (a->b goes out of screen) - if (b._code & edge) { - p = _getEdgeIntersection(b, a, edge, bounds, round); - p._code = _getBitCode(p, bounds); - clippedPoints.push(p); - } - clippedPoints.push(a); - - // else if b is inside the clip window (a->b enters the screen) - } else if (!(b._code & edge)) { - p = _getEdgeIntersection(b, a, edge, bounds, round); - p._code = _getBitCode(p, bounds); - clippedPoints.push(p); - } - } - points = clippedPoints; - } - - return points; -} - - -let PolyUtil = (Object.freeze || Object)({ - clipPolygon: clipPolygon -}); - -/* - * @namespace Projection - * @section - * Leaflet comes with a set of already defined Projections out of the box: - * - * @projection L.Projection.LonLat - * - * Equirectangular, or Plate Carree projection — the most simple projection, - * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as - * latitude. Also suitable for flat worlds, e.g. game maps. Used by the - * `EPSG:4326` and `Simple` CRS. - */ - -let LonLat = { - project: function (latlng) { - return new Point(latlng.lng, latlng.lat); - }, - - unproject: function (point) { - return new LatLng(point.y, point.x); - }, - - bounds: new Bounds([-180, -90], [180, 90]) -}; - -/* - * @namespace Projection - * @projection L.Projection.Mercator - * - * Elliptical Mercator projection — more complex than Spherical Mercator. Takes into account that Earth is a geoid, not a perfect sphere. Used by the EPSG:3395 CRS. - */ - -let Mercator = { - R: 6378137, - R_MINOR: 6356752.314245179, - - bounds: new Bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]), - - project: function (latlng) { - let d = Math.PI / 180, - r = this.R, - y = latlng.lat * d, - tmp = this.R_MINOR / r, - e = Math.sqrt(1 - tmp * tmp), - con = e * Math.sin(y); - - let ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2); - y = -r * Math.log(Math.max(ts, 1E-10)); - - return new Point(latlng.lng * d * r, y); - }, - - unproject: function (point) { - let d = 180 / Math.PI, - r = this.R, - tmp = this.R_MINOR / r, - e = Math.sqrt(1 - tmp * tmp), - ts = Math.exp(-point.y / r), - phi = Math.PI / 2 - 2 * Math.atan(ts); - - for (let i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) { - con = e * Math.sin(phi); - con = Math.pow((1 - con) / (1 + con), e / 2); - dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi; - phi += dphi; - } - - return new LatLng(phi * d, point.x * d / r); - } -}; - -/* - * @class Projection - - * An object with methods for projecting geographical coordinates of the world onto - * a flat surface (and back). See [Map projection](http://en.wikipedia.org/wiki/Map_projection). - - * @property bounds: Bounds - * The bounds (specified in CRS units) where the projection is valid - - * @method project(latlng: LatLng): Point - * Projects geographical coordinates into a 2D point. - * Only accepts actual `L.LatLng` instances, not arrays. - - * @method unproject(point: Point): LatLng - * The inverse of `project`. Projects a 2D point into a geographical location. - * Only accepts actual `L.Point` instances, not arrays. - - * Note that the projection instances do not inherit from Leafet's `Class` object, - * and can't be instantiated. Also, new classes can't inherit from them, - * and methods can't be added to them with the `include` function. - - */ - - - - -let index = (Object.freeze || Object)({ - LonLat: LonLat, - Mercator: Mercator, - SphericalMercator: SphericalMercator -}); - -/* - * @namespace CRS - * @crs L.CRS.EPSG3395 - * - * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection. - */ -var EPSG3395 = extend({}, Earth, { - code: 'EPSG:3395', - projection: Mercator, - - transformation: (function () { - let scale = 0.5 / (Math.PI * Mercator.R); - return toTransformation(scale, 0.5, -scale, 0.5); - }()) -}); - -/* - * @namespace CRS - * @crs L.CRS.EPSG4326 - * - * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection. - * - * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic), - * which is a breaking change from 0.7.x behaviour. If you are using a `TileLayer` - * with this CRS, ensure that there are two 256x256 pixel tiles covering the - * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90), - * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set. - */ - -var EPSG4326 = extend({}, Earth, { - code: 'EPSG:4326', - projection: LonLat, - transformation: toTransformation(1 / 180, 1, -1 / 180, 0.5) -}); - -/* - * @namespace CRS - * @crs L.CRS.Simple - * - * A simple CRS that maps longitude and latitude into `x` and `y` directly. - * May be used for maps of flat surfaces (e.g. game maps). Note that the `y` - * axis should still be inverted (going from bottom to top). `distance()` returns - * simple euclidean distance. - */ - -let Simple = extend({}, CRS, { - projection: LonLat, - transformation: toTransformation(1, 0, -1, 0), - - scale: function (zoom) { - return Math.pow(2, zoom); - }, - - zoom: function (scale) { - return Math.log(scale) / Math.LN2; - }, - - distance: function (latlng1, latlng2) { - let dx = latlng2.lng - latlng1.lng, - dy = latlng2.lat - latlng1.lat; - - return Math.sqrt(dx * dx + dy * dy); - }, - - infinite: true -}); - -CRS.Earth = Earth; -CRS.EPSG3395 = EPSG3395; -CRS.EPSG3857 = EPSG3857; -CRS.EPSG900913 = EPSG900913; -CRS.EPSG4326 = EPSG4326; -CRS.Simple = Simple; - -/* - * @class Layer - * @inherits Evented - * @aka L.Layer - * @aka ILayer - * - * A set of methods from the Layer base class that all Leaflet layers use. - * Inherits all methods, options and events from `L.Evented`. - * - * @example - * - * ```js - * let layer = L.Marker(latlng).addTo(map); - * layer.addTo(map); - * layer.remove(); - * ``` - * - * @event add: Event - * Fired after the layer is added to a map - * - * @event remove: Event - * Fired after the layer is removed from a map - */ - - -let Layer = Evented.extend({ - - // Classes extending `L.Layer` will inherit the following options: - options: { - // @option pane: String = 'overlayPane' - // By default the layer will be added to the map's [overlay pane](#map-overlaypane). Overriding this option will cause the layer to be placed on another pane by default. - pane: 'overlayPane', - - // @option attribution: String = null - // String to be shown in the attribution control, describes the layer data, e.g. "© Mapbox". - attribution: null, - - bubblingMouseEvents: true - }, - - /* @section - * Classes extending `L.Layer` will inherit the following methods: - * - * @method addTo(map: Map|LayerGroup): this - * Adds the layer to the given map or layer group. - */ - addTo: function (map) { - map.addLayer(this); - return this; - }, - - // @method remove: this - // Removes the layer from the map it is currently active on. - remove: function () { - return this.removeFrom(this._map || this._mapToAdd); - }, - - // @method removeFrom(map: Map): this - // Removes the layer from the given map - removeFrom: function (obj) { - if (obj) { - obj.removeLayer(this); - } - return this; - }, - - // @method getPane(name? : String): HTMLElement - // Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer. - getPane: function (name) { - return this._map.getPane(name ? (this.options[name] || name) : this.options.pane); - }, - - addInteractiveTarget: function (targetEl) { - this._map._targets[stamp(targetEl)] = this; - return this; - }, - - removeInteractiveTarget: function (targetEl) { - delete this._map._targets[stamp(targetEl)]; - return this; - }, - - // @method getAttribution: String - // Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution). - getAttribution: function () { - return this.options.attribution; - }, - - _layerAdd: function (e) { - let map = e.target; - - // check in case layer gets added and then removed before the map is ready - if (!map.hasLayer(this)) { return; } - - this._map = map; - this._zoomAnimated = map._zoomAnimated; - - if (this.getEvents) { - let events = this.getEvents(); - map.on(events, this); - this.once('remove', function () { - map.off(events, this); - }, this); - } - - this.onAdd(map); - - if (this.getAttribution && map.attributionControl) { - map.attributionControl.addAttribution(this.getAttribution()); - } - - this.fire('add'); - map.fire('layeradd', {layer: this}); - } -}); - -/* @section Extension methods - * @uninheritable - * - * Every layer should extend from `L.Layer` and (re-)implement the following methods. - * - * @method onAdd(map: Map): this - * Should contain code that creates DOM elements for the layer, adds them to `map panes` where they should belong and puts listeners on relevant map events. Called on [`map.addLayer(layer)`](#map-addlayer). - * - * @method onRemove(map: Map): this - * Should contain all clean up code that removes the layer's elements from the DOM and removes listeners previously added in [`onAdd`](#layer-onadd). Called on [`map.removeLayer(layer)`](#map-removelayer). - * - * @method getEvents(): Object - * This optional method should return an object like `{ viewreset: this._reset }` for [`addEventListener`](#evented-addeventlistener). The event handlers in this object will be automatically added and removed from the map with your layer. - * - * @method getAttribution(): String - * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible. - * - * @method beforeAdd(map: Map): this - * Optional method. Called on [`map.addLayer(layer)`](#map-addlayer), before the layer is added to the map, before events are initialized, without waiting until the map is in a usable state. Use for early initialization only. - */ - - -/* @namespace Map - * @section Layer events - * - * @event layeradd: LayerEvent - * Fired when a new layer is added to the map. - * - * @event layerremove: LayerEvent - * Fired when some layer is removed from the map - * - * @section Methods for Layers and Controls - */ -Map.include({ - // @method addLayer(layer: Layer): this - // Adds the given layer to the map - addLayer: function (layer) { - if (!layer._layerAdd) { - throw new Error('The provided object is not a Layer.'); - } - - let id = stamp(layer); - if (this._layers[id]) { return this; } - this._layers[id] = layer; - - layer._mapToAdd = this; - - if (layer.beforeAdd) { - layer.beforeAdd(this); - } - - this.whenReady(layer._layerAdd, layer); - - return this; - }, - - // @method removeLayer(layer: Layer): this - // Removes the given layer from the map. - removeLayer: function (layer) { - let id = stamp(layer); - - if (!this._layers[id]) { return this; } - - if (this._loaded) { - layer.onRemove(this); - } - - if (layer.getAttribution && this.attributionControl) { - this.attributionControl.removeAttribution(layer.getAttribution()); - } - - delete this._layers[id]; - - if (this._loaded) { - this.fire('layerremove', {layer: layer}); - layer.fire('remove'); - } - - layer._map = layer._mapToAdd = null; - - return this; - }, - - // @method hasLayer(layer: Layer): Boolean - // Returns `true` if the given layer is currently added to the map - hasLayer: function (layer) { - return !!layer && (stamp(layer) in this._layers); - }, - - /* @method eachLayer(fn: Function, context?: Object): this - * Iterates over the layers of the map, optionally specifying context of the iterator function. - * ``` - * map.eachLayer(function(layer){ - * layer.bindPopup('Hello'); - * }); - * ``` - */ - eachLayer: function (method, context) { - for (var i in this._layers) { - method.call(context, this._layers[i]); - } - return this; - }, - - _addLayers: function (layers) { - layers = layers ? (isArray(layers) ? layers : [layers]) : []; - - for (let i = 0, len = layers.length; i < len; i++) { - this.addLayer(layers[i]); - } - }, - - _addZoomLimit: function (layer) { - if (isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) { - this._zoomBoundLayers[stamp(layer)] = layer; - this._updateZoomLevels(); - } - }, - - _removeZoomLimit: function (layer) { - let id = stamp(layer); - - if (this._zoomBoundLayers[id]) { - delete this._zoomBoundLayers[id]; - this._updateZoomLevels(); - } - }, - - _updateZoomLevels: function () { - let minZoom = Infinity, - maxZoom = -Infinity, - oldZoomSpan = this._getZoomSpan(); - - for (var i in this._zoomBoundLayers) { - let options = this._zoomBoundLayers[i].options; - - minZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom); - maxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom); - } - - this._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom; - this._layersMinZoom = minZoom === Infinity ? undefined : minZoom; - - // @section Map state change events - // @event zoomlevelschange: Event - // Fired when the number of zoomlevels on the map is changed due - // to adding or removing a layer. - if (oldZoomSpan !== this._getZoomSpan()) { - this.fire('zoomlevelschange'); - } - - if (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) { - this.setZoom(this._layersMaxZoom); - } - if (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) { - this.setZoom(this._layersMinZoom); - } - } -}); - -/* - * @class LayerGroup - * @aka L.LayerGroup - * @inherits Layer - * - * Used to group several layers and handle them as one. If you add it to the map, - * any layers added or removed from the group will be added/removed on the map as - * well. Extends `Layer`. - * - * @example - * - * ```js - * L.layerGroup([marker1, marker2]) - * .addLayer(polyline) - * .addTo(map); - * ``` - */ - -let LayerGroup = Layer.extend({ - - initialize: function (layers, options) { - setOptions(this, options); - - this._layers = {}; - - var i, len; - - if (layers) { - for (i = 0, len = layers.length; i < len; i++) { - this.addLayer(layers[i]); - } - } - }, - - // @method addLayer(layer: Layer): this - // Adds the given layer to the group. - addLayer: function (layer) { - let id = this.getLayerId(layer); - - this._layers[id] = layer; - - if (this._map) { - this._map.addLayer(layer); - } - - return this; - }, - - // @method removeLayer(layer: Layer): this - // Removes the given layer from the group. - // @alternative - // @method removeLayer(id: Number): this - // Removes the layer with the given internal ID from the group. - removeLayer: function (layer) { - let id = layer in this._layers ? layer : this.getLayerId(layer); - - if (this._map && this._layers[id]) { - this._map.removeLayer(this._layers[id]); - } - - delete this._layers[id]; - - return this; - }, - - // @method hasLayer(layer: Layer): Boolean - // Returns `true` if the given layer is currently added to the group. - // @alternative - // @method hasLayer(id: Number): Boolean - // Returns `true` if the given internal ID is currently added to the group. - hasLayer: function (layer) { - return !!layer && (layer in this._layers || this.getLayerId(layer) in this._layers); - }, - - // @method clearLayers(): this - // Removes all the layers from the group. - clearLayers: function () { - return this.eachLayer(this.removeLayer, this); - }, - - // @method invoke(methodName: String, …): this - // Calls `methodName` on every layer contained in this group, passing any - // additional parameters. Has no effect if the layers contained do not - // implement `methodName`. - invoke: function (methodName) { - let args = Array.prototype.slice.call(arguments, 1), - i, layer; - - for (i in this._layers) { - layer = this._layers[i]; - - if (layer[methodName]) { - layer[methodName].apply(layer, args); - } - } - - return this; - }, - - onAdd: function (map) { - this.eachLayer(map.addLayer, map); - }, - - onRemove: function (map) { - this.eachLayer(map.removeLayer, map); - }, - - // @method eachLayer(fn: Function, context?: Object): this - // Iterates over the layers of the group, optionally specifying context of the iterator function. - // ```js - // group.eachLayer(function (layer) { - // layer.bindPopup('Hello'); - // }); - // ``` - eachLayer: function (method, context) { - for (var i in this._layers) { - method.call(context, this._layers[i]); - } - return this; - }, - - // @method getLayer(id: Number): Layer - // Returns the layer with the given internal ID. - getLayer: function (id) { - return this._layers[id]; - }, - - // @method getLayers(): Layer[] - // Returns an array of all the layers added to the group. - getLayers: function () { - let layers = []; - this.eachLayer(layers.push, layers); - return layers; - }, - - // @method setZIndex(zIndex: Number): this - // Calls `setZIndex` on every layer contained in this group, passing the z-index. - setZIndex: function (zIndex) { - return this.invoke('setZIndex', zIndex); - }, - - // @method getLayerId(layer: Layer): Number - // Returns the internal ID for a layer - getLayerId: function (layer) { - return stamp(layer); - } -}); - - -// @factory L.layerGroup(layers?: Layer[], options?: Object) -// Create a layer group, optionally given an initial set of layers and an `options` object. -let layerGroup = (layers, options) => { - return new LayerGroup(layers, options); -}; - -/* - * @class FeatureGroup - * @aka L.FeatureGroup - * @inherits LayerGroup - * - * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers: - * * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip)) - * * Events are propagated to the `FeatureGroup`, so if the group has an event - * handler, it will handle events from any of the layers. This includes mouse events - * and custom events. - * * Has `layeradd` and `layerremove` events - * - * @example - * - * ```js - * L.featureGroup([marker1, marker2, polyline]) - * .bindPopup('Hello world!') - * .on('click', function() { alert('Clicked on a member of the group!'); }) - * .addTo(map); - * ``` - */ - -let FeatureGroup = LayerGroup.extend({ - - addLayer: function (layer) { - if (this.hasLayer(layer)) { - return this; - } - - layer.addEventParent(this); - - LayerGroup.prototype.addLayer.call(this, layer); - - // @event layeradd: LayerEvent - // Fired when a layer is added to this `FeatureGroup` - return this.fire('layeradd', {layer: layer}); - }, - - removeLayer: function (layer) { - if (!this.hasLayer(layer)) { - return this; - } - if (layer in this._layers) { - layer = this._layers[layer]; - } - - layer.removeEventParent(this); - - LayerGroup.prototype.removeLayer.call(this, layer); - - // @event layerremove: LayerEvent - // Fired when a layer is removed from this `FeatureGroup` - return this.fire('layerremove', {layer: layer}); - }, - - // @method setStyle(style: Path options): this - // Sets the given path options to each layer of the group that has a `setStyle` method. - setStyle: function (style) { - return this.invoke('setStyle', style); - }, - - // @method bringToFront(): this - // Brings the layer group to the top of all other layers - bringToFront: function () { - return this.invoke('bringToFront'); - }, - - // @method bringToBack(): this - // Brings the layer group to the back of all other layers - bringToBack: function () { - return this.invoke('bringToBack'); - }, - - // @method getBounds(): LatLngBounds - // Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children). - getBounds: function () { - let bounds = new LatLngBounds(); - - for (var id in this._layers) { - let layer = this._layers[id]; - bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng()); - } - return bounds; - } -}); - -// @factory L.featureGroup(layers: Layer[]) -// Create a feature group, optionally given an initial set of layers. -let featureGroup = (layers) => { - return new FeatureGroup(layers); -}; - -/* - * @class Icon - * @aka L.Icon - * - * Represents an icon to provide when creating a marker. - * - * @example - * - * ```js - * let myIcon = L.icon({ - * iconUrl: 'my-icon.png', - * iconRetinaUrl: 'my-icon@2x.png', - * iconSize: [38, 95], - * iconAnchor: [22, 94], - * popupAnchor: [-3, -76], - * shadowUrl: 'my-icon-shadow.png', - * shadowRetinaUrl: 'my-icon-shadow@2x.png', - * shadowSize: [68, 95], - * shadowAnchor: [22, 94] - * }); - * - * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map); - * ``` - * - * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default. - * - */ - -let Icon = Class.extend({ - - /* @section - * @aka Icon options - * - * @option iconUrl: String = null - * **(required)** The URL to the icon image (absolute or relative to your script path). - * - * @option iconRetinaUrl: String = null - * The URL to a retina sized version of the icon image (absolute or relative to your - * script path). Used for Retina screen devices. - * - * @option iconSize: Point = null - * Size of the icon image in pixels. - * - * @option iconAnchor: Point = null - * The coordinates of the "tip" of the icon (relative to its top left corner). The icon - * will be aligned so that this point is at the marker's geographical location. Centered - * by default if size is specified, also can be set in CSS with negative margins. - * - * @option popupAnchor: Point = [0, 0] - * The coordinates of the point from which popups will "open", relative to the icon anchor. - * - * @option tooltipAnchor: Point = [0, 0] - * The coordinates of the point from which tooltips will "open", relative to the icon anchor. - * - * @option shadowUrl: String = null - * The URL to the icon shadow image. If not specified, no shadow image will be created. - * - * @option shadowRetinaUrl: String = null - * - * @option shadowSize: Point = null - * Size of the shadow image in pixels. - * - * @option shadowAnchor: Point = null - * The coordinates of the "tip" of the shadow (relative to its top left corner) (the same - * as iconAnchor if not specified). - * - * @option className: String = '' - * A custom class name to assign to both icon and shadow images. Empty by default. - */ - - options: { - popupAnchor: [0, 0], - tooltipAnchor: [0, 0], - }, - - initialize: function (options) { - setOptions(this, options); - }, - - // @method createIcon(oldIcon?: HTMLElement): HTMLElement - // Called internally when the icon has to be shown, returns a `` HTML element - // styled according to the options. - createIcon: function (oldIcon) { - return this._createIcon('icon', oldIcon); - }, - - // @method createShadow(oldIcon?: HTMLElement): HTMLElement - // As `createIcon`, but for the shadow beneath it. - createShadow: function (oldIcon) { - return this._createIcon('shadow', oldIcon); - }, - - _createIcon: function (name, oldIcon) { - let src = this._getIconUrl(name); - - if (!src) { - if (name === 'icon') { - throw new Error('iconUrl not set in Icon options (see the docs).'); - } - return null; - } - - let img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null); - this._setIconStyles(img, name); - - return img; - }, - - _setIconStyles: function (img, name) { - let options = this.options; - let sizeOption = options[name + 'Size']; - - if (typeof sizeOption === 'number') { - sizeOption = [sizeOption, sizeOption]; - } - - let size = toPoint(sizeOption), - anchor = toPoint(name === 'shadow' && options.shadowAnchor || options.iconAnchor || - size && size.divideBy(2, true)); - - img.className = 'leaflet-marker-' + name + ' ' + (options.className || ''); - - if (anchor) { - img.style.marginLeft = (-anchor.x) + 'px'; - img.style.marginTop = (-anchor.y) + 'px'; - } - - if (size) { - img.style.width = size.x + 'px'; - img.style.height = size.y + 'px'; - } - }, - - _createImg: function (src, el) { - el = el || document.createElement('img'); - el.src = src; - return el; - }, - - _getIconUrl: function (name) { - return retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url']; - } -}); - - -// @factory L.icon(options: Icon options) -// Creates an icon instance with the given options. -function icon(options) { - return new Icon(options); -} - -/* - * @miniclass Icon.Default (Icon) - * @aka L.Icon.Default - * @section - * - * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when - * no icon is specified. Points to the blue marker image distributed with Leaflet - * releases. - * - * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options` - * (which is a set of `Icon options`). - * - * If you want to _completely_ replace the default icon, override the - * `L.Marker.prototype.options.icon` with your own icon instead. - */ - -let IconDefault = Icon.extend({ - - options: { - iconUrl: 'marker-icon.png', - iconRetinaUrl: 'marker-icon-2x.png', - shadowUrl: 'marker-shadow.png', - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], - tooltipAnchor: [16, -28], - shadowSize: [41, 41] - }, - - _getIconUrl: function (name) { - if (!IconDefault.imagePath) { // Deprecated, backwards-compatibility only - IconDefault.imagePath = this._detectIconPath(); - } - - // @option imagePath: String - // `Icon.Default` will try to auto-detect the location of the - // blue icon images. If you are placing these images in a non-standard - // way, set this option to point to the right path. - return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name); - }, - - _detectIconPath: function () { - let el = create$1('div', 'leaflet-default-icon-path', document.body); - let path = getStyle(el, 'background-image') || - getStyle(el, 'backgroundImage'); // IE8 - - document.body.removeChild(el); - - if (path === null || path.indexOf('url') !== 0) { - path = ''; - } else { - path = path.replace(/^url\(["']?/, '').replace(/marker-icon\.png["']?\)$/, ''); - } - - return path; - } -}); - -/* - * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable. - */ - - -/* @namespace Marker - * @section Interaction handlers - * - * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example: - * - * ```js - * marker.dragging.disable(); - * ``` - * - * @property dragging: Handler - * Marker dragging handler (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)). - */ - -let MarkerDrag = Handler.extend({ - initialize: function (marker) { - this._marker = marker; - }, - - addHooks: function () { - let icon = this._marker._icon; - - if (!this._draggable) { - this._draggable = new Draggable(icon, icon, true); - } - - this._draggable.on({ - dragstart: this._onDragStart, - predrag: this._onPreDrag, - drag: this._onDrag, - dragend: this._onDragEnd - }, this).enable(); - - addClass(icon, 'leaflet-marker-draggable'); - }, - - removeHooks: function () { - this._draggable.off({ - dragstart: this._onDragStart, - predrag: this._onPreDrag, - drag: this._onDrag, - dragend: this._onDragEnd - }, this).disable(); - - if (this._marker._icon) { - removeClass(this._marker._icon, 'leaflet-marker-draggable'); - } - }, - - moved: function () { - return this._draggable && this._draggable._moved; - }, - - _adjustPan: function (e) { - let marker = this._marker, - map = marker._map, - speed = this._marker.options.autoPanSpeed, - padding = this._marker.options.autoPanPadding, - iconPos = L.DomUtil.getPosition(marker._icon), - bounds = map.getPixelBounds(), - origin = map.getPixelOrigin(); - - let panBounds = toBounds( - bounds.min._subtract(origin).add(padding), - bounds.max._subtract(origin).subtract(padding) - ); - - if (!panBounds.contains(iconPos)) { - // Compute incremental movement - let movement = toPoint( - (Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) - - (Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x), - - (Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) - - (Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y) - ).multiplyBy(speed); - - map.panBy(movement, {animate: false}); - - this._draggable._newPos._add(movement); - this._draggable._startPos._add(movement); - - L.DomUtil.setPosition(marker._icon, this._draggable._newPos); - this._onDrag(e); - - this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e)); - } - }, - - _onDragStart: function () { - // @section Dragging events - // @event dragstart: Event - // Fired when the user starts dragging the marker. - - // @event movestart: Event - // Fired when the marker starts moving (because of dragging). - - this._oldLatLng = this._marker.getLatLng(); - this._marker - .closePopup() - .fire('movestart') - .fire('dragstart'); - }, - - _onPreDrag: function (e) { - if (this._marker.options.autoPan) { - cancelAnimFrame(this._panRequest); - this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e)); - } - }, - - _onDrag: function (e) { - let marker = this._marker, - shadow = marker._shadow, - iconPos = getPosition(marker._icon), - latlng = marker._map.layerPointToLatLng(iconPos); - - // update shadow position - if (shadow) { - setPosition(shadow, iconPos); - } - - marker._latlng = latlng; - e.latlng = latlng; - e.oldLatLng = this._oldLatLng; - - // @event drag: Event - // Fired repeatedly while the user drags the marker. - marker - .fire('move', e) - .fire('drag', e); - }, - - _onDragEnd: function (e) { - // @event dragend: DragEndEvent - // Fired when the user stops dragging the marker. - - cancelAnimFrame(this._panRequest); - - // @event moveend: Event - // Fired when the marker stops moving (because of dragging). - delete this._oldLatLng; - this._marker - .fire('moveend') - .fire('dragend', e); - } -}); - -/* - * @class Marker - * @inherits Interactive layer - * @aka L.Marker - * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`. - * - * @example - * - * ```js - * L.marker([50.5, 30.5]).addTo(map); - * ``` - */ - -let Marker = Layer.extend({ - - // @section - // @aka Marker options - options: { - // @option icon: Icon = * - // Icon instance to use for rendering the marker. - // See [Icon documentation](#L.Icon) for details on how to customize the marker icon. - // If not specified, a common instance of `L.Icon.Default` is used. - icon: new IconDefault(), - - // Option inherited from "Interactive layer" abstract class - interactive: true, - - // @option draggable: Boolean = false - // Whether the marker is draggable with mouse/touch or not. - draggable: false, - - // @option autoPan: Boolean = false - // Set it to `true` if you want the map to do panning animation when marker hits the edges. - autoPan: false, - - // @option autoPanPadding: Point = Point(50, 50) - // Equivalent of setting both top left and bottom right autopan padding to the same value. - autoPanPadding: [50, 50], - - // @option autoPanSpeed: Number = 10 - // Number of pixels the map should move by. - autoPanSpeed: 10, - - // @option keyboard: Boolean = true - // Whether the marker can be tabbed to with a keyboard and clicked by pressing enter. - keyboard: true, - - // @option title: String = '' - // Text for the browser tooltip that appear on marker hover (no tooltip by default). - title: '', - - // @option alt: String = '' - // Text for the `alt` attribute of the icon image (useful for accessibility). - alt: '', - - // @option zIndexOffset: Number = 0 - // By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively). - zIndexOffset: 0, - - // @option opacity: Number = 1.0 - // The opacity of the marker. - opacity: 1, - - // @option riseOnHover: Boolean = false - // If `true`, the marker will get on top of others when you hover the mouse over it. - riseOnHover: false, - - // @option riseOffset: Number = 250 - // The z-index offset used for the `riseOnHover` feature. - riseOffset: 250, - - // @option pane: String = 'markerPane' - // `Map pane` where the markers icon will be added. - pane: 'markerPane', - - // @option bubblingMouseEvents: Boolean = false - // When `true`, a mouse event on this marker will trigger the same event on the map - // (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used). - bubblingMouseEvents: false - }, - - /* @section - * - * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods: - */ - - initialize: function (latlng, options) { - setOptions(this, options); - this._latlng = toLatLng(latlng); - }, - - onAdd: function (map) { - this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation; - - if (this._zoomAnimated) { - map.on('zoomanim', this._animateZoom, this); - } - - this._initIcon(); - this.update(); - }, - - onRemove: function (map) { - if (this.dragging && this.dragging.enabled()) { - this.options.draggable = true; - this.dragging.removeHooks(); - } - delete this.dragging; - - if (this._zoomAnimated) { - map.off('zoomanim', this._animateZoom, this); - } - - this._removeIcon(); - this._removeShadow(); - }, - - getEvents: function () { - return { - zoom: this.update, - viewreset: this.update - }; - }, - - // @method getLatLng: LatLng - // Returns the current geographical position of the marker. - getLatLng: function () { - return this._latlng; - }, - - // @method setLatLng(latlng: LatLng): this - // Changes the marker position to the given point. - setLatLng: function (latlng) { - let oldLatLng = this._latlng; - this._latlng = toLatLng(latlng); - this.update(); - - // @event move: Event - // Fired when the marker is moved via [`setLatLng`](#marker-setlatlng) or by [dragging](#marker-dragging). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`. - return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng}); - }, - - // @method setZIndexOffset(offset: Number): this - // Changes the [zIndex offset](#marker-zindexoffset) of the marker. - setZIndexOffset: function (offset) { - this.options.zIndexOffset = offset; - return this.update(); - }, - - // @method setIcon(icon: Icon): this - // Changes the marker icon. - setIcon: function (icon) { - - this.options.icon = icon; - - if (this._map) { - this._initIcon(); - this.update(); - } - - if (this._popup) { - this.bindPopup(this._popup, this._popup.options); - } - - return this; - }, - - getElement: function () { - return this._icon; - }, - - update: function () { - - if (this._icon && this._map) { - let pos = this._map.latLngToLayerPoint(this._latlng).round(); - this._setPos(pos); - } - - return this; - }, - - _initIcon: function () { - let options = this.options, - classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide'); - - let icon = options.icon.createIcon(this._icon), - addIcon = false; - - // if we're not reusing the icon, remove the old one and init new one - if (icon !== this._icon) { - if (this._icon) { - this._removeIcon(); - } - addIcon = true; - - if (options.title) { - icon.title = options.title; - } - - if (icon.tagName === 'IMG') { - icon.alt = options.alt || ''; - } - } - - addClass(icon, classToAdd); - - if (options.keyboard) { - icon.tabIndex = '0'; - } - - this._icon = icon; - - if (options.riseOnHover) { - this.on({ - mouseover: this._bringToFront, - mouseout: this._resetZIndex - }); - } - - let newShadow = options.icon.createShadow(this._shadow), - addShadow = false; - - if (newShadow !== this._shadow) { - this._removeShadow(); - addShadow = true; - } - - if (newShadow) { - addClass(newShadow, classToAdd); - newShadow.alt = ''; - } - this._shadow = newShadow; - - - if (options.opacity < 1) { - this._updateOpacity(); - } - - - if (addIcon) { - this.getPane().appendChild(this._icon); - } - this._initInteraction(); - if (newShadow && addShadow) { - this.getPane('shadowPane').appendChild(this._shadow); - } - }, - - _removeIcon: function () { - if (this.options.riseOnHover) { - this.off({ - mouseover: this._bringToFront, - mouseout: this._resetZIndex - }); - } - - remove(this._icon); - this.removeInteractiveTarget(this._icon); - - this._icon = null; - }, - - _removeShadow: function () { - if (this._shadow) { - remove(this._shadow); - } - this._shadow = null; - }, - - _setPos: function (pos) { - setPosition(this._icon, pos); - - if (this._shadow) { - setPosition(this._shadow, pos); - } - - this._zIndex = pos.y + this.options.zIndexOffset; - - this._resetZIndex(); - }, - - _updateZIndex: function (offset) { - this._icon.style.zIndex = this._zIndex + offset; - }, - - _animateZoom: function (opt) { - let pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round(); - - this._setPos(pos); - }, - - _initInteraction: function () { - - if (!this.options.interactive) { return; } - - addClass(this._icon, 'leaflet-interactive'); - - this.addInteractiveTarget(this._icon); - - if (MarkerDrag) { - let draggable = this.options.draggable; - if (this.dragging) { - draggable = this.dragging.enabled(); - this.dragging.disable(); - } - - this.dragging = new MarkerDrag(this); - - if (draggable) { - this.dragging.enable(); - } - } - }, - - // @method setOpacity(opacity: Number): this - // Changes the opacity of the marker. - setOpacity: function (opacity) { - this.options.opacity = opacity; - if (this._map) { - this._updateOpacity(); - } - - return this; - }, - - _updateOpacity: function () { - let opacity = this.options.opacity; - - setOpacity(this._icon, opacity); - - if (this._shadow) { - setOpacity(this._shadow, opacity); - } - }, - - _bringToFront: function () { - this._updateZIndex(this.options.riseOffset); - }, - - _resetZIndex: function () { - this._updateZIndex(0); - }, - - _getPopupAnchor: function () { - return this.options.icon.options.popupAnchor; - }, - - _getTooltipAnchor: function () { - return this.options.icon.options.tooltipAnchor; - } -}); - - -// factory L.marker(latlng: LatLng, options? : Marker options) - -// @factory L.marker(latlng: LatLng, options? : Marker options) -// Instantiates a Marker object given a geographical point and optionally an options object. -function marker(latlng, options) { - return new Marker(latlng, options); -} - -/* - * @class Path - * @aka L.Path - * @inherits Interactive layer - * - * An abstract class that contains options and constants shared between vector - * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`. - */ - -let Path = Layer.extend({ - - // @section - // @aka Path options - options: { - // @option stroke: Boolean = true - // Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles. - stroke: true, - - // @option color: String = '#3388ff' - // Stroke color - color: '#3388ff', - - // @option weight: Number = 3 - // Stroke width in pixels - weight: 3, - - // @option opacity: Number = 1.0 - // Stroke opacity - opacity: 1, - - // @option lineCap: String= 'round' - // A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke. - lineCap: 'round', - - // @option lineJoin: String = 'round' - // A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke. - lineJoin: 'round', - - // @option dashArray: String = null - // A string that defines the stroke [dash pattern](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility). - dashArray: null, - - // @option dashOffset: String = null - // A string that defines the [distance into the dash pattern to start the dash](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility). - dashOffset: null, - - // @option fill: Boolean = depends - // Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles. - fill: false, - - // @option fillColor: String = * - // Fill color. Defaults to the value of the [`color`](#path-color) option - fillColor: null, - - // @option fillOpacity: Number = 0.2 - // Fill opacity. - fillOpacity: 0.2, - - // @option fillRule: String = 'evenodd' - // A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined. - fillRule: 'evenodd', - - // className: '', - - // Option inherited from "Interactive layer" abstract class - interactive: true, - - // @option bubblingMouseEvents: Boolean = true - // When `true`, a mouse event on this path will trigger the same event on the map - // (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used). - bubblingMouseEvents: true - }, - - beforeAdd: function (map) { - // Renderer is set here because we need to call renderer.getEvents - // before this.getEvents. - this._renderer = map.getRenderer(this); - }, - - onAdd: function () { - this._renderer._initPath(this); - this._reset(); - this._renderer._addPath(this); - }, - - onRemove: function () { - this._renderer._removePath(this); - }, - - // @method redraw(): this - // Redraws the layer. Sometimes useful after you changed the coordinates that the path uses. - redraw: function () { - if (this._map) { - this._renderer._updatePath(this); - } - return this; - }, - - // @method setStyle(style: Path options): this - // Changes the appearance of a Path based on the options in the `Path options` object. - setStyle: function (style) { - setOptions(this, style); - if (this._renderer) { - this._renderer._updateStyle(this); - } - return this; - }, - - // @method bringToFront(): this - // Brings the layer to the top of all path layers. - bringToFront: function () { - if (this._renderer) { - this._renderer._bringToFront(this); - } - return this; - }, - - // @method bringToBack(): this - // Brings the layer to the bottom of all path layers. - bringToBack: function () { - if (this._renderer) { - this._renderer._bringToBack(this); - } - return this; - }, - - getElement: function () { - return this._path; - }, - - _reset: function () { - // defined in child classes - this._project(); - this._update(); - }, - - _clickTolerance: function () { - // used when doing hit detection for Canvas layers - return (this.options.stroke ? this.options.weight / 2 : 0) + this._renderer.options.tolerance; - } -}); - -/* - * @class CircleMarker - * @aka L.CircleMarker - * @inherits Path - * - * A circle of a fixed size with radius specified in pixels. Extends `Path`. - */ - -let CircleMarker = Path.extend({ - - // @section - // @aka CircleMarker options - options: { - fill: true, - - // @option radius: Number = 10 - // Radius of the circle marker, in pixels - radius: 10 - }, - - initialize: function (latlng, options) { - setOptions(this, options); - this._latlng = toLatLng(latlng); - this._radius = this.options.radius; - }, - - // @method setLatLng(latLng: LatLng): this - // Sets the position of a circle marker to a new location. - setLatLng: function (latlng) { - this._latlng = toLatLng(latlng); - this.redraw(); - return this.fire('move', {latlng: this._latlng}); - }, - - // @method getLatLng(): LatLng - // Returns the current geographical position of the circle marker - getLatLng: function () { - return this._latlng; - }, - - // @method setRadius(radius: Number): this - // Sets the radius of a circle marker. Units are in pixels. - setRadius: function (radius) { - this.options.radius = this._radius = radius; - return this.redraw(); - }, - - // @method getRadius(): Number - // Returns the current radius of the circle - getRadius: function () { - return this._radius; - }, - - setStyle : function (options) { - let radius = options && options.radius || this._radius; - Path.prototype.setStyle.call(this, options); - this.setRadius(radius); - return this; - }, - - _project: function () { - this._point = this._map.latLngToLayerPoint(this._latlng); - this._updateBounds(); - }, - - _updateBounds: function () { - let r = this._radius, - r2 = this._radiusY || r, - w = this._clickTolerance(), - p = [r + w, r2 + w]; - this._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p)); - }, - - _update: function () { - if (this._map) { - this._updatePath(); - } - }, - - _updatePath: function () { - this._renderer._updateCircle(this); - }, - - _empty: function () { - return this._radius && !this._renderer._bounds.intersects(this._pxBounds); - }, - - // Needed by the `Canvas` renderer for interactivity - _containsPoint: function (p) { - return p.distanceTo(this._point) <= this._radius + this._clickTolerance(); - } -}); - - -// @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options) -// Instantiates a circle marker object given a geographical point, and an optional options object. -function circleMarker(latlng, options) { - return new CircleMarker(latlng, options); -} - -/* - * @class Circle - * @aka L.Circle - * @inherits CircleMarker - * - * A class for drawing circle overlays on a map. Extends `CircleMarker`. - * - * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion). - * - * @example - * - * ```js - * L.circle([50.5, 30.5], {radius: 200}).addTo(map); - * ``` - */ - -let Circle = CircleMarker.extend({ - - initialize: function (latlng, options, legacyOptions) { - if (typeof options === 'number') { - // Backwards compatibility with 0.7.x factory (latlng, radius, options?) - options = extend({}, legacyOptions, {radius: options}); - } - setOptions(this, options); - this._latlng = toLatLng(latlng); - - if (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); } - - // @section - // @aka Circle options - // @option radius: Number; Radius of the circle, in meters. - this._mRadius = this.options.radius; - }, - - // @method setRadius(radius: Number): this - // Sets the radius of a circle. Units are in meters. - setRadius: function (radius) { - this._mRadius = radius; - return this.redraw(); - }, - - // @method getRadius(): Number - // Returns the current radius of a circle. Units are in meters. - getRadius: function () { - return this._mRadius; - }, - - // @method getBounds(): LatLngBounds - // Returns the `LatLngBounds` of the path. - getBounds: function () { - let half = [this._radius, this._radiusY || this._radius]; - - return new LatLngBounds( - this._map.layerPointToLatLng(this._point.subtract(half)), - this._map.layerPointToLatLng(this._point.add(half))); - }, - - setStyle: Path.prototype.setStyle, - - _project: function () { - - let lng = this._latlng.lng, - lat = this._latlng.lat, - map = this._map, - crs = map.options.crs; - - if (crs.distance === Earth.distance) { - let d = Math.PI / 180, - latR = (this._mRadius / Earth.R) / d, - top = map.project([lat + latR, lng]), - bottom = map.project([lat - latR, lng]), - p = top.add(bottom).divideBy(2), - lat2 = map.unproject(p).lat, - lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) / - (Math.cos(lat * d) * Math.cos(lat2 * d))) / d; - - if (isNaN(lngR) || lngR === 0) { - lngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425 - } - - this._point = p.subtract(map.getPixelOrigin()); - this._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x; - this._radiusY = p.y - top.y; - - } else { - var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0])); - - this._point = map.latLngToLayerPoint(this._latlng); - this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x; - } - - this._updateBounds(); - } -}); - -// @factory L.circle(latlng: LatLng, options?: Circle options) -// Instantiates a circle object given a geographical point, and an options object -// which contains the circle radius. -// @alternative -// @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options) -// Obsolete way of instantiating a circle, for compatibility with 0.7.x code. -// Do not use in new applications or plugins. -function circle(latlng, options, legacyOptions) { - return new Circle(latlng, options, legacyOptions); -} - -/* - * @class Polyline - * @aka L.Polyline - * @inherits Path - * - * A class for drawing polyline overlays on a map. Extends `Path`. - * - * @example - * - * ```js - * // create a red polyline from an array of LatLng points - * let latlngs = [ - * [45.51, -122.68], - * [37.77, -122.43], - * [34.04, -118.2] - * ]; - * - * let polyline = L.polyline(latlngs, {color: 'red'}).addTo(map); - * - * // zoom the map to the polyline - * map.fitBounds(polyline.getBounds()); - * ``` - * - * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape: - * - * ```js - * // create a red polyline from an array of arrays of LatLng points - * let latlngs = [ - * [[45.51, -122.68], - * [37.77, -122.43], - * [34.04, -118.2]], - * [[40.78, -73.91], - * [41.83, -87.62], - * [32.76, -96.72]] - * ]; - * ``` - */ - - -let Polyline = Path.extend({ - - // @section - // @aka Polyline options - options: { - // @option smoothFactor: Number = 1.0 - // How much to simplify the polyline on each zoom level. More means - // better performance and smoother look, and less means more accurate representation. - smoothFactor: 1.0, - - // @option noClip: Boolean = false - // Disable polyline clipping. - noClip: false - }, - - initialize: function (latlngs, options) { - setOptions(this, options); - this._setLatLngs(latlngs); - }, - - // @method getLatLngs(): LatLng[] - // Returns an array of the points in the path, or nested arrays of points in case of multi-polyline. - getLatLngs: function () { - return this._latlngs; - }, - - // @method setLatLngs(latlngs: LatLng[]): this - // Replaces all the points in the polyline with the given array of geographical points. - setLatLngs: function (latlngs) { - this._setLatLngs(latlngs); - return this.redraw(); - }, - - // @method isEmpty(): Boolean - // Returns `true` if the Polyline has no LatLngs. - isEmpty: function () { - return !this._latlngs.length; - }, - - // @method closestLayerPoint: Point - // Returns the point closest to `p` on the Polyline. - closestLayerPoint: function (p) { - let minDistance = Infinity, - minPoint = null, - closest = _sqClosestPointOnSegment, - p1, p2; - - for (let j = 0, jLen = this._parts.length; j < jLen; j++) { - let points = this._parts[j]; - - for (let i = 1, len = points.length; i < len; i++) { - p1 = points[i - 1]; - p2 = points[i]; - - let sqDist = closest(p, p1, p2, true); - - if (sqDist < minDistance) { - minDistance = sqDist; - minPoint = closest(p, p1, p2); - } - } - } - if (minPoint) { - minPoint.distance = Math.sqrt(minDistance); - } - return minPoint; - }, - - // @method getCenter(): LatLng - // Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline. - getCenter: function () { - // throws error when not yet added to map as this center calculation requires projected coordinates - if (!this._map) { - throw new Error('Must add layer to map before using getCenter()'); - } - - var i, halfDist, segDist, dist, p1, p2, ratio, - points = this._rings[0], - len = points.length; - - if (!len) { return null; } - - // polyline centroid algorithm; only uses the first ring if there are multiple - - for (i = 0, halfDist = 0; i < len - 1; i++) { - halfDist += points[i].distanceTo(points[i + 1]) / 2; - } - - // The line is so small in the current view that all points are on the same pixel. - if (halfDist === 0) { - return this._map.layerPointToLatLng(points[0]); - } - - for (i = 0, dist = 0; i < len - 1; i++) { - p1 = points[i]; - p2 = points[i + 1]; - segDist = p1.distanceTo(p2); - dist += segDist; - - if (dist > halfDist) { - ratio = (dist - halfDist) / segDist; - return this._map.layerPointToLatLng([ - p2.x - ratio * (p2.x - p1.x), - p2.y - ratio * (p2.y - p1.y) - ]); - } - } - }, - - // @method getBounds(): LatLngBounds - // Returns the `LatLngBounds` of the path. - getBounds: function () { - return this._bounds; - }, - - // @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this - // Adds a given point to the polyline. By default, adds to the first ring of - // the polyline in case of a multi-polyline, but can be overridden by passing - // a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)). - addLatLng: function (latlng, latlngs) { - latlngs = latlngs || this._defaultShape(); - latlng = toLatLng(latlng); - latlngs.push(latlng); - this._bounds.extend(latlng); - return this.redraw(); - }, - - _setLatLngs: function (latlngs) { - this._bounds = new LatLngBounds(); - this._latlngs = this._convertLatLngs(latlngs); - }, - - _defaultShape: function () { - return isFlat(this._latlngs) ? this._latlngs : this._latlngs[0]; - }, - - // recursively convert latlngs input into actual LatLng instances; calculate bounds along the way - _convertLatLngs: function (latlngs) { - let result = [], - flat = isFlat(latlngs); - - for (let i = 0, len = latlngs.length; i < len; i++) { - if (flat) { - result[i] = toLatLng(latlngs[i]); - this._bounds.extend(result[i]); - } else { - result[i] = this._convertLatLngs(latlngs[i]); - } - } - - return result; - }, - - _project: function () { - let pxBounds = new Bounds(); - this._rings = []; - this._projectLatlngs(this._latlngs, this._rings, pxBounds); - - let w = this._clickTolerance(), - p = new Point(w, w); - - if (this._bounds.isValid() && pxBounds.isValid()) { - pxBounds.min._subtract(p); - pxBounds.max._add(p); - this._pxBounds = pxBounds; - } - }, - - // recursively turns latlngs into a set of rings with projected coordinates - _projectLatlngs: function (latlngs, result, projectedBounds) { - let flat = latlngs[0] instanceof LatLng, - len = latlngs.length, - i, ring; - - if (flat) { - ring = []; - for (i = 0; i < len; i++) { - ring[i] = this._map.latLngToLayerPoint(latlngs[i]); - projectedBounds.extend(ring[i]); - } - result.push(ring); - } else { - for (i = 0; i < len; i++) { - this._projectLatlngs(latlngs[i], result, projectedBounds); - } - } - }, - - // clip polyline by renderer bounds so that we have less to render for performance - _clipPoints: function () { - let bounds = this._renderer._bounds; - - this._parts = []; - if (!this._pxBounds || !this._pxBounds.intersects(bounds)) { - return; - } - - if (this.options.noClip) { - this._parts = this._rings; - return; - } - - let parts = this._parts, - i, j, k, len, len2, segment, points; - - for (i = 0, k = 0, len = this._rings.length; i < len; i++) { - points = this._rings[i]; - - for (j = 0, len2 = points.length; j < len2 - 1; j++) { - segment = clipSegment(points[j], points[j + 1], bounds, j, true); - - if (!segment) { continue; } - - parts[k] = parts[k] || []; - parts[k].push(segment[0]); - - // if segment goes out of screen, or it's the last one, it's the end of the line part - if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) { - parts[k].push(segment[1]); - k++; - } - } - } - }, - - // simplify each clipped part of the polyline for performance - _simplifyPoints: function () { - let parts = this._parts, - tolerance = this.options.smoothFactor; - - for (let i = 0, len = parts.length; i < len; i++) { - parts[i] = simplify(parts[i], tolerance); - } - }, - - _update: function () { - if (!this._map) { return; } - - this._clipPoints(); - this._simplifyPoints(); - this._updatePath(); - }, - - _updatePath: function () { - this._renderer._updatePoly(this); - }, - - // Needed by the `Canvas` renderer for interactivity - _containsPoint: function (p, closed) { - var i, j, k, len, len2, part, - w = this._clickTolerance(); - - if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; } - - // hit detection for polylines - for (i = 0, len = this._parts.length; i < len; i++) { - part = this._parts[i]; - - for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { - if (!closed && (j === 0)) { continue; } - - if (pointToSegmentDistance(p, part[k], part[j]) <= w) { - return true; - } - } - } - return false; - } -}); - -// @factory L.polyline(latlngs: LatLng[], options?: Polyline options) -// Instantiates a polyline object given an array of geographical points and -// optionally an options object. You can create a `Polyline` object with -// multiple separate lines (`MultiPolyline`) by passing an array of arrays -// of geographic points. -function polyline(latlngs, options) { - return new Polyline(latlngs, options); -} - -// Retrocompat. Allow plugins to support Leaflet versions before and after 1.1. -Polyline._flat = _flat; - -/* - * @class Polygon - * @aka L.Polygon - * @inherits Polyline - * - * A class for drawing polygon overlays on a map. Extends `Polyline`. - * - * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points. - * - * - * @example - * - * ```js - * // create a red polygon from an array of LatLng points - * let latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]]; - * - * let polygon = L.polygon(latlngs, {color: 'red'}).addTo(map); - * - * // zoom the map to the polygon - * map.fitBounds(polygon.getBounds()); - * ``` - * - * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape: - * - * ```js - * let latlngs = [ - * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring - * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole - * ]; - * ``` - * - * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape. - * - * ```js - * let latlngs = [ - * [ // first polygon - * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring - * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole - * ], - * [ // second polygon - * [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]] - * ] - * ]; - * ``` - */ - -let Polygon = Polyline.extend({ - - options: { - fill: true - }, - - isEmpty: function () { - return !this._latlngs.length || !this._latlngs[0].length; - }, - - getCenter: function () { - // throws error when not yet added to map as this center calculation requires projected coordinates - if (!this._map) { - throw new Error('Must add layer to map before using getCenter()'); - } - - var i, j, p1, p2, f, area, x, y, center, - points = this._rings[0], - len = points.length; - - if (!len) { return null; } - - // polygon centroid algorithm; only uses the first ring if there are multiple - - area = x = y = 0; - - for (i = 0, j = len - 1; i < len; j = i++) { - p1 = points[i]; - p2 = points[j]; - - f = p1.y * p2.x - p2.y * p1.x; - x += (p1.x + p2.x) * f; - y += (p1.y + p2.y) * f; - area += f * 3; - } - - if (area === 0) { - // Polygon is so small that all points are on same pixel. - center = points[0]; - } else { - center = [x / area, y / area]; - } - return this._map.layerPointToLatLng(center); - }, - - _convertLatLngs: function (latlngs) { - let result = Polyline.prototype._convertLatLngs.call(this, latlngs), - len = result.length; - - // remove last point if it equals first one - if (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) { - result.pop(); - } - return result; - }, - - _setLatLngs: function (latlngs) { - Polyline.prototype._setLatLngs.call(this, latlngs); - if (isFlat(this._latlngs)) { - this._latlngs = [this._latlngs]; - } - }, - - _defaultShape: function () { - return isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0]; - }, - - _clipPoints: function () { - // polygons need a different clipping algorithm so we redefine that - - let bounds = this._renderer._bounds, - w = this.options.weight, - p = new Point(w, w); - - // increase clip padding by stroke width to avoid stroke on clip edges - bounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p)); - - this._parts = []; - if (!this._pxBounds || !this._pxBounds.intersects(bounds)) { - return; - } - - if (this.options.noClip) { - this._parts = this._rings; - return; - } - - for (let i = 0, len = this._rings.length, clipped; i < len; i++) { - clipped = clipPolygon(this._rings[i], bounds, true); - if (clipped.length) { - this._parts.push(clipped); - } - } - }, - - _updatePath: function () { - this._renderer._updatePoly(this, true); - }, - - // Needed by the `Canvas` renderer for interactivity - _containsPoint: function (p) { - let inside = false, - part, p1, p2, i, j, k, len, len2; - - if (!this._pxBounds.contains(p)) { return false; } - - // ray casting algorithm for detecting if point is in polygon - for (i = 0, len = this._parts.length; i < len; i++) { - part = this._parts[i]; - - for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { - p1 = part[j]; - p2 = part[k]; - - if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) { - inside = !inside; - } - } - } - - // also check if it's on polygon stroke - return inside || Polyline.prototype._containsPoint.call(this, p, true); - } - -}); - - -// @factory L.polygon(latlngs: LatLng[], options?: Polyline options) -function polygon(latlngs, options) { - return new Polygon(latlngs, options); -} - -/* - * @class GeoJSON - * @aka L.GeoJSON - * @inherits FeatureGroup - * - * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse - * GeoJSON data and display it on the map. Extends `FeatureGroup`. - * - * @example - * - * ```js - * L.geoJSON(data, { - * style: function (feature) { - * return {color: feature.properties.color}; - * } - * }).bindPopup(function (layer) { - * return layer.feature.properties.description; - * }).addTo(map); - * ``` - */ - -let GeoJSON = FeatureGroup.extend({ - - /* @section - * @aka GeoJSON options - * - * @option pointToLayer: Function = * - * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally - * called when data is added, passing the GeoJSON point feature and its `LatLng`. - * The default is to spawn a default `Marker`: - * ```js - * function(geoJsonPoint, latlng) { - * return L.marker(latlng); - * } - * ``` - * - * @option style: Function = * - * A `Function` defining the `Path options` for styling GeoJSON lines and polygons, - * called internally when data is added. - * The default value is to not override any defaults: - * ```js - * function (geoJsonFeature) { - * return {} - * } - * ``` - * - * @option onEachFeature: Function = * - * A `Function` that will be called once for each created `Feature`, after it has - * been created and styled. Useful for attaching events and popups to features. - * The default is to do nothing with the newly created layers: - * ```js - * function (feature, layer) {} - * ``` - * - * @option filter: Function = * - * A `Function` that will be used to decide whether to include a feature or not. - * The default is to include all features: - * ```js - * function (geoJsonFeature) { - * return true; - * } - * ``` - * Note: dynamically changing the `filter` option will have effect only on newly - * added data. It will _not_ re-evaluate already included features. - * - * @option coordsToLatLng: Function = * - * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s. - * The default is the `coordsToLatLng` static method. - */ - - initialize: function (geojson, options) { - setOptions(this, options); - - this._layers = {}; - - if (geojson) { - this.addData(geojson); - } - }, - - // @method addData( data ): this - // Adds a GeoJSON object to the layer. - addData: function (geojson) { - let features = isArray(geojson) ? geojson : geojson.features, - i, len, feature; - - if (features) { - for (i = 0, len = features.length; i < len; i++) { - // only add this if geometry or geometries are set and not null - feature = features[i]; - if (feature.geometries || feature.geometry || feature.features || feature.coordinates) { - this.addData(feature); - } - } - return this; - } - - let options = this.options; - - if (options.filter && !options.filter(geojson)) { return this; } - - let layer = geometryToLayer(geojson, options); - if (!layer) { - return this; - } - layer.feature = asFeature(geojson); - - layer.defaultOptions = layer.options; - this.resetStyle(layer); - - if (options.onEachFeature) { - options.onEachFeature(geojson, layer); - } - - return this.addLayer(layer); - }, - - // @method resetStyle( layer ): this - // Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events. - resetStyle: function (layer) { - // reset any custom styles - layer.options = extend({}, layer.defaultOptions); - this._setLayerStyle(layer, this.options.style); - return this; - }, - - // @method setStyle( style ): this - // Changes styles of GeoJSON vector layers with the given style function. - setStyle: function (style) { - return this.eachLayer(function (layer) { - this._setLayerStyle(layer, style); - }, this); - }, - - _setLayerStyle: function (layer, style) { - if (typeof style === 'function') { - style = style(layer.feature); - } - if (layer.setStyle) { - layer.setStyle(style); - } - } -}); - -// @section -// There are several static functions which can be called without instantiating L.GeoJSON: - -// @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer -// Creates a `Layer` from a given GeoJSON feature. Can use a custom -// [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng) -// functions if provided as options. -function geometryToLayer(geojson, options) { - - let geometry = geojson.type === 'Feature' ? geojson.geometry : geojson, - coords = geometry ? geometry.coordinates : null, - layers = [], - pointToLayer = options && options.pointToLayer, - _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng, - latlng, latlngs, i, len; - - if (!coords && !geometry) { - return null; - } - - switch (geometry.type) { - case 'Point': - latlng = _coordsToLatLng(coords); - return pointToLayer ? pointToLayer(geojson, latlng) : new Marker(latlng); - - case 'MultiPoint': - for (i = 0, len = coords.length; i < len; i++) { - latlng = _coordsToLatLng(coords[i]); - layers.push(pointToLayer ? pointToLayer(geojson, latlng) : new Marker(latlng)); - } - return new FeatureGroup(layers); - - case 'LineString': - case 'MultiLineString': - latlngs = coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, _coordsToLatLng); - return new Polyline(latlngs, options); - - case 'Polygon': - case 'MultiPolygon': - latlngs = coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, _coordsToLatLng); - return new Polygon(latlngs, options); - - case 'GeometryCollection': - for (i = 0, len = geometry.geometries.length; i < len; i++) { - let layer = geometryToLayer({ - geometry: geometry.geometries[i], - type: 'Feature', - properties: geojson.properties - }, options); - - if (layer) { - layers.push(layer); - } - } - return new FeatureGroup(layers); - - default: - throw new Error('Invalid GeoJSON object.'); - } -} - -// @function coordsToLatLng(coords: Array): LatLng -// Creates a `LatLng` object from an array of 2 numbers (longitude, latitude) -// or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points. -function coordsToLatLng(coords) { - return new LatLng(coords[1], coords[0], coords[2]); -} - -// @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array -// Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array. -// `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default). -// Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function. -function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) { - let latlngs = []; - - for (let i = 0, len = coords.length, latlng; i < len; i++) { - latlng = levelsDeep ? - coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) : - (_coordsToLatLng || coordsToLatLng)(coords[i]); - - latlngs.push(latlng); - } - - return latlngs; -} - -// @function latLngToCoords(latlng: LatLng, precision?: Number): Array -// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng) -function latLngToCoords(latlng, precision) { - precision = typeof precision === 'number' ? precision : 6; - return latlng.alt !== undefined ? - [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] : - [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)]; -} - -// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array -// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs) -// `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default. -function latLngsToCoords(latlngs, levelsDeep, closed, precision) { - let coords = []; - - for (let i = 0, len = latlngs.length; i < len; i++) { - coords.push(levelsDeep ? - latLngsToCoords(latlngs[i], levelsDeep - 1, closed, precision) : - latLngToCoords(latlngs[i], precision)); - } - - if (!levelsDeep && closed) { - coords.push(coords[0]); - } - - return coords; -} - -function getFeature(layer, newGeometry) { - return layer.feature ? - extend({}, layer.feature, {geometry: newGeometry}) : - asFeature(newGeometry); -} - -// @function asFeature(geojson: Object): Object -// Normalize GeoJSON geometries/features into GeoJSON features. -function asFeature(geojson) { - if (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') { - return geojson; - } - - return { - type: 'Feature', - properties: {}, - geometry: geojson - }; -} - -let PointToGeoJSON = { - toGeoJSON: function (precision) { - return getFeature(this, { - type: 'Point', - coordinates: latLngToCoords(this.getLatLng(), precision) - }); - } -}; - -// @namespace Marker -// @method toGeoJSON(): Object -// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature). -Marker.include(PointToGeoJSON); - -// @namespace CircleMarker -// @method toGeoJSON(): Object -// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature). -Circle.include(PointToGeoJSON); -CircleMarker.include(PointToGeoJSON); - - -// @namespace Polyline -// @method toGeoJSON(): Object -// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature). -Polyline.include({ - toGeoJSON: function (precision) { - let multi = !isFlat(this._latlngs); - - let coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision); - - return getFeature(this, { - type: (multi ? 'Multi' : '') + 'LineString', - coordinates: coords - }); - } -}); - -// @namespace Polygon -// @method toGeoJSON(): Object -// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature). -Polygon.include({ - toGeoJSON: function (precision) { - let holes = !isFlat(this._latlngs), - multi = holes && !isFlat(this._latlngs[0]); - - let coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision); - - if (!holes) { - coords = [coords]; - } - - return getFeature(this, { - type: (multi ? 'Multi' : '') + 'Polygon', - coordinates: coords - }); - } -}); - - -// @namespace LayerGroup -LayerGroup.include({ - toMultiPoint: function (precision) { - let coords = []; - - this.eachLayer(function (layer) { - coords.push(layer.toGeoJSON(precision).geometry.coordinates); - }); - - return getFeature(this, { - type: 'MultiPoint', - coordinates: coords - }); - }, - - // @method toGeoJSON(): Object - // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`). - toGeoJSON: function (precision) { - - let type = this.feature && this.feature.geometry && this.feature.geometry.type; - - if (type === 'MultiPoint') { - return this.toMultiPoint(precision); - } - - let isGeometryCollection = type === 'GeometryCollection', - jsons = []; - - this.eachLayer(function (layer) { - if (layer.toGeoJSON) { - let json = layer.toGeoJSON(precision); - if (isGeometryCollection) { - jsons.push(json.geometry); - } else { - let feature = asFeature(json); - // Squash nested feature collections - if (feature.type === 'FeatureCollection') { - jsons.push.apply(jsons, feature.features); - } else { - jsons.push(feature); - } - } - } - }); - - if (isGeometryCollection) { - return getFeature(this, { - geometries: jsons, - type: 'GeometryCollection' - }); - } - - return { - type: 'FeatureCollection', - features: jsons - }; - } -}); - -// @namespace GeoJSON -// @factory L.geoJSON(geojson?: Object, options?: GeoJSON options) -// Creates a GeoJSON layer. Optionally accepts an object in -// [GeoJSON format](http://geojson.org/geojson-spec.html) to display on the map -// (you can alternatively add it later with `addData` method) and an `options` object. -function geoJSON(geojson, options) { - return new GeoJSON(geojson, options); -} - -// Backward compatibility. -let geoJson = geoJSON; - -/* - * @class ImageOverlay - * @aka L.ImageOverlay - * @inherits Interactive layer - * - * Used to load and display a single image over specific bounds of the map. Extends `Layer`. - * - * @example - * - * ```js - * let imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg', - * imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]]; - * L.imageOverlay(imageUrl, imageBounds).addTo(map); - * ``` - */ - -let ImageOverlay = Layer.extend({ - - // @section - // @aka ImageOverlay options - options: { - // @option opacity: Number = 1.0 - // The opacity of the image overlay. - opacity: 1, - - // @option alt: String = '' - // Text for the `alt` attribute of the image (useful for accessibility). - alt: '', - - // @option interactive: Boolean = false - // If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered. - interactive: false, - - // @option crossOrigin: Boolean = false - // If true, the image will have its crossOrigin attribute set to ''. This is needed if you want to access image pixel data. - crossOrigin: false, - - // @option errorOverlayUrl: String = '' - // URL to the overlay image to show in place of the overlay that failed to load. - errorOverlayUrl: '', - - // @option zIndex: Number = 1 - // The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the tile layer. - zIndex: 1, - - // @option className: String = '' - // A custom class name to assign to the image. Empty by default. - className: '', - }, - - initialize: function (url, bounds, options) { // (String, LatLngBounds, Object) - this._url = url; - this._bounds = toLatLngBounds(bounds); - - setOptions(this, options); - }, - - onAdd: function () { - if (!this._image) { - this._initImage(); - - if (this.options.opacity < 1) { - this._updateOpacity(); - } - } - - if (this.options.interactive) { - addClass(this._image, 'leaflet-interactive'); - this.addInteractiveTarget(this._image); - } - - this.getPane().appendChild(this._image); - this._reset(); - }, - - onRemove: function () { - remove(this._image); - if (this.options.interactive) { - this.removeInteractiveTarget(this._image); - } - }, - - // @method setOpacity(opacity: Number): this - // Sets the opacity of the overlay. - setOpacity: function (opacity) { - this.options.opacity = opacity; - - if (this._image) { - this._updateOpacity(); - } - return this; - }, - - setStyle: function (styleOpts) { - if (styleOpts.opacity) { - this.setOpacity(styleOpts.opacity); - } - return this; - }, - - // @method bringToFront(): this - // Brings the layer to the top of all overlays. - bringToFront: function () { - if (this._map) { - toFront(this._image); - } - return this; - }, - - // @method bringToBack(): this - // Brings the layer to the bottom of all overlays. - bringToBack: function () { - if (this._map) { - toBack(this._image); - } - return this; - }, - - // @method setUrl(url: String): this - // Changes the URL of the image. - setUrl: function (url) { - this._url = url; - - if (this._image) { - this._image.src = url; - } - return this; - }, - - // @method setBounds(bounds: LatLngBounds): this - // Update the bounds that this ImageOverlay covers - setBounds: function (bounds) { - this._bounds = toLatLngBounds(bounds); - - if (this._map) { - this._reset(); - } - return this; - }, - - getEvents: function () { - let events = { - zoom: this._reset, - viewreset: this._reset - }; - - if (this._zoomAnimated) { - events.zoomanim = this._animateZoom; - } - - return events; - }, - - // @method: setZIndex(value: Number) : this - // Changes the [zIndex](#imageoverlay-zindex) of the image overlay. - setZIndex: function (value) { - this.options.zIndex = value; - this._updateZIndex(); - return this; - }, - - // @method getBounds(): LatLngBounds - // Get the bounds that this ImageOverlay covers - getBounds: function () { - return this._bounds; - }, - - // @method getElement(): HTMLElement - // Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement) - // used by this overlay. - getElement: function () { - return this._image; - }, - - _initImage: function () { - let wasElementSupplied = this._url.tagName === 'IMG'; - let img = this._image = wasElementSupplied ? this._url : create$1('img'); - - addClass(img, 'leaflet-image-layer'); - if (this._zoomAnimated) { addClass(img, 'leaflet-zoom-animated'); } - if (this.options.className) { addClass(img, this.options.className); } - - img.onselectstart = falseFn; - img.onmousemove = falseFn; - - // @event load: Event - // Fired when the ImageOverlay layer has loaded its image - img.onload = bind(this.fire, this, 'load'); - img.onerror = bind(this._overlayOnError, this, 'error'); - - if (this.options.crossOrigin) { - img.crossOrigin = ''; - } - - if (this.options.zIndex) { - this._updateZIndex(); - } - - if (wasElementSupplied) { - this._url = img.src; - return; - } - - img.src = this._url; - img.alt = this.options.alt; - }, - - _animateZoom: function (e) { - let scale = this._map.getZoomScale(e.zoom), - offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min; - - setTransform(this._image, offset, scale); - }, - - _reset: function () { - let image = this._image, - bounds = new Bounds( - this._map.latLngToLayerPoint(this._bounds.getNorthWest()), - this._map.latLngToLayerPoint(this._bounds.getSouthEast())), - size = bounds.getSize(); - - setPosition(image, bounds.min); - - image.style.width = size.x + 'px'; - image.style.height = size.y + 'px'; - }, - - _updateOpacity: function () { - setOpacity(this._image, this.options.opacity); - }, - - _updateZIndex: function () { - if (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) { - this._image.style.zIndex = this.options.zIndex; - } - }, - - _overlayOnError: function () { - // @event error: Event - // Fired when the ImageOverlay layer has loaded its image - this.fire('error'); - - let errorUrl = this.options.errorOverlayUrl; - if (errorUrl && this._url !== errorUrl) { - this._url = errorUrl; - this._image.src = errorUrl; - } - } -}); - -// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options) -// Instantiates an image overlay object given the URL of the image and the -// geographical bounds it is tied to. -let imageOverlay = (url, bounds, options) => { - return new ImageOverlay(url, bounds, options); -}; - -/* - * @class VideoOverlay - * @aka L.VideoOverlay - * @inherits ImageOverlay - * - * Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`. - * - * A video overlay uses the [`