ট্র্যাকিং ম্যাপ হল যেকোনো খাদ্য ডেলিভারি বা রাইডশেয়ার অ্যাপের সবচেয়ে বেশি এনগেজমেন্টের স্ক্রিন। এটি সেই স্ক্রিন যেখানে গ্রাহকরা অপেক্ষার সময় তাকিয়ে থাকে। সঠিকভাবে বাস্তবায়ন, মসৃণ গতিবিধি, সঠিক ইটিএ এবং স্পষ্ট রুট লাইন পেশাদার অ্যাপ এবং অবিশ্বাস্য অ্যাপের মধ্যে পার্থক্য তৈরি করে।
এই টিউটোরিয়াল গ্রাহক-মুখী ট্র্যাকিং ম্যাপ তৈরি করে প্রাথমিক নীতি থেকে শুরু করে: একটি ব্যাকএন্ড যা WebSocket এর মাধ্যমে GPS অবস্থান সম্প্রচার করে, একটি ফ্রন্টএন্ড যা সেগুলি গ্রহণ করে এবং ড্রাইভার মার্কারকে ঝাঁপানো ছাড়াই সরায়, MapAtlas Routing API থেকে একটি রুট লাইন এবং একটি লাইভ ইটিএ ডিসপ্লে। সম্পূর্ণ বাস্তবায়ন ৭০ লাইনের কম ক্লায়েন্ট-সাইড জাভাস্ক্রিপ্ট, যেকোনো ব্যাকএন্ডের সাথে একীভূত করার জন্য ডিজাইন করা যা WebSocket বার্তা পুশ করতে পারে।
আর্কিটেকচার খাদ্য ডেলিভারি, গ্রসারি, রাইডশেয়ার, ফিল্ড সার্ভিস এবং অন্য যেকোনো ব্যবহারের ক্ষেত্রে কাজ করে যেখানে একটি যানবাহন একটি নির্দিষ্ট গন্তব্যের দিকে চলে এবং একটি গ্রাহক এটি রিয়েল-টাইমে ঘটতে দেখে।
Architecture Overview
Before writing code, it helps to understand the data flow:
- Driver app (mobile, GPS hardware) sends latitude/longitude to your backend every 3–5 seconds.
- Backend (Node.js, Python, Go, your choice) persists the last known position and broadcasts it via WebSocket to all connected order subscribers.
- Customer browser receives WebSocket messages and moves a marker on the map using interpolated animation.
- Routing API is called once when the order is created to fetch the planned route. The decoded polyline is displayed as a line layer.
- ETA is recalculated by comparing distance remaining to average speed, or by re-calling the Routing API from the driver's current position.
The backend implementation is outside the scope of this tutorial, but any WebSocket server that sends messages in this format works with the frontend code below:
{
"type": "position_update",
"orderId": "order-8821",
"lat": 52.3741,
"lng": 4.8952,
"heading": 92,
"speed": 28,
"timestamp": 1738234521000
}
Step 1: Map Initialisation
Set up the map centred on the delivery origin. The Routing API call happens in Step 4, so for now just initialise the canvas.
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';
const map = new mapmetricsgl.Map({
container: 'tracking-map',
style: 'https://tiles.mapatlas.eu/styles/basic/style.json?key=YOUR_API_KEY',
center: [4.9041, 52.3676],
zoom: 14
});
// Destination marker (restaurant or pickup point)
const destination = [4.9001, 52.3791];
new mapmetricsgl.Marker({ color: '#EF4444' })
.setLngLat(destination)
.setPopup(new mapmetricsgl.Popup().setHTML('<strong>Pickup point</strong>'))
.addTo(map);
Step 2: Driver Marker with Heading Rotation
Create the driver marker separately so you can update its position on each GPS ping. A custom HTML element lets you rotate the marker icon to reflect the driver's heading, a small detail that makes the tracking feel much more realistic.
// Custom element so we can rotate it
const driverEl = document.createElement('div');
driverEl.innerHTML = '🚗';
driverEl.style.cssText = 'font-size:28px;transform-origin:center;transition:transform 0.3s';
const driverMarker = new mapmetricsgl.Marker({ element: driverEl, anchor: 'center' })
.setLngLat([4.9041, 52.3676])
.addTo(map);
function setDriverHeading(heading) {
driverEl.style.transform = `rotate(${heading}deg)`;
}
Step 3: WebSocket Connection and Smooth Interpolation
This is the core of the tracking map. Connecting to the WebSocket is one line; the interesting part is interpolating the marker position between GPS pings so it slides smoothly rather than teleporting.
let prevPos = null; // { lat, lng }
let animFrame = null;
function interpolateMarker(fromLat, fromLng, toLat, toLng, durationMs) {
const startTime = performance.now();
function step(now) {
const elapsed = now - startTime;
const t = Math.min(elapsed / durationMs, 1); // 0 → 1
const lat = fromLat + (toLat - fromLat) * t;
const lng = fromLng + (toLng - fromLng) * t;
driverMarker.setLngLat([lng, lat]);
if (t < 1) {
animFrame = requestAnimationFrame(step);
}
}
if (animFrame) cancelAnimationFrame(animFrame);
animFrame = requestAnimationFrame(step);
}
const ws = new WebSocket('wss://your-backend.example.com/track/order-8821');
ws.addEventListener('message', (event) => {
const msg = JSON.parse(event.data);
if (msg.type !== 'position_update') return;
const { lat, lng, heading } = msg;
if (prevPos) {
// Smooth animation from previous to new position
interpolateMarker(prevPos.lat, prevPos.lng, lat, lng, 400);
} else {
// First ping, place marker immediately
driverMarker.setLngLat([lng, lat]);
map.flyTo({ center: [lng, lat], zoom: 15 });
}
setDriverHeading(heading);
updateETA(lat, lng);
prevPos = { lat, lng };
});
ws.addEventListener('close', () => {
console.log('Driver has arrived or connection closed.');
});
The 400ms interpolation window matches a typical GPS ping interval of 3–5 seconds reasonably well, the marker is always slightly behind reality but never jumps noticeably.
Step 4: Draw the Planned Route from the Routing API
Fetch the full route when the order is assigned. Store the polyline coordinates and draw them as a GeoJSON line layer. The Route Optimization API tutorial covers multi-stop scenarios; for a simple A-to-B delivery the request is straightforward.
async function fetchAndDrawRoute(originLat, originLng, destLat, destLng) {
const url = new URL('https://api.mapatlas.eu/v1/routing/route');
url.searchParams.set('origin', `${originLat},${originLng}`);
url.searchParams.set('destination', `${destLat},${destLng}`);
url.searchParams.set('profile', 'driving');
url.searchParams.set('key', 'YOUR_API_KEY');
const res = await fetch(url);
const data = await res.json();
if (!data.routes?.length) return;
const route = data.routes[0];
map.on('load', () => {
map.addSource('route', {
type: 'geojson',
data: {
type: 'Feature',
geometry: route.geometry // GeoJSON LineString
}
});
map.addLayer({
id: 'route-line',
type: 'line',
source: 'route',
layout: { 'line-join': 'round', 'line-cap': 'round' },
paint: {
'line-color': '#3B82F6',
'line-width': 4,
'line-opacity': 0.8
}
});
});
return route.duration; // seconds
}
Step 5: ETA Calculation and Display
Calculate ETA by comparing the driver's current position to the destination. For high accuracy, re-call the Routing API from the driver's current position every 30 seconds to get a fresh travel time estimate.
function haversineKm(lat1, lon1, lat2, lon2) {
const R = 6371;
const dLat = ((lat2 - lat1) * Math.PI) / 180;
const dLon = ((lon2 - lon1) * Math.PI) / 180;
const a = Math.sin(dLat / 2) ** 2 +
Math.cos((lat1 * Math.PI) / 180) *
Math.cos((lat2 * Math.PI) / 180) *
Math.sin(dLon / 2) ** 2;
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
let lastRouteFetch = 0;
async function updateETA(driverLat, driverLng) {
const [destLng, destLat] = destination;
const distKm = haversineKm(driverLat, driverLng, destLat, destLng);
// Fast client-side estimate (assume 30 km/h urban average)
const minutesEstimate = Math.ceil((distKm / 30) * 60);
document.getElementById('eta').textContent =
distKm < 0.1
? 'Arriving now'
: `ETA: ${minutesEstimate} min (${distKm.toFixed(1)} km)`;
// Re-fetch from Routing API every 30 seconds for accuracy
const now = Date.now();
if (now - lastRouteFetch > 30_000) {
lastRouteFetch = now;
const url = new URL('https://api.mapatlas.eu/v1/routing/route');
url.searchParams.set('origin', `${driverLat},${driverLng}`);
url.searchParams.set('destination', `${destLat},${destLng}`);
url.searchParams.set('profile', 'driving');
url.searchParams.set('key', 'YOUR_API_KEY');
const res = await fetch(url);
const data = await res.json();
if (data.routes?.length) {
const mins = Math.ceil(data.routes[0].duration / 60);
document.getElementById('eta').textContent = `ETA: ${mins} min`;
}
}
}
GDPR Considerations for Driver Tracking
ড্রাইভার GPS স্থানাঙ্ক GDPR আর্টিকেল ৪(১) এর অধীনে ব্যক্তিগত ডেটা। ইউ খাদ্য ডেলিভারি এবং রাইডশেয়ার প্ল্যাটফর্মগুলি এই বিষয়ে যে নিয়মকানুন পরিচালনা করে তা অস্পষ্ট নয়:
ডেটা ন্যূনতমকরণ: শুধুমাত্র ডিসপ্যাচের জন্য প্রয়োজনীয় ক্ষেত্র ট্র্যাক করুন, অবস্থান, শিরোনাম, গতি। অপারেশনালভাবে প্রয়োজনীয় তার বাইরে কাঁচা GPS ইতিহাস লগ করবেন না।
ধারণ সীমা: দানাদার ট্রিপ ট্র্যাকিং ডেটা অর্ডার সম্পূর্ণ হওয়ার পরে মুছে দেওয়া বা অপরিবর্তনীয়ভাবে অজ্ঞানীভূত করা উচিত। একীভূত রুট ডেটা (একজন স্বতন্ত্র ড্রাইভারের সাথে সংযোগ ছাড়াই) নেটওয়ার্ক অপ্টিমাইজেশনের জন্য দীর্ঘতর সংরক্ষণ করা যেতে পারে।
আইনি ভিত্তি: আর্টিকেল ৬(১)(এফ) এর অধীনে বৈধ স্বার্থ রিয়েল-টাইম ডিসপ্যাচ ট্র্যাকিং কভার করে। ট্র্যাকিং ডেটার যেকোনো গৌণ ব্যবহারের জন্য (বিশ্লেষণ, বেঞ্চমার্কিং), আপনাকে একটি পৃথক ভিত্তি নথিভুক্ত করতে হবে।
ড্রাইভার স্বচ্ছতা: ড্রাইভার অনবোর্ডিংয়ে স্পষ্ট ট্র্যাকিং প্রকাশ অন্তর্ভুক্ত করুন। ড্রাইভারদের বলা উচিত কী সংগ্রহ করা হয়, এটি কতক্ষণ ধরে রাখা হয় এবং কে এটি অ্যাক্সেস করতে পারে।
ডেটা আবাস: MapAtlas সমস্ত API অনুরোধ EU এর মধ্যে প্রক্রিয়া করে। এটি US-ভিত্তিক ম্যাপিং প্রদানকারীদের সাথে উদ্ভূত তৃতীয়-দেশ স্থানান্তরের উদ্বেগ দূর করে। সম্পূর্ণ সম্মতির চিত্র দেখতে EU Developer's Guide to GDPR-Compliant Map APIs দেখুন।
রাইডশেয়ারিং এবং মোবিলিটি শিল্প ব্যবহারের ক্ষেত্রে বিশেষভাবে, MapAtlas মান হিসাবে DPA ডকুমেন্টেশন এবং EU সার্ভার গ্যারান্টি অন্তর্ভুক্ত করে। লজিস্টিক এবং ডেলিভারি শিল্প পৃষ্ঠা ফ্লিট এবং মাল্টি-ড্রাইভার পরিস্থিতি কভার করে।
Production Hardening
গ্রাহকদের কাছে ট্র্যাকিং বৈশিষ্ট্য শিপ করার আগে, এই আইটেমগুলি পরীক্ষা করুন:
- WebSocket পুনরায় সংযোগ: সূচকীয় ব্যাকঅফ সহ
ws.addEventListener('close', reconnect)যোগ করুন। মোবাইল নেটওয়ার্ক ঘন ঘন সংযোগ ড্রপ করে। - স্টেল অবস্থান পরিচালনা: যদি 15 সেকেন্ডে কোনও আপডেট না আসে, শেষ অবস্থান দৃশ্যমান রাখার পরিবর্তে একটি "ড্রাইভার স্থানীয়করণ" অবস্থা দেখান।
- আগমন সনাক্তকরণ: যখন
distKm < 0.1, একটি "পৌঁছেছে" অবস্থা ট্রিগার করুন, WebSocket বন্ধ করুন এবং একটি নিশ্চিতকরণ স্ক্রিন দেখান। - ক্যামেরা ড্রাইভার অনুসরণ করে: প্রতিটি অবস্থান আপডেটে
map.panTo([lng, lat])কল করুন ড্রাইভারকে কেন্দ্রে রাখতে। ব্যবহারকারীদের ম্যাপ অন্বেষণ করতে চাইলে ফলো মোড অক্ষম করার জন্য একটি "লক" টগল দিন।
Next Steps
- আপনার বিনামূল্যে MapAtlas API কী এর জন্য সাইন আপ করুন এবং নির্মাণ শুরু করুন
- আপনার ডেলিভারি অ্যাপে মাল্টি-স্টপ ডিসপ্যাচ যোগ করতে Route Optimization API টিউটোরিয়াল পড়ুন
- ডায়নামিক, ডেটা-চালিত ম্যাপ স্তরের আরেকটি উদাহরণের জন্য Real Estate Property Map টিউটোরিয়াল অন্বেষণ করুন
Frequently Asked Questions
How do I show a driver's location moving smoothly on a map?
GPS pings arrive every few seconds, creating visible jumps if you update the marker position directly. Smooth interpolation animates the marker between the previous position and the new one over a short duration (300–500ms), using requestAnimationFrame to move the marker in small increments. This gives the appearance of continuous movement even with infrequent GPS updates.
Is driver location data subject to GDPR?
Yes. A driver's real-time GPS coordinates are personal data under GDPR Article 4. EU food delivery and rideshare platforms must minimise retention, tracking data should be deleted or anonymised once the trip is complete. Processing requires a legal basis and must be disclosed in the driver's privacy notice.
Can I use the MapAtlas Routing API to show the planned route on the tracking map?
Yes. Fetch the route from the Routing API when a trip is created, decode the polyline, and add it as a GeoJSON line layer on the map. As the driver moves, you can optionally re-fetch the route from the current position to recalculate the ETA dynamically.
