maxGraph/packages/html/stories/AutoLayout.stories.js

206 lines
5.2 KiB
JavaScript
Raw Normal View History

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';
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 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) InternalEvent.disableContextMenu(container);
class MyCustomCellRenderer extends CellRenderer {
installCellOverlayListeners(state, overlay, shape) {
super.installCellOverlayListeners(state, overlay, shape);
InternalEvent.addListener(
shape.node,
mxClient.IS_POINTER ? 'pointerdown' : 'mousedown',
(evt) => {
overlay.fireEvent(new EventObject('pointerdown', 'event', evt, 'state', state));
}
);
if (!mxClient.IS_POINTER && mxClient.IS_TOUCH) {
InternalEvent.addListener(shape.node, 'touchstart', (evt) => {
overlay.fireEvent(new EventObject('pointerdown', 'event', evt, 'state', state));
});
}
}
}
class MyCustomEdgeHandler extends EdgeHandler {
connect(edge, terminal, isSource, isClone, me) {
super.connect(edge, terminal, isSource, isClone, me);
executeLayout();
}
}
class MyCustomGraph extends Graph {
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);
// 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, Constants.DIRECTION_WEST);
let v1;
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(InternalEvent.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 CellOverlay(
new ImageBox('images/add.png', 24, 24),
'Add outgoing'
);
overlay.cursor = 'hand';
// Installs a handler for clicks on the overlay
overlay.addListener(InternalEvent.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 = utils.convertPoint(
graph.container,
EventUtils.getClientX(evt2),
EventUtils.getClientY(evt2)
);
graph.connectionHandler.start(state, pt.x, pt.y);
graph.isMouseDown = true;
graph.isMouseTrigger = EventUtils.isMouseEvent(evt2);
InternalEvent.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.batchUpdate(() => {
v1 = graph.insertVertex({
parent,
value: 'Hello,',
position: [0, 0],
size: [80, 30],
});
addOverlay(v1);
});
graph.resizeCell = function () {
Graph.prototype.resizeCell.apply(this, arguments);
executeLayout();
};
graph.connectionHandler.addListener(InternalEvent.CONNECT, function () {
executeLayout();
});
return container;
};
export const Default = Template.bind({});