af-mobile-client-vue3 1.1.43 → 1.1.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
WebGLPointOptions,
|
|
16
16
|
WMSLayerConfig,
|
|
17
17
|
WMSOptions,
|
|
18
|
+
TrackData,
|
|
18
19
|
} from './types'
|
|
19
20
|
import locationIcon from '@af-mobile-client-vue3/assets/img/component/positioning.png'
|
|
20
21
|
import { getConfigByName } from '@af-mobile-client-vue3/services/api/common'
|
|
@@ -23,11 +24,12 @@ import { Map, View } from 'ol'
|
|
|
23
24
|
import { defaults as defaultControls, ScaleLine } from 'ol/control'
|
|
24
25
|
import Feature from 'ol/Feature'
|
|
25
26
|
import Point from 'ol/geom/Point'
|
|
27
|
+
import LineString from 'ol/geom/LineString'
|
|
26
28
|
import { defaults as defaultInteractions } from 'ol/interaction'
|
|
27
29
|
import { Image as ImageLayer, Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
|
|
28
30
|
import { fromLonLat, toLonLat } from 'ol/proj'
|
|
29
31
|
import { ImageWMS, Vector as VectorSource, XYZ } from 'ol/source'
|
|
30
|
-
import { Fill, Icon, Stroke, Style, Text } from 'ol/style'
|
|
32
|
+
import { Fill, Icon, Stroke, Style, Text, Circle } from 'ol/style'
|
|
31
33
|
import { Button } from 'vant'
|
|
32
34
|
import { getCurrentInstance, onUnmounted, ref } from 'vue'
|
|
33
35
|
import { wgs84ToGcj02Projection } from './utils/wgs84ToGcj02'
|
|
@@ -83,6 +85,10 @@ let locationTimer: ReturnType<typeof setInterval> | null = null
|
|
|
83
85
|
/** 位置图标图层 */
|
|
84
86
|
let locationLayer: VectorLayer<VectorSource> | null = null
|
|
85
87
|
|
|
88
|
+
/** 存储轨迹图层 */
|
|
89
|
+
const trackLayers: Record<number, VectorLayer<VectorSource>> = {}
|
|
90
|
+
const trackLayerStatus = ref<TrackData[]>([])
|
|
91
|
+
|
|
86
92
|
/**
|
|
87
93
|
* 创建位置图标图层
|
|
88
94
|
*/
|
|
@@ -890,6 +896,139 @@ function navigationHandleLocation() {
|
|
|
890
896
|
}
|
|
891
897
|
}
|
|
892
898
|
|
|
899
|
+
/**
|
|
900
|
+
* 添加轨迹图层
|
|
901
|
+
* @param trackData - 轨迹数据
|
|
902
|
+
*/
|
|
903
|
+
function addTrackLayer(trackData: TrackData): void {
|
|
904
|
+
if (!map)
|
|
905
|
+
return
|
|
906
|
+
|
|
907
|
+
const vectorSource = new VectorSource()
|
|
908
|
+
const vectorLayer = new VectorLayer({
|
|
909
|
+
source: vectorSource,
|
|
910
|
+
visible: true,
|
|
911
|
+
zIndex: 2,
|
|
912
|
+
})
|
|
913
|
+
|
|
914
|
+
// 创建轨迹线要素
|
|
915
|
+
const coordinates = trackData.trackData.map(coord => fromLonLat(coord))
|
|
916
|
+
const lineString = new Feature({
|
|
917
|
+
geometry: new LineString(coordinates),
|
|
918
|
+
})
|
|
919
|
+
|
|
920
|
+
// 设置轨迹线样式
|
|
921
|
+
const lineStyle = new Style({
|
|
922
|
+
stroke: new Stroke({
|
|
923
|
+
color: trackData.color,
|
|
924
|
+
width: 3,
|
|
925
|
+
}),
|
|
926
|
+
})
|
|
927
|
+
lineString.setStyle(lineStyle)
|
|
928
|
+
|
|
929
|
+
// 创建起点和终点图标
|
|
930
|
+
const startPoint = new Feature({
|
|
931
|
+
geometry: new Point(coordinates[0]),
|
|
932
|
+
})
|
|
933
|
+
const endPoint = new Feature({
|
|
934
|
+
geometry: new Point(coordinates[coordinates.length - 1]),
|
|
935
|
+
})
|
|
936
|
+
|
|
937
|
+
// 设置起点图标样式 - 使用绿色圆形图标
|
|
938
|
+
const startStyle = new Style({
|
|
939
|
+
image: new Circle({
|
|
940
|
+
radius: 8,
|
|
941
|
+
fill: new Fill({
|
|
942
|
+
color: '#4CAF50',
|
|
943
|
+
}),
|
|
944
|
+
stroke: new Stroke({
|
|
945
|
+
color: '#fff',
|
|
946
|
+
width: 2,
|
|
947
|
+
}),
|
|
948
|
+
}),
|
|
949
|
+
text: new Text({
|
|
950
|
+
text: '起点',
|
|
951
|
+
offsetY: -15,
|
|
952
|
+
font: '12px sans-serif',
|
|
953
|
+
fill: new Fill({
|
|
954
|
+
color: '#333',
|
|
955
|
+
}),
|
|
956
|
+
stroke: new Stroke({
|
|
957
|
+
color: '#fff',
|
|
958
|
+
width: 2,
|
|
959
|
+
}),
|
|
960
|
+
}),
|
|
961
|
+
})
|
|
962
|
+
|
|
963
|
+
// 设置终点图标样式 - 使用红色圆形图标
|
|
964
|
+
const endStyle = new Style({
|
|
965
|
+
image: new Circle({
|
|
966
|
+
radius: 8,
|
|
967
|
+
fill: new Fill({
|
|
968
|
+
color: '#F44336',
|
|
969
|
+
}),
|
|
970
|
+
stroke: new Stroke({
|
|
971
|
+
color: '#fff',
|
|
972
|
+
width: 2,
|
|
973
|
+
}),
|
|
974
|
+
}),
|
|
975
|
+
text: new Text({
|
|
976
|
+
text: '终点',
|
|
977
|
+
offsetY: -15,
|
|
978
|
+
font: '12px sans-serif',
|
|
979
|
+
fill: new Fill({
|
|
980
|
+
color: '#333',
|
|
981
|
+
}),
|
|
982
|
+
stroke: new Stroke({
|
|
983
|
+
color: '#fff',
|
|
984
|
+
width: 2,
|
|
985
|
+
}),
|
|
986
|
+
}),
|
|
987
|
+
})
|
|
988
|
+
|
|
989
|
+
startPoint.setStyle(startStyle)
|
|
990
|
+
endPoint.setStyle(endStyle)
|
|
991
|
+
|
|
992
|
+
// 添加要素到图层
|
|
993
|
+
vectorSource.addFeatures([lineString, startPoint, endPoint])
|
|
994
|
+
|
|
995
|
+
// 添加到地图
|
|
996
|
+
map.addLayer(vectorLayer)
|
|
997
|
+
trackLayers[trackData.id] = vectorLayer
|
|
998
|
+
|
|
999
|
+
// 更新图层状态,确保 show 属性被正确设置
|
|
1000
|
+
const trackDataWithShow = {
|
|
1001
|
+
...trackData,
|
|
1002
|
+
show: true, // 默认显示
|
|
1003
|
+
}
|
|
1004
|
+
trackLayerStatus.value.push(trackDataWithShow)
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* 控制轨迹图层显示/隐藏
|
|
1009
|
+
* @param trackId - 轨迹ID
|
|
1010
|
+
* @param visible - 是否显示
|
|
1011
|
+
*/
|
|
1012
|
+
function setTrackLayerVisible(trackId: number, visible: boolean): void {
|
|
1013
|
+
const layer = trackLayers[trackId]
|
|
1014
|
+
if (layer) {
|
|
1015
|
+
layer.setVisible(visible)
|
|
1016
|
+
// 更新图层状态
|
|
1017
|
+
const layerIndex = trackLayerStatus.value.findIndex(layer => layer.id === trackId)
|
|
1018
|
+
if (layerIndex !== -1) {
|
|
1019
|
+
trackLayerStatus.value[layerIndex].show = visible
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* 切换轨迹图层显示状态
|
|
1026
|
+
*/
|
|
1027
|
+
function handleToggleTrackLayer(track: TrackData): void {
|
|
1028
|
+
track.show = !track.show
|
|
1029
|
+
setTrackLayerVisible(track.id, track.show)
|
|
1030
|
+
}
|
|
1031
|
+
|
|
893
1032
|
// 暴露方法给父组件
|
|
894
1033
|
defineExpose({
|
|
895
1034
|
init,
|
|
@@ -909,6 +1048,9 @@ defineExpose({
|
|
|
909
1048
|
handleLocation,
|
|
910
1049
|
startNavigation,
|
|
911
1050
|
stopNavigation,
|
|
1051
|
+
addTrackLayer,
|
|
1052
|
+
setTrackLayerVisible,
|
|
1053
|
+
handleToggleTrackLayer,
|
|
912
1054
|
})
|
|
913
1055
|
|
|
914
1056
|
// 组件卸载时清理地图实例
|
|
@@ -1008,6 +1150,25 @@ onUnmounted(() => {
|
|
|
1008
1150
|
</div>
|
|
1009
1151
|
</div>
|
|
1010
1152
|
</div>
|
|
1153
|
+
|
|
1154
|
+
<!-- 轨迹图层 -->
|
|
1155
|
+
<div v-if="trackLayerStatus.length > 0" class="control-panel layer-control">
|
|
1156
|
+
<div class="control-title">
|
|
1157
|
+
<i class="van-icon van-icon-location-o" /> 轨迹图层
|
|
1158
|
+
</div>
|
|
1159
|
+
<div class="layer-list">
|
|
1160
|
+
<div
|
|
1161
|
+
v-for="track in trackLayerStatus"
|
|
1162
|
+
:key="track.id"
|
|
1163
|
+
class="layer-item"
|
|
1164
|
+
:class="{ active: track.show }"
|
|
1165
|
+
@click="handleToggleTrackLayer(track)"
|
|
1166
|
+
>
|
|
1167
|
+
<i class="van-icon" :class="track.show ? 'van-icon-eye' : 'van-icon-closed-eye'" />
|
|
1168
|
+
<span>{{ track.name }}</span>
|
|
1169
|
+
</div>
|
|
1170
|
+
</div>
|
|
1171
|
+
</div>
|
|
1011
1172
|
</div>
|
|
1012
1173
|
</div>
|
|
1013
1174
|
</div>
|
|
@@ -132,3 +132,14 @@ export interface WMSOptions {
|
|
|
132
132
|
/** WMS 服务配置 */
|
|
133
133
|
wms: WMSConfig
|
|
134
134
|
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 轨迹数据类型
|
|
138
|
+
*/
|
|
139
|
+
export interface TrackData {
|
|
140
|
+
id: number
|
|
141
|
+
name: string
|
|
142
|
+
trackData: [number, number][] // 经纬度数组
|
|
143
|
+
color: string
|
|
144
|
+
show?: boolean // 是否显示
|
|
145
|
+
}
|
|
@@ -3,6 +3,7 @@ import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDat
|
|
|
3
3
|
import { showNotify } from 'vant'
|
|
4
4
|
import { onMounted, ref } from 'vue'
|
|
5
5
|
import XOlMap from '../../../components/data/XOlMap/index.vue'
|
|
6
|
+
import { trackTestData } from './testData'
|
|
6
7
|
import 'vant/lib/index.css'
|
|
7
8
|
|
|
8
9
|
const mapRef = ref()
|
|
@@ -265,6 +266,13 @@ function handleAddMassPoints() {
|
|
|
265
266
|
})
|
|
266
267
|
}
|
|
267
268
|
|
|
269
|
+
// 添加轨迹测试
|
|
270
|
+
function handleAddTrack() {
|
|
271
|
+
trackTestData.forEach((track) => {
|
|
272
|
+
mapRef.value.addTrackLayer(track)
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
|
|
268
276
|
// 导航模式相关
|
|
269
277
|
const isNavigationMode = ref(false)
|
|
270
278
|
|
|
@@ -322,6 +330,15 @@ function stopNavigation() {
|
|
|
322
330
|
</van-button>
|
|
323
331
|
</div>
|
|
324
332
|
|
|
333
|
+
<div class="control-group">
|
|
334
|
+
<div class="group-title">
|
|
335
|
+
轨迹示例
|
|
336
|
+
</div>
|
|
337
|
+
<van-button type="primary" size="small" @click="handleAddTrack">
|
|
338
|
+
添加测试轨迹
|
|
339
|
+
</van-button>
|
|
340
|
+
</div>
|
|
341
|
+
|
|
325
342
|
<div class="control-group">
|
|
326
343
|
<div class="group-title">
|
|
327
344
|
导航模式测试
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 轨迹测试数据
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// 轨迹数据类型定义
|
|
6
|
+
export interface TrackData {
|
|
7
|
+
id: number
|
|
8
|
+
name: string
|
|
9
|
+
trackData: [number, number][] // 经纬度数组
|
|
10
|
+
color: string
|
|
11
|
+
show?: boolean // 是否显示
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 生成随机轨迹点
|
|
16
|
+
* @param startPoint - 起始点 [经度, 纬度]
|
|
17
|
+
* @param pointCount - 点的数量
|
|
18
|
+
* @param maxOffset - 最大偏移量(经纬度)
|
|
19
|
+
* @returns 轨迹点数组
|
|
20
|
+
*/
|
|
21
|
+
function generateRandomTrack(
|
|
22
|
+
startPoint: [number, number],
|
|
23
|
+
pointCount: number,
|
|
24
|
+
maxOffset: number = 0.01,
|
|
25
|
+
): [number, number][] {
|
|
26
|
+
const points: [number, number][] = [startPoint]
|
|
27
|
+
let currentPoint = startPoint
|
|
28
|
+
|
|
29
|
+
for (let i = 1; i < pointCount; i++) {
|
|
30
|
+
// 生成随机偏移量,使用正态分布使轨迹更自然
|
|
31
|
+
const offsetLng = (Math.random() - 0.5) * maxOffset * (1 + Math.random() * 0.5)
|
|
32
|
+
const offsetLat = (Math.random() - 0.5) * maxOffset * (1 + Math.random() * 0.5)
|
|
33
|
+
|
|
34
|
+
// 添加一些随机性,使轨迹更自然
|
|
35
|
+
const randomFactor = Math.random() > 0.8 ? 2 : 1 // 偶尔会有较大的偏移
|
|
36
|
+
const newPoint: [number, number] = [
|
|
37
|
+
currentPoint[0] + offsetLng * randomFactor,
|
|
38
|
+
currentPoint[1] + offsetLat * randomFactor,
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
points.push(newPoint)
|
|
42
|
+
currentPoint = newPoint
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return points
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 测试数据
|
|
49
|
+
export const trackTestData: TrackData[] = [
|
|
50
|
+
{
|
|
51
|
+
id: 1,
|
|
52
|
+
name: '张三的轨迹',
|
|
53
|
+
trackData: generateRandomTrack([108.948024, 34.263161], 1000, 0.005),
|
|
54
|
+
color: '#FF0000',
|
|
55
|
+
show: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 2,
|
|
59
|
+
name: '李四的轨迹',
|
|
60
|
+
trackData: generateRandomTrack([108.948024, 34.263161], 500, 0.003),
|
|
61
|
+
color: '#00FF00',
|
|
62
|
+
show: true,
|
|
63
|
+
},
|
|
64
|
+
]
|