2021-09-07 09:07:27 +00:00
|
|
|
import {
|
|
|
|
Graph,
|
2021-09-07 12:21:22 +00:00
|
|
|
RubberBand,
|
2021-09-07 09:07:27 +00:00
|
|
|
InternalEvent,
|
|
|
|
CellRenderer,
|
|
|
|
EdgeHandler,
|
|
|
|
mxHierarchicalLayout,
|
|
|
|
Constants,
|
|
|
|
CellOverlay,
|
|
|
|
ImageBox,
|
|
|
|
mxClient,
|
|
|
|
mxMorphing,
|
|
|
|
EventObject,
|
|
|
|
EventUtils,
|
|
|
|
} from '@maxgraph/core';
|
2021-04-24 12:30:27 +00:00
|
|
|
|
|
|
|
import { globalTypes } from '../.storybook/preview';
|
|
|
|
|
|
|
|
export default {
|
|
|
|
title: 'Layouts/AutoLayout',
|
|
|
|
argTypes: {
|
|
|
|
...globalTypes,
|
|
|
|
contextMenu: {
|
|
|
|
type: 'boolean',
|
2021-08-30 14:20:26 +00:00
|
|
|
defaultValue: false,
|
2021-04-24 12:30:27 +00:00
|
|
|
},
|
|
|
|
rubberBand: {
|
|
|
|
type: 'boolean',
|
2021-08-30 14:20:26 +00:00
|
|
|
defaultValue: true,
|
|
|
|
},
|
|
|
|
},
|
2021-04-24 12:30:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const Template = ({ label, ...args }) => {
|
|
|
|
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';
|
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
if (!args.contextMenu) InternalEvent.disableContextMenu(container);
|
2021-04-24 12:30:27 +00:00
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
class MyCustomCellRenderer extends CellRenderer {
|
2021-04-24 12:30:27 +00:00
|
|
|
installCellOverlayListeners(state, overlay, shape) {
|
|
|
|
super.installCellOverlayListeners(state, overlay, shape);
|
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
InternalEvent.addListener(
|
2021-04-24 12:30:27 +00:00
|
|
|
shape.node,
|
|
|
|
mxClient.IS_POINTER ? 'pointerdown' : 'mousedown',
|
2021-08-30 14:20:26 +00:00
|
|
|
(evt) => {
|
|
|
|
overlay.fireEvent(new EventObject('pointerdown', 'event', evt, 'state', state));
|
2021-04-24 12:30:27 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!mxClient.IS_POINTER && mxClient.IS_TOUCH) {
|
2021-08-30 14:20:26 +00:00
|
|
|
InternalEvent.addListener(shape.node, 'touchstart', (evt) => {
|
|
|
|
overlay.fireEvent(new EventObject('pointerdown', 'event', evt, 'state', state));
|
2021-04-24 12:30:27 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
class MyCustomEdgeHandler extends EdgeHandler {
|
2021-04-24 12:30:27 +00:00
|
|
|
connect(edge, terminal, isSource, isClone, me) {
|
|
|
|
super.connect(edge, terminal, isSource, isClone, me);
|
|
|
|
executeLayout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
class MyCustomGraph extends Graph {
|
2021-04-24 12:30:27 +00:00
|
|
|
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
|
2021-09-07 12:21:22 +00:00
|
|
|
if (args.rubberBand) new RubberBand(graph);
|
2021-04-24 12:30:27 +00:00
|
|
|
|
|
|
|
// Gets the default parent for inserting new cells. This
|
|
|
|
// is normally the first child of the root (ie. layer 0).
|
|
|
|
const parent = graph.getDefaultParent();
|
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
const layout = new mxHierarchicalLayout(graph, Constants.DIRECTION_WEST);
|
2021-05-02 06:04:34 +00:00
|
|
|
|
|
|
|
let v1;
|
2021-04-24 12:30:27 +00:00
|
|
|
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);
|
2021-08-30 14:20:26 +00:00
|
|
|
morph.addListener(InternalEvent.DONE, () => {
|
2021-04-24 12:30:27 +00:00
|
|
|
graph.getModel().endUpdate();
|
|
|
|
if (post != null) {
|
|
|
|
post();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
morph.startAnimation();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
const addOverlay = (cell) => {
|
2021-04-24 12:30:27 +00:00
|
|
|
// Creates a new overlay with an image and a tooltip
|
2021-08-30 14:20:26 +00:00
|
|
|
const overlay = new CellOverlay(
|
|
|
|
new ImageBox('images/add.png', 24, 24),
|
2021-04-24 12:30:27 +00:00
|
|
|
'Add outgoing'
|
|
|
|
);
|
|
|
|
overlay.cursor = 'hand';
|
|
|
|
|
|
|
|
// Installs a handler for clicks on the overlay
|
2021-08-30 14:20:26 +00:00
|
|
|
overlay.addListener(InternalEvent.CLICK, (sender, evt2) => {
|
2021-04-24 12:30:27 +00:00
|
|
|
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);
|
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
const pt = utils.convertPoint(
|
2021-04-24 12:30:27 +00:00
|
|
|
graph.container,
|
2021-08-30 14:20:26 +00:00
|
|
|
EventUtils.getClientX(evt2),
|
|
|
|
EventUtils.getClientY(evt2)
|
2021-04-24 12:30:27 +00:00
|
|
|
);
|
|
|
|
graph.connectionHandler.start(state, pt.x, pt.y);
|
|
|
|
graph.isMouseDown = true;
|
2021-08-30 14:20:26 +00:00
|
|
|
graph.isMouseTrigger = EventUtils.isMouseEvent(evt2);
|
|
|
|
InternalEvent.consume(evt2);
|
2021-04-24 12:30:27 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// Sets the overlay for the cell in the graph
|
|
|
|
graph.addCellOverlay(cell, overlay);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Adds cells to the model in a single step
|
2021-05-02 06:04:34 +00:00
|
|
|
graph.batchUpdate(() => {
|
2021-04-24 12:30:27 +00:00
|
|
|
v1 = graph.insertVertex({
|
|
|
|
parent,
|
|
|
|
value: 'Hello,',
|
|
|
|
position: [0, 0],
|
|
|
|
size: [80, 30],
|
|
|
|
});
|
|
|
|
addOverlay(v1);
|
2021-05-02 06:04:34 +00:00
|
|
|
});
|
2021-04-24 12:30:27 +00:00
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
graph.resizeCell = function () {
|
|
|
|
Graph.prototype.resizeCell.apply(this, arguments);
|
2021-04-24 12:30:27 +00:00
|
|
|
executeLayout();
|
|
|
|
};
|
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
graph.connectionHandler.addListener(InternalEvent.CONNECT, function () {
|
2021-04-24 12:30:27 +00:00
|
|
|
executeLayout();
|
|
|
|
});
|
|
|
|
|
|
|
|
return container;
|
2021-08-30 14:20:26 +00:00
|
|
|
};
|
2021-04-24 12:30:27 +00:00
|
|
|
|
2021-08-30 14:20:26 +00:00
|
|
|
export const Default = Template.bind({});
|