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>