Bỏ qua để đến nội dung

Dẫn đường từng bước

Trang này dành cho web (@mapslibvn/web@mapslibvn/react). Bạn đã có tuyến từ client.directions(); phần còn lại chạy trên thiết bị: bám vị trí GPS vào tuyến, biết đang ở bước nào, đọc câu rẽ đúng lúc, phát hiện lệch và tự gọi lại directions(). Máy chủ chỉ tốn tài nguyên lúc tính tuyến.

import 'maplibre-gl/dist/maplibre-gl.css';
import * as maplibregl from 'maplibre-gl';
import { createMap } from '@mapslibvn/web';
const map = createMap(
{ container: 'map', apiKey: 'mlv_live_…', apiBase: 'https://api.ai-solutions.io.vn' },
{ maplibre: maplibregl },
);
// 1. Tính tuyến (tham số [lat, lng]; response dùng [lng, lat])
const response = await map.places.directions({
from: [10.7798, 106.699],
to: [10.7725, 106.698],
mode: 'motorbike',
});
// 2. Vẽ tuyến (tuyến chính, tuyến thay thế nếu có, marker đích)
map.routes.show(response);
map.fitBounds(response.routes[0].bbox, 60);
// 3. Dẫn đường — gọi trong sự kiện bấm nút để trình duyệt cho phép GPS và âm thanh
startButton.onclick = () => map.navigation.start({ response });

start() mở navigator.geolocation.watchPosition, bám mỗi điểm GPS vào tuyến, xoay camera theo hướng đi, đọc câu chỉ dẫn bằng speechSynthesis giọng tiếng Việt và tự tính lại tuyến khi bạn lệch. Gọi map.navigation.stop() để dừng; tuyến vẫn trên bản đồ cho tới khi map.routes.clear().

Muốn thử ngay không cần code: mở Playground → bấm “Dẫn đường”.

SDK không có bảng chỉ dẫn sẵn. Nghe progress và vẽ theo ý bạn:

import { formatDistanceShort } from '@mapslibvn/web';
map.navigation.on('progress', (p) => {
const next = p.nextStep ?? p.step; // bước rẽ sắp tới
icon.dataset.kind = next.kind; // ManeuverKind → icon của bạn
instruction.textContent = next.instruction; // "Rẽ phải vào Nguyễn Du."
distance.textContent = formatDistanceShort(p.distanceToStep_m); // "190 m"
eta.textContent = `${Math.round(p.remaining_s / 60)} phút · ${formatDistanceShort(p.remaining_m)}`;
});
map.navigation.on('arrive', () => banner.textContent = 'Đã đến nơi');
map.navigation.on('offRoute', () => banner.textContent = 'Lệch tuyến, đang tính lại…');
map.navigation.on('positionError', (e) => {
if (e.code === 'denied') banner.textContent = 'Bạn chưa cho phép truy cập vị trí';
});
Sự kiện Payload Khi nào
status { status, previous } idle → navigating → off_route → rerouting → navigating → arrived
progress NavigationProgress mỗi điểm GPS hợp lệ (≈ 1 lần/giây)
step { stepIndex, step } vừa qua một điểm rẽ
waypoint { legIndex, waypoint } qua một điểm dừng via
announce { text, kind, stepIndex, priority } có câu cần đọc — SDK đã đọc nếu voice bật; dùng để hiện phụ đề
offRoute { distance_m, fix } lệch tuyến đã xác nhận (3 điểm GPS liên tiếp và ≥ 5 giây)
reroute { reason, response } có tuyến mới; SDK đã vẽ lại
rerouteFailed { error, attempts, final } gọi lại thất bại; final = true sau 3 lần, SDK ngừng tự gọi
arrive { waypoint, fix } trong bán kính đến nơi
followChange boolean người dùng kéo bản đồ (tắt bám) hoặc recenter()
positionError { code: 'denied' | 'unavailable' | 'timeout', message } lỗi Geolocation
voiceUnavailable máy không có giọng đọc cho ngôn ngữ đã chọn

NavigationProgress có: status, route, legIndex, stepIndex, step, nextStep, snapped ([lng, lat] đã bám), bearing, traveled_m, remaining_m, remaining_s, distanceToStep_m, offRoute_m, fix.

