UNPKG

gojs

Version:

Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams

469 lines (441 loc) 19.8 kB
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Data Visualization GoJS Sample</title> <meta name="description" content="Interactive visualization of multi-dimensional data with HTML tooltips." /> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Copyright 1998-2020 by Northwoods Software Corporation. --> <!-- The div needs an explicit size or else we won't see anything. Lets also add a border to help see the edges. --> <style type="text/css"> #myDiagramDiv { border: solid 1px black; width: 400px; height: 400px; margin-right: 12px; float: left; background-color: whitesmoke; } #controls { border: solid 1px gray; width: 250px; background: #ffffff; padding: 5px; float: left; } #infoBoxHolder { z-index: 300; position: absolute; left: 5px; } #infoBox { border: 1px solid #999; padding: 8px; background-color: whitesmoke; opacity: 0.9; position: relative; width: 170px; font-family: arial, helvetica, sans-serif; font-weight: bold; font-size: 11px; } /* this is known as the "clearfix" hack to allow floated objects to add to the height of a div */ #infoBox:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; } div.infoTitle { width: 100px; font-weight: normal; color: #787878; float: left; margin-left: 4px; } div.infoValues { width: 30px; text-align: right; float: right; } label:hover, label:focus { background: #CEDFF2; } </style> <script src="../release/go.js"></script> <script src="../extensions/Figures.js"></script> <script src="../assets/js/goSamples.js"></script> <!-- this is only for the GoJS Samples framework --> <script id="code"> var myDiagram; var myLocation = { // this controls the data properties used by data binding conversions x: "sepalLength", y: "sepalWidth" } var lastStroked = null; // this remembers the last highlight Shape function init() { if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this var $ = go.GraphObject.make; // for conciseness in defining templates var myToolTip = $(go.HTMLInfo, { show: showToolTip, // do nothing on hide: This tooltip doesn't hide unless the mouse leaves the diagram }) myDiagram = $(go.Diagram, "myDiagramDiv", // create a Diagram for the DIV HTML element { "animationManager.initialAnimationStyle": go.AnimationManager.AnimateLocations, contentAlignment: go.Spot.Center, // content is always centered in the viewport autoScale: go.Diagram.Uniform, // scale always has all content fitting in the viewport "toolManager.hoverDelay": 10, // how quickly tooltips are shown isReadOnly: true, // don't let users modify anything mouseOver: doMouseOver, // this event handler is defined below click: doMouseOver // this event handler is defined below }); // define a simple Node template myDiagram.nodeTemplate = $(go.Node, "Auto", { selectable: false, toolTip: myToolTip }, new go.Binding("location", "", function(nothing, elt) { return new go.Point(elt.data[myLocation.x] * 200, elt.data[myLocation.y] * 200) }), new go.AnimationTrigger("position", null, go.AnimationTrigger.Bundled), $(go.Shape, "Hexagon", { name: "SHAPE", width: 20, height: 20, strokeWidth: 4, stroke: null }, new go.Binding("fill", "species", function(name) { switch (name) { case "Iris-setosa": return "rgba(240, 120, 50, .6)"; case "Iris-versicolor": return "rgba(240, 230, 120, .6)"; case "Iris-virginica": return "rgba(125, 200, 120, .6)"; } return "black"; })) ); // This is the fundamental data set, taken from: // https://en.wikipedia.org/wiki/Iris_flower_data_set var irisData = [ [5.1, 3.5, 1.4, 0.2, "Iris-setosa"], [4.9, 3.0, 1.4, 0.2, "Iris-setosa"], [4.7, 3.2, 1.3, 0.2, "Iris-setosa"], [4.6, 3.1, 1.5, 0.2, "Iris-setosa"], [5.0, 3.6, 1.4, 0.2, "Iris-setosa"], [5.4, 3.9, 1.7, 0.4, "Iris-setosa"], [4.6, 3.4, 1.4, 0.3, "Iris-setosa"], [5.0, 3.4, 1.5, 0.2, "Iris-setosa"], [4.4, 2.9, 1.4, 0.2, "Iris-setosa"], [4.9, 3.1, 1.5, 0.1, "Iris-setosa"], [5.4, 3.7, 1.5, 0.2, "Iris-setosa"], [4.8, 3.4, 1.6, 0.2, "Iris-setosa"], [4.8, 3.0, 1.4, 0.1, "Iris-setosa"], [4.3, 3.0, 1.1, 0.1, "Iris-setosa"], [5.8, 4.0, 1.2, 0.2, "Iris-setosa"], [5.7, 4.4, 1.5, 0.4, "Iris-setosa"], [5.4, 3.9, 1.3, 0.4, "Iris-setosa"], [5.1, 3.5, 1.4, 0.3, "Iris-setosa"], [5.7, 3.8, 1.7, 0.3, "Iris-setosa"], [5.1, 3.8, 1.5, 0.3, "Iris-setosa"], [5.4, 3.4, 1.7, 0.2, "Iris-setosa"], [5.1, 3.7, 1.5, 0.4, "Iris-setosa"], [4.6, 3.6, 1.0, 0.2, "Iris-setosa"], [5.1, 3.3, 1.7, 0.5, "Iris-setosa"], [4.8, 3.4, 1.9, 0.2, "Iris-setosa"], [5.0, 3.0, 1.6, 0.2, "Iris-setosa"], [5.0, 3.4, 1.6, 0.4, "Iris-setosa"], [5.2, 3.5, 1.5, 0.2, "Iris-setosa"], [5.2, 3.4, 1.4, 0.2, "Iris-setosa"], [4.7, 3.2, 1.6, 0.2, "Iris-setosa"], [4.8, 3.1, 1.6, 0.2, "Iris-setosa"], [5.4, 3.4, 1.5, 0.4, "Iris-setosa"], [5.2, 4.1, 1.5, 0.1, "Iris-setosa"], [5.5, 4.2, 1.4, 0.2, "Iris-setosa"], [4.9, 3.1, 1.5, 0.2, "Iris-setosa"], [5.0, 3.2, 1.2, 0.2, "Iris-setosa"], [5.5, 3.5, 1.3, 0.2, "Iris-setosa"], [4.9, 3.6, 1.4, 0.1, "Iris-setosa"], [4.4, 3.0, 1.3, 0.2, "Iris-setosa"], [5.1, 3.4, 1.5, 0.2, "Iris-setosa"], [5.0, 3.5, 1.3, 0.3, "Iris-setosa"], [4.5, 2.3, 1.3, 0.3, "Iris-setosa"], [4.4, 3.2, 1.3, 0.2, "Iris-setosa"], [5.0, 3.5, 1.6, 0.6, "Iris-setosa"], [5.1, 3.8, 1.9, 0.4, "Iris-setosa"], [4.8, 3.0, 1.4, 0.3, "Iris-setosa"], [5.1, 3.8, 1.6, 0.2, "Iris-setosa"], [4.6, 3.2, 1.4, 0.2, "Iris-setosa"], [5.3, 3.7, 1.5, 0.2, "Iris-setosa"], [5.0, 3.3, 1.4, 0.2, "Iris-setosa"], [7.0, 3.2, 4.7, 1.4, "Iris-versicolor"], [6.4, 3.2, 4.5, 1.5, "Iris-versicolor"], [6.9, 3.1, 4.9, 1.5, "Iris-versicolor"], [5.5, 2.3, 4.0, 1.3, "Iris-versicolor"], [6.5, 2.8, 4.6, 1.5, "Iris-versicolor"], [5.7, 2.8, 4.5, 1.3, "Iris-versicolor"], [6.3, 3.3, 4.7, 1.6, "Iris-versicolor"], [4.9, 2.4, 3.3, 1.0, "Iris-versicolor"], [6.6, 2.9, 4.6, 1.3, "Iris-versicolor"], [5.2, 2.7, 3.9, 1.4, "Iris-versicolor"], [5.0, 2.0, 3.5, 1.0, "Iris-versicolor"], [5.9, 3.0, 4.2, 1.5, "Iris-versicolor"], [6.0, 2.2, 4.0, 1.0, "Iris-versicolor"], [6.1, 2.9, 4.7, 1.4, "Iris-versicolor"], [5.6, 2.9, 3.6, 1.3, "Iris-versicolor"], [6.7, 3.1, 4.4, 1.4, "Iris-versicolor"], [5.6, 3.0, 4.5, 1.5, "Iris-versicolor"], [5.8, 2.7, 4.1, 1.0, "Iris-versicolor"], [6.2, 2.2, 4.5, 1.5, "Iris-versicolor"], [5.6, 2.5, 3.9, 1.1, "Iris-versicolor"], [5.9, 3.2, 4.8, 1.8, "Iris-versicolor"], [6.1, 2.8, 4.0, 1.3, "Iris-versicolor"], [6.3, 2.5, 4.9, 1.5, "Iris-versicolor"], [6.1, 2.8, 4.7, 1.2, "Iris-versicolor"], [6.4, 2.9, 4.3, 1.3, "Iris-versicolor"], [6.6, 3.0, 4.4, 1.4, "Iris-versicolor"], [6.8, 2.8, 4.8, 1.4, "Iris-versicolor"], [6.7, 3.0, 5.0, 1.7, "Iris-versicolor"], [6.0, 2.9, 4.5, 1.5, "Iris-versicolor"], [5.7, 2.6, 3.5, 1.0, "Iris-versicolor"], [5.5, 2.4, 3.8, 1.1, "Iris-versicolor"], [5.5, 2.4, 3.7, 1.0, "Iris-versicolor"], [5.8, 2.7, 3.9, 1.2, "Iris-versicolor"], [6.0, 2.7, 5.1, 1.6, "Iris-versicolor"], [5.4, 3.0, 4.5, 1.5, "Iris-versicolor"], [6.0, 3.4, 4.5, 1.6, "Iris-versicolor"], [6.7, 3.1, 4.7, 1.5, "Iris-versicolor"], [6.3, 2.3, 4.4, 1.3, "Iris-versicolor"], [5.6, 3.0, 4.1, 1.3, "Iris-versicolor"], [5.5, 2.5, 4.0, 1.3, "Iris-versicolor"], [5.5, 2.6, 4.4, 1.2, "Iris-versicolor"], [6.1, 3.0, 4.6, 1.4, "Iris-versicolor"], [5.8, 2.6, 4.0, 1.2, "Iris-versicolor"], [5.0, 2.3, 3.3, 1.0, "Iris-versicolor"], [5.6, 2.7, 4.2, 1.3, "Iris-versicolor"], [5.7, 3.0, 4.2, 1.2, "Iris-versicolor"], [5.7, 2.9, 4.2, 1.3, "Iris-versicolor"], [6.2, 2.9, 4.3, 1.3, "Iris-versicolor"], [5.1, 2.5, 3.0, 1.1, "Iris-versicolor"], [5.7, 2.8, 4.1, 1.3, "Iris-versicolor"], [6.3, 3.3, 6.0, 2.5, "Iris-virginica"], [5.8, 2.7, 5.1, 1.9, "Iris-virginica"], [7.1, 3.0, 5.9, 2.1, "Iris-virginica"], [6.3, 2.9, 5.6, 1.8, "Iris-virginica"], [6.5, 3.0, 5.8, 2.2, "Iris-virginica"], [7.6, 3.0, 6.6, 2.1, "Iris-virginica"], [4.9, 2.5, 4.5, 1.7, "Iris-virginica"], [7.3, 2.9, 6.3, 1.8, "Iris-virginica"], [6.7, 2.5, 5.8, 1.8, "Iris-virginica"], [7.2, 3.6, 6.1, 2.5, "Iris-virginica"], [6.5, 3.2, 5.1, 2.0, "Iris-virginica"], [6.4, 2.7, 5.3, 1.9, "Iris-virginica"], [6.8, 3.0, 5.5, 2.1, "Iris-virginica"], [5.7, 2.5, 5.0, 2.0, "Iris-virginica"], [5.8, 2.8, 5.1, 2.4, "Iris-virginica"], [6.4, 3.2, 5.3, 2.3, "Iris-virginica"], [6.5, 3.0, 5.5, 1.8, "Iris-virginica"], [7.7, 3.8, 6.7, 2.2, "Iris-virginica"], [7.7, 2.6, 6.9, 2.3, "Iris-virginica"], [6.0, 2.2, 5.0, 1.5, "Iris-virginica"], [6.9, 3.2, 5.7, 2.3, "Iris-virginica"], [5.6, 2.8, 4.9, 2.0, "Iris-virginica"], [7.7, 2.8, 6.7, 2.0, "Iris-virginica"], [6.3, 2.7, 4.9, 1.8, "Iris-virginica"], [6.7, 3.3, 5.7, 2.1, "Iris-virginica"], [7.2, 3.2, 6.0, 1.8, "Iris-virginica"], [6.2, 2.8, 4.8, 1.8, "Iris-virginica"], [6.1, 3.0, 4.9, 1.8, "Iris-virginica"], [6.4, 2.8, 5.6, 2.1, "Iris-virginica"], [7.2, 3.0, 5.8, 1.6, "Iris-virginica"], [7.4, 2.8, 6.1, 1.9, "Iris-virginica"], [7.9, 3.8, 6.4, 2.0, "Iris-virginica"], [6.4, 2.8, 5.6, 2.2, "Iris-virginica"], [6.3, 2.8, 5.1, 1.5, "Iris-virginica"], [6.1, 2.6, 5.6, 1.4, "Iris-virginica"], [7.7, 3.0, 6.1, 2.3, "Iris-virginica"], [6.3, 3.4, 5.6, 2.4, "Iris-virginica"], [6.4, 3.1, 5.5, 1.8, "Iris-virginica"], [6.0, 3.0, 4.8, 1.8, "Iris-virginica"], [6.9, 3.1, 5.4, 2.1, "Iris-virginica"], [6.7, 3.1, 5.6, 2.4, "Iris-virginica"], [6.9, 3.1, 5.1, 2.3, "Iris-virginica"], [5.8, 2.7, 5.1, 1.9, "Iris-virginica"], [6.8, 3.2, 5.9, 2.3, "Iris-virginica"], [6.7, 3.3, 5.7, 2.5, "Iris-virginica"], [6.7, 3.0, 5.2, 2.3, "Iris-virginica"], [6.3, 2.5, 5.0, 1.9, "Iris-virginica"], [6.5, 3.0, 5.2, 2.0, "Iris-virginica"], [6.2, 3.4, 5.4, 2.3, "Iris-virginica"], [5.9, 3.0, 5.1, 1.8, "Iris-virginica"] ]; // now convert that data into an Array of JavaScript Objects, // to be used as the Model.nodeDataArray var array = []; for (var i = 0; i < irisData.length; i++) { var line = irisData[i]; var data = { sepalLength: line[0], sepalWidth: line[1], petalLength: line[2], petalWidth: line[3], species: line[4] }; array.push(data); } // create the Model for the Diagram to display myDiagram.model = new go.Model(array); // Called when the mouse is over the diagram's background function doMouseOver(e) { if (e === undefined) e = myDiagram.lastInput; var doc = e.documentPoint; // find all Nodes that are within 100 units var list = myDiagram.findObjectsNear(doc, 100, null, function(x) { return x instanceof go.Node; }); // now find the one that is closest to e.documentPoint var closest = null; var closestDist = 999999999; list.each(function(node) { var dist = doc.distanceSquaredPoint(node.getDocumentPoint(go.Spot.Center)); if (dist < closestDist) { closestDist = dist; closest = node; } }); showToolTip(closest, myDiagram); } // Called with a Node (or null) that the mouse is over or near function showToolTip(obj, diagram) { if (obj !== null) { var node = obj.part; var e = diagram.lastInput; var shape = node.findObject("SHAPE"); shape.stroke = "white"; if (lastStroked !== null && lastStroked !== shape) lastStroked.stroke = null; lastStroked = shape; updateInfoBox(e.viewPoint, node.data); } else { if (lastStroked !== null) lastStroked.stroke = null; lastStroked = null; document.getElementById("infoBoxHolder").innerHTML = ""; } } // Make sure the infoBox is momentarily hidden if the user tries to mouse over it var infoBoxH = document.getElementById("infoBoxHolder"); infoBoxH.addEventListener("mousemove", function() { var box = document.getElementById("infoBoxHolder"); box.style.left = parseInt(box.style.left) + "px"; box.style.top = parseInt(box.style.top) + 30 + "px"; }, false); var diagramDiv = document.getElementById("myDiagramDiv"); // Make sure the infoBox is hidden when the mouse is not over the Diagram diagramDiv.addEventListener("mouseout", function(e) { if (lastStroked !== null) lastStroked.stroke = null; lastStroked = null; var infoBox = document.getElementById("infoBox"); var elem = document.elementFromPoint(e.clientX, e.clientY); if (elem !== null && (elem === infoBox || elem.parentNode === infoBox)) { var box = document.getElementById("infoBoxHolder"); box.style.left = parseInt(box.style.left) + "px"; box.style.top = parseInt(box.style.top) + 30 + "px"; } else { var box = document.getElementById("infoBoxHolder"); box.innerHTML = ""; } }, false); } // end init // This function is called to update the tooltip information // depending on the bound data of the Node that is closest to the pointer. function updateInfoBox(mousePt, data) { var box = document.getElementById("infoBoxHolder"); box.innerHTML = ""; var infobox = document.createElement("div"); infobox.id = "infoBox"; box.appendChild(infobox); for (var i = 0; i < 9; i++) { var child = document.createElement("div"); switch (i) { case 0: child.textContent = data.species; break; case 1: child.className = "infoTitle"; child.textContent = "Sepal Length"; break; case 2: child.className = "infoValues"; child.textContent = data.sepalLength; break; case 3: child.className = "infoTitle"; child.textContent = "Sepal Width"; break; case 4: child.className = "infoValues"; child.textContent = data.sepalWidth; break; case 5: child.className = "infoTitle"; child.textContent = "Petal Length"; break; case 6: child.className = "infoValues"; child.textContent = data.petalLength; break; case 7: child.className = "infoTitle"; child.textContent = "Petal Width"; break; case 8: child.className = "infoValues"; child.textContent = data.petalWidth; break; } infobox.appendChild(child); } box.style.left = mousePt.x + 30 + "px"; box.style.top = mousePt.y + 20 + "px"; } // This function is called which a radio button is pressed. // It changes the value of a variable that the node template's location conversion function uses. // It then updates all target bindings, causing all node locations to change. function changeAxes(e) { var value = e.value; if (e.name === "X") { myLocation.x = value; } else { myLocation.y = value; } myDiagram.startTransaction("updateBindings"); myDiagram.updateAllTargetBindings(); myDiagram.commitTransaction("updateBindings"); } </script> </head> <body onload="init()"> <div id="sample"> <div style="display: inline-block"> <!--The DIV for the Diagram needs an explicit size or else we won't see anything. Also add a border to help see the edges. --> <div id="myDiagramDiv" style="background-color: #3D3D3D; border: solid 1px black; width:500px; height:500px"></div> <!-- This sibling of the Diagram provides information when the mouse is near a Diagram Node --> <div id="infoBoxHolder"> <!-- Initially Empty, it is populated when updateInfoBox is called --> </div> <div id="controls"> <div style="border: solid 1px gray; float: left; padding: 2px;"> <p style="text-align: center;">X-axis</p> <hr/> <input type="radio" name="X" onclick="changeAxes(this)" value="sepalLength" id="SLx" checked/> <label for="SLx">Sepal Length</label><br/> <input type="radio" name="X" onclick="changeAxes(this)" value="sepalWidth" id="SWx" /> <label for="SWx">Sepal Width</label><br/> <input type="radio" name="X" onclick="changeAxes(this)" value="petalLength" id="PLx"/> <label for="PLx">Petal Length</label><br/> <input type="radio" name="X" onclick="changeAxes(this)" value="petalWidth" id="PWx"/> <label for="PWx">Petal Width</label><br/> </div> <div style="border: solid 1px gray; float: left; margin-left: 10px; padding: 2px;"> <p style="text-align: center;">Y-axis</p> <hr/> <input type="radio" name="Y" onclick="changeAxes(this)" value="sepalLength" id="SLy"/> <label for="SLy">Sepal Length</label><br/> <input type="radio" name="Y" onclick="changeAxes(this)" value="sepalWidth" id="SWy" checked/> <label for="SWy">Sepal Width</label><br/> <input type="radio" name="Y" onclick="changeAxes(this)" value="petalLength" id="PLy"/> <label for="PLy">Petal Length</label><br/> <input type="radio" name="Y" onclick="changeAxes(this)" value="petalWidth" id="PWy"/> <label for="PWy">Petal Width</label><br/> </div> <div id="description" style="float: left;"> <p>This sample gives an example of a Diagram interacting with other HTML elements on the page.</p> <p>As the mouse moves over the diagram, a formatted HTML DIV element displays information about the nearest Node.</p> <p>The data displayed is from the <a href="https://en.wikipedia.org/wiki/Iris_flower_data_set">Iris flower data set</a>, describing the variations in dimensions of three related flower species.</p> </div> </div> </div> </div> </body> </html>