maxGraph/packages/html/stories/UserObject.stories.js

305 lines
8.4 KiB
JavaScript

import mxgraph from '@mxgraph/core';
import { popup } from '@mxgraph/core/src/util/gui/mxWindow';
import { globalTypes } from '../.storybook/preview';
export default {
title: 'Xml_Json/UserObject',
argTypes: {
...globalTypes
}
};
const Template = ({ label, ...args }) => {
const {
mxGraph,
mxRectangle,
mxDomHelpers,
mxKeyHandler,
mxEvent,
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());
popup(mxUtils.getPrettyXml(node), true);
})
);
// Changes the style for match the markup
// Creates the default style for vertices
let style = graph.getStylesheet().getDefaultVertexStyle();
style.strokeColor = 'gray';
style.rounded = true;
style.shadow = true;
style.fillColor = '#DFDFDF';
style.gradientColor = 'white';
style.fontColor = 'black';
style.fontSize = '12';
style.spacing = 4;
// Creates the default style for edges
style = graph.getStylesheet().getDefaultEdgeStyle();
style.strokeColor = '#0C0C0C';
style.labelBackgroundColor = 'white';
style.edge = mxEdgeStyle.ElbowConnector;
style.rounded = true;
style.fontColor = 'black';
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({});