概述
前两天,发布了一片文章websocket实现GPS数据的实时推送与地图的展示,文章发出后引来了不少读者的关注,也有不少读者要求做进步一优化。本文应大家的要求,对上文的内容做一个优化,优化地方包括:
- 加入了GPS方向的展示;
- 加入了GPS精度的展示;
- 加入了GPS轨迹的展示;
效果
实现
node模拟数据
const io = require('nodejs-websocket')
let connection = null
let gps = {}
for (let i = 0; i < 20; i++) {
gps['gps' + i] = {
offsetX: randomNum(-0.0001, 0.0001),
offsetY: randomNum(-0.0001, 0.0001),
accuracy: randomNum(50, 200)
}
}
io.createServer(con => {
console.log('new connection...')
connection = con
sendData()
connection.on("close", function (code, reason) {
console.log("Connection closed")
})
connection.on("error",() => {
console.log('服务异常关闭...')
})
}).listen(3000)
function sendData() {
connection.sendText(getGpsPositions())
setTimeout(sendData, 1000)
}
function getGpsPositions() {
const [xmin, ymin, xmax, ymax] = [113.9875, 22.51947, 114.1066, 22.5711]
let data = []
for (let k in gps) {
const d = gps[k]
let {lon, lat} = d
if(!d.lon) {
d.lon = randomNum(xmin, xmax)
d.lat = randomNum(ymin, ymax)
d.rotate = 0
} else {
d.lon = d.lon + d.offsetX
d.lat = d.lat + d.offsetY
const angle = Math.atan2((lat - d.lat), (d.lon - lon))
d.rotate = angle * (180/Math.PI)
}
data.push({
code: k,
coords: [d.lon, d.lat],
accuracy: d.accuracy + randomNum(-0.5, 0.5),
rotate: d.rotate
})
}
return JSON.stringify(data)
}
function randomNum(min, max){
return Math.random() * (max - min) + min
}
mapboxgl实现
map.on('load', () => {
const icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAD+SURBVFhH7ZahDsIwFEUbFB5PMJgJHEFg8GDxfAAeyT4EQ8CA5DNQkPA/4zQ8yMsCC13bIehNTpYtffe2b1s3k5SUVFZhTA5DOY2ulhy1enBmEhdYQvtxuSER2IeixB4mMiS+CDuocM0NVtCRoXFEwEACqzjCVErCC/OdCqvCdmUNXSkNIwxHEuCC7cpcLPyF2UaZu/DsSiZW9YTBUAx98OsKxVdl5oPtSi62L73biMoK+XAxBwcxeiaz96H+LaDwpIxc8H8IKa6z+nCvIUbfrj78RoTZWMyriLcVY/xp9Xa1cT9GmGcSpmnuc0zQVkJ/9kOygMZ+yZKS/l3G3AESgItFg3XtsAAAAABJRU5ErkJggg=='
const arrow = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAnElEQVQ4T63TsQ0CMQyF4f/NgMQQ0CBR0FIx190cFIiWhhFoKdgEiRUeSoF0gO8cjkub+Evs2OLPpc9422dgBRwlNZn/BtjeApdOUJsh0QuuwKYWiYAFcAKWHaSR1EbpfAHlkO0ICdMJgV+QXmAAmUu6v9IZA8wkPVKgtg7TF7H25t4UbN+A9ahGmqqVD8AO2GdzUF45+I3ZJJb9JxbwRhEhB66xAAAAAElFTkSuQmCC'
map.loadImage(icon, (error1, image1) => {
if (error1) throw error1;
map.addImage('red-arrow', image1);
map.loadImage(arrow, (error, image) => {
if (error) throw error;
map.addImage('white-arrow', image);
map.addSource('accuracy', {
type: 'geojson',
data: getGeojson([])
});
map.addLayer({
id: "accuracy",
type: "fill",
source: "accuracy",
paint: {
"fill-color": 'red',
'fill-opacity': 0.1
}
});
map.addSource('route', {
type: 'geojson',
data: getGeojson([])
});
map.addLayer({
id: "route",
type: "line",
source: "route",
'layout': {
'line-cap': 'round',
'line-join': 'round'
},
'paint': {
'line-color': '#09801a',
'line-width': 8
}
});
map.addLayer({
'id':'route-arrow',
'source': 'route',
'type': 'symbol',
'layout': {
'symbol-placement': 'line',
'symbol-spacing': 50,
'icon-image': 'white-arrow',
'icon-size': 0.5,
'icon-allow-overlap': true
}
})
map.addSource('points', {
type: 'geojson',
data: getGeojson([])
});
map.addLayer({
id: "circle",
"type": "symbol",
source: "points",
layout: {
'icon-image': 'red-arrow',
'icon-size': 0.8,
'icon-rotate': ['get', 'rotate'],
'icon-allow-overlap': true
}
});
ws = new WebSocket("ws://localhost:3000")
ws.onopen = function() {
console.log("当前客户端已经连接到websocket服务器")
}
let routeCoords = {}
ws.onmessage = function (evt) {
const data = JSON.parse(evt.data)
let accuracyFeatures = []
let routeFeatures = []
let features = data.map(d => {
const pt = {
"type":"Feature",
"properties": d,
"geometry":{
"type":"Point",
"coordinates": d.coords
}
}
if(!routeCoords[d.code]) routeCoords[d.code] = []
routeCoords[d.code].push(d.coords)
if(routeCoords[d.code].length > 1) routeFeatures.push(turf.lineString(routeCoords[d.code]))
const circle = turf.buffer(pt, d.accuracy / 1000)
accuracyFeatures.push(circle)
return pt
})
map.getSource('accuracy').setData(getGeojson(accuracyFeatures))
map.getSource('route').setData(getGeojson(routeFeatures))
map.getSource('points').setData(getGeojson(features))
};
ws.onclose = function(){
alert("连接已关闭...");
};
})
});
})
function getGeojson(features) {
return {
"type": "FeatureCollection",
"features": features
}
}
|