Measure Distance on Map
Let users measure distances by clicking on the map. Draws a polyline, shows live distance in kilometers & meters, and allows removing points by clicking them again.
Features
- Click to add points
- Click an existing point to remove it
- Real-time distance calculation (Turf.js)
- Clean visual feedback with red markers & line
- Double-click zoom disabled for smooth experience
Full Working Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Measure Distance</title>
<link
rel="stylesheet"
href="https://unpkg.com/bkoi-gl@latest/dist/style/bkoi-gl.css"
/>
<script src="https://unpkg.com/bkoi-gl@latest/dist/iife/bkoi-gl.js"></script>
<script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body,
#map {
height: 100%;
font-family: system-ui, sans-serif;
overflow: hidden;
}
#info {
position: absolute;
top: 12px;
left: 12px;
z-index: 10;
pointer-events: none;
}
.box {
background: rgba(15, 15, 20, 0.88);
color: #fff;
padding: 10px 16px;
border-radius: 12px;
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
min-width: 240px;
font-size: 14px;
line-height: 1.5;
}
.title {
color: #ffb800;
font-weight: 600;
margin-bottom: 4px;
}
.dist {
font-size: 18px;
font-weight: 700;
color: #4ade80;
letter-spacing: 0.5px;
}
.sub {
color: #aaa;
font-size: 13px;
}
</style>
</head>
<body>
<div id="map"></div>
<div id="info">
<div class="box">
<div class="title">Distance Measurement</div>
<div id="msg" style="color: #ffdd00">Click map to start measuring</div>
</div>
</div>
<script>
const map = new bkoigl.Map({
container: "map",
style: "https://map.barikoi.com/styles/barikoi-light/style.json",
center: [90.37008547313786, 23.79253097629713],
zoom: 9,
accessToken: "YOUR_BARIKOI_API_KEY",
});
const info = document.getElementById("msg");
const points = [];
const data = { type: "FeatureCollection", features: [] };
map.on("load", () => {
map.addSource("measure", { type: "geojson", data });
map.addLayer({
id: "pts",
type: "circle",
source: "measure",
paint: {
"circle-radius": 9,
"circle-color": "#ff3b30",
"circle-stroke-width": 3,
"circle-stroke-color": "#fff",
},
filter: ["==", "$type", "Point"],
});
map.addLayer({
id: "line",
type: "line",
source: "measure",
paint: {
"line-color": "#ff3b30",
"line-width": 5,
"line-opacity": 0.9,
},
filter: ["==", "$type", "LineString"],
});
map.on("click", (e) => {
const hit = map.queryRenderedFeatures(e.point, { layers: ["pts"] });
data.features = data.features.filter(
(f) => f.geometry.type !== "LineString"
);
if (hit.length) {
const id = hit[0].properties.id;
points.splice(
points.findIndex((p) => p.properties.id === id),
1
);
} else {
points.push({
type: "Feature",
geometry: {
type: "Point",
coordinates: [e.lngLat.lng, e.lngLat.lat],
},
properties: { id: Date.now() + "" },
});
}
data.features = [...points];
if (points.length > 1) {
const line = turf.lineString(
points.map((p) => p.geometry.coordinates)
);
data.features.push(line);
const km = turf.length(line);
info.innerHTML = `
`;
} else {
info.innerHTML = points.length
? `<div style="color:#4ade80">Point added • Click to continue</div>`
: `<div style="color:#ffdd00">Click map to start measuring</div>`;
}
map.getSource("measure").setData(data);
});
map.on("mousemove", (e) => {
map.getCanvas().style.cursor = map.queryRenderedFeatures(e.point, {
layers: ["pts"],
}).length
? "pointer"
: "crosshair";
});
map.doubleClickZoom.disable();
});
</script>
</body>
</html>
How It Works
| Action | Result |
|---|---|
| Click empty area | Adds a red marker |
| Click a marker | Removes that point |
| 2+ points | Draws line & shows live distance |
| New click | Rebuilds entire measurement |
Measure anything — instantly and beautifully.