5 changed files with 890 additions and 24 deletions
@ -0,0 +1,851 @@ |
|||
<template> |
|||
<div class="map-container"> |
|||
<div id="map-container" ref="mapContainer"> |
|||
<div class="search" v-if="showSearch"> |
|||
<div class="searchText"> |
|||
<img src="/src/assets/highScore/searchIcon.png" /> |
|||
<div style="margin-bottom: 10%"> |
|||
<a-input |
|||
v-model:value="keyword" |
|||
:bordered="false" |
|||
placeholder="搜索" |
|||
class="custom-textarea" |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<Board ref="boardRef" /> |
|||
<DevInfo ref="devRef"></DevInfo> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, reactive, shallowRef, onMounted, onBeforeUnmount, watch, defineEmits } from 'vue'; |
|||
import AMapLoader from '@amap/amap-jsapi-loader'; |
|||
import { Scene, PointLayer, RasterLayer, LineLayer } from '@antv/l7'; |
|||
import { Map } from '@antv/l7-maps'; |
|||
import { useRouter } from 'vue-router'; |
|||
const searchValue = ref(); |
|||
const boardRef = ref(); |
|||
const devRef = ref(); |
|||
const router = useRouter(); |
|||
const emit = defineEmits(['checkWarring', 'showModal']); |
|||
// const emit1 = defineEmits(['showModal']); |
|||
const layerGroups = reactive<Record<string, { iconLayer: any; textLayer: any }>>({}); |
|||
interface LayerConfig { |
|||
id: string; |
|||
type: |
|||
| 'road' |
|||
| 'tunnel' |
|||
| 'board' |
|||
| 'fire' |
|||
| 'device' |
|||
| 'highWay' |
|||
| 'explosives' |
|||
| 'tourism' |
|||
| 'ThreeShuttleBus' |
|||
| 'fireWorks' |
|||
| 'chemistryCar' |
|||
| 'warn' |
|||
| 'people' |
|||
| 'car' |
|||
| 'materials'; |
|||
data: any; |
|||
style?: { |
|||
color?: string; |
|||
size?: number; |
|||
zIndex?: number; |
|||
opacity?: number; |
|||
}; |
|||
options?: { |
|||
iconUrl?: string; |
|||
borderWidth?: number; |
|||
}; |
|||
} |
|||
interface Props { |
|||
// 地图配置 |
|||
center?: [number, number]; |
|||
zoom?: number; |
|||
// 搜索配置 |
|||
showSearch?: boolean; |
|||
searchPlaceholder?: string; |
|||
// 地图服务配置 |
|||
tileUrl?: string; |
|||
amapKey?: string; |
|||
tdtKey?: string; |
|||
roadLayer?: LayerConfig; |
|||
tunnelLayer?: LayerConfig; |
|||
boardLayer?: LayerConfig; |
|||
fireLayer?: LayerConfig; |
|||
deviceLayer?: LayerConfig; |
|||
highWayLayer?: LayerConfig; |
|||
explosivesLayer?: LayerConfig; |
|||
tourismLayer?: LayerConfig; |
|||
ThreeShuttleBusLayer?: LayerConfig; |
|||
fireWorksLayer?: LayerConfig; |
|||
chemistryCarLayer?: LayerConfig; |
|||
lineLayer?: LayerConfig; |
|||
warnLayer?: LayerConfig; |
|||
peopleLayer?: LayerConfig; |
|||
carLayer?: LayerConfig; |
|||
materialsLayer?: LayerConfig; |
|||
} |
|||
|
|||
const props = withDefaults(defineProps<Props>(), { |
|||
center: () => [106.548817, 29.586823], |
|||
zoom: 10, |
|||
showSearch: true, |
|||
searchPlaceholder: '请输入搜索位置', |
|||
markerSize: 55, |
|||
tileUrl: '', |
|||
amapKey: '890b7bd3ba085d8adf3710dfc6a7b395', |
|||
tdtKey: '06b92b37abfb8a2f0dd1e623c1715ee5', |
|||
}); |
|||
|
|||
const keyword = ref(''); |
|||
const mapContainer = ref<HTMLElement | null>(null); |
|||
const scene = shallowRef<Scene | null>(null); |
|||
const map = shallowRef<any>(null); |
|||
// 初始化L7地图 |
|||
const initL7Map = async () => { |
|||
scene.value = new Scene({ |
|||
id: 'map-container', |
|||
map: new Map({ |
|||
center: props.center, |
|||
zoom: props.zoom, |
|||
}), |
|||
}); |
|||
|
|||
scene.value.on('loaded', async () => { |
|||
// 1. 底图图层 |
|||
if (props.tileUrl) { |
|||
const baseLayer = new RasterLayer({ zIndex: 0 }).source(props.tileUrl, { |
|||
parser: { type: 'rasterTile', tileSize: 256, dataType: 'image' }, |
|||
}); |
|||
scene.value?.addLayer(baseLayer); |
|||
} |
|||
//圆圈 |
|||
if (props.warnLayer) { |
|||
const pointLayer = new PointLayer() |
|||
.source({ |
|||
type: 'FeatureCollection', |
|||
features: [ |
|||
{ |
|||
type: 'Feature', |
|||
properties: {}, |
|||
geometry: { |
|||
type: 'Point', |
|||
coordinates: [106.5488177260367, 29.58682303545917], |
|||
}, |
|||
}, |
|||
], |
|||
}) |
|||
.shape('circle') |
|||
.size(230) // 圆圈直径(像素) |
|||
.color('#045697') // 填充颜色 |
|||
.style({ |
|||
stroke: '#04c4cb', // 边框颜色 |
|||
strokeWidth: 3, // 边框宽度 |
|||
opacity: 0.5, // 透明度 |
|||
}); |
|||
scene.value?.addLayer(pointLayer); |
|||
} |
|||
// 2. 事件图层 |
|||
if (props.warnLayer) { |
|||
await scene.value.addImage( |
|||
'warn-icon', |
|||
new URL('@/assets/coordinated/warnicon.png', import.meta.url).href, |
|||
); |
|||
const warnLayer = new PointLayer({ |
|||
zIndex: props.warnLayer.style?.zIndex || 1, |
|||
name: 'warn-layer', |
|||
visible: true, |
|||
}) |
|||
|
|||
.source(props.warnLayer.data, { |
|||
parser: { |
|||
type: 'json', |
|||
x: 'lng', |
|||
y: 'lat', |
|||
}, |
|||
}) |
|||
.shape('warn-icon') |
|||
.size(props.warnLayer.style?.size || 2); |
|||
scene.value?.addLayer(warnLayer); |
|||
warnLayer.on('click', e => { |
|||
console.log('事件图层', e); |
|||
emit('showModal'); |
|||
}); |
|||
layerInstances['warnLayer'] = warnLayer; |
|||
} |
|||
|
|||
// 3. 人员图层 |
|||
if (props.peopleLayer) { |
|||
await scene.value.addImage( |
|||
'people-icon', |
|||
new URL('@/assets/coordinated/people.png', import.meta.url).href, |
|||
); |
|||
|
|||
const peopleLayer = new PointLayer({ |
|||
zIndex: props.peopleLayer.style?.zIndex || 2, |
|||
name: 'people-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.peopleLayer.data) |
|||
.shape('people-icon') |
|||
.size(props.peopleLayer.style?.size || 50); |
|||
scene.value?.addLayer(peopleLayer); |
|||
layerInstances['peopleLayer'] = peopleLayer; |
|||
peopleLayer.on('click', e => { |
|||
emit('showModal'); |
|||
}); |
|||
} |
|||
|
|||
// 4. 车辆图层 |
|||
if (props.carLayer) { |
|||
await scene.value.addImage( |
|||
'car-icon', |
|||
new URL('@/assets/coordinated/car.png', import.meta.url).href, |
|||
); |
|||
|
|||
const carLayer = new PointLayer({ |
|||
zIndex: props.carLayer.style?.zIndex || 4, |
|||
name: 'car-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.carLayer.data) |
|||
.shape('car-icon') |
|||
.size(props.carLayer.style?.size || 15) |
|||
.style({ |
|||
offsets: [0, 20], |
|||
}); |
|||
scene.value?.addLayer(carLayer); |
|||
carLayer.on('click', e => { |
|||
emit('showModal'); |
|||
}); |
|||
layerInstances['carLayer'] = carLayer; |
|||
} |
|||
|
|||
// 5. 物资图层 |
|||
if (props.materialsLayer) { |
|||
await scene.value.addImage( |
|||
'materials-icon', |
|||
new URL('@/assets/coordinated/Materials.png', import.meta.url).href, |
|||
); |
|||
|
|||
const materialsLayer = new PointLayer({ |
|||
zIndex: props.materialsLayer.style?.zIndex || 5, |
|||
name: 'materials-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.materialsLayer.data) |
|||
.shape('materials-icon') |
|||
.size(props.materialsLayer.style?.size || 25) |
|||
.animate({ |
|||
enable: true, |
|||
speed: 1, |
|||
rings: 3, |
|||
}); |
|||
scene.value?.addLayer(materialsLayer); |
|||
materialsLayer.on('click', e => { |
|||
emit('showModal'); |
|||
}); |
|||
layerInstances['materialsLayer'] = materialsLayer; |
|||
} |
|||
|
|||
// 2. 公路图层(线图层) |
|||
if (props.roadLayer) { |
|||
const roadLayer = new LineLayer({ |
|||
zIndex: props.roadLayer.style?.zIndex || 1, |
|||
name: 'road-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.roadLayer.data) |
|||
.size(props.roadLayer.style?.size || 2) |
|||
.color(props.roadLayer.style?.color || '#4a7af0'); |
|||
scene.value?.addLayer(roadLayer); |
|||
layerInstances['lineLayer'] = roadLayer; |
|||
} |
|||
|
|||
// 3. 隧道图层(点图层+文字标注) |
|||
if (props.tunnelLayer) { |
|||
await scene.value.addImage( |
|||
'tunnel-icon', |
|||
new URL('@/assets/images/traffic/point/tunnel.svg', import.meta.url).href, |
|||
); |
|||
|
|||
const tunnelLayer = new PointLayer({ |
|||
zIndex: props.tunnelLayer.style?.zIndex || 2, |
|||
name: 'tunnel-layer', |
|||
visible: false, |
|||
}) |
|||
.source(props.tunnelLayer.data) |
|||
.shape('tunnel-icon') |
|||
.size(props.tunnelLayer.style?.size || 50); |
|||
scene.value?.addLayer(tunnelLayer); |
|||
layerInstances['tunnelLayer'] = tunnelLayer; |
|||
tunnelLayer.on('click', e => { |
|||
console.log('隧道图层', e); |
|||
router.push('/tunnel/' + e.feature.id); |
|||
}); |
|||
} |
|||
|
|||
// 4. 情报板图层 |
|||
if (props.boardLayer) { |
|||
await scene.value.addImage( |
|||
'board-icon', |
|||
new URL('@/assets/images/traffic/point/board.svg', import.meta.url).href, |
|||
); |
|||
|
|||
const boardLayer = new PointLayer({ |
|||
zIndex: props.boardLayer.style?.zIndex || 4, |
|||
name: 'board-layer', |
|||
visible: false, |
|||
}) |
|||
.source(props.boardLayer.data) |
|||
.shape('board-icon') |
|||
.size(props.boardLayer.style?.size || 15) |
|||
.style({ |
|||
offsets: [0, 20], |
|||
}); |
|||
scene.value?.addLayer(boardLayer); |
|||
boardLayer.on('click', e => { |
|||
console.log('情报板图层', e); |
|||
boardRef.value.open = true; |
|||
}); |
|||
layerInstances['boardLayer'] = boardLayer; |
|||
} |
|||
|
|||
// 5. 火灾图层 |
|||
if (props.fireLayer) { |
|||
await scene.value.addImage( |
|||
'fire-icon', |
|||
new URL('@/assets/images/traffic/point/fire.svg', import.meta.url).href, |
|||
); |
|||
|
|||
const fireLayer = new PointLayer({ |
|||
zIndex: props.fireLayer.style?.zIndex || 5, |
|||
name: 'fire-layer', |
|||
visible: false, |
|||
}) |
|||
.source(props.fireLayer.data) |
|||
.shape('fire-icon') |
|||
.size(props.fireLayer.style?.size || 25) |
|||
.animate({ |
|||
enable: true, |
|||
speed: 1, |
|||
rings: 3, |
|||
}); |
|||
scene.value?.addLayer(fireLayer); |
|||
fireLayer.on('click', e => { |
|||
console.log('监控', e); |
|||
devRef.value.open = true; |
|||
}); |
|||
layerInstances['fireLayer'] = fireLayer; |
|||
} |
|||
|
|||
// 6. 隧道分布器图层 |
|||
if (props.deviceLayer) { |
|||
await scene.value.addImage( |
|||
'device-icon', |
|||
new URL('@/assets/images/traffic/point/device.svg', import.meta.url).href, |
|||
); |
|||
|
|||
const deviceLayer = new PointLayer({ |
|||
zIndex: props.deviceLayer.style?.zIndex || 6, |
|||
name: 'device-layer', |
|||
visible: false, |
|||
}) |
|||
.source(props.deviceLayer.data) |
|||
.shape('device-icon') |
|||
.size(props.deviceLayer.style?.size || 15); |
|||
scene.value?.addLayer(deviceLayer); |
|||
deviceLayer.on('click', e => { |
|||
console.log('监控', e); |
|||
devRef.value.open = true; |
|||
}); |
|||
layerInstances['deviceLayer'] = deviceLayer; |
|||
} |
|||
|
|||
//7.高速公路文字标注图层 |
|||
if (props.highWayLayer) { |
|||
// await scene.value.addImage( |
|||
// 'highWay-icon', |
|||
// new URL('@/assets/images/watch/blueBg.png', import.meta.url).href, |
|||
// ); |
|||
const layer = new PointLayer({ |
|||
zIndex: props.highWayLayer.style?.zIndex || 7, |
|||
name: 'highWay-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.highWayLayer.data.list, { |
|||
parser: { |
|||
type: 'json', |
|||
x: 'j', |
|||
y: 'w', |
|||
}, |
|||
}) |
|||
.shape('square') |
|||
.color('c') |
|||
.size(15) |
|||
.style({ |
|||
stroke: 'white', |
|||
strokeWidth: 0.5, |
|||
}); |
|||
scene.value?.addLayer(layer); |
|||
|
|||
const highWayLayer = new PointLayer({ |
|||
zIndex: props.highWayLayer.style?.zIndex || 7, |
|||
name: 'highWay-layer', |
|||
visible: true, |
|||
}) |
|||
|
|||
.source(props.highWayLayer.data.list, { |
|||
parser: { |
|||
type: 'json', |
|||
x: 'j', |
|||
y: 'w', |
|||
}, |
|||
}) |
|||
.shape('m', 'text') |
|||
// .shape('highWay-icon') |
|||
.size(props.highWayLayer.style?.size || 15) |
|||
.color('f') |
|||
.style({ |
|||
textAnchor: 'center', |
|||
textOffset: [0, 0], |
|||
spacing: 2, |
|||
padding: [1, 1], |
|||
strokeOpacity: 1.0, |
|||
}); |
|||
scene.value?.addLayer(highWayLayer); |
|||
|
|||
// const highWayLayer1 = new PointLayer({ |
|||
// zIndex: props.highWayLayer.style?.zIndex || 7, |
|||
// name: 'highWay-layer', |
|||
// visible: true, |
|||
// }) |
|||
|
|||
// .source(props.highWayLayer.data.list, { |
|||
// parser: { |
|||
// type: 'json', |
|||
// x: 'j', |
|||
// y: 'w', |
|||
// }, |
|||
// }) |
|||
// .shape('m', 'text') |
|||
// .size(12) |
|||
// .color('f') |
|||
// .style({ |
|||
// textAnchor: 'center', |
|||
// textOffset: [0, 0], |
|||
// spacing: 2, |
|||
// padding: [1, 1], |
|||
// strokeOpacity: 1.0, |
|||
// }); |
|||
// scene.value?.addLayer(highWayLayer1); |
|||
layerInstances['highWayLayer'] = highWayLayer; |
|||
} |
|||
|
|||
//8.民用爆炸品专用车图层 |
|||
if (props.explosivesLayer) { |
|||
await scene.value.addImage( |
|||
'explosives-icon', |
|||
new URL('@/assets/images/danger/point/1.svg', import.meta.url).href, |
|||
); |
|||
|
|||
const iconLayer = new PointLayer({ |
|||
zIndex: props.explosivesLayer.style?.zIndex || 6, |
|||
name: 'explosives-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.explosivesLayer.data) |
|||
.shape('explosives-icon') |
|||
.size(props.explosivesLayer.style?.size || 15); |
|||
|
|||
const textLayer = new PointLayer({ |
|||
zIndex: props.explosivesLayer.style?.zIndex || 6, |
|||
name: 'explosives-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.explosivesLayer.data) |
|||
.shape('text') |
|||
.size(15) |
|||
.color('#026b88') |
|||
.style({ |
|||
textOffset: [5, 70], // 文本相对锚点的偏移量 [水平, 垂直] |
|||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left |
|||
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 |
|||
stroke: '#00DCFF', // 描边颜色 |
|||
strokeWidth: 0.5, // 描边宽度 |
|||
strokeOpacity: 1.0, |
|||
}); |
|||
// 添加到场景 |
|||
scene.value?.addLayer(iconLayer); |
|||
scene.value?.addLayer(textLayer); |
|||
iconLayer.on('click', e => { |
|||
emit('checkWarring'); |
|||
}); |
|||
// 保存图层组 |
|||
layerGroups['explosivesLayer'] = { |
|||
iconLayer, |
|||
textLayer, |
|||
}; |
|||
} |
|||
|
|||
//9.旅游包车图层 |
|||
if (props.tourismLayer) { |
|||
await scene.value.addImage( |
|||
'tourism-icon', |
|||
new URL('@/assets/images/danger/point/2.svg', import.meta.url).href, |
|||
); |
|||
|
|||
const iconLayer = new PointLayer({ |
|||
zIndex: props.tourismLayer.style?.zIndex || 6, |
|||
name: 'tourism-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.tourismLayer.data) |
|||
.shape('tourism-icon') |
|||
.size(props.tourismLayer.style?.size || 15); |
|||
const textLayer = new PointLayer({ |
|||
zIndex: props.tourismLayer.style?.zIndex || 6, |
|||
name: 'tourism-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.tourismLayer.data) |
|||
.shape('text') |
|||
.size(15) |
|||
.color('#023d7d') |
|||
.style({ |
|||
textOffset: [5, 70], // 文本相对锚点的偏移量 [水平, 垂直] |
|||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left |
|||
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 |
|||
stroke: '#0276b6', // 描边颜色 |
|||
strokeWidth: 0.5, // 描边宽度 |
|||
strokeOpacity: 1.0, |
|||
}); |
|||
// 添加到场景 |
|||
scene.value?.addLayer(iconLayer); |
|||
scene.value?.addLayer(textLayer); |
|||
iconLayer.on('click', e => { |
|||
emit('checkWarring'); |
|||
}); |
|||
// 保存图层组 |
|||
layerGroups['tourismLayer'] = { |
|||
iconLayer, |
|||
textLayer, |
|||
}; |
|||
} |
|||
|
|||
//10.三类以上班线客车 |
|||
if (props.ThreeShuttleBusLayer) { |
|||
await scene.value.addImage( |
|||
'ThreeShuttleBus-icon', |
|||
new URL('@/assets/images/danger/point/3.svg', import.meta.url).href, |
|||
); |
|||
|
|||
const iconLayer = new PointLayer({ |
|||
zIndex: props.ThreeShuttleBusLayer.style?.zIndex || 6, |
|||
name: 'Three-shuttle-bus-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.ThreeShuttleBusLayer.data) |
|||
.shape('ThreeShuttleBus-icon') |
|||
.size(props.ThreeShuttleBusLayer.style?.size || 15); |
|||
const textLayer = new PointLayer({ |
|||
zIndex: props.ThreeShuttleBusLayer.style?.zIndex || 6, |
|||
name: 'Three-shuttle-bus-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.ThreeShuttleBusLayer.data) |
|||
.shape('text') |
|||
.size(15) |
|||
.color('#028978') |
|||
.style({ |
|||
textOffset: [5, 70], // 文本相对锚点的偏移量 [水平, 垂直] |
|||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left |
|||
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 |
|||
stroke: '#03a583', // 描边颜色 |
|||
strokeWidth: 0.5, // 描边宽度 |
|||
strokeOpacity: 1.0, |
|||
}); |
|||
// 添加到场景 |
|||
scene.value?.addLayer(iconLayer); |
|||
scene.value?.addLayer(textLayer); |
|||
iconLayer.on('click', e => { |
|||
emit('checkWarring'); |
|||
}); |
|||
// 保存图层组 |
|||
layerGroups['ThreeShuttleBusLayer'] = { |
|||
iconLayer, |
|||
textLayer, |
|||
}; |
|||
} |
|||
|
|||
//11.烟花爆竹专用车 |
|||
if (props.fireWorksLayer) { |
|||
await scene.value.addImage( |
|||
'fireWorks-icon', |
|||
new URL('@/assets/images/danger/point/4.svg', import.meta.url).href, |
|||
); |
|||
|
|||
const iconLayer = new PointLayer({ |
|||
zIndex: props.fireWorksLayer.style?.zIndex || 6, |
|||
name: 'fire-works-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.fireWorksLayer.data) |
|||
.shape('fireWorks-icon') |
|||
.size(props.fireWorksLayer.style?.size || 15); |
|||
|
|||
const textLayer = new PointLayer({ |
|||
zIndex: props.fireWorksLayer.style?.zIndex || 6, |
|||
name: 'fire-works-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.fireWorksLayer.data) |
|||
.shape('text') |
|||
.size(15) |
|||
.color('#864a05') |
|||
.style({ |
|||
textOffset: [5, 70], // 文本相对锚点的偏移量 [水平, 垂直] |
|||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left |
|||
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 |
|||
stroke: '#ba7b3d', // 描边颜色 |
|||
strokeWidth: 0.5, // 描边宽度 |
|||
strokeOpacity: 1.0, |
|||
}); |
|||
// 添加到场景 |
|||
scene.value?.addLayer(iconLayer); |
|||
scene.value?.addLayer(textLayer); |
|||
iconLayer.on('click', e => { |
|||
emit('checkWarring'); |
|||
}); |
|||
// 保存图层组 |
|||
layerGroups['fireWorksLayer'] = { |
|||
iconLayer, |
|||
textLayer, |
|||
}; |
|||
} |
|||
|
|||
//12.危险化学品专用车 |
|||
if (props.chemistryCarLayer) { |
|||
await scene.value.addImage( |
|||
'chemistryCar-icon', |
|||
new URL('@/assets/images/danger/point/5.svg', import.meta.url).href, |
|||
); |
|||
|
|||
const iconLayer = new PointLayer({ |
|||
zIndex: props.chemistryCarLayer.style?.zIndex || 6, |
|||
name: 'chemistry-car-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.chemistryCarLayer.data) |
|||
.shape('chemistryCar-icon') |
|||
.size(props.chemistryCarLayer.style?.size || 15); |
|||
|
|||
const textLayer = new PointLayer({ |
|||
zIndex: props.chemistryCarLayer.style?.zIndex || 6, |
|||
name: 'chemistry-car-layer', |
|||
visible: true, |
|||
}) |
|||
.source(props.chemistryCarLayer.data) |
|||
.shape('text') |
|||
.size(15) |
|||
.color('#902506') |
|||
.style({ |
|||
textOffset: [5, 70], // 文本相对锚点的偏移量 [水平, 垂直] |
|||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left |
|||
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 |
|||
stroke: '#c84724', // 描边颜色 |
|||
strokeWidth: 0.5, // 描边宽度 |
|||
strokeOpacity: 1.0, |
|||
}); |
|||
// 添加到场景 |
|||
scene.value?.addLayer(iconLayer); |
|||
scene.value?.addLayer(textLayer); |
|||
iconLayer.on('click', e => { |
|||
emit('checkWarring'); |
|||
}); |
|||
// 保存图层组 |
|||
layerGroups['chemistryCarLayer'] = { |
|||
iconLayer, |
|||
textLayer, |
|||
}; |
|||
} |
|||
|
|||
// 13.3D弧线 |
|||
if (props.lineLayer) { |
|||
await scene.value.addImage( |
|||
'marker', |
|||
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*BJ6cTpDcuLcAAAAAAAAAAABkARQnAQ', |
|||
); |
|||
const data = { |
|||
type: 'FeatureCollection', |
|||
features: [ |
|||
{ |
|||
type: 'Feature', |
|||
geometry: { |
|||
type: 'Point', |
|||
coordinates: [106.5828177260367, 29.55982303545917], |
|||
}, |
|||
}, |
|||
], |
|||
}; |
|||
const imageLayer = new PointLayer().source(data).shape('marker').size(20).style({ |
|||
zIndex: 10, |
|||
}); |
|||
const layer = new LineLayer({}) |
|||
.source(props.lineLayer.data, { |
|||
parser: { |
|||
type: 'json', |
|||
x: 'lng1', |
|||
y: 'lat1', |
|||
x1: 'lng2', |
|||
y1: 'lat2', |
|||
z: 'height', // 使用高度字段 |
|||
}, |
|||
}) |
|||
.size(2) |
|||
.shape('arc3d') |
|||
.color('#dfe2b4') |
|||
.style({ |
|||
zIndex: 1, |
|||
curvature: 3.0, |
|||
}); |
|||
|
|||
// 提取所有终点坐标 |
|||
const endPoints = props.lineLayer.data.map(item => ({ |
|||
lng: item.lng2, |
|||
lat: item.lat2, |
|||
name: item.name, |
|||
})); |
|||
|
|||
// 添加终点圆点图层 |
|||
const endPointLayer = new PointLayer() |
|||
.source(endPoints, { |
|||
parser: { |
|||
type: 'json', |
|||
x: 'lng', |
|||
y: 'lat', |
|||
}, |
|||
}) |
|||
.shape('circle') |
|||
.size(8) |
|||
.color('#5289d2') |
|||
.style({ |
|||
stroke: '#FFF', |
|||
strokeWidth: 2, |
|||
zIndex: 10, |
|||
}); |
|||
scene.value?.addLayer(imageLayer); |
|||
scene.value?.addLayer(endPointLayer); |
|||
scene.value?.addLayer(layer); |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
const layerInstances = reactive<Record<string, any>>({}); |
|||
|
|||
// 暴露图层控制方法给父组件 |
|||
defineExpose({ |
|||
setLayerVisible: (layerName: string, visible: boolean) => { |
|||
const layer = layerInstances[layerName]; |
|||
if (layer) { |
|||
visible ? layer.show() : layer.hide(); |
|||
} |
|||
}, |
|||
setLayerGroupVisible: (groupName: string, visible: boolean) => { |
|||
const group = layerGroups[groupName]; |
|||
if (group) { |
|||
group.iconLayer[visible ? 'show' : 'hide'](); |
|||
group.textLayer[visible ? 'show' : 'hide'](); |
|||
} |
|||
}, |
|||
}); |
|||
|
|||
onMounted(() => { |
|||
initL7Map(); |
|||
}); |
|||
|
|||
onBeforeUnmount(() => { |
|||
if (map.value) { |
|||
map.value.destroy(); |
|||
} |
|||
if (scene.value) { |
|||
scene.value.destroy(); |
|||
} |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.map-container { |
|||
position: absolute; |
|||
top: -2%; |
|||
left: 7%; |
|||
width: 6000px; |
|||
height: 2500px; |
|||
border-radius: 15% / 50%; /* 使边框变成椭圆形,横轴和纵轴不同的比例 */ |
|||
overflow: hidden; /* 防止内容溢出 */ |
|||
position: relative; |
|||
filter: brightness(0.88) contrast(1.22) grayscale(0) hue-rotate(360deg) opacity(1) saturate(1.1) |
|||
sepia(0.54) invert(0.9); |
|||
} |
|||
.map-search-input { |
|||
position: absolute; |
|||
z-index: 999; |
|||
top: 10px; |
|||
left: 10px; |
|||
padding: 8px; |
|||
width: 300px; |
|||
border: 1px solid #ddd; |
|||
border-radius: 4px; |
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.search { |
|||
z-index: 9999; |
|||
position: absolute; |
|||
top: -4%; |
|||
left: 0; |
|||
background: url('/src/assets/highScore/searchBg.png') no-repeat 0 0/100% 100%; |
|||
width: 250px; |
|||
height: 32px; |
|||
.searchText { |
|||
width: 246px; |
|||
height: 32px; |
|||
display: flex; |
|||
position: relative; |
|||
position: absolute; |
|||
top: 6%; |
|||
left: 2%; |
|||
img { |
|||
position: absolute; |
|||
top: 20%; |
|||
left: 2%; |
|||
width: 15px; |
|||
height: 16px; |
|||
} |
|||
div { |
|||
position: absolute; |
|||
top: -10%; |
|||
left: 8%; |
|||
} |
|||
.custom-textarea::placeholder { |
|||
color: white; |
|||
opacity: 1; |
|||
font-size: 18px; |
|||
} |
|||
.ant-input { |
|||
margin-bottom: 10px; |
|||
font-size: 18px; |
|||
// background-color: #0c2237; |
|||
width: 350px; |
|||
color: white; |
|||
} |
|||
} |
|||
} |
|||
</style> |
Loading…
Reference in new issue