Truck route with options
Truck route with options
Choose the profile driving-truck and give weight and height: roads with matching bans and limits are avoided, and the response reports the kilometres subject to the GO toll. For cars (driving) you can avoid tolls and motorways and get up to two alternatives. Click start and destination.
Click the map for the start, then for the destination.
Code
// Truck route: start and destination by click, vehicle size, avoid tolls and motorways, alternatives in grey.
const TOKEN = 'YOUR_TOKEN'; // your public token (mx_pk_…) from https://account.mapx.at
// Adds the token to every request MapLibre makes to mapx.at (style, tiles, fonts, sprites), never to other hosts.
const transformRequest = (url) => ({ url: /^https:\/\/([\w-]+\.)?mapx\.at\//.test(url) ? url + (url.includes('?') ? '&' : '?') + 'access_token=' + TOKEN : url });
const AUTH = { headers: { Authorization: 'Bearer ' + TOKEN } };
maplibregl.addProtocol('pmtiles', new pmtiles.Protocol().tile);
const map = new maplibregl.Map({ transformRequest, container: 'map', style: 'https://api.mapx.at/v1/styles/streets', center: [15.4, 48.2], zoom: 8 });
map.addControl(new maplibregl.NavigationControl());
const $ = (id) => document.getElementById(id);
const pts = [], markers = [];
map.on('load', () => {
map.addSource('routes', { type: 'geojson', data: { type: 'FeatureCollection', features: [] } });
map.addLayer({ id: 'routes', type: 'line', source: 'routes', layout: { 'line-cap': 'round' }, paint: { 'line-color': ['case', ['==', ['get', 'main'], 1], '#2346d8', '#9aa4b8'], 'line-width': ['case', ['==', ['get', 'main'], 1], 6, 4] } });
});
map.on('click', (e) => {
if (pts.length === 2) { pts.length = 0; markers.splice(0).forEach((m) => m.remove()); }
pts.push([e.lngLat.lng, e.lngLat.lat]);
markers.push(new maplibregl.Marker({ color: pts.length === 1 ? '#1d7f4e' : '#c8372d' }).setLngLat(e.lngLat).addTo(map));
if (pts.length === 2) route();
});
for (const id of ['profile', 'toll', 'motorway', 'weight', 'height']) $(id).addEventListener('change', () => pts.length === 2 && route());
async function route() {
const profile = $('profile').value, q = new URLSearchParams({ overview: 'full', geometries: 'geojson', alternatives: 'true' });
if (profile === 'driving-truck') { q.set('weight', $('weight').value); q.set('height', $('height').value); q.delete('alternatives'); }
const exclude = ['toll', 'motorway'].filter((k) => $(k).checked);
if (profile === 'driving' && exclude.length) q.set('exclude', exclude.join(','));
try {
const res = await fetch(`https://api.mapx.at/v1/directions/${profile}/${pts.map((p) => p.join(',')).join(';')}?${q}`, AUTH);
if (!res.ok) throw new Error((await res.json()).detail ?? 'HTTP ' + res.status);
const { routes } = await res.json();
map.getSource('routes').setData({ type: 'FeatureCollection', features: routes.map((r, i) => ({ type: 'Feature', properties: { main: i === 0 ? 1 : 0 }, geometry: r.geometry })).reverse() });
const r = routes[0];
$('info').textContent = `${(r.distance / 1000).toFixed(1)} km, ${Math.round(r.duration / 60)} min` + (r.toll?.truck_go_km != null ? `, ${r.toll.truck_go_km.toFixed(1)} km subject to GO toll` : '') + (routes.length > 1 ? `, ${routes.length - 1} alternative(s)` : '');
} catch (err) { $('info').textContent = 'Error: ' + err.message; }
}Complete HTML file
Save and open in a browser. All it needs is MapLibre GL JS 4.7.1 and pmtiles 3.2.1 from a CDN, plus your public token (replace YOUR_TOKEN), no build.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>mapx Beispiel</title>
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css">
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
<script src="https://unpkg.com/pmtiles@3.2.1/dist/pmtiles.js"></script>
<style>html,body{margin:0;font:14px system-ui,sans-serif}#map{height:70vh}</style>
</head>
<body>
<label>Profile <select id="profile"><option value="driving-truck">Truck</option><option value="driving">Car</option></select></label><label>Weight t <input id="weight" type="number" value="40" min="0.5" max="60" step="0.5" style="width:5rem"></label><label>Height m <input id="height" type="number" value="4" min="1.5" max="5" step="0.1" style="width:5rem"></label><label><input id="toll" type="checkbox"> no toll (car)</label><label><input id="motorway" type="checkbox"> no motorway (car)</label>
<div id="map"></div>
<p id="info">Click the map for the start, then for the destination.</p>
<script>
// Truck route: start and destination by click, vehicle size, avoid tolls and motorways, alternatives in grey.
const TOKEN = 'YOUR_TOKEN'; // your public token (mx_pk_…) from https://account.mapx.at
// Adds the token to every request MapLibre makes to mapx.at (style, tiles, fonts, sprites), never to other hosts.
const transformRequest = (url) => ({ url: /^https:\/\/([\w-]+\.)?mapx\.at\//.test(url) ? url + (url.includes('?') ? '&' : '?') + 'access_token=' + TOKEN : url });
const AUTH = { headers: { Authorization: 'Bearer ' + TOKEN } };
maplibregl.addProtocol('pmtiles', new pmtiles.Protocol().tile);
const map = new maplibregl.Map({ transformRequest, container: 'map', style: 'https://api.mapx.at/v1/styles/streets', center: [15.4, 48.2], zoom: 8 });
map.addControl(new maplibregl.NavigationControl());
const $ = (id) => document.getElementById(id);
const pts = [], markers = [];
map.on('load', () => {
map.addSource('routes', { type: 'geojson', data: { type: 'FeatureCollection', features: [] } });
map.addLayer({ id: 'routes', type: 'line', source: 'routes', layout: { 'line-cap': 'round' }, paint: { 'line-color': ['case', ['==', ['get', 'main'], 1], '#2346d8', '#9aa4b8'], 'line-width': ['case', ['==', ['get', 'main'], 1], 6, 4] } });
});
map.on('click', (e) => {
if (pts.length === 2) { pts.length = 0; markers.splice(0).forEach((m) => m.remove()); }
pts.push([e.lngLat.lng, e.lngLat.lat]);
markers.push(new maplibregl.Marker({ color: pts.length === 1 ? '#1d7f4e' : '#c8372d' }).setLngLat(e.lngLat).addTo(map));
if (pts.length === 2) route();
});
for (const id of ['profile', 'toll', 'motorway', 'weight', 'height']) $(id).addEventListener('change', () => pts.length === 2 && route());
async function route() {
const profile = $('profile').value, q = new URLSearchParams({ overview: 'full', geometries: 'geojson', alternatives: 'true' });
if (profile === 'driving-truck') { q.set('weight', $('weight').value); q.set('height', $('height').value); q.delete('alternatives'); }
const exclude = ['toll', 'motorway'].filter((k) => $(k).checked);
if (profile === 'driving' && exclude.length) q.set('exclude', exclude.join(','));
try {
const res = await fetch(`https://api.mapx.at/v1/directions/${profile}/${pts.map((p) => p.join(',')).join(';')}?${q}`, AUTH);
if (!res.ok) throw new Error((await res.json()).detail ?? 'HTTP ' + res.status);
const { routes } = await res.json();
map.getSource('routes').setData({ type: 'FeatureCollection', features: routes.map((r, i) => ({ type: 'Feature', properties: { main: i === 0 ? 1 : 0 }, geometry: r.geometry })).reverse() });
const r = routes[0];
$('info').textContent = `${(r.distance / 1000).toFixed(1)} km, ${Math.round(r.duration / 60)} min` + (r.toll?.truck_go_km != null ? `, ${r.toll.truck_go_km.toFixed(1)} km subject to GO toll` : '') + (routes.length > 1 ? `, ${routes.length - 1} alternative(s)` : '');
} catch (err) { $('info').textContent = 'Error: ' + err.message; }
}
</script>
</body>
</html>APIs used
- Directions
GET api.mapx.at/v1/directions/{profile}/{coordinates}