import mxgraph from '@mxgraph/core';
import { globalTypes } from '../.storybook/preview';
export default {
title: 'Misc/Monitor',
argTypes: {
...globalTypes
}
};
const Template = ({ label, ...args }) => {
const {
mxGraph,
mxEdgeStyle,
mxDomHelpers,
mxXmlUtils,
mxPerimeter,
mxUtils,
mxConstants,
mxCloneUtils,
mxCodec
} = 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);
mxConstants.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 = mxXmlUtils.parseXml(xml);
const codec = new mxCodec(doc);
codec.decode(doc.documentElement, graph.getModel());
const buttons = document.createElement('div');
div.appendChild(buttons);
// Creates a button to invoke the refresh function
buttons.appendChild(
mxDomHelpers.button('Update', function(evt) {
// XML is normally fetched from URL at server using mxUtils.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 = mxXmlUtils.parseXml(xml);
if (doc != null && doc.documentElement != null) {
const model = graph.getModel();
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 mxCellOverlay(image, tooltip);
// Installs a handler for clicks on the overlay
overlay.addListener(mxEvent.CLICK, function(sender, evt) {
mxUtils.alert(`${tooltip}\nLast update: ${new Date()}`);
});
return overlay;
}
/**
* Creates and returns an empty graph inside the given container.
*/
function createGraph(container) {
const graph = new mxGraph(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.strokeColor = 'black';
style.strokeColor = '#808080';
style.fillColor = 'white';
style.gradientColor = 'white';
style.gradientDirection = mxConstants.DIRECTION_EAST;
style.rounded = true;
style.shadow = true;
style.fontStyle = 1;
style = graph.getStylesheet().getDefaultEdgeStyle();
style.edge = mxEdgeStyle.ElbowConnector;
style.strokeColor = '#808080';
style.rounded = true;
style.shadow = true;
style = [];
style.shape = mxConstants.SHAPE_SWIMLANE;
style.perimiter = mxPerimeter.RectanglePerimeter;
style.strokeColor = '#a0a0a0';
style.strokeColor = '#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 = mxConstants.SHAPE_RHOMBUS;
style.perimiter = mxPerimeter.RhombusPerimeter;
style.strokeColor = '#91BCC0';
style.strokeColor = 'gray';
style.fillColor = '#91BCC0';
style.gradientColor = 'white';
style.align = mxConstants.ALIGN_CENTER;
style.verticalAlign = mxConstants.ALIGN_MIDDLE;
style.fontSize = 16;
graph.getStylesheet().putCellStyle('step', style);
style = [];
style.shape = mxConstants.SHAPE_ELLIPSE;
style.perimiter = mxPerimeter.EllipsePerimeter;
style.strokeColor = 'gray';
style.fillColor = '#A0C88F';
style.gradientColor = 'white';
style.strokeColor = '#A0C88F';
style.align = mxConstants.ALIGN_CENTER;
style.verticalAlign = mxConstants.ALIGN_MIDDLE;
style.fontSize = 16;
graph.getStylesheet().putCellStyle('start', style);
style = mxCloneUtils.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({});