import {
Graph,
EdgeStyle,
DomHelpers,
xmlUtils,
Perimeter,
utils,
constants,
cloneUtils,
Codec,
} from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
export default {
title: 'Misc/Monitor',
argTypes: {
...globalTypes,
},
};
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);
// Should we allow overriding constants?
// constants.SHADOWCOLOR = '#e0e0e0';
// Creates the graph inside the given container
const graph = createGraph(container);
// Creates a process display using the activity names as IDs to refer to the elements
const xml =
' | | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
' | ' +
'';
const doc = xmlUtils.parseXml(xml);
const codec = new Codec(doc);
codec.decode(doc.documentElement, graph.getDataModel());
const buttons = document.createElement('div');
div.appendChild(buttons);
// Creates a button to invoke the refresh function
buttons.appendChild(
DomHelpers.button('Update', function (evt) {
// XML is normally fetched from URL at server using utils.get - this is a client-side
// string with randomized states to demonstrate the idea of the workflow monitor
const xml =
`` +
`` +
``;
update(graph, xml);
})
);
/**
* Updates the display of the given graph using the XML data
*/
function update(graph, xml) {
if (xml != null && xml.length > 0) {
const doc = xmlUtils.parseXml(xml);
if (doc != null && doc.documentElement != null) {
const model = graph.getDataModel();
const nodes = doc.documentElement.getElementsByTagName('update');
if (nodes != null && nodes.length > 0) {
model.beginUpdate();
try {
for (let i = 0; i < nodes.length; i++) {
// Processes the activity nodes inside the process node
const id = nodes[i].getAttribute('id');
const state = nodes[i].getAttribute('state');
// Gets the cell for the given activity name from the model
const cell = model.getCell(id);
// Updates the cell color and adds some tooltip information
if (cell != null) {
// Resets the fillcolor and the overlay
graph.setCellStyles('fillColor', 'white', [cell]);
graph.removeCellOverlays(cell);
// Changes the cell color for the known states
if (state == 'Running') {
graph.setCellStyles('fillColor', '#f8cecc', [cell]);
} else if (state == 'Waiting') {
graph.setCellStyles('fillColor', '#fff2cc', [cell]);
} else if (state == 'Completed') {
graph.setCellStyles('fillColor', '#d4e1f5', [cell]);
}
// Adds tooltip information using an overlay icon
if (state != 'Init') {
// Sets the overlay for the cell in the graph
graph.addCellOverlay(
cell,
createOverlay(graph.warningImage, `State: ${state}`)
);
}
}
} // for
} finally {
model.endUpdate();
}
}
}
}
}
/**
* Creates an overlay object using the given tooltip and text for the alert window
* which is being displayed on click.
*/
function createOverlay(image, tooltip) {
const overlay = new CellOverlay(image, tooltip);
// Installs a handler for clicks on the overlay
overlay.addListener(InternalEvent.CLICK, function (sender, evt) {
utils.alert(`${tooltip}\nLast update: ${new Date()}`);
});
return overlay;
}
/**
* Creates and returns an empty graph inside the given container.
*/
function createGraph(container) {
const graph = new Graph(container);
graph.setTooltips(true);
graph.setEnabled(false);
// Disables folding
graph.isCellFoldable = function (cell, collapse) {
return false;
};
// Creates the stylesheet for the process display
let style = graph.getStylesheet().getDefaultVertexStyle();
style.fontSize = 11;
style.fontColor = 'black';
style.strokeColor = '#808080';
style.fillColor = 'white';
style.gradientColor = 'white';
style.gradientDirection = constants.DIRECTION.EAST;
style.rounded = true;
style.shadow = true;
style.fontStyle = 1;
style = graph.getStylesheet().getDefaultEdgeStyle();
style.edge = EdgeStyle.ElbowConnector;
style.strokeColor = '#808080';
style.rounded = true;
style.shadow = true;
style = [];
style.shape = constants.SHAPE.SWIMLANE;
style.perimiter = Perimeter.RectanglePerimeter;
style.strokeColor = '#a0a0a0';
style.fontColor = '#606060';
style.fillColor = '#E0E0DF';
style.gradientColor = 'white';
style.startSize = 30;
style.rounded = false;
style.fontSize = 12;
style.fontStyle = 0;
style.horizontal = false;
// To improve text quality for vertical labels in some old IE versions...
style.labelBackgroundColor = '#efefef';
graph.getStylesheet().putCellStyle('swimlane', style);
style = [];
style.shape = constants.SHAPE.RHOMBUS;
style.perimiter = Perimeter.RhombusPerimeter;
style.strokeColor = '#91BCC0';
style.fontColor = 'gray';
style.fillColor = '#91BCC0';
style.gradientColor = 'white';
style.align = constants.ALIGN.CENTER;
style.verticalAlign = constants.ALIGN.MIDDLE;
style.fontSize = 16;
graph.getStylesheet().putCellStyle('step', style);
style = [];
style.shape = constants.SHAPE.ELLIPSE;
style.perimiter = Perimeter.EllipsePerimeter;
style.fontColor = 'gray';
style.fillColor = '#A0C88F';
style.gradientColor = 'white';
style.strokeColor = '#A0C88F';
style.align = constants.ALIGN.CENTER;
style.verticalAlign = constants.ALIGN.MIDDLE;
style.fontSize = 16;
graph.getStylesheet().putCellStyle('start', style);
style = cloneUtils.clone(style);
style.fillColor = '#DACCBC';
style.strokeColor = '#AF7F73';
graph.getStylesheet().putCellStyle('end', style);
return graph;
}
/**
* Returns a random state.
*/
function getState() {
let state = 'Init';
const rnd = Math.random() * 4;
if (rnd > 3) {
state = 'Completed';
} else if (rnd > 2) {
state = 'Running';
} else if (rnd > 1) {
state = 'Waiting';
}
return state;
}
return div;
};
export const Default = Template.bind({});