gojs
Version:
Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams
354 lines (330 loc) • 16.8 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
<meta name="description" content="A finite state machine chart with editable and interactive features."/>
<link rel="stylesheet" href="../assets/css/style.css"/>
<!-- Copyright 1998-2023 by Northwoods Software Corporation. -->
<title>State Chart</title>
</head>
<body>
<!-- This top nav is not part of the sample code -->
<nav id="navTop" class="w-full z-30 top-0 text-white bg-nwoods-primary">
<div class="w-full container max-w-screen-lg mx-auto flex flex-wrap sm:flex-nowrap items-center justify-between mt-0 py-2">
<div class="md:pl-4">
<a class="text-white hover:text-white no-underline hover:no-underline
font-bold text-2xl lg:text-4xl rounded-lg hover:bg-nwoods-secondary " href="../">
<h1 class="my-0 p-1 ">GoJS</h1>
</a>
</div>
<button id="topnavButton" class="rounded-lg sm:hidden focus:outline-none focus:ring" aria-label="Navigation">
<svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
<path id="topnavOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
<path id="topnavClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
</svg>
</button>
<div id="topnavList" class="hidden sm:block items-center w-auto mt-0 text-white p-0 z-20">
<ul class="list-reset list-none font-semibold flex justify-end flex-wrap sm:flex-nowrap items-center px-0 pb-0">
<li class="p-1 sm:p-0"><a class="topnav-link" href="../learn/">Learn</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="../samples/">Samples</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="../intro/">Intro</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="../api/">API</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/products/register.html">Register</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="../download.html">Download</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="https://forum.nwoods.com/c/gojs/11">Forum</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/contact.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/sales/index.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a></li>
</ul>
</div>
</div>
<hr class="border-b border-gray-600 opacity-50 my-0 py-0" />
</nav>
<div class="md:flex flex-col md:flex-row md:min-h-screen w-full max-w-screen-xl mx-auto">
<div id="navSide" class="flex flex-col w-full md:w-48 text-gray-700 bg-white flex-shrink-0"></div>
<!-- * * * * * * * * * * * * * -->
<!-- Start of GoJS sample code -->
<script src="../release/go.js"></script>
<div id="allSampleContent" class="p-4 w-full">
<script id="code">
function init() {
// Since 2.2 you can also author concise templates with method chaining instead of GraphObject.make
// For details, see https://gojs.net/latest/intro/buildingObjects.html
const $ = go.GraphObject.make; // for conciseness in defining templates
// some constants that will be reused within templates
var roundedRectangleParams = {
parameter1: 2, // set the rounded corner
spot1: go.Spot.TopLeft, spot2: go.Spot.BottomRight // make content go all the way to inside edges of rounded corners
};
myDiagram =
new go.Diagram("myDiagramDiv", // must name or refer to the DIV HTML element
{
"animationManager.initialAnimationStyle": go.AnimationManager.None,
"InitialAnimationStarting": e => {
var animation = e.subject.defaultAnimation;
animation.easing = go.Animation.EaseOutExpo;
animation.duration = 900;
animation.add(e.diagram, 'scale', 0.1, 1);
animation.add(e.diagram, 'opacity', 0, 1);
},
// have mouse wheel events zoom in and out instead of scroll up and down
"toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,
// support double-click in background creating a new node
"clickCreatingTool.archetypeNodeData": { text: "new node" },
// enable undo & redo
"undoManager.isEnabled": true,
positionComputation: (diagram, pt) => {
return new go.Point(Math.floor(pt.x), Math.floor(pt.y));
}
});
// when the document is modified, add a "*" to the title and enable the "Save" button
myDiagram.addDiagramListener("Modified", e => {
var button = document.getElementById("SaveButton");
if (button) button.disabled = !myDiagram.isModified;
var idx = document.title.indexOf("*");
if (myDiagram.isModified) {
if (idx < 0) document.title += "*";
} else {
if (idx >= 0) document.title = document.title.slice(0, idx);
}
});
// define the Node template
myDiagram.nodeTemplate =
$(go.Node, "Auto",
{
locationSpot: go.Spot.Top,
isShadowed: true, shadowBlur: 1,
shadowOffset: new go.Point(0, 1),
shadowColor: "rgba(0, 0, 0, .14)"
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
// define the node's outer shape, which will surround the TextBlock
$(go.Shape, "RoundedRectangle", roundedRectangleParams,
{
name: "SHAPE", fill: "#ffffff", strokeWidth: 0,
stroke: null,
portId: "", // this Shape is the Node's port, not the whole Node
fromLinkable: true, fromLinkableSelfNode: true, fromLinkableDuplicates: true,
toLinkable: true, toLinkableSelfNode: true, toLinkableDuplicates: true,
cursor: "pointer"
}),
$(go.TextBlock,
{
font: "bold small-caps 11pt helvetica, bold arial, sans-serif", margin: 7, stroke: "rgba(0, 0, 0, .87)",
editable: true // editing the text automatically updates the model data
},
new go.Binding("text").makeTwoWay())
);
// unlike the normal selection Adornment, this one includes a Button
myDiagram.nodeTemplate.selectionAdornmentTemplate =
$(go.Adornment, "Spot",
$(go.Panel, "Auto",
$(go.Shape, "RoundedRectangle", roundedRectangleParams,
{ fill: null, stroke: "#7986cb", strokeWidth: 3 }),
$(go.Placeholder) // a Placeholder sizes itself to the selected Node
),
// the button to create a "next" node, at the top-right corner
$("Button",
{
alignment: go.Spot.TopRight,
click: addNodeAndLink // this function is defined below
},
$(go.Shape, "PlusLine", { width: 6, height: 6 })
) // end button
); // end Adornment
myDiagram.nodeTemplateMap.add("Start",
$(go.Node, "Spot", { desiredSize: new go.Size(75, 75) },
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape, "Circle",
{
fill: "#52ce60", /* green */
stroke: null,
portId: "",
fromLinkable: true, fromLinkableSelfNode: true, fromLinkableDuplicates: true,
toLinkable: true, toLinkableSelfNode: true, toLinkableDuplicates: true,
cursor: "pointer"
}),
$(go.TextBlock, "Start",
{
font: "bold 16pt helvetica, bold arial, sans-serif",
stroke: "whitesmoke"
})
)
);
myDiagram.nodeTemplateMap.add("End",
$(go.Node, "Spot", { desiredSize: new go.Size(75, 75) },
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape, "Circle",
{
fill: "maroon",
stroke: null,
portId: "",
fromLinkable: true, fromLinkableSelfNode: true, fromLinkableDuplicates: true,
toLinkable: true, toLinkableSelfNode: true, toLinkableDuplicates: true,
cursor: "pointer"
}),
$(go.Shape, "Circle", { fill: null, desiredSize: new go.Size(65, 65), strokeWidth: 2, stroke: "whitesmoke" }),
$(go.TextBlock, "End",
{
font: "bold 16pt helvetica, bold arial, sans-serif",
stroke: "whitesmoke"
})
)
);
// clicking the button inserts a new node to the right of the selected node,
// and adds a link to that new node
function addNodeAndLink(e, obj) {
var adornment = obj.part;
var diagram = e.diagram;
diagram.startTransaction("Add State");
// get the node data for which the user clicked the button
var fromNode = adornment.adornedPart;
var fromData = fromNode.data;
// create a new "State" data object, positioned off to the right of the adorned Node
var toData = { text: "new" };
var p = fromNode.location.copy();
p.x += 200;
toData.loc = go.Point.stringify(p); // the "loc" property is a string, not a Point object
// add the new node data to the model
var model = diagram.model;
model.addNodeData(toData);
// create a link data from the old node data to the new node data
var linkdata = {
from: model.getKeyForNodeData(fromData), // or just: fromData.id
to: model.getKeyForNodeData(toData),
text: "transition"
};
// and add the link data to the model
model.addLinkData(linkdata);
// select the new Node
var newnode = diagram.findNodeForData(toData);
diagram.select(newnode);
diagram.commitTransaction("Add State");
// if the new node is off-screen, scroll the diagram to show the new node
diagram.scrollToRect(newnode.actualBounds);
}
// replace the default Link template in the linkTemplateMap
myDiagram.linkTemplate =
$(go.Link, // the whole link panel
{
curve: go.Link.Bezier,
adjusting: go.Link.Stretch,
reshapable: true, relinkableFrom: true, relinkableTo: true,
toShortLength: 3
},
new go.Binding("points").makeTwoWay(),
new go.Binding("curviness"),
$(go.Shape, // the link shape
{ strokeWidth: 1.5 },
new go.Binding('stroke', 'progress', progress => progress ? "#52ce60" /* green */ : 'black'),
new go.Binding('strokeWidth', 'progress', progress => progress ? 2.5 : 1.5)),
$(go.Shape, // the arrowhead
{ toArrow: "standard", stroke: null },
new go.Binding('fill', 'progress', progress => progress ? "#52ce60" /* green */ : 'black')),
$(go.Panel, "Auto",
$(go.Shape, // the label background, which becomes transparent around the edges
{
fill: $(go.Brush, "Radial",
{ 0: "rgb(245, 245, 245)", 0.7: "rgb(245, 245, 245)", 1: "rgba(245, 245, 245, 0)" }),
stroke: null
}),
$(go.TextBlock, "transition", // the label text
{
textAlign: "center",
font: "9pt helvetica, arial, sans-serif",
margin: 4,
editable: true // enable in-place editing
},
// editing the text automatically updates the model data
new go.Binding("text").makeTwoWay())
)
);
// read in the JSON data from the "mySavedModel" element
load();
}
// Show the diagram's model in JSON format
function save() {
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
myDiagram.isModified = false;
}
function load() {
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
}
window.addEventListener('DOMContentLoaded', init);
</script>
<div id="sample">
<div id="myDiagramDiv" style="border: solid 1px black; width: 100%; height: 460px; background: whitesmoke"></div>
<p>
This sample creates a state chart to story-board an online shopping experience.
</p>
<p>
The text is editable for both the nodes and the links.
The user can draw as many links from one node to another node as desired,
and the links can be reshaped or deleted when selected.
Double-clicking in the background of the diagram creates a new node.
The mouse wheel is set to zoom in and out instead of scroll.
</p>
<p>
This sample customizes the <a>Part.selectionAdornmentTemplate</a>
of the node to a template that contains a button
The button is positioned to be at the Top-Right corner of the node by
being in a Spot Panel with its <a>GraphObject.alignment</a> property set to Spot.TopRight.
</p>
<p>
The Button's <a>GraphObject.click</a> method creates a new node data,
adds it to the model, and creates a link from the original node data to the new node data.
All of this is done inside a transaction, so that it can be undone by the user
(Ctrl+Z and Ctrl+Y will undo and redo transactions). After the node is created,
<a>Diagram.scrollToRect</a> is called in case it is off-screen.
</p>
<div>
<div>
<button id="SaveButton" onclick="save()">Save</button>
<button onclick="load()">Load</button>
Diagram Model saved in JSON format:
</div>
<textarea id="mySavedModel" style="width:100%;height:300px">
{ "class": "go.GraphLinksModel",
"nodeKeyProperty": "id",
"nodeDataArray": [
{"id":-1, "loc":"155 -138", "category":"Start"},
{"id":0, "loc":"190 15", "text":"Shopping"},
{"id":1, "loc":"353 32", "text":"Browse Items"},
{"id":2, "loc":"353 166", "text":"Search Items"},
{"id":3, "loc":"512 12", "text":"View Item"},
{"id":4, "loc":"661 17", "text":"View Cart"},
{"id":5, "loc":"644 171", "text":"Update Cart"},
{"id":6, "loc":"800 96", "text":"Checkout"},
{"id":-2, "loc":"757 229", "category":"End"}
],
"linkDataArray": [
{ "from": -1, "to": 0, "text": "Visit online store" },
{ "from": 0, "to": 1, "progress": "true", "text": "Browse" },
{ "from": 0, "to": 2, "progress": "true", "text": "Use search bar" },
{ "from": 1, "to": 2, "progress": "true", "text": "Use search bar" },
{ "from": 2, "to": 3, "progress": "true", "text": "Click item" },
{ "from": 2, "to": 2, "text": "Another search", "curviness": 20 },
{ "from": 1, "to": 3, "progress": "true", "text": "Click item" },
{ "from": 3, "to": 0, "text": "Not interested", "curviness": -100 },
{ "from": 3, "to": 4, "progress": "true", "text": "Add to cart" },
{ "from": 4, "to": 0, "text": "More shopping", "curviness": -150 },
{ "from": 4, "to": 5, "text": "Update needed", "curviness": -50 },
{ "from": 5, "to": 4, "text": "Update made" },
{ "from": 4, "to": 6, "progress": "true", "text": "Proceed" },
{ "from": 6, "to": 5, "text": "Update needed" },
{ "from": 6, "to": -2, "progress": "true", "text": "Purchase made" }
]
}
</textarea>
</div>
</div>
</div>
<!-- * * * * * * * * * * * * * -->
<!-- End of GoJS sample code -->
</div>
</body>
<!-- This script is part of the gojs.net website, and is not needed to run the sample -->
<script src="../assets/js/goSamples.js"></script>
</html>