深入解析:vue3+arcgisAPI4示例:轨迹点模拟移动(附源码下载)

demo源码运行环境以及配置

运行环境:依赖Node安装环境,需要安装Node。 运行软件:vscode或者其他应用。
配置方式:下载demo源码,vscode打开,然后顺序执行以下命令:
(1)下载demo环境依赖包命令:npm install -g
(2)yarn install
(3)启动demo命令:yarn dev
(4)打包demo命令: yarn build:prod

示例效果
在这里插入图片描述
实现思路

使用模拟数据线图层geojson,获取线的点集合数据,接着点和点之间直线插值点,获取到插值点信息集,最后结合arcgis api
4达成达到轨迹点模拟圆滑移动效果。

核心部分代码

<template>
  <div id="viewDiv">
    <
    /div>
    <div class=
    "titleContainer center">
    <span>vue3+arcgisAPI4示例:轨迹点模拟移动效果<
      /span>
      <
      /div>
      <el-button type="primary" class=
      "buttonRight btn1" @click="starBtn">开始模拟<
      /el-button>
      <el-button type="primary" class=
      "buttonRight btn2" @click="clearBtn">清除模拟<
      /el-button>
      <
      /template>
      <script setup>
        import { onMounted, onUnmounted, ref
        } from "vue";
        import "@arcgis/core/assets/esri/themes/light/main.css";
        import Map from "@arcgis/core/Map";
        import MapView from "@arcgis/core/views/MapView";
        import Basemap from "@arcgis/core/Basemap.js";
        import esriConfig from "@arcgis/core/config";
        import GeoJSONLayer from "@arcgis/core/layers/GeoJSONLayer.js";
        import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer";
        import GroupLayer from "@arcgis/core/layers/GroupLayer.js";
        import Graphic from "@arcgis/core/Graphic.js";
        import Point from "@arcgis/core/geometry/Point.js";
        import { distance
        } from "@arcgis/core/geometry/geometryEngine.js";
        import { geographicToWebMercator
        } from "@arcgis/core/geometry/support/webMercatorUtils.js";
        import { removeElementById
        } from '@/utils/index';
        import axios from "axios";
        let view, map, graphicsLayer = null;
        let animationFrameId = null;
        // 动画帧ID
        let features = [];
        // 存储轨迹点
        onMounted(() =>
        {
        initMap();
        });
        // 组件卸载时取消动画
        onUnmounted(() =>
        {
        if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = null;
        }
        });
        const initMap = () =>
        {
        esriConfig.apiKey = 'AAPKca495ea263b64e44b61eaaecdbddebfcwEQjC8k8-6XGMrrXyCie6xzybboRl4REq-TwDQTm8Wz-8sL6REARz1wcm14Kq9ny';
        // 初始化创建地图对象
        const novaLayer = Basemap.fromId("arcgis-imagery-standard");
        map = new Map({
        // basemap: "satellite",
        basemap: novaLayer,
        });
        // 初始化创建视图view对象
        view = new MapView({
        container: "viewDiv",
        map: map,
        center: [111.69795926864639, 23.2026556059399],
        zoom: 15
        });
        // 去除logo
        view.ui.remove(["attribution", "zoom"]);
        // 监听视图view初始化加载完成执行
        view.when(function () {
        removeElementById('loader-wrapper');
        loadPointLineLayer();
        });
        }
        const loadPointLineLayer = async () =>
        {
        // 使用axios请求获取GeoJSON数据
        const response = await axios.get("./src/views/carTrack/carTrackPoint.geojson");
        const geojsonData = response.data;
        features = geojsonData.features;
        // 创建GeoJSON图层,使用blob URL而不是文件URL
        const blob = new Blob([JSON.stringify(geojsonData)], { type: "application/json"
        });
        const blobUrl = URL.createObjectURL(blob);
        let pointsLayer = new GeoJSONLayer({
        url: blobUrl
        })
        const response1 = await axios.get("./src/views/carTrack/carTrackLine.geojson");
        const geojsonData1 = response1.data;
        // 创建GeoJSON图层,使用blob URL而不是文件URL
        const blob1 = new Blob([JSON.stringify(geojsonData1)], { type: "application/json"
        });
        const blobUrl1 = URL.createObjectURL(blob1);
        let lineLayer = new GeoJSONLayer({
        url: blobUrl1
        })
        const groupLayer = new GroupLayer({
        layers: [
        pointsLayer,
        lineLayer
        ]
        });
        map.add(groupLayer);
        graphicsLayer = new GraphicsLayer({ id: 'graphicsLayer'
        });
        map.add(graphicsLayer);
        }
        const starBtn = () =>
        {
        // 读取模拟车辆轨迹数据
        let points = [];
        // 取消可能存在的动画
        if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = null;
        }
        // 生成所有轨迹点
        for (let i = 0; i < features.length; i++) {
        const feature = features[i];
        if (i !== features.length - 1) {
        points = points.concat(getPointSAlongLine(feature, features[i + 1], 1))
        }
        else {
        points = points.concat(getPointSAlongLine(feature, feature, 1))
        }
        }
        // 使用requestAnimationFrame实现动画
        let currentIndex = 0;
        let lastTimestamp = 0;
        const frameInterval = 100;
        // 控制动画速度,相当于之前的100ms
        const animate = (timestamp) =>
        {
        // 计算时间差
        if (!lastTimestamp) lastTimestamp = timestamp;
        const elapsed = timestamp - lastTimestamp;
        // 当经过的时间超过帧间隔时更新位置
        if (elapsed >= frameInterval) {
        lastTimestamp = timestamp;
        if (currentIndex < points.length) {
        refreshAlarmPoint(points[currentIndex]);
        currentIndex++;
        // 继续动画
        animationFrameId = requestAnimationFrame(animate);
        } else {
        // 动画结束
        animationFrameId = null;
        }
        } else {
        // 如果时间间隔不够,继续等待
        animationFrameId = requestAnimationFrame(animate);
        }
        };
        // 启动动画
        animationFrameId = requestAnimationFrame(animate);
        }
        const clearBtn = () =>
        {
        // 取消可能存在的动画
        if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = null;
        }
        if (graphicsLayer) {
        graphicsLayer.removeAll();
        }
        }
        // 刷新绘制实时报警点
        const refreshAlarmPoint = (point) =>
        {
        if (graphicsLayer) {
        graphicsLayer.removeAll();
        }
        // 创建节点圆圈符号
        const symbol = {
        type: "simple-marker",
        style: "circle",
        color: [255, 255, 255], // 白色填充
        size: 12,
        outline: {
        color: [66, 135, 245], // 蓝色边框
        width: 2
        }
        };
        const graphic = new Graphic({
        geometry: point,
        symbol: symbol
        });
        graphicsLayer.add(graphic);
        }
        /**
        * 计算起点和终点连线上距离起点指定距离的坐标点
        * @param {Array} startPoint - 起点坐标
        * @param {Array} endPoint - 终点坐标
        * @param {Number} dis- 距离起点的距离,单位:米
        * @returns {Array} - 计算得到的坐标点
        */
        ……
        <
        /script>
posted @ 2025-08-04 08:11  yfceshi  阅读(6)  评论(0)    收藏  举报