UNPKG

create-gojs-kit

Version:

A CLI for downloading GoJS samples, extensions, and docs

830 lines (758 loc) 34.5 kB
<!DOCTYPE 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 Grafcet diagram editor, showing buttons for creating new nodes and links related to the selected node." /> <meta itemprop="description" content="A Grafcet diagram editor, showing buttons for creating new nodes and links related to the selected node." /> <meta property="og:description" content="A Grafcet diagram editor, showing buttons for creating new nodes and links related to the selected node." /> <meta name="twitter:description" content="A Grafcet diagram editor, showing buttons for creating new nodes and links related to the selected node." /> <link rel="preconnect" href="https://rsms.me/"> <link rel="stylesheet" href="../assets/css/style.css"> <!-- Copyright 1998-2025 by Northwoods Software Corporation. --> <meta itemprop="name" content="Grafcet Diagram Editor, Type of Sequential Function Chart for Automation Design" /> <meta property="og:title" content="Grafcet Diagram Editor, Type of Sequential Function Chart for Automation Design" /> <meta name="twitter:title" content="Grafcet Diagram Editor, Type of Sequential Function Chart for Automation Design" /> <meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/grafcet.png" /> <meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/grafcet.png" /> <meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/grafcet.png" /> <meta property="og:url" content="https://gojs.net/latest/samples/grafcet.html" /> <meta property="twitter:url" content="https://gojs.net/latest/samples/grafcet.html" /> <meta name="twitter:card" content="summary_large_image" /> <meta property="og:type" content="website" /> <meta property="twitter:domain" content="gojs.net" /> <title> Grafcet Diagram Editor, Type of Sequential Function Chart for Automation Design | GoJS Diagramming Library </title> </head> <body> <!-- This top nav is not part of the sample code --> <nav id="navTop" class=" w-full h-[var(--topnav-h)] z-30 bg-white border-b border-b-gray-200"> <div class="max-w-screen-xl mx-auto flex flex-wrap items-start justify-between px-4"> <a class="text-white bg-nwoods-primary font-bold !leading-[calc(var(--topnav-h)_-_1px)] my-0 px-2 text-4xl lg:text-5xl logo" href="../"> GoJS </a> <div class="relative"> <button id="topnavButton" class="h-[calc(var(--topnav-h)_-_1px)] px-2 m-0 text-gray-900 bg-inherit shadow-none md:hidden hover:!bg-inherit hover:!text-nwoods-accent hover:!shadow-none" aria-label="Navigation"> <svg class="h-7 w-7 block" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <path d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <div id="topnavList" class="hidden md:block"> <div class="absolute right-0 z-30 flex flex-col items-end rounded border border-gray-200 p-4 pl-12 shadow bg-white text-gray-900 font-semibold md:flex-row md:space-x-4 md:items-start md:border-0 md:p-0 md:shadow-none md:bg-inherit"> <a href="../learn/">Learn</a> <a href="../samples/">Samples</a> <a href="../intro/">Intro</a> <a href="../api/">API</a> <a href="../download.html">Download</a> <a href="https://forum.nwoods.com/c/gojs/11" target="_blank" rel="noopener">Forum</a> <a id="tc" href="https://nwoods.com/contact.html" target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/contact.html', 'contact');">Contact</a> <a id="tb" href="https://nwoods.com/sales/index.html" target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/sales/index.html', 'buy');">Buy</a> </div> </div> </div> </div> </nav> <script> window.addEventListener("DOMContentLoaded", function () { // topnav var topButton = document.getElementById("topnavButton"); var topnavList = document.getElementById("topnavList"); if (topButton && topnavList) { topButton.addEventListener("click", function (e) { topnavList .classList .toggle("hidden"); e.stopPropagation(); }); document.addEventListener("click", function (e) { // if the clicked element isn't the list, close the list if (!topnavList.classList.contains("hidden") && !e.target.closest("#topnavList")) { topButton.click(); } }); // set active <a> element var url = window .location .href .toLowerCase(); var aTags = topnavList.getElementsByTagName('a'); for (var i = 0; i < aTags.length; i++) { var lowerhref = aTags[i] .href .toLowerCase(); if (lowerhref.endsWith('.html')) lowerhref = lowerhref.slice(0, -5); if (url.startsWith(lowerhref)) { aTags[i] .classList .add('active'); break; } } } }); </script> <div class="flex flex-col prose"> <div class="w-full max-w-screen-xl mx-auto"> <!-- * * * * * * * * * * * * * --> <!-- Start of GoJS sample code --> <script src="https://cdn.jsdelivr.net/npm/gojs@3.1.0"></script> <div id="allSampleContent" class="p-4 w-full"> <script id="code"> // This custom LinkingTool just turns on Diagram.allowLink when it starts, // and turns it off again when it stops so that users cannot draw new links modelessly. class CustomLinkingTool extends go.LinkingTool { constructor(init) { super(); if (init) Object.assign(this, init); } // user-drawn linking is normally disabled, // but needs to be turned on when using this tool doStart() { this.diagram.allowLink = true; super.doStart(); } doStop() { super.doStop(); this.diagram.allowLink = false; } } // end CustomLinkingTool // This custom Link class is smart about computing the link point and direction // at "Parallel" and "Exclusive" nodes. class BarLink extends go.Link { constructor(init) { super(); if (init) Object.assign(this, init); } getLinkPoint(node, port, spot, from, ortho, othernode, otherport) { const r = port.getDocumentBounds(); const op = otherport.getDocumentBounds(); const below = op.centerY > r.centerY; const y = below ? r.bottom : r.top; if (node.category === 'Parallel' || node.category === 'Exclusive') { if (op.right < r.left) return new go.Point(r.left, y); if (op.left > r.right) return new go.Point(r.right, y); return new go.Point((Math.max(r.left, op.left) + Math.min(r.right, op.right)) / 2, y); } else { return new go.Point(r.centerX, y); } } getLinkDirection(node, port, linkpoint, spot, from, ortho, othernode, otherport) { const p = port.getDocumentPoint(go.Spot.Center); const op = otherport.getDocumentPoint(go.Spot.Center); const below = op.y > p.y; return below ? 90 : 270; } } // end BarLink class function init() { myDiagram = new go.Diagram('myDiagramDiv', { allowLink: false, // linking is only started via buttons, not modelessly; // see the "startLink..." functions and CustomLinkingTool defined above // double-click in the background creates a new "Start" node 'clickCreatingTool.archetypeNodeData': { category: 'Start', step: 1, text: 'Action' }, linkingTool: new CustomLinkingTool(), // defined above to automatically turn on allowLink 'undoManager.isEnabled': true }); // when the document is modified, add a "*" to the title and enable the "Save" button myDiagram.addDiagramListener('Modified', e => { const button = document.getElementById('saveModel'); if (button) button.disabled = !myDiagram.isModified; const idx = document.title.indexOf('*'); if (myDiagram.isModified) { if (idx < 0) document.title += '*'; } else { if (idx >= 0) document.title = document.title.slice(0, idx); } }); // This implements a selection Adornment that is a horizontal bar of command buttons // that appear when the user selects a node. // Each button has a click function to execute the command, a tooltip for a textual description, // and a Binding of "visible" to hide the button if it cannot be executed for that particular node. const commandsAdornment = go.GraphObject.build('ContextMenu') .add( new go.Panel('Auto') .add( new go.Shape({ fill: null, stroke: 'deepskyblue', strokeWidth: 2, shadowVisible: false }), new go.Placeholder() ), new go.Panel('Horizontal', { defaultStretch: go.Stretch.Vertical }) .add( go.GraphObject.build('Button', { click: addExclusive, toolTip: makeTooltip('Add Exclusive') }) .bindObject('visible', '', canAddSplit) .add( new go.Shape({ geometryString: 'M0 0 L10 0', fill: null, stroke: 'red', margin: 3 }) ), go.GraphObject.build('Button', { click: addParallel, toolTip: makeTooltip('Add Parallel') }) .bindObject('visible', '', canAddSplit) .add( new go.Shape({ geometryString: 'M0 0 L10 0 M0 3 10 3', fill: null, stroke: 'red', margin: 3 }) ), go.GraphObject.build('Button', { click: addStep, toolTip: makeTooltip('Add Step') }) .bindObject('visible', '', canAddStep) .add( new go.Shape({ geometryString: 'M0 0 L10 0 10 6 0 6z', fill: 'lightyellow', margin: 3 }) ), go.GraphObject.build('Button', { click: startLinkDown, toolTip: makeTooltip('Draw Link Down') }) .bindObject('visible', '', canStartLink) .add( new go.Shape({ geometryString: 'M0 0 M5 0 L5 10 M3 8 5 10 7 8 M10 0', fill: null, margin: 3 }) ), go.GraphObject.build('Button', { click: startLinkAround, toolTip: makeTooltip('Draw Link Skip') }) .bindObject('visible', '', canStartLink) .add( new go.Shape({ geometryString: 'M0 0 M3 0 L3 2 7 2 7 6 3 6 3 10 M1 8 3 10 5 8 M10 0', fill: null, margin: 3 }) ), go.GraphObject.build('Button', { click: startLinkUp, toolTip: makeTooltip('Draw Link Repeat') }) .bindObject('visible', '', canStartLink) .add( new go.Shape({ geometryString: 'M0 0 M3 2 L3 0 7 0 7 10 3 10 3 8 M5 6 7 4 9 6 M10 0', fill: null, margin: 3 }) ) ) ); function makeTooltip(str) { // a helper function for defining tooltips for buttons return go.GraphObject.build('ToolTip') .add(new go.TextBlock(str)); } // Commands for adding new Nodes function addStep(e, obj) { const node = obj.part.adornedPart; const model = myDiagram.model; model.startTransaction('add Step'); const loc = node.location.copy(); loc.y += 50; const nodedata = { location: go.Point.stringify(loc) }; model.addNodeData(nodedata); const nodekey = model.getKeyForNodeData(nodedata); const linkdata = { from: model.getKeyForNodeData(node.data), to: nodekey, text: 'c' }; model.addLinkData(linkdata); const newnode = myDiagram.findNodeForData(nodedata); myDiagram.select(newnode); model.commitTransaction('add Step'); } function canAddStep(adorn) { const node = adorn.adornedPart; if (node.category === '' || node.category === 'Start') { return node.findLinksOutOf().count === 0; } else if (node.category === 'Parallel' || node.category === 'Exclusive') { return true; } return false; } function addParallel(e, obj) { addSplit(obj.part.adornedPart, 'Parallel'); } function addExclusive(e, obj) { addSplit(obj.part.adornedPart, 'Exclusive'); } function addSplit(node, type) { const model = myDiagram.model; model.startTransaction('add ' + type); const loc = node.location.copy(); loc.y += 50; const nodedata = { category: type, location: go.Point.stringify(loc) }; model.addNodeData(nodedata); const nodekey = model.getKeyForNodeData(nodedata); const linkdata = { from: model.getKeyForNodeData(node.data), to: nodekey }; model.addLinkData(linkdata); const newnode = myDiagram.findNodeForData(nodedata); myDiagram.select(newnode); model.commitTransaction('add ' + type); } function canAddSplit(adorn) { const node = adorn.adornedPart; if (node.category === '' || node.category === 'Start') { return node.findLinksOutOf().count === 0; } else if (node.category === 'Parallel' || node.category === 'Exclusive') { return false; } return false; } // Commands for starting drawing new Links function startLinkDown(e, obj) { startLink(obj.part.adornedPart, '', 'c'); } function startLinkAround(e, obj) { startLink(obj.part.adornedPart, 'Skip', 's'); } function startLinkUp(e, obj) { startLink(obj.part.adornedPart, 'Repeat', 'r'); } function startLink(node, category, condition) { const tool = myDiagram.toolManager.linkingTool; // to control what kind of Link is created, // change the LinkingTool.archetypeLinkData's category myDiagram.model.setCategoryForLinkData(tool.archetypeLinkData, category); // also change the text indicating the condition, which the user can edit tool.archetypeLinkData.text = condition; tool.startObject = node.port; myDiagram.currentTool = tool; tool.doActivate(); } function canStartLink(adorn) { const node = adorn.adornedPart; return true; // this could be smarter } // The various kinds of Nodes function nodeStyle(node) { node.locationSpot = go.Spot.Center; node.selectionAdornmentTemplate = commandsAdornment; // shared selection Adornment node.bindTwoWay('location', 'location', go.Point.parse, go.Point.stringify); } myDiagram.nodeTemplateMap.add('Start', new go.Node('Horizontal', { locationObjectName: 'STEPPANEL', selectionObjectName: 'STEPPANEL' }) .apply(nodeStyle) .add( new go.Panel('Auto', { // this is the port element, not the whole Node name: 'STEPPANEL', portId: '', fromSpot: go.Spot.Bottom, fromLinkable: true }) .add( new go.Shape({ fill: 'lightgreen' }), new go.Panel('Auto', { margin: 3 }) .add( new go.Shape({ fill: null, minSize: new go.Size(20, 20) }), new go.TextBlock('Start', { margin: 3, editable: true }) .bindTwoWay('text', 'step') ) ), // a connector line between the texts new go.Shape('LineH', { width: 10, height: 1 }), // the boxed, editable text on the side new go.Panel('Auto') .add( new go.Shape({ fill: 'white' }), new go.TextBlock('Action', { margin: 3, editable: true }) .bindTwoWay('text') ) )); myDiagram.nodeTemplateMap.add('', new go.Node('Horizontal', { locationObjectName: 'STEPPANEL', selectionObjectName: 'STEPPANEL' }) .apply(nodeStyle) .add( new go.Panel('Auto', { // this is the port element, not the whole Node name: 'STEPPANEL', portId: '', fromSpot: go.Spot.Bottom, fromLinkable: true, toSpot: go.Spot.Top, toLinkable: true }) .add( new go.Shape({ fill: 'lightyellow', minSize: new go.Size(20, 20) }), new go.TextBlock('Step', { margin: 3, editable: true }) .bindTwoWay('text', 'step') ), new go.Shape('LineH', { width: 10, height: 1 }), new go.Panel('Auto') .add( new go.Shape({ fill: 'white' }), new go.TextBlock('Action', { margin: 3, editable: true }) .bindTwoWay('text') ) )); const resizeAdornment = new go.Adornment("Spot") .add( new go.Placeholder(), new go.Shape({ // left resize handle alignment: go.Spot.Left, cursor: 'col-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'dodgerblue' }), new go.Shape({ // right resize handle alignment: go.Spot.Right, cursor: 'col-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'dodgerblue' }) ); myDiagram.nodeTemplateMap.add('Parallel', new go.Node({ // special resizing: just at the ends resizable: true, resizeObjectName: 'SHAPE', resizeAdornmentTemplate: resizeAdornment, fromLinkable: true, toLinkable: true }) .apply(nodeStyle) .add( new go.Shape({ // horizontal pair of lines stretched to an initial width of 200 name: 'SHAPE', geometryString: 'M0 0 L100 0 M0 4 L100 4', fill: 'transparent', stroke: 'red', width: 200 }) .bindTwoWay('desiredSize', 'size', go.Size.parse, go.Size.stringify) )); myDiagram.nodeTemplateMap.add('Exclusive', new go.Node({ // special resizing: just at the ends resizable: true, resizeObjectName: 'SHAPE', resizeAdornmentTemplate: resizeAdornment, fromLinkable: true, toLinkable: true }) .apply(nodeStyle) .add( new go.Shape({ // horizontal line stretched to an initial width of 200 name: 'SHAPE', geometryString: 'M0 0 L100 0', fill: 'transparent', stroke: 'red', width: 200 }) .bindTwoWay('desiredSize', 'size', go.Size.parse, go.Size.stringify) )); // the various kinds of Links myDiagram.linkTemplateMap.add('', new BarLink({ routing: go.Routing.Orthogonal }) // subclass defined above .add( new go.Shape({ strokeWidth: 1.5 }), new go.Shape('LineH', { // only visible when there is text width: 20, height: 1, visible: false }) .bind('visible', 'text', t => t !== ''), new go.TextBlock({ // only visible when there is text alignmentFocus: new go.Spot(0, 0.5, -12, 0), editable: true }) .bindTwoWay('text') .bind('visible', 'text', t => t !== '') )); myDiagram.linkTemplateMap.add('Skip', new go.Link({ routing: go.Routing.AvoidsNodes, fromSpot: go.Spot.Bottom, toSpot: go.Spot.Top, fromEndSegmentLength: 4, toEndSegmentLength: 4 }) .add( new go.Shape({ strokeWidth: 1.5 }), new go.Shape('LineH', { // only visible when there is text width: 20, height: 1, visible: false }) .bind('visible', 'text', t => t !== ''), new go.TextBlock({ // only visible when there is text alignmentFocus: new go.Spot(1, 0.5, 12, 0), editable: true }) .bindTwoWay('text') .bind('visible', 'text', t => t !== '') )); myDiagram.linkTemplateMap.add('Repeat', new go.Link({ routing: go.Routing.AvoidsNodes, fromSpot: go.Spot.Bottom, toSpot: go.Spot.Top, fromEndSegmentLength: 4, toEndSegmentLength: 4 }) .add( new go.Shape({ strokeWidth: 1.5 }), new go.Shape({ toArrow: 'OpenTriangle', segmentIndex: 3, segmentFraction: 0.75 }), new go.Shape({ toArrow: 'OpenTriangle', segmentIndex: 3, segmentFraction: 0.25 }), new go.Shape('LineH', { // only visible when there is text width: 20, height: 1, visible: false }) .bind('visible', 'text', t => t !== ''), new go.TextBlock({ // only visible when there is text alignmentFocus: new go.Spot(1, 0.5, 12, 0), editable: true }) .bindTwoWay('text') .bind('visible', 'text', t => t !== '') )); // start off with a simple diagram load(); } // save a model to and load a model from JSON text, displayed below the Diagram 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: 800px; height: 600px"></div> <p>A grafcet diagram is similar to a <a href="sequentialFunction.html">sequential function chart</a>.</p> <p> All the <a>TextBlock</a>s in this sample are editable on double click. </p> <p> Select a Node to show a list of Buttons that enable creating new Nodes or drawing new Links. These buttons are defined as an adornment that is used in a common <a>Part.selectionAdornmentTemplate</a>. This diagram uses many custom functions, including an overridden <a>LinkingTool</a> and a special Link class, <b>BarLink</b>. </p> <div id="buttons"> <button id="saveModel" onclick="save()">Save</button> <button id="loadModel" onclick="load()">Load</button> Diagram Model saved in JSON format: </div> <textarea id="mySavedModel" style="width: 100%; height: 300px"> { "class": "go.GraphLinksModel", "nodeDataArray": [ {"key":1, "category":"Start", "location":"300 50", "step":"1", "text":"Action 1"}, {"key":2, "category":"Parallel", "location":"300 100"}, {"key":3, "location":"225 125", "step":"3", "text":"Action 2"}, {"key":4, "location":"325 150", "step":"4", "text":"Action 3"}, {"key":5, "location":"225 175", "step":"5", "text":"Action 4"}, {"key":6, "category":"Parallel", "location":"300 200"}, {"key":7, "location":"300 250", "step":"7", "text":"Action 6"}, {"key":11, "category":"Start", "location":"300 350", "step":"11", "text":"Action 1"}, {"key":12, "category":"Exclusive", "location":"300 400"}, {"key":13, "location":"225 450", "step":"13", "text":"Action 2"}, {"key":14, "location":"325 475", "step":"14", "text":"Action 3"}, {"key":15, "location":"225 500", "step":"15", "text":"Action 4"}, {"key":16, "category":"Exclusive", "location":"300 550"}, {"key":17, "location":"300 600", "step":"17", "text":"Action 6"}, {"key":21, "location":"500 50", "step":"21", "text":"Act 1"}, {"key":22, "location":"500 100", "step":"22", "text":"Act 2"}, {"key":23, "location":"500 150", "step":"23", "text":"Act 3"}, {"key":24, "location":"500 200", "step":"24", "text":"Act 4"}, {"key":31, "location":"500 400", "step":"31", "text":"Act 1"}, {"key":32, "location":"500 450", "step":"32", "text":"Act 2"}, {"key":33, "location":"500 500", "step":"33", "text":"Act 3"}, {"key":34, "location":"500 550", "step":"34", "text":"Act 4"} ], "linkDataArray": [ {"from":1, "to":2, "text":"condition 1"}, {"from":2, "to":3}, {"from":2, "to":4}, {"from":3, "to":5, "text":"condition 2"}, {"from":4, "to":6}, {"from":5, "to":6}, {"from":6, "to":7, "text":"condition 5"}, {"from":11, "to":12, "text":"condition 1"}, {"from":12, "to":13, "text":"condition 12"}, {"from":12, "to":14, "text":"condition 13"}, {"from":13, "to":15, "text":"condition 2"}, {"from":14, "to":16, "text":"condition 14"}, {"from":15, "to":16, "text":"condition 15"}, {"from":16, "to":17, "text":"condition 5"}, {"from":21, "to":22, "text":"c1"}, {"from":22, "to":23, "text":"c2"}, {"from":23, "to":24, "text":"c3"}, {"from":21, "to":24, "text":"c14", "category":"Skip"}, {"from":31, "to":32, "text":"c1"}, {"from":32, "to":33, "text":"c2"}, {"from":33, "to":34, "text":"c3"}, {"from":33, "to":32, "text":"c14", "category":"Repeat"} ]} </textarea> </div> </div> <!-- * * * * * * * * * * * * * --> <!-- End of GoJS sample code --> </div> <div id="allTagDescriptions" class="p-4 w-full max-w-screen-xl mx-auto"> <hr/> <h3 class="text-xl">GoJS Features in this sample</h3> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>Links</h4> <p> The <a href="../api/symbols/Link.html" target="api">Link</a> class is used to implement a visual relationship between nodes. Links are normally created by the presence of link data objects in the <a href="../api/symbols/GraphLinksModel.html#linkDataArray" target="api">GraphLinksModel.linkDataArray</a> or by a parent key reference as the value of the <a href="../api/symbols/TreeModel.html#nodeParentKeyProperty" target="api">TreeModel.nodeParentKeyProperty</a> of a node data object in a <a href="../api/symbols/TreeModel.html" target="api">TreeModel</a>. More information can be found in the <a href="../intro/links.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#links">Related samples</a> </p> <hr> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>ToolTips</h4> <p> A tooltip is an <a href="../api/symbols/Adornment.html" target="api">Adornment</a> that is shown when the mouse hovers over an object that has its <a href="../api/symbols/GraphObject.html#toolTip" target="api">GraphObject.toolTip</a> set. The tooltip part is bound to the same data as the part itself. </p> <p> It is typical to implement a tooltip as a "ToolTip" Panel holding a <a href="../api/symbols/TextBlock.html" target="api">TextBlock</a> or a Panel of TextBlocks and other objects. Each "ToolTip" is just an "Auto" Panel <a href="../api/symbols/Adornment.html" target="api">Adornment</a> that is shadowed, and where the border is a rectangular <a href="../api/symbols/Shape.html" target="api">Shape</a> with a light gray fill. However you can implement the tooltip as any arbitrarily complicated Adornment. </p> <p> More information can be found in the <a href="../intro/tooltips.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#tooltips">Related samples</a> </p> <hr> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>Tools</h4> <p> <a href="../api/symbols/Tool.html" target="api">Tool</a>s handle all input events, such as mouse and keyboard interactions, in a Diagram. There are many kinds of predefined Tool classes that implement all of the common operations that users do. </p> <p> For flexibility and simplicity, all input events are canonicalized as <a href="../api/symbols/InputEvent.html" target="api">InputEvent</a>s and redirected by the diagram to go to the <a href="../api/symbols/Diagram.html#currentTool" target="api">Diagram.currentTool</a>. By default the Diagram.currentTool is an instance of <a href="../api/symbols/ToolManager.html" target="api">ToolManager</a> held as the <a href="../api/symbols/Diagram.html#toolManager" target="api">Diagram.toolManager</a>. The ToolManager implements support for all mode-less tools. The ToolManager is responsible for finding another tool that is ready to run and then making it the new current tool. This causes the new tool to process all of the input events (mouse, keyboard, and touch) until the tool decides that it is finished, at which time the diagram's current tool reverts back to the <a href="../api/symbols/Diagram.html#defaultTool" target="api">Diagram.defaultTool</a>, which is normally the ToolManager, again. </p> <p> More information can be found in the <a href="../intro/tools.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#tools">Related samples</a> </p> <hr> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>Buttons</h4> <p> GoJS defines several <a href="../api/symbols/Panel.html" target="api">Panel</a>s for common uses. These include "Button", "TreeExpanderButton", "SubGraphExpanderButton", "PanelExpanderButton", "ContextMenuButton", and "CheckBoxButton". "ContextMenuButton"s are typically used inside of "ContextMenu" Panels; "CheckBoxButton"s are used in the implementation of "CheckBox" Panels. </p> <p> These predefined panels can be used as if they were <a href="../api/symbols/Panel.html" target="api">Panel</a>-derived classes in calls to <a href="../api/symbols/GraphObject.html#build" target="api">GraphObject.build</a>. They are implemented as simple visual trees of <a href="../api/symbols/GraphObject.html" target="api">GraphObject</a>s in <a href="../api/symbols/Panel.html" target="api">Panel</a>s, with pre-set properties and event handlers. </p> <p> More information can be found in the <a href="../intro/buttons.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#buttons">Related samples</a> </p> <hr> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>Geometry Path Strings</h4> <p> The <b>GoJS</b> <a href="../api/symbols/Geometry.html" target="api">Geometry</a> class controls the "shape" of a <a href="../api/symbols/Shape.html" target="api">Shape</a>, whereas the <a href="../api/symbols/Shape.html#fill" target="api">Shape.fill</a> and <a href="../api/symbols/Shape.html#stroke" target="api">Shape.stroke</a> and other shape properties control the colors and appearance of the shape. For common shape figures, there are predefined geometries that can be used by setting <a href="../api/symbols/Shape.html#figure" target="api">Shape.figure</a>. However one can also define custom geometries. </p> <p> One can construct any Geometry by allocating and initializing a <a href="../api/symbols/Geometry.html" target="api">Geometry</a> of at least one <a href="../api/symbols/PathFigure.html" target="api">PathFigure</a> holding some <a href="../api/symbols/PathSegment.html" target="api">PathSegment</a>s. But you may find that using the string representation of a Geometry is easier to write and save in a database. Use the static method <a href="../api/symbols/Geometry.html#parse" target="api">Geometry.parse</a> or the <a href="../api/symbols/Shape.html#geometryString" target="api">Shape.geometryString</a> property to transform a geometry path string into a <a href="../api/symbols/Geometry.html" target="api">Geometry</a> object. </p> <p> More information can be found in the <a href="../intro/geometry.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#geometries">Related samples</a> </p> <hr> <!-- blacklist tags that do not correspond to a specific GoJS feature --> </div> </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>