UNPKG

create-gojs-kit

Version:

A CLI for downloading GoJS samples, extensions, and docs

329 lines (283 loc) 14.6 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 Link class using a custom tapered geometry by overriding Link.makeGeometry." /> <meta itemprop="description" content="A Link class using a custom tapered geometry by overriding Link.makeGeometry." /> <meta property="og:description" content="A Link class using a custom tapered geometry by overriding Link.makeGeometry." /> <meta name="twitter:description" content="A Link class using a custom tapered geometry by overriding Link.makeGeometry." /> <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="Tapered Links Custom Computed Geometry for Link Path Shapes" /> <meta property="og:title" content="Tapered Links Custom Computed Geometry for Link Path Shapes" /> <meta name="twitter:title" content="Tapered Links Custom Computed Geometry for Link Path Shapes" /> <meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/taperedlinks.png" /> <meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/taperedlinks.png" /> <meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/taperedlinks.png" /> <meta property="og:url" content="https://gojs.net/latest/samples/taperedLinks.html" /> <meta property="twitter:url" content="https://gojs.net/latest/samples/taperedLinks.html" /> <meta name="twitter:card" content="summary_large_image" /> <meta property="og:type" content="website" /> <meta property="twitter:domain" content="gojs.net" /> <title> Tapered Links Custom Computed Geometry for Link Path Shapes | 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"> // a Link class with custom path Geometry class TaperedLink extends go.Link { constructor(init) { super(); if (init) Object.assign(this, init); } // produce a Geometry from the Link's route makeGeometry() { // maybe use the standard geometry for this route, instead? const numpts = this.pointsCount; if (numpts < 4 || this.computeCurve() !== go.Curve.Bezier) { return super.makeGeometry(); } const p0 = this.getPoint(0); const p1 = this.getPoint(numpts > 4 ? 2 : 1); const p2 = this.getPoint(numpts > 4 ? numpts - 3 : 2); const p3 = this.getPoint(numpts - 1); const fromHoriz = Math.abs(p0.y - p1.y) < Math.abs(p0.x - p1.x); const toHoriz = Math.abs(p2.y - p3.y) < Math.abs(p2.x - p3.x); let p0x = p0.x + (fromHoriz ? 0 : -4); let p0y = p0.y + (fromHoriz ? -4 : 0); let p1x = p1.x + (fromHoriz ? 0 : -3); let p1y = p1.y + (fromHoriz ? -3 : 0); let p2x = p2.x + (toHoriz ? 0 : -2); let p2y = p2.y + (toHoriz ? -2 : 0); let p3x = p3.x + (toHoriz ? 0 : -1); let p3y = p3.y + (toHoriz ? -1 : 0); const fig = new go.PathFigure(p0x, p0y, true); // filled fig.add(new go.PathSegment(go.SegmentType.Bezier, p3x, p3y, p1x, p1y, p2x, p2y)); p0x = p0.x + (fromHoriz ? 0 : 4); p0y = p0.y + (fromHoriz ? 4 : 0); p1x = p1.x + (fromHoriz ? 0 : 3); p1y = p1.y + (fromHoriz ? 3 : 0); p2x = p2.x + (toHoriz ? 0 : 2); p2y = p2.y + (toHoriz ? 2 : 0); p3x = p3.x + (toHoriz ? 0 : 1); p3y = p3.y + (toHoriz ? 1 : 0); fig.add(new go.PathSegment(go.SegmentType.Line, p3x, p3y)); fig.add(new go.PathSegment(go.SegmentType.Bezier, p0x, p0y, p2x, p2y, p1x, p1y).close()); const geo = new go.Geometry(); geo.add(fig); geo.normalize(); return geo; } } // end TaperedLink class function init() { myDiagram = new go.Diagram('myDiagramDiv', { layout: new go.ForceDirectedLayout(), 'undoManager.isEnabled': true }); // This controls whether links overlap each other at each side of the node, // or if the links are spread out on each side of the node. const SPREADLINKS = true; // must be set before defining templates! myDiagram.nodeTemplate = new go.Node('Auto', { locationSpot: go.Spot.Center }) .add( new go.Shape({ figure: 'RoundedRectangle', parameter1: 10, fill: 'orange', // default fill color portId: '', fromLinkable: true, fromSpot: SPREADLINKS ? go.Spot.AllSides : go.Spot.None, toLinkable: true, toSpot: SPREADLINKS ? go.Spot.AllSides : go.Spot.None, cursor: 'pointer' }) .bind('fill', 'color'), new go.TextBlock({ margin: 10, font: 'bold 12pt sans-serif' }) .bind('text') ); myDiagram.linkTemplate = new TaperedLink({ // subclass of Link, defined below curve: go.Curve.Bezier, routing: SPREADLINKS ? go.Routing.Normal : go.Routing.Orthogonal, fromEndSegmentLength: SPREADLINKS ? 50 : 1, toEndSegmentLength: SPREADLINKS ? 50 : 1, relinkableFrom: true, relinkableTo: true }) .add( new go.Shape({ stroke: null, strokeWidth: 0 }) .bind('fill', 'color') ); // create a few nodes and links myDiagram.model = new go.GraphLinksModel( [ { key: 1, text: 'one', color: 'lightyellow' }, { key: 2, text: 'two', color: 'brown' }, { key: 3, text: 'three', color: 'green' }, { key: 4, text: 'four', color: 'slateblue' }, { key: 5, text: 'five', color: 'aquamarine' }, { key: 6, text: 'six', color: 'lightgreen' }, { key: 7, text: 'seven' } ], [ { from: 5, to: 6, color: 'orange' }, { from: 1, to: 2, color: 'red' }, { from: 1, to: 3, color: 'blue' }, { from: 1, to: 4, color: 'goldenrod' }, { from: 2, to: 5, color: 'fuchsia' }, { from: 3, to: 5, color: 'green' }, { from: 4, to: 5, color: 'black' }, { from: 6, to: 7 } ] ); } window.addEventListener('DOMContentLoaded', init); </script> <div id="sample"> <div id="myDiagramDiv" style="border: solid 1px black; width: 100%; height: 700px; min-width: 200px"></div> <p>This sample demonstrates customization of the <a>Link</a> <a>Shape</a>'s <a>Geometry</a>.</p> <p> The TaperedLink class in this sample inherits from Link and overrides the makeGeometry method. For Bezier-curve Links, this computes a Geometry that is thick at the "from" end and thin at the "to" end. The implementation is very simple and does not account for links that are coming out from a node at angles that are not a multiple of 90 degrees. </p> </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>Force Directed Layout</h4> <p> This predefined layout treats the graph as if it were a system of physical bodies with forces acting on and between them. The layout iteratively moves nodes and links to minimize the total sum of forces on each node. The resulting layout will normally not contain overlapping Nodes, excluding cases where the graph is densely interconnected. More information can be found in the <a href="../intro/layouts.html#ForceDirectedLayout">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#force-directed">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> </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>