gojs
Version:
Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams
278 lines (257 loc) • 12.6 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 map integrating a GoJS Diagram and the Leaflet mapping library."/>
<link rel="stylesheet" href="../assets/css/style.css"/>
<!-- Copyright 1998-2023 by Northwoods Software Corporation. -->
<title>Leaflet.js and GoJS</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">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.8.0/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">
function init() {
if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this
/* 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: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 18,
minZoom: 2,
tileSize: 512,
zoomOffset: -1,
id: "mapbox/streets-v11",
accessToken: "pk.eyJ1IjoiZ29qcyIsImEiOiJjaXppcnNkbDgwMzQ3MnFsNDFnY2phb2QwIn0.7AuVKrWdxQnJxa_W7qC3-w"
}).addTo(myLeafletMap);
myLeafletMap.on("zoomend", updateNodes);
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 */
// 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;
myDiagram = new go.Diagram("myDiagramDiv",
{
"InitialLayoutCompleted": e => updatePosition(),
"dragSelectingTool.isEnabled": false,
"animationManager.isEnabled": false,
scrollMode: go.Diagram.InfiniteScroll,
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.ChangedEvent.Transaction &&
(e.propertyName === "FinishedUndo" || e.propertyName === "FinishedRedo")) {
setTimeout(() => updateNodes());
}
},
});
// the node template describes how each Node should be constructed
myDiagram.nodeTemplate =
$(go.Node, "Auto",
{
locationSpot: go.Spot.Center,
cursor: "pointer",
toolTip:
$("ToolTip",
$(go.TextBlock, { margin: 4, textAlign: "center" },
new go.Binding("text", "", d => `${d.key}\n[${d.latlong[0].toFixed(6)}, ${d.latlong[1].toFixed(6)}]`))
)
},
$(go.Shape, "Circle",
{
fill: "rgba(0, 255, 0, .4)", stroke: "#082D47", strokeWidth: 1,
width: 7, height: 7
}),
// 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.
new go.Binding("location", "latlong", data => {
const pos = myLeafletMap.project(data, myLeafletMap.getZoom());
return new go.Point(pos.x, pos.y);
}).makeTwoWay((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];
}
})
);
myDiagram.linkTemplate =
$(go.Link,
{
layerName: "Background",
curve: go.Link.Bezier, curviness: 5,
toolTip:
$("ToolTip",
$(go.TextBlock, { margin: 4, textAlign: "center" },
new go.Binding("text", "", d => `${d.from} -- ${d.to}`)),
)
},
$(go.Shape, { strokeWidth: 3, stroke: "rgba(100,100,255,.7)" })
);
// DraggingTool needs to disable panning of Leaflet map
myDiagram.toolManager.draggingTool.doActivate = function() { // method override must be function, not =>
myLeafletMap.dragging.disable();
go.DraggingTool.prototype.doActivate.call(this);
}
myDiagram.toolManager.draggingTool.doDeactivate = function() { // method override must be function, not =>
myLeafletMap.dragging.enable();
go.DraggingTool.prototype.doDeactivate.call(this);
}
// 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.694500] },
{ key: "Le Havre", latlong: [49.492755, 0.125278] },
{ key: "Rouen", latlong: [49.449031, 1.094128] },
{ key: "Lille", latlong: [50.636379, 3.070620] },
// 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.795480, -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" }
]);
} // 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="http://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.
</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>
</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>