Ở bài viết trước tôi đã sử dụng thư viện leafletjs để Code mô phỏng lộ trình của xe taxi chạy trên bản đồ. Tiếp tục ở bài viết này tôi mô phỏng một xí nghiệp khoảng 50 xe chạy trực tuyến trên bản đồ. Ở đây dữ liệu trực tuyến là mô phỏng. Trong thực tế các bạn có thể sử dụng websocket, signalR để push trực tiếp dữ liệu xe (có thể từ hộp đen hoặc một nguồn dữ liệu nào đó) và hiển thị trên bản đồ theo thời gian thực.

  • Biển số
  • Tọa độ

Click vào xe hoặc chọn chọn xe ở table bên trái để theo dõi lộ trình.

Cũng tương tự như mô phỏng lộ trình của một xe, thì ở mô phỏng nhiều xe cũng có 2 phần hiển thị là bảng bên trái sẽ hiển thị danh sách các xe và bản đồ. Vì vậy tôi cũng khai báo class View như sau:

var View = function ()
{
    this.online = null;
    this.onAdd = function () { };
    this.show = function (vehicle) { };     // Nhận trạng thái xe hiện thời và hiển thị
    this.active = function (vehicle) { };   // Khi một xe được lựa chọn thì sẽ active để xem riêng xe đó nổi bật hơn
    this.deactive = function (vechile) { }; // Bỏ focus về xe đang được xem
}

Để hiển thị danh sách xe bên bảng bên trái tôi tạo class TableView kế thừa tới View như sau:

var TableView = function ()
{
    $.extend(this, new View());
    this.container = null;
    var tableBody = null;

    this.onAdd = function ()
    {            
        this.container.find(".area-online").remove();
        var area = $("<div class='area-online box' style='position:absolute; width: 190px; bottom: 2px; left: 2px; z-index:999; padding: 1px'>");
        area.append(article.find("[data-form=template]").html());
        this.container.append(area);
        tableBody = area.find(".table-ul-body .table-ul");
    }
    
    // Khi tín hiệu xe được gửi xuống client => sẽ hiển thị tọa độ của xem ở bên bảng bên trái
    this.show = function (vehicle)
    {
        if (vehicle.row == null)
        {
            var $this = this;
            var row = $("<ul>"); row.css("cursor", "pointer");
            row.append("<li class='col0'>{0}</li>".format(vehicle.VehiclePlate));
            var col2 = $("<li class='col3'></li>"); row.append(col2);
            vehicle.row = row;
            vehicle.col2 = col2;                
            vehicle.row.click(function () { $this.online.active(vehicle); });
            tableBody.append(row);
        }
        
        vehicle.col2.html("{0}, {1}".format(vehicle.state.v, vehicle.state.k));
    }
    this.active = function (vehicle) { vehicle.row.addClass("bg-success text-white"); };     // Xe được chọn thì cho thành màu xanh
    this.deactive = function (vehicle) { vehicle.row.removeClass("bg-success text-white"); };
}

Để hiển thị các xe đang online trên bản đồ tôi tạo ra class MapView kế thừa tới View như sau:

var MapView = function ()
{
    $.extend(this, new View());
    this.map = null;

    var vehicleIcons = [];        
    for (var i = 0; i <= 7; i++)
    {
        vehicleIcons.push("/Projects/Web/Modules/Examples/CodeFun/MapVehicleTracking/icons/{0}.png".format(i));            
    }

    // Khi nhận được tín hiệu xe thì sẽ cập nhật tọa độ của xe và hiển thị trên bản đồ
    // Có tính toán hướng xe sau mỗi lần nhận tín hiệu
    this.show = function (vehicle)
    {
        if (vehicle.marker == null)
        {
            var $this = this;
            vehicle.marker = L.marker([vehicle.state.v, vehicle.state.k], { zIndexOffset: 1000 });
            var iconElement = $("<div><div class='badge badge-secondary' style='font-size:10px'>{0}</div><img src='' /></div>".format(vehicle.VehiclePlate));
            var markerIcon = L.divIcon({ className: 'vehicle-icon', html: iconElement[0] });
            vehicle.marker.setIcon(markerIcon);
            vehicle.imgIcon = iconElement.find("img");
            vehicle.labelPlate = iconElement.find(".badge");
            vehicle.marker.addTo(this.map);
            vehicle.imgIcon.attr("src", vehicleIcons[Core.random(8)]);
            vehicle.marker.on("click", function () { $this.online.active(vehicle); });
        }
        else
        {
            if (vehicle.oldState == null) vehicle.direction = Core.random(8);
            else vehicle.direction = getDir(vehicle.direction, vehicle.oldState.v, vehicle.oldState.k, vehicle.state.v, vehicle.state.k);

            vehicle.marker.setLatLng(L.latLng(vehicle.state.v, vehicle.state.k));
            vehicle.imgIcon.attr("src", vehicleIcons[vehicle.direction]);

            if (vehicle.active)
                this.active(vehicle);
        }
    }
    
    // Bản đồ sẽ di chuyển theo xe nếu như xe được chọn
    this.active = function (vehicle)
    {
        vehicle.labelPlate.removeClass("badge-secondary").addClass("badge-danger");
        this.map.panTo(vehicle.marker.getLatLng(), { animate: true });
    }
    this.deactive = function (vehicle)
    {
        vehicle.labelPlate.removeClass("badge-danger").addClass("badge-secondary");
    }
}

Và cuối cùng tôi khai báo một class Online. Tại class này sẽ có phương thức nhận dữ liệu và truyền gửi tới các View để hiển thị thông tin xe

var Online = function ()
{
    var views = []; // Các view để thực hiện hiển thị xe
    var vehicles = {};
    
    // Code Code
    
    // Nhận trạng thái các xe và gửi tới các view
    this.receive = function (vehiclePlate, vehicleState)
    {
        var vehicle = vehicles[vehiclePlate];
        if (vehicle == null) vehicle = vehicles[vehiclePlate] = { VehiclePlate: vehiclePlate };
        
        // Code code
        withView(function (v) { v.show(vehicle); });
    }
    
    // Code Code
}

Khai báo và sử dụng class Online như sau

var online = new Online();

var tableView = new TableView();
tableView.container = divMapId;
online.addView(tableView);

var mapView = new MapView();
mapView.map = map;
online.addView(mapView);

Như vậy là các bước chuẩn bị cho việc hiển thị xe trực tuyến trên bản đồ đã hoàn tất. Nhiệm vụ bây giờ chỉ việc đẩy dữ liệu từ server gửi về client để hiển thị. Như tôi đã nói ở đầu bài viết là chúng ta có thể sử dụng websocket để đẩy dữ liệu về. Sau khi nhận được dữ liệu từ server push về thì sẽ gọi phương thức online.receive(vehiclePlate, state). và chúng ta sẽ thấy các xe của xí nghiệp chuyển động trên bản đồ.

Để xem mã nguồn các bạn có thể click vào đây. Để xem dữ liệu demo các bạn click vào đây.

Nếu các bạn thấy mô phỏng này hay và bổ ích. Hãy like và share để mình có động lực làm các mô phỏng tiếp theo nhé.

Sơn 20