Tuỳ chọn Mặc định Ghi chú
response bắt buộc DirectionsResponse
routeIndex 0 tuyến thay thế nếu alternatives: true
provider map.places ai tính lại tuyến; bất kỳ object có directions(opts)
reroute 'auto' 'manual': chỉ phát offRoute, bạn tự gọi map.navigation.reroute() hoặc start() lại
lang lang của bản đồ 'vi' | 'en' — giọng đọc và câu “Trong X nữa”
voice true false tắt; { rate, volume } chỉnh giọng
follow true false không đụng camera; { zoom, pitch, padding } chỉnh (mặc định zoom 17 / 16,5 / 15,5 cho đi bộ / xe máy / ô tô, pitch 45)
source GPS trình duyệt nguồn vị trí khác — xem giả lập bên dưới
thresholds theo phương tiện ghi đè từng ngưỡng
wakeLock true giữ màn hình sáng khi trình duyệt hỗ trợ

Ngưỡng mặc định theo phương tiện:

đi bộ xe máy ô tô
Lệch tuyến (m, tối thiểu; thực tế = max với 1,5 × sai số GPS) 25 40 50
Đọc “Trong X nữa, …” khi còn (m) 40 200 400
Đọc câu rẽ khi còn (m) 15 50 80
Bán kính đến nơi (m) 15 25 30
Bỏ điểm GPS có sai số hơn (m) 60 100 100

Tính lại tuyến gọi directions()tính vào quota Chỉ đường của khoá; SDK cách hai lần gọi ít nhất 15 giây và dừng sau 3 lần lỗi liên tiếp.

import { playbackSource, simulateFixes } from '@mapslibvn/web';
const route = response.routes[0];
map.navigation.start({
response,
voice: false,
source: playbackSource(simulateFixes(route, { jitter_m: 4 }), { rate: 10 }), // nhanh gấp 10
});

simulateFixes đi dọc tuyến với vận tốc theo phương tiện; jitter_m thêm nhiễu GPS. Muốn thử lệch tuyến, dịch toạ độ một đoạn fix rồi truyền vào playbackSource. Playground → Dẫn đường có nút Giả lập làm đúng việc này.

Máy trạng thái nằm trong @mapslibvn/core, không cần MapLibre hay DOM:

import { createNavigator, createClient } from '@mapslibvn/core';
const client = createClient({ apiKey, baseUrl });
const nav = createNavigator({ response, provider: client });
nav.on('announce', (a) => console.log(a.text));
nav.update({ lng: 106.699, lat: 10.7798, accuracy_m: 8, heading: 160, speed_mps: 4, timestamp: Date.now() });

Đây cũng là phần React Native dùng lại (xem Dẫn đường trên React Native).

import { useNavigation } from '@mapslibvn/react';
function Panel({ response }) {
const { status, progress, start, stop } = useNavigation();
return status === 'idle'
? <button onClick={() => start({ response })}>Bắt đầu</button>
: <div>{progress?.nextStep?.instruction} <button onClick={stop}>Dừng</button></div>;
}

Hook phải nằm trong <MapsLibVNMap>. Xem React mục 6.

  • Cần HTTPS (hoặc localhost) để có Geolocation.
  • Không dẫn đường nền trên web. iOS và Android tạm dừng watchPosition khi tắt màn hình hoặc chuyển app; SDK chỉ giữ màn hình sáng bằng Wake Lock khi có. Dẫn đường nền có ở SDK React Native: Dẫn đường trên React Native.
  • Giọng tiếng Việt tuỳ máy. Safari/iOS có sẵn; Chrome máy tính có khi cần mạng; Android tuỳ gói TTS đã cài. Không có → sự kiện voiceUnavailable, chữ vẫn hiện. Gọi start() trong sự kiện bấm nút để iOS cho phép phát âm.
  • GPS phố hẹp nhiễu 20–50 m là bình thường; ngưỡng lệch đã tính theo sai số GPS. Đứng yên thì hướng mũi tên lấy theo tuyến, không theo la bàn — SDK React Native có la bàn + gyro, xem Dẫn đường trên React Native mục 10.
  • Toạ độ bạn gửi khi tính lại tuyến nằm trong URL request như mọi lượt directions() — xem Điều khoản tenant mục 5.

Đọc thêm: REST API — directions, SDK JavaScript.