← Gallery / Layers
Draw arcs and paths
The same five journeys twice: PathLayer follows the real driving route, ArcLayer curves straight between endpoints.
<!DOCTYPE html>
<!--
Two ways to draw a line between two places, on the same five journeys.
PathLayer follows the road, because the data is the real driving route.
ArcLayer ignores it and curves straight from origin to destination — the
right choice when only the endpoints and the volume matter.
Toggle one layer off in the legend to see the difference clearly.
-->
<html>
<head>
<meta charset="utf-8" />
<title>OnlyMapJS — Draw arcs and paths</title>
<link rel="stylesheet" href="https://unpkg.com/@nika-js/onlymap/dist/onlymapjs.css" />
<script type="module" src="https://unpkg.com/@nika-js/onlymap/dist/onlymap.standalone.js"></script>
<style>
html, body { margin: 0; height: 100%; font-family: system-ui, sans-serif; }
om-map { display: block; height: 100vh; }
</style>
</head>
<body>
<om-map center="[103.86, 1.335]" zoom="11.3" pitch="45" basemap="positron">
<!-- The routes are a plain .geojson of LineString features, exactly what a
routing service returns (these came from OSRM with geometries=geojson).
$geometry.coordinates reaches into the feature's own geometry, so the
file needs no reshaping first.
width-units="pixels" matters: deck.gl measures width in metres by
default, so a 4 m road vanishes as soon as you zoom out. -->
<om-layer id="routes" type="PathLayer"
data="../../data/sg-routes.geojson"
label="Driving route (follows roads)" color="#dc2626"
get-path="$geometry.coordinates"
get-color="[220, 38, 38]"
get-width="4"
width-units="pixels"
width-min-pixels="2"
cap-rounded joint-rounded
pickable></om-layer>
<!-- Same five journeys as straight arcs. Two positions per row instead of
a path, and two colours so direction reads at a glance — the source
colour fades into the target colour along the curve.
get-height controls how far the arc bows off the ground. -->
<om-layer id="flows" type="ArcLayer"
data="../../data/sg-commutes.json"
label="Commute flow (endpoints only)" color="#0ea5e9"
get-source-position="[$from_lon, $from_lat]"
get-target-position="[$to_lon, $to_lat]"
get-source-color="[14, 165, 233, 200]"
get-target-color="[249, 115, 22, 220]"
get-width="scale($trips, sqrt, [2, 10], domain=[0, 22000])"
get-height="0.5"
width-units="pixels"
pickable></om-layer>
<om-widget type="legend" title="Layers" interactive position="top-right"></om-widget>
<om-widget type="zoom-controls" position="bottom-right"></om-widget>
<om-widget type="scale-bar" position="bottom-left"></om-widget>
<om-overlay id="route-detail" anchor-from="selection" visible="false">
<style>
.card { background: #fff; padding: 8px 12px; border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,.2); font-size: 13px; white-space: nowrap; }
.card em { color: #64748b; font-style: normal; }
</style>
<div class="card"><strong>{{name}}</strong><br /><em>{{distance_km}} km · {{duration_min}} min by road</em></div>
</om-overlay>
<om-behavior on="click" layer="routes" action="show-overlay" target="route-detail"></om-behavior>
<om-overlay id="flow-detail" anchor-from="selection" visible="false">
<style>
.card { background: #fff; padding: 8px 12px; border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,.2); font-size: 13px; white-space: nowrap; }
.card em { color: #64748b; font-style: normal; }
</style>
<div class="card"><strong>{{from}} → {{to}}</strong><br /><em>{{trips}} trips each morning</em></div>
</om-overlay>
<om-behavior on="click" layer="flows" action="show-overlay" target="flow-detail"></om-behavior>
<om-widget type="attribution"
text="Routes generated with OSRM from OpenStreetMap data © OpenStreetMap contributors, ODbL"
position="bottom-start"></om-widget>
<om-fallback>
<p style="font: 15px system-ui, sans-serif; padding: 24px; max-width: 42ch">
<strong>This map needs JavaScript.</strong><br />
Open this file in a web browser such as Chrome, Safari, or Firefox.
</p>
</om-fallback>
</om-map>
</body>
</html>
The snippet above loads the latest release. The demo above it is pinned to v0.5.2, so it keeps working when a new version ships.