openlayers 轨迹回放(历史轨迹),实时轨迹

发布于:2024-06-27 ⋅ 阅读:(17) ⋅ 点赞:(0)

本篇介绍一下使用openlayers轨迹回放(历史轨迹),实时轨迹

1 需求

  • 轨迹回放(历史轨迹)
  • 实时轨迹

2 分析

主要是利用定时器,不断添加feature

  • 轨迹回放(历史轨迹),一般是一次性拿到所有坐标点,按照时间间隔不断循环添加feature
  • 实时轨迹,一般是通过websocket监听,不断获取最新坐标点,根据上报的频率,可能需要抽样

3 实现

<template>
  <div id="map" class="map"></div>
</template>

<script setup lang="ts">
import { Feature, Map, View } from 'ol';
import { LineString, Point } from 'ol/geom';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { get } from 'ol/proj';
import { Vector as VectorSource, XYZ } from 'ol/source';
import { Circle, Fill, Icon, Stroke, Style } from 'ol/style';
import iconSrc from '@/assets/image/truck.png';

const projection = get('EPSG:4326');

const layerTypeMap = {
  vector: ['vec', 'cva'], // [矢量底图, 矢量注记]
  image: ['img', 'cia'], // [影像底图, 影像注记]
  terrain: ['ter', 'cta'] // [地形晕渲, 地形注记]
};

const map = shallowRef();
const source = shallowRef<VectorSource>(new VectorSource());
const trace = ref();

onMounted(() => {
  initMap('image');
  initTrace();
});

const initMap = (layerType = 'image') => {
  const key = '替换为天地图key';

  // c: 经纬度投影 w: 墨卡托投影
  const matrixSet = 'c';
  map.value = new Map({
    target: 'map',
    layers: [
      // 底图
      new TileLayer({
        source: new XYZ({
          url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][0]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
          projection
        })
      }),
      // 注记
      new TileLayer({
        source: new XYZ({
          url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][1]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
          projection
        })
      }),
      new VectorLayer({
        source: source.value,
        style: new Style({
          stroke: new Stroke({
            color: 'rgba(228, 147, 87, 1)',
            width: 3
          })
        })
      })
    ],
    view: new View({
      center: [116.406393, 39.909006],
      projection: projection,
      zoom: 5,
      maxZoom: 17,
      minZoom: 1
    })
  });
};

const initTrace = () => {
  trace.value = [
    [110, 30],
    [110.2, 30],
    [110.4, 30.2],
    [110.8, 30.4],
    [111, 31],
    [111.3, 31],
    [111.6, 31],
    [111.9, 31],
    [112, 31],
    [112.3, 31],
    [112.5, 31],
    [112.8, 31],
    [113, 31],
    [114, 31],
    [115.3, 32],
    [115.5, 32],
    [115.8, 31.8],
    [116, 31.4],
    [116.2, 31.1],
    [116.5, 30.5],
    [115, 30.2],
    [114, 29.8],
    [113, 29.6],
    [112, 29.4],
    [111, 30.2],
    [110, 30.4],
    [109, 30.6],
    [108, 31]
   
  ];
  const iconFeature = new Feature({
    geometry: new Point(trace.value[0])
  });
  const icon = new Icon({
    crossOrigin: 'anonymous',
    src: iconSrc, // 或者new URL('../../assets/svg/truck.svg',import.meta.url).href
    color: 'red',
    opacity: 1,
    width: 30,
    height: 30
  });
  iconFeature.setStyle(
    new Style({
      image: icon
    })
  );

  source.value?.addFeature(iconFeature);
  let i = 0;
  const interval = setInterval(() => {
    if (trace.value[i + 1]) {
      iconFeature.setGeometry(new Point(trace.value[i + 1]));
      let arc = 0;
      if (
        (trace.value[i + 1][0] - trace.value[i][0] >= 0 &&
          trace.value[i + 1][1] - trace.value[i][1] >= 0) ||
        (trace.value[i + 1][0] - trace.value[i][0] < 0 &&
          trace.value[i + 1][1] - trace.value[i][1] > 0)
      ) {
        arc = Math.atan(
          (trace.value[i + 1][0] - trace.value[i][0]) / (trace.value[i + 1][1] - trace.value[i][1])
        );
      } else if (
        trace.value[i + 1][0] - trace.value[i][0] > 0 &&
        trace.value[i + 1][1] - trace.value[i][1] < 0 ||
				trace.value[i + 1][0] - trace.value[i][0] < 0 &&
        trace.value[i + 1][1] - trace.value[i][1] < 0
      ) {
        arc =
          Math.PI +
          Math.atan(
            (trace.value[i + 1][0] - trace.value[i][0]) /
              (trace.value[i + 1][1] - trace.value[i][1])
          );
      } 
     
      icon.setRotation(arc);//设置航向角(与正北的夹角)
      source.value?.addFeature(
        new Feature({
          geometry: new LineString([trace.value[i], trace.value[i + 1]])
        })
      );
      i++;
    } else {
      clearInterval(interval);
    }
  }, 200);
};
</script>
<style scoped lang="scss">
.map {
  width: 100%;
  height: 100%;
}
</style>