UNPKG

create-gojs-kit

Version:

A CLI for downloading GoJS samples, extensions, and docs

416 lines (369 loc) 17.9 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 map integrating a GoJS Diagram and the Leaflet mapping library." /> <meta itemprop="description" content="A map integrating a GoJS Diagram and the Leaflet mapping library." /> <meta property="og:description" content="A map integrating a GoJS Diagram and the Leaflet mapping library." /> <meta name="twitter:description" content="A map integrating a GoJS Diagram and the Leaflet mapping library." /> <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="Geographic Diagram in Front of Leaflet.js Map" /> <meta property="og:title" content="Geographic Diagram in Front of Leaflet.js Map" /> <meta name="twitter:title" content="Geographic Diagram in Front of Leaflet.js Map" /> <meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/leaflet.png" /> <meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/leaflet.png" /> <meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/leaflet.png" /> <meta property="og:url" content="https://gojs.net/latest/samples/leaflet.html" /> <meta property="twitter:url" content="https://gojs.net/latest/samples/leaflet.html" /> <meta name="twitter:card" content="summary_large_image" /> <meta property="og:type" content="website" /> <meta property="twitter:domain" content="gojs.net" /> <title> Geographic Diagram in Front of Leaflet.js Map | 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"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css" /> <script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.js"></script> <style type="text/css"> /* CSS applied to the Leaflet map */ .mapDiagram { border: solid 1px black; width: 500px; height: 500px; } #myDiagramDiv { z-index: 701; } </style> <script id="code"> // customize dragging to avoid built-in dragging by Leaflet class LeafletDraggingTool extends go.DraggingTool { constructor(init) { super(); if (init) Object.assign(this, init); } doActivate() { myLeafletMap.dragging.disable(); super.doActivate(); } doDeactivate() { myLeafletMap.dragging.enable(); super.doDeactivate(); } } function init() { /* Leaflet init */ const defaultZoom = 6; const defaultOrigin = [50.02185841773444, 0.15380859375]; myLeafletMap = L.map('map', {}).setView(defaultOrigin, defaultZoom); L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', { attribution: '&copy; <a href="https://www.mapbox.com/about/maps/">Mapbox</a> &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>', maxZoom: 18, minZoom: 2, tileSize: 512, zoomOffset: -1, id: 'mapbox/streets-v11', accessToken: 'pk.eyJ1IjoiZ29qcyIsImEiOiJjbHMyN3QxcnIwZ2ZoMmxvMzVvNGg3MTRrIn0.8u9prGrtYU2zmuFhxsr76g' //this doesn't work, ask about it probably }).addTo(myLeafletMap); myLeafletMap.on('zoomend', updateNodes); //myLeafletMap.on('zoom', updateNodes); //maybe this is slow? who knows... myLeafletMap.on('move', updatePosition); myLeafletMap.on('moveend', updatePosition); let myUpdatingGoJS = false; // prevent modifying data.latlong properties upon Leaflet "move" events function updateNodes() { // called when zoom level has changed myUpdatingGoJS = true; myDiagram.commit(diag => { diag.nodes.each(n => n.updateTargetBindings('latlong')); // without virtualization this can be slow if there are many nodes }, null); myUpdatingGoJS = false; } function updatePosition() { // called when map has been panned (i.e. top-left corner is at a different latlong) const mapb = myLeafletMap.getBounds(); const pos = myLeafletMap.project([mapb.getNorth(), mapb.getWest()], myLeafletMap.getZoom()); myDiagram.position = new go.Point(pos.x, pos.y); } /* GoJS init */ myDiagram = new go.Diagram('myDiagramDiv', { InitialLayoutCompleted: e => updatePosition(), draggingTool: new LeafletDraggingTool(), 'dragSelectingTool.isEnabled': false, 'animationManager.isEnabled': false, scrollMode: go.ScrollMode.Infinite, allowZoom: false, allowHorizontalScroll: false, allowVerticalScroll: false, hasHorizontalScrollbar: false, hasVerticalScrollbar: false, padding: 0, defaultCursor: 'default', 'toolManager.hoverDelay': 100, // how quickly tooltips are shown 'undoManager.isEnabled': true, ModelChanged: e => { if (e.change === go.ChangeType.Transaction && (e.propertyName === 'FinishedUndo' || e.propertyName === 'FinishedRedo')) { setTimeout(() => updateNodes()); } } }); // the node template describes how each Node should be constructed myDiagram.nodeTemplate = new go.Node('Auto', { locationSpot: go.Spot.Center, cursor: 'pointer', toolTip: go.GraphObject.build('ToolTip') .add( new go.TextBlock({ margin: 4, textAlign: 'center' }) .bind('text', '', d => `${d.key}\n[${d.latlong[0].toFixed(6)}, ${d.latlong[1].toFixed(6)}]`) ) }) // A two-way data binding with an Array of latitude,longitude numbers. // We have to explicitly avoid updating the source data Array // when myUpdatingGoJS is true; otherwise there would be accumulating errors. .bindTwoWay('location', 'latlong', data => { const pos = myLeafletMap.project(data, myLeafletMap.getZoom()); return new go.Point(pos.x, pos.y); }, (pt, data) => { if (myUpdatingGoJS) { return data.latlong; // no-op } else { const ll = myLeafletMap.unproject(L.point(pt.x, pt.y), myLeafletMap.getZoom()); return [ll.lat, ll.lng]; } }) .add( new go.Shape('Circle', { fill: 'rgba(0, 255, 0, .4)', stroke: '#082D47', strokeWidth: 1, width: 7, height: 7 }) ); myDiagram.linkTemplate = new go.Link({ layerName: 'Background', curve: go.Curve.Bezier, curviness: 5, toolTip: go.GraphObject.build('ToolTip') .add( new go.TextBlock({ margin: 4, textAlign: 'center' }) .bind('text', '', d => `${d.from} -- ${d.to}`) ) }) .add( new go.Shape({ strokeWidth: 3, stroke: 'rgba(100,100,255,.7)' }) ); // create the model data that will be represented by Nodes and Links myDiagram.model = new go.GraphLinksModel( [ // France { key: 'Paris', latlong: [48.876569, 2.359017] }, { key: 'Brest', latlong: [48.387778, -4.479921] }, { key: 'Rennes', latlong: [48.103375, -1.672809] }, { key: 'Le Mans', latlong: [47.995562, 0.192413] }, { key: 'Nantes', latlong: [47.217579, -1.541839] }, { key: 'Tours', latlong: [47.388502, 0.6945] }, { key: 'Le Havre', latlong: [49.492755, 0.125278] }, { key: 'Rouen', latlong: [49.449031, 1.094128] }, { key: 'Lille', latlong: [50.636379, 3.07062] }, // Belgium { key: 'Brussels', latlong: [50.836271, 4.333963] }, { key: 'Antwerp', latlong: [51.217495, 4.421204] }, { key: 'Liege', latlong: [50.624168, 5.566008] }, // UK { key: 'London', latlong: [51.531132, -0.125132] }, { key: 'Bristol', latlong: [51.449541, -2.581118] }, { key: 'Birmingham', latlong: [52.477405, -1.898494] }, { key: 'Liverpool', latlong: [53.408396, -2.978809] }, { key: 'Manchester', latlong: [53.476346, -2.229651] }, { key: 'Leeds', latlong: [53.79548, -1.548345] }, { key: 'Glasgow', latlong: [55.863287, -4.250989] } ], [ { from: 'Brest', to: 'Rennes' }, { from: 'Rennes', to: 'Le Mans' }, { from: 'Nantes', to: 'Le Mans' }, { from: 'Le Mans', to: 'Paris' }, { from: 'Tours', to: 'Paris' }, { from: 'Le Havre', to: 'Rouen' }, { from: 'Rouen', to: 'Paris' }, { from: 'Lille', to: 'Paris' }, { from: 'London', to: 'Lille' }, { from: 'Lille', to: 'Brussels' }, { from: 'Brussels', to: 'Antwerp' }, { from: 'Brussels', to: 'Liege' }, { from: 'Bristol', to: 'London' }, { from: 'Birmingham', to: 'London' }, { from: 'Leeds', to: 'London' }, { from: 'Liverpool', to: 'Birmingham' }, { from: 'Manchester', to: 'Liverpool' }, { from: 'Manchester', to: 'Leeds' }, { from: 'Glasgow', to: 'Manchester' }, { from: 'Glasgow', to: 'Leeds' } //more here later ] ); } // end init window.addEventListener('DOMContentLoaded', init); </script> <div id="sample"> <div id="map" class="mapDiagram"> <div id="myDiagramDiv" class="mapDiagram"></div> </div> <p> This sample integrates GoJS as a layer in front of the <a href="https://leafletjs.com/">Leaflet mapping library</a>. This demonstrates how to use GoJS within a GIS application by displaying a Diagram of nodes and links atop the map, using latitude and longitude for their coordinates. </p> <p> You can pan and zoom with Leaflet, and select and drag with GoJS. The GoJS div is on top of the Leaflet map, but this sample selectively bubbles events to leaflet by using a custom Tool. Dragged nodes will update their latitude and longitude data in the <a>Diagram.model</a>. </p> <p> This diagram displays a few train stations and routes in France, Belgium, and the UK. The data is only meant as an example of using GoJS and is not meant to be accurate. We also have a separate sample that demonstrates the ability to reshape routes between points, instead of only having a simple point-to-point curve. </p> <p> Note that the map is fetched through the <a href="https://mapbox.com/">Mapbox</a> API. Access tokens can expire, and you'll need to get your own token. </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>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> </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>