/* Copyright 2021-present The maxGraph project Contributors Copyright (c) 2006-2020, JGraph Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ import { CellTracker, Client, cloneUtils, constants, domUtils, EventObject, FastOrganicLayout, Graph, InternalEvent, MaxXmlRequest, Perimeter, } from '@maxgraph/core'; import { globalTypes, globalValues } from './shared/args.js'; export default { title: 'Xml_Json/FileIO', argTypes: { ...globalTypes, }, args: { ...globalValues, }, }; const Template = ({ label, ...args }) => { 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 (!Client.isBrowserSupported()) { // Displays an error message if the browser is // not supported. alert('Browser is not supported!', 200, false); } else { // Creates the graph inside the given container const graph = new Graph(container); graph.setEnabled(false); graph.setPanning(true); graph.setTooltips(true); graph.getPlugin('PanningHandler').useLeftButtonForPanning = true; // Adds a highlight on the cell under the mousepointer new CellTracker(graph); // Changes the default vertex style in-place let style = graph.getStylesheet().getDefaultVertexStyle(); style.shape = constants.SHAPE.ROUNDED; style.perimiter = Perimeter.RectanglePerimeter; style.gradientColor = 'white'; style.perimeterSpacing = 4; style.shadow = true; style = graph.getStylesheet().getDefaultEdgeStyle(); style.labelBackgroundColor = 'white'; style = cloneUtils.clone(style); style.startArrow = constants.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 FastOrganicLayout(graph); // Moves stuff wider apart than usual layout.forceConstant = 140; // Adds a button to execute the layout const button = document.createElement('button'); domUtils.write(button, 'Arrange'); InternalEvent.addListener(button, 'click', (evt) => { const parent = graph.getDefaultParent(); layout.execute(parent); }); // Load cells and layouts the graph graph.batchUpdate(() => { // Loads the custom file format (TXT file) parse(graph, 'fileio.txt'); // Loads the Graph 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); }); graph.dblClick = function (evt, cell) { const mxe = new EventObject(InternalEvent.DOUBLE_CLICK, { event: evt, cell }); this.fireEvent(mxe); if ( this.isEnabled() && !InternalEvent.isConsumed(evt) && !mxe.isConsumed() && cell != null ) { alert(`Show properties for cell ${cell.customId || cell.getId()}`); } }; } } // Custom parser for simple file format function parse(graph, filename) { const model = graph.getDataModel(); // 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 = MaxXmlRequest.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.batchUpdate(() => { 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'; } } } } } }); } // Parses the Graph XML file format function read(graph, filename) { const req = MaxXmlRequest.load(filename); const root = req.getDocumentElement(); const dec = new Codec(root.ownerDocument); dec.decode(root, graph.getDataModel()); } return div; }; export const Default = Template.bind({});