功能
首先说一下功能,需要在地图上进行车辆落点,通过颜色来区分车辆类型,可以看到车辆动态变化,点击车辆时可看到点击车辆的一些信息
实现思路
初始化地图
首先import引入mapboxgl且初始化地图,并通过websocket接收数据
注意:Mapbox要先设置accessToken,可以在main.js里设置, 也可以在当前组件引入mapboxgl后设置
let map = null;
import mapboxgl from "mapbox-gl";
/**
* 初始化地图,并在地图准备后进行websocket连接接收数据
*/
export function initMap() {
map = new mapboxgl.Map({
container: "map",
style: {
version: 8,
sources: {
"wms-imagery": {
type: "raster",
tiles: ["/commonmaps/{z}/{x}/{y}.png"]
}
},
layers: [
{
id: "blue_map_tgis",
source: "wms-imagery",
"source-layer": "blue_map",
type: "raster"
}
]
},
zoom: 12,
center: [114.05488009848239, 22.542219921599056]
});
map.on("load", async function () {
initWebSocket();
});
}
数据处理函数及websocket连接
websocket连接拿到数据后,对数据进行处理组合成geojson格式,这里我们把数据处理单独抽出来一个函数
/**
* 数据处理
*/
function transformGeoJson(data) {
const geoJSON = {
type: "FeatureCollection",
features: []
};
data.forEach((item) => {
let lng = item.lng / 1000000;
let lat = item.lat / 1000000;
const geo = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [lng, lat]
},
properties: {
info1: "信息1",
info2: "信息2",
info3: "信息3",
info4: "信息4",
info5: "信息5",
}
};
geoJSON.features.push(geo);
});
return geoJSON;
}
/**
* websocket连接
*/
function initWebSocket() {
websock = new WebSocket(`ws://${location.host}/cardata`);
websock.onopen = function () {
console.log("open");
};
websock.onmessage = function websocketonmessage(e) {
const data = JSON.parse(e.data);
const carData = Object.values(data);
const geoJSON = transformGeoJson(carData);
// 判断是否包含了该source,如果包含就通过setData直接更新data,否则第一次就通过addLayer函数添加
const geojsonSource = map.getSource("carDataSource");
if (geojsonSource) {
geojsonSource.setData(geoJSON);
} else {
addLayer(geoJSON, "carDataLayer", "carDataSource");
}
};
websock.onclose = function websocketclose() {
console.log("连接关闭");
};
}
图层添加
处理完拿到geojson数据,通过上方代码map.getSource判断是否包含了该source,如果包含就通过setData直接更新data,这里就是动态更新数据,否则第一次就通过addLayer函数添加,这里颜色通过match来进行匹配,这里我是随机的两种颜色,也可以根据项目自身需求来进行修改
/**
* 添加数据源和添加图层
* @param {*} geoJSON 数据
* @param {*} layerId 图层ID
* @param {*} sourceId SOURCEID
*/
function addLayer(geoJSON, layerId, sourceId) {
map.addSource(sourceId, {
type: "geojson",
data: geoJSON
});
map.addLayer({
id: layerId,
type: "circle",
minzoom: 6,
source: sourceId,
paint: {
"circle-radius": {
base: 1.75,
stops: [
[12, 2],
[22, 180]
]
},
"circle-color": ["match", ["get", "status"], 1, /* 1是绿色 */ "#00DA98", /* 否则红色 */ "#ff0000"]
}
});
changeMapCursor();
handlerPopup()
}
鼠标手势更改
changeMapCursor函数是实现当鼠标移到我们添加的车辆上面时,鼠标变成手型
/**
* 改变鼠标手势
*/
function changeMapCursor() {
const layers = map.getStyle().layers;
layers.forEach((layer) => {
const layerId = layer.id;
if (layerId.includes("carDataLayer")) {
map.on("mousemove", layerId, function () {
map.getCanvas().style.cursor = "pointer";
});
map.on("mouseleave", layerId, function () {
map.getCanvas().style.cursor = "";
});
}
});
}
弹框处理函数
handlerPopup函数是处理点击出现弹框信息,你也可以通过点击拿到feature,填写相关的属性信息
/**
* 弹框函数
*/
function handlerPopup() {
const popup = new mapboxgl.Popup({
closeButton: true, // 如果为 true ,弹窗右上角 将出现关闭按钮
closeOnClick: true // 如果为 true ,点击地图时 弹窗将关闭
});
map.on("click", "carSimLayer", (e) => {
const feature = e.features[0];
const html = `
<div class='info'>
<div class="info-item"><span class="label">车辆信息1:</span>我是信息1</div>
<div class="info-item"><span class="label">车辆信息2:</span> 我是信息2</div>
<div class="info-item"><span class="label">车辆信息3:</span>我是信息3</div>
<div class="info-item"><span class="label">车辆信息4:</span> 我是信息4</div>
<div class="info-item"><span class="label">车辆信息5:</span>我是信息5</div>
</div>
`;
// 弹框位置直接设置在点击的位置
popup.setLngLat(feature.geometry.coordinates).setHTML(html).addTo(map);
});
}
实现效果
到这里基本就已经实现了整个功能,但还有一点不太好的是,更新位置时不是平滑的,是闪烁更新,少了个插值之类的,这个后面再看怎么实现,下面我们看看实现的效果:
扩展
我这里只是简单的用红绿点表示车辆,大家可以替换成车辆BIM模型,效果会更好