- Add css support in storybook.

- Add icons to mxgraph.
- Convert some examples to storybook.
development
Junsik Shim 2021-04-19 21:56:58 +09:00
parent def8468d64
commit 1d05e161c9
32 changed files with 808 additions and 34 deletions

81
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -0,0 +1,166 @@
div.mxRubberband {
position: absolute;
overflow: hidden;
border-style: solid;
border-width: 1px;
border-color: #0000FF;
background: #0077FF;
}
.mxCellEditor {
background: url(data:image/gif;base64,R0lGODlhMAAwAIAAAP///wAAACH5BAEAAAAALAAAAAAwADAAAAIxhI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8egpAAA7);
_background: url('../images/transparent.gif');
border-color: transparent;
border-style: solid;
display: inline-block;
position: absolute;
overflow: visible;
word-wrap: normal;
border-width: 0;
min-width: 1px;
resize: none;
padding: 0px;
margin: 0px;
}
.mxPlainTextEditor * {
padding: 0px;
margin: 0px;
}
div.mxWindow {
-webkit-box-shadow: 3px 3px 12px #C0C0C0;
-moz-box-shadow: 3px 3px 12px #C0C0C0;
box-shadow: 3px 3px 12px #C0C0C0;
background: url(data:image/gif;base64,R0lGODlhGgAUAIAAAOzs7PDw8CH5BAAAAAAALAAAAAAaABQAAAIijI+py70Ao5y02lud3lzhD4ZUR5aPiKajyZbqq7YyB9dhAQA7);
_background: url('../images/window.gif');
border:1px solid #c3c3c3;
position: absolute;
overflow: hidden;
z-index: 1;
}
table.mxWindow {
border-collapse: collapse;
table-layout: fixed;
font-family: Arial;
font-size: 8pt;
}
td.mxWindowTitle {
background: url(data:image/gif;base64,R0lGODlhFwAXAMQAANfX18rKyuHh4c7OzsDAwMHBwc/Pz+Li4uTk5NHR0dvb2+jo6O/v79/f3/n5+dnZ2dbW1uPj44yMjNPT0+Dg4N3d3ebm5szMzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAXABcAAAWQICESxWiW5Ck6bOu+MMvMdG3f86LvfO/rlqBwSCwaj8ikUohoOp/QaDNCrVqvWKpgezhsv+AwmEIum89ocmPNbrvf64p8Tq/b5Yq8fs/v5x+AgYKDhIAAh4iJiouHEI6PkJGSjhOVlpeYmZUJnJ2en6CcBqMDpaanqKgXq6ytrq+rAbKztLW2shK5uru8vbkhADs=) repeat-x;
_background: url('../images/window-title.gif') repeat-x;
text-overflow: ellipsis;
white-space: nowrap;
text-align: center;
font-weight: bold;
overflow: hidden;
height: 13px;
padding: 2px;
padding-top: 4px;
padding-bottom: 6px;
color: black;
}
td.mxWindowPane {
vertical-align: top;
padding: 0px;
}
div.mxWindowPane {
overflow: hidden;
position: relative;
}
td.mxWindowPane td {
font-family: Arial;
font-size: 8pt;
}
td.mxWindowPane input, td.mxWindowPane select, td.mxWindowPane textarea, td.mxWindowPane radio {
border-color: #8C8C8C;
border-style: solid;
border-width: 1px;
font-family: Arial;
font-size: 8pt;
padding: 1px;
}
td.mxWindowPane button {
background: url(data:image/gif;base64,R0lGODlhCgATALMAAP7+/t7e3vj4+Ojo6OXl5e/v7/n5+fb29vPz8/39/e3t7fHx8e7u7v///wAAAAAAACH5BAAAAAAALAAAAAAKABMAAAQ2MMlJhb0Y6c2X/2AhjiRjnqiirizqMkEsz0Rt30Ou7y8K/ouDcEg0GI9IgHLJbDif0Kh06owAADs=) repeat-x;
_background: url('../images/button.gif') repeat-x;
font-family: Arial;
font-size: 8pt;
padding: 2px;
float: left;
}
img.mxToolbarItem {
margin-right: 6px;
margin-bottom: 6px;
border-width: 1px;
}
select.mxToolbarCombo {
vertical-align: top;
border-style: inset;
border-width: 2px;
}
div.mxToolbarComboContainer {
padding: 2px;
}
img.mxToolbarMode {
margin: 2px;
margin-right: 4px;
margin-bottom: 4px;
border-width: 0px;
}
img.mxToolbarModeSelected {
margin: 0px;
margin-right: 2px;
margin-bottom: 2px;
border-width: 2px;
border-style: inset;
}
div.mxTooltip {
-webkit-box-shadow: 3px 3px 12px #C0C0C0;
-moz-box-shadow: 3px 3px 12px #C0C0C0;
box-shadow: 3px 3px 12px #C0C0C0;
background: #FFFFCC;
border-style: solid;
border-width: 1px;
border-color: black;
font-family: Arial;
font-size: 8pt;
position: absolute;
cursor: default;
padding: 4px;
color: black;
}
div.mxPopupMenu {
-webkit-box-shadow: 3px 3px 12px #C0C0C0;
-moz-box-shadow: 3px 3px 12px #C0C0C0;
box-shadow: 3px 3px 12px #C0C0C0;
background: url(data:image/gif;base64,R0lGODlhGgAUAIAAAOzs7PDw8CH5BAAAAAAALAAAAAAaABQAAAIijI+py70Ao5y02lud3lzhD4ZUR5aPiKajyZbqq7YyB9dhAQA7);
_background: url('../images/window.gif');
position: absolute;
border-style: solid;
border-width: 1px;
border-color: black;
}
table.mxPopupMenu {
border-collapse: collapse;
margin-top: 1px;
margin-bottom: 1px;
}
tr.mxPopupMenuItem {
color: black;
cursor: pointer;
}
tr.mxPopupMenuItemHover {
background-color: #000066;
color: #FFFFFF;
cursor: pointer;
}
td.mxPopupMenuItem {
padding: 2px 30px 2px 10px;
white-space: nowrap;
font-family: Arial;
font-size: 8pt;
}
td.mxPopupMenuIcon {
background-color: #D0D0D0;
padding: 2px 4px 2px 4px;
}
.mxDisabled {
opacity: 0.2 !important;
cursor:default !important;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 843 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

View File

@ -173,6 +173,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,

View File

@ -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) {

View File

@ -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 = {};
}

View File

@ -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,

View File

@ -4,7 +4,7 @@
"description": "",
"main": "index.js",
"scripts": {
"dev": "start-storybook -p 8901"
"dev": "start-storybook -p 8901 -s ./public"
},
"author": "",
"license": "ISC",

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 B

View File

@ -0,0 +1,131 @@
import mxgraph from '@mxgraph/core';
import HelloWorld from './HelloWorld.stories';
export default {
title: 'Connections/Anchors',
argTypes: {
...HelloWorld.argTypes
}
};
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({});

View File

@ -0,0 +1,120 @@
import mxgraph from '@mxgraph/core';
export default {
title: 'Connections/EdgeTolerance',
argTypes: {
width: {
type: 'number',
defaultValue: 800
},
height: {
type: 'number',
defaultValue: 600
}
}
};
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 (this.getModel().isEdge(cell)) {
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(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({});

View File

@ -0,0 +1,261 @@
import mxgraph from '@mxgraph/core';
import HelloWorld from './HelloWorld.stories';
export default {
title: 'Backgrounds/ExtendCanvas',
argTypes: {
...HelloWorld.argTypes
}
};
const Template = ({ label, ...args }) => {
const {
mxGraph,
mxEvent,
mxRubberband,
mxRectangle,
mxGraphView,
mxPoint,
mxDomHelpers,
mxUtils
} = mxgraph;
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-
* translation, which depends on this value, and small enough to give
* a small empty buffer around the graph. Default is 400x400.
*/
const scrollTileSize = new mxRectangle(0, 0, 400, 400);
class MyCustomGraph extends mxGraph {
/**
* Returns the padding for pages in page view with scrollbars.
*/
getPagePadding() {
return new mxPoint(
Math.max(0, Math.round(this.container.offsetWidth - 34)),
Math.max(0, Math.round(this.container.offsetHeight - 34))
);
}
/**
* Returns the size of the page format scaled with the page size.
*/
getPageSize() {
return this.pageVisible
? new mxRectangle(
0,
0,
this.pageFormat.width * this.pageScale,
this.pageFormat.height * this.pageScale
)
: scrollTileSize;
}
/**
* Returns a rectangle describing the position and count of the
* background pages, where x and y are the position of the top,
* left page and width and height are the vertical and horizontal
* page count.
*/
getPageLayout() {
const size = this.pageVisible ? this.getPageSize() : scrollTileSize;
const bounds = this.getGraphBounds();
if (bounds.width === 0 || bounds.height === 0) {
return new mxRectangle(0, 0, 1, 1);
}
// Computes untransformed graph bounds
const x = Math.ceil(bounds.x / this.view.scale - this.view.translate.x);
const y = Math.ceil(bounds.y / this.view.scale - this.view.translate.y);
const w = Math.floor(bounds.width / this.view.scale);
const h = Math.floor(bounds.height / this.view.scale);
const x0 = Math.floor(x / size.width);
const y0 = Math.floor(y / size.height);
const w0 = Math.ceil((x + w) / size.width) - x0;
const h0 = Math.ceil((y + h) / size.height) - y0;
return new mxRectangle(x0, y0, w0, h0);
}
getPreferredPageSize(bounds, width, height) {
const pages = this.getPageLayout();
const size = this.getPageSize();
return new mxRectangle(
0,
0,
pages.width * size.width,
pages.height * size.height
);
}
sizeDidChange() {
if (this.container != null && mxUtils.hasScrollbars(this.container)) {
const pages = this.getPageLayout();
const pad = this.getPagePadding();
const size = this.getPageSize();
// Updates the minimum graph size
const minw = Math.ceil(
(2 * pad.x) / this.view.scale + pages.width * size.width
);
const minh = Math.ceil(
(2 * pad.y) / this.view.scale + pages.height * size.height
);
const min = this.minimumGraphSize;
// LATER: Fix flicker of scrollbar size in IE quirks mode
// after delayed call in window.resize event handler
if (min == null || min.width !== minw || min.height !== minh) {
this.minimumGraphSize = new mxRectangle(0, 0, minw, minh);
}
// Updates auto-translate to include padding and graph size
const dx = pad.x / this.view.scale - pages.x * size.width;
const dy = pad.y / this.view.scale - pages.y * size.height;
if (
!this.autoTranslate &&
(this.view.translate.x !== dx || this.view.translate.y !== dy)
) {
this.autoTranslate = true;
this.view.x0 = pages.x;
this.view.y0 = pages.y;
// NOTE: THIS INVOKES THIS METHOD AGAIN. UNFORTUNATELY THERE IS NO WAY AROUND THIS SINCE THE
// BOUNDS ARE KNOWN AFTER THE VALIDATION AND SETTING THE TRANSLATE TRIGGERS A REVALIDATION.
// SHOULD MOVE TRANSLATE/SCALE TO VIEW.
const tx = this.view.translate.x;
const ty = this.view.translate.y;
this.view.setTranslate(dx, dy);
this.container.scrollLeft += (dx - tx) * this.view.scale;
this.container.scrollTop += (dy - ty) * this.view.scale;
this.autoTranslate = false;
return;
}
super.sizeDidChange();
}
}
}
// Creates the graph inside the given container
const graph = new MyCustomGraph(container);
graph.panningHandler.ignoreCell = true;
graph.setPanning(true);
// Fits the number of background pages to the graph
graph.view.getBackgroundPageBounds = function() {
const layout = this.graph.getPageLayout();
const page = this.graph.getPageSize();
return new mxRectangle(
this.scale * (this.translate.x + layout.x * page.width),
this.scale * (this.translate.y + layout.y * page.height),
this.scale * layout.width * page.width,
this.scale * layout.height * page.height
);
};
/**
* Guesses autoTranslate to avoid another repaint (see below).
* Works if only the scale of the graph changes or if pages
* are visible and the visible pages do not change.
*/
const graphViewValidate = graph.view.validate;
graph.view.validate = function() {
if (
this.graph.container != null &&
mxUtils.hasScrollbars(this.graph.container)
) {
const pad = this.graph.getPagePadding();
const size = this.graph.getPageSize();
// Updating scrollbars here causes flickering in quirks and is not needed
// if zoom method is always used to set the current scale on the graph.
const tx = this.translate.x;
const ty = this.translate.y;
this.translate.x = pad.x / this.scale - (this.x0 || 0) * size.width;
this.translate.y = pad.y / this.scale - (this.y0 || 0) * size.height;
}
graphViewValidate.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: '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,
});
});
// Sets initial scrollbar positions
window.setTimeout(() => {
const bounds = graph.getGraphBounds();
const width = Math.max(
bounds.width,
scrollTileSize.width * graph.view.scale
);
const height = Math.max(
bounds.height,
scrollTileSize.height * graph.view.scale
);
graph.container.scrollTop = Math.floor(
Math.max(
0,
bounds.y - Math.max(20, (graph.container.clientHeight - height) / 4)
)
);
graph.container.scrollLeft = Math.floor(
Math.max(
0,
bounds.x - Math.max(0, (graph.container.clientWidth - width) / 2)
)
);
}, 0);
return container;
}
export const Default = Template.bind({});

View File

@ -1,7 +1,12 @@
import mxgraph from '@mxgraph/core';
import HelloWorld from './HelloWorld.stories';
export default {
title: 'Backgrounds/Grid'
title: 'Backgrounds/Grid',
argTypes: {
...HelloWorld.argTypes
}
};
const Template = ({ label, ...args }) => {
@ -21,11 +26,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 +40,8 @@ const Template = ({ label, ...args }) => {
graph.setPanning(true);
// Enables rubberband selection
new mxRubberband(graph);
if (args.rubberBand)
new mxRubberband(graph);
let repaintGrid;

View File

@ -1,7 +1,25 @@
import mxgraph from '@mxgraph/core';
export default {
title: 'Basic/HelloWorld'
title: 'Basic/HelloWorld',
argTypes: {
width: {
type: 'number',
defaultValue: 800
},
height: {
type: 'number',
defaultValue: 600
},
contextMenu: {
type: 'boolean',
defaultValue: false
},
rubberBand: {
type: 'boolean',
defaultValue: true
}
}
};
const Template = ({ label, ...args }) => {
@ -10,14 +28,17 @@ 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.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 +51,7 @@ const Template = ({ label, ...args }) => {
size: [80, 30],
relative: false,
});
const vertex2 = graph.insertVertex({
parent,
value: 'World!',
@ -37,9 +59,9 @@ const Template = ({ label, ...args }) => {
size: [80, 30],
relative: false,
});
const edge = graph.insertEdge({
parent,
// value: 'to the',
source: vertex1,
target: vertex2,
});

View File

@ -11,14 +11,10 @@ module.exports = {
}
},
exclude: /node_modules/
},
{
test: /\.(sa|sc|c)ss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
]
},
resolve: {
extensions: ['.ts', '.js', '.scss']
extensions: ['.ts', '.js', '.css']
}
}