Series Leaflet Tutorials | Bài 3: Bùng nổ dữ liệu - Quản lý hàng nghìn thiết bị với MarkerCluster
Khi làm hệ thống bản đồ cho Metro, bạn sẽ quản lý hàng ngàn thiết bị đầu cuối tại 14 trạm (hoặc nhiều hơn). Nếu hiển thị tất cả cùng lúc, bản đồ sẽ bị "rác". MarkerCluster là giải pháp cứu cánh: nó tự động gom các Marker gần nhau thành một "cụm" (cluster) khi ở mức Zoom thấp, và bung ra khi người dùng Zoom vào gần.
1. Cài đặt MarkerCluster
Đây là một plugin mở rộng của Leaflet. Bạn cần nhúng thêm file CSS và JS từ CDN:
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css" />
<script src="https://unpkg.com/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js"></script>
2. Thực hành: Gom nhóm hàng nghìn thiết bị AFC
Giả sử bạn có một danh sách dữ liệu các cổng soát vé từ database trả về dạng JSON.
// 1. Tạo một đối tượng markerClusterGroup
var markers = L.markerClusterGroup({
spiderfyOnMaxZoom: true, // Bung ra khi click vào cụm ở mức zoom cao nhất
showCoverageOnHover: true, // Hiện vùng bao quanh các marker khi hover vào cụm
zoomToBoundsOnClick: true // Zoom vào vùng chứa các marker khi click vào cụm
});
// 2. Giả lập dữ liệu thiết bị AFC từ server
var afcDevices = [
{lat: 10.7766, lng: 106.7009, name: "FAM-01-Bến Thành"},
{lat: 10.7767, lng: 106.7010, name: "FAM-02-Bến Thành"},
{lat: 10.7812, lng: 106.6975, name: "TVM-01-Nhà Hát TP"},
// ... hàng trăm thiết bị khác
];
// 3. Thêm các marker vào nhóm thay vì trực tiếp vào bản đồ
afcDevices.forEach(function(device) {
var marker = L.marker([device.lat, device.lng])
.bindPopup(device.name);
markers.addLayer(marker);
});
// 4. Thêm cả cụm marker vào bản đồ
map.addLayer(markers);
3. Tối ưu trải nghiệm cho kỹ sư vận hành
Đối với hệ thống Metro, ngoài việc gom nhóm, bạn có thể tùy chỉnh màu sắc của cụm dựa trên tình trạng thiết bị (Ví dụ: Cụm có màu đỏ nếu có thiết bị đang bị lỗi):
var markers = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
var count = cluster.getChildCount();
var className = 'my-cluster-label';
// Logic: Nếu có thiết bị lỗi (ví dụ trong cluster có marker đỏ), cụm sẽ màu đỏ
return L.divIcon({
html: '<b>' + count + '</b>',
className: className,
iconSize: L.point(40, 40)
});
}
});
Tại sao kỹ thuật này lại sống còn?
- Performance: Leaflet chỉ cần render các phần tử thực sự hiện diện trong Viewport, giúp trình duyệt không bị treo (Memory leak).
- UX: Giúp nhân viên vận hành tập trung vào khu vực cần thiết thay vì hoa mắt bởi hàng ngàn icon thiết bị.
Clarity: Khi zoom vào, dữ liệu được bung ra tự nhiên, giúp quản lý phân tầng từ trạm (station) xuống đến từng cổng (gate).
Vậy là bạn đã có kỹ thuật để "cân" hàng nghìn thiết bị trên bản đồ rồi!
Ở Bài 4, bạn muốn chúng ta làm việc với GeoJSON – cách mà server (Laravel) trả về dữ liệu hình học (tuyến đường, vùng ga) và bạn chỉ cần dùng Leaflet để "vẽ" lại chúng tự động, hay là chuyển sang làm việc với sự kiện (Event Handling) để click vào ga là hiện ra thông tin trạng thái thiết bị thời gian thực?
All rights reserved