websocket实现GPS数据的实时推送与地图的展示(优化)

原创
03/30 04:05
阅读数 124

概述

前两天,发布了一片文章websocket实现GPS数据的实时推送与地图的展示,文章发出后引来了不少读者的关注,也有不少读者要求做进步一优化。本文应大家的要求,对上文的内容做一个优化,优化地方包括:

  1. 加入了GPS方向的展示;
  2. 加入了GPS精度的展示;
  3. 加入了GPS轨迹的展示;

效果

img1.gif

实现

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)
  }
}

// 执行websocket处理连接方法
io.createServer(con => {
  console.log('new connection...')
  connection = con
  sendData()
  //处理客户端发送过来的消息
  // connection.on("text",function(data){
  //     console.log("接收到的客户端消息:" + data);
  // })
  //监听关闭
  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
          }
        })

        // GPS 位置
        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
    }
  }

本文同步分享在 博客“牛老师讲GIS”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部