<!-- Copyright (c) 2006-2013, JGraph Ltd Monitor example for mxGraph. This eample demonstrates using a graph to display the current state of a workflow. --> <html> <head> <title>mxGraph Workflow Monitor</title> <!-- Sets the basepath for the library if not in same directory --> <script type="text/javascript"> mxBasePath = '../src'; </script> <!-- Loads and initializes the library --> <script type="text/javascript" src="../src/js/mxClient.js"></script> <!-- Example code --> <script type="text/javascript"> // 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 the browser is supported if (!mxClient.isBrowserSupported()) { // Displays an error message if the browser is not supported. mxUtils.error('Browser is not supported!', 200, false); } else { mxConstants.SHADOWCOLOR = '#e0e0e0'; // Creates the graph inside the given container var graph = createGraph(container); // Creates a process display using the activity names as IDs to refer to the elements var xml = '<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/>'+ '<mxCell id="2" value="Claim Handling Process" style="swimlane" vertex="1" parent="1"><mxGeometry x="1" width="850" height="400" as="geometry"/></mxCell>'+ '<mxCell id="3" value="Claim Manager" style="swimlane" vertex="1" parent="2"><mxGeometry x="30" width="820" height="200" as="geometry"/></mxCell>'+ '<mxCell id="5" value="" style="start" vertex="1" parent="3"><mxGeometry x="40" y="85" width="30" height="30" as="geometry"/></mxCell>'+ '<mxCell id="AuthorizeClaim" value="Authorize
Claim" vertex="1" parent="3"><mxGeometry x="90" y="80" width="100" height="40" as="geometry"/></mxCell>'+ '<mxCell id="6" value="X" style="step" vertex="1" parent="3"><mxGeometry x="210" y="85" width="30" height="30" as="geometry"/></mxCell>'+ '<mxCell id="ApproveClaim" value="Approve
Claim" vertex="1" parent="3"><mxGeometry x="260" y="80" width="100" height="40" as="geometry"/></mxCell>'+ '<mxCell id="7" value="X" style="step" vertex="1" parent="3"><mxGeometry x="380" y="85" width="30" height="30" as="geometry"/></mxCell>'+ '<mxCell id="8" value="" edge="1" parent="3" source="5" target="AuthorizeClaim"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="9" value="" edge="1" parent="3" source="AuthorizeClaim" target="6"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="10" value="" edge="1" parent="3" source="6" target="ApproveClaim"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="11" value="" edge="1" parent="3" source="ApproveClaim" target="7"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="12" value="" edge="1" parent="3" source="7" target="AuthorizeClaim"><mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="140" y="40"/></Array></mxGeometry></mxCell>'+ '<mxCell id="ReviewClaim" value="Review
Claim" vertex="1" parent="3"><mxGeometry x="480" y="80" width="100" height="40" as="geometry"/></mxCell>'+ '<mxCell id="22" value="X" style="step" vertex="1" parent="3"><mxGeometry x="600" y="85" width="30" height="30" as="geometry"/></mxCell>'+ '<mxCell id="23" value="" edge="1" parent="3" source="ReviewClaim" target="22"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="ApproveReviewedClaim" value="Approve Rev.
Claim" vertex="1" parent="3"><mxGeometry x="650" y="80" width="100" height="40" as="geometry"/></mxCell>'+ '<mxCell id="26" value="" edge="1" parent="3" source="22" target="ApproveReviewedClaim"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="27" value="X" style="step" vertex="1" parent="3"><mxGeometry x="770" y="85" width="30" height="30" as="geometry"/></mxCell>'+ '<mxCell id="28" value="" edge="1" target="27" parent="3" source="ApproveReviewedClaim"><mxGeometry relative="1" as="geometry"><mxPoint x="740" y="100" as="sourcePoint"/><mxPoint x="760" y="100" as="targetPoint"/></mxGeometry></mxCell>'+ '<mxCell id="32" value="" edge="1" parent="3" source="27" target="ReviewClaim"><mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="665" y="160"/></Array></mxGeometry></mxCell>'+ '<mxCell id="4" value="Accountant" style="swimlane" vertex="1" parent="2"><mxGeometry x="30" y="200" width="820" height="200" as="geometry"/></mxCell>'+ '<mxCell id="EnterAccountingData" value="Enter
Data" vertex="1" parent="4"><mxGeometry x="430" y="80" width="100" height="40" as="geometry"/></mxCell>'+ '<mxCell id="14" value="X" style="step" vertex="1" parent="4"><mxGeometry x="550" y="85" width="30" height="30" as="geometry"/></mxCell>'+ '<mxCell id="15" value="" edge="1" parent="4" source="EnterAccountingData" target="14"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="CheckAccountingData" value="Check
Data" vertex="1" parent="4"><mxGeometry x="600" y="80" width="100" height="40" as="geometry"/></mxCell>'+ '<mxCell id="16" value="" edge="1" parent="4" source="14" target="CheckAccountingData"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="17" value="X" style="step" vertex="1" parent="4"><mxGeometry x="720" y="85" width="30" height="30" as="geometry"/></mxCell>'+ '<mxCell id="18" value="" edge="1" parent="4" source="CheckAccountingData" target="17"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="19" value="" style="end" vertex="1" parent="4"><mxGeometry x="770" y="85" width="30" height="30" as="geometry"/></mxCell>'+ '<mxCell id="20" value="" edge="1" parent="4" source="17" target="19"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="31" value="" edge="1" parent="4" source="17" target="EnterAccountingData"><mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="625" y="160"/></Array></mxGeometry></mxCell>'+ '<mxCell id="13" value="" edge="1" parent="2" source="7" target="EnterAccountingData"><mxGeometry relative="1" as="geometry"/></mxCell>'+ '<mxCell id="24" value="" edge="1" parent="2" source="14" target="ReviewClaim" style="edgeStyle=none"><mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="595" y="180"/><mxPoint x="480" y="180"/><mxPoint x="480" y="100"/></Array></mxGeometry></mxCell>'+ '<mxCell id="29" value="" edge="1" parent="2" source="22" target="EnterAccountingData"><mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="469" y="40"/></Array></mxGeometry></mxCell>'+ '<mxCell id="30" value="" edge="1" parent="2" source="27" target="EnterAccountingData"><mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="469" y="40"/></Array></mxGeometry></mxCell>'+ '<mxCell id="33" value="" edge="1" parent="2" source="6" target="EnterAccountingData"><mxGeometry relative="1" as="geometry"><Array as="points"><mxPoint x="255" y="200"/></Array></mxGeometry></mxCell>'+ '</root></mxGraphModel>'; var doc = mxUtils.parseXml(xml); var codec = new mxCodec(doc); codec.decode(doc.documentElement, graph.getModel()); } // Creates a button to invoke the refresh function document.body.appendChild(mxUtils.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 var xml = '<process><update id="ApproveClaim" state="'+getState()+'"/><update id="AuthorizeClaim" state="'+getState()+'"/>'+ '<update id="CheckAccountingData" state="'+getState()+'"/><update id="ReviewClaim" state="'+getState()+'"/>'+ '<update id="ApproveReviewedClaim" state="'+getState()+'"/><update id="EnterAccountingData" state="'+getState()+'"/></process>'; update(graph, xml); })); }; /** * Updates the display of the given graph using the XML data */ function update(graph, xml) { if (xml != null && xml.length > 0) { var doc = mxUtils.parseXml(xml); if (doc != null && doc.documentElement != null) { var model = graph.getModel(); var nodes = doc.documentElement.getElementsByTagName('update'); if (nodes != null && nodes.length > 0) { model.beginUpdate(); try { for (var i = 0; i < nodes.length; i++) { // Processes the activity nodes inside the process node var id = nodes[i].getAttribute('id'); var state = nodes[i].getAttribute('state'); // Gets the cell for the given activity name from the model var cell = model.getCell(id); // Updates the cell color and adds some tooltip information if (cell != null) { // Resets the fillcolor and the overlay graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, 'white', [cell]); graph.removeCellOverlays(cell); // Changes the cell color for the known states if (state == 'Running') { graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, '#f8cecc', [cell]); } else if (state == 'Waiting') { graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, '#fff2cc', [cell]); } else if (state == 'Completed') { graph.setCellStyles(mxConstants.STYLE_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) { var 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) { var 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 var style = graph.getStylesheet().getDefaultVertexStyle(); style[mxConstants.STYLE_FONTSIZE] = 11; style[mxConstants.STYLE_FONTCOLOR] = 'black'; style[mxConstants.STYLE_STROKECOLOR] = '#808080'; style[mxConstants.STYLE_FILLCOLOR] = 'white'; style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; style[mxConstants.STYLE_GRADIENT_DIRECTION] = mxConstants.DIRECTION_EAST; style[mxConstants.STYLE_ROUNDED] = true; style[mxConstants.STYLE_SHADOW] = true; style[mxConstants.STYLE_FONTSTYLE] = 1; style = graph.getStylesheet().getDefaultEdgeStyle(); style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector; style[mxConstants.STYLE_STROKECOLOR] = '#808080'; style[mxConstants.STYLE_ROUNDED] = true; style[mxConstants.STYLE_SHADOW] = true; style = []; style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE; style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter; style[mxConstants.STYLE_STROKECOLOR] = '#a0a0a0'; style[mxConstants.STYLE_FONTCOLOR] = '#606060'; style[mxConstants.STYLE_FILLCOLOR] = '#E0E0DF'; style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; style[mxConstants.STYLE_STARTSIZE] = 30; style[mxConstants.STYLE_ROUNDED] = false; style[mxConstants.STYLE_FONTSIZE] = 12; style[mxConstants.STYLE_FONTSTYLE] = 0; style[mxConstants.STYLE_HORIZONTAL] = false; // To improve text quality for vertical labels in some old IE versions... style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = '#efefef'; graph.getStylesheet().putCellStyle('swimlane', style); style = []; style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RHOMBUS; style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RhombusPerimeter; style[mxConstants.STYLE_STROKECOLOR] = '#91BCC0'; style[mxConstants.STYLE_FONTCOLOR] = 'gray'; style[mxConstants.STYLE_FILLCOLOR] = '#91BCC0'; style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; style[mxConstants.STYLE_FONTSIZE] = 16; graph.getStylesheet().putCellStyle('step', style); style = []; style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE; style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter; style[mxConstants.STYLE_FONTCOLOR] = 'gray'; style[mxConstants.STYLE_FILLCOLOR] = '#A0C88F'; style[mxConstants.STYLE_GRADIENTCOLOR] = 'white'; style[mxConstants.STYLE_STROKECOLOR] = '#A0C88F'; style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER; style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE; style[mxConstants.STYLE_FONTSIZE] = 16; graph.getStylesheet().putCellStyle('start', style); style = mxUtils.clone(style); style[mxConstants.STYLE_FILLCOLOR] = '#DACCBC'; style[mxConstants.STYLE_STROKECOLOR] = '#AF7F73'; graph.getStylesheet().putCellStyle('end', style); return graph; }; /** * Returns a random state. */ function getState() { var state = 'Init'; var rnd = Math.random() * 4; if (rnd > 3) { state = 'Completed'; } else if (rnd > 2) { state = 'Running'; } else if (rnd > 1) { state = 'Waiting'; } return state; }; </script> </head> <!-- Page passes the container and control to the main function --> <body onload="main(document.getElementById('graphContainer'));"> <!-- Acts as a container for the graph --> <div id="graphContainer" style="overflow:hidden;position:relative;width:861px;height:406px;cursor:default;"> </div> <br> </body> </html>