2022-11-29 18:27:14 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<section class="AiMap" :class="{mask}">
|
|
|
|
|
|
<div ref="amap" class="map"/>
|
|
|
|
|
|
<div v-if="mask" class="mask"/>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import AMapLoader from "@amap/amap-jsapi-loader";
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: "AiMap",
|
|
|
|
|
|
props: {
|
|
|
|
|
|
plugins: {default: () => ['AMap.DistrictSearch', 'AMap.LineSearch']},
|
|
|
|
|
|
map: Object,
|
|
|
|
|
|
lib: Object,
|
|
|
|
|
|
mapStyle: String,
|
|
|
|
|
|
areaId: String,
|
|
|
|
|
|
is3d: Boolean,
|
|
|
|
|
|
ops: {default: () => ({})},
|
|
|
|
|
|
markers: {default: () => []},
|
|
|
|
|
|
mask: Boolean,
|
|
|
|
|
|
searchBus: {default: "2"},
|
|
|
|
|
|
pulseLines: Boolean,
|
|
|
|
|
|
onlyShowArea: Boolean
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
viewMode() {
|
|
|
|
|
|
return this.is3d ? '3D' : '2D'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
amap: null,
|
|
|
|
|
|
mapLib: null,
|
|
|
|
|
|
loca: null
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
markers: {
|
|
|
|
|
|
deep: true, handler() {
|
|
|
|
|
|
this.addMarkers()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
initMap() {
|
|
|
|
|
|
let {plugins, viewMode, mapStyle} = this
|
|
|
|
|
|
AMapLoader.load({
|
|
|
|
|
|
key: '54a02a43d9828a8f9cd4f26fe281e74e',
|
|
|
|
|
|
version: '2.0',
|
|
|
|
|
|
plugins,
|
|
|
|
|
|
Loca: {version: '2.0.0'}
|
|
|
|
|
|
}).then(AMap => {
|
|
|
|
|
|
this.mapLib = AMap
|
|
|
|
|
|
this.$emit('update:lib', AMap)
|
2023-01-09 17:28:30 +08:00
|
|
|
|
if (this.$refs.amap) {
|
|
|
|
|
|
this.amap = new AMap.Map(this.$refs.amap, {
|
|
|
|
|
|
mapStyle,
|
|
|
|
|
|
viewMode,
|
|
|
|
|
|
terrain: true,
|
|
|
|
|
|
resizeEnable: true,
|
|
|
|
|
|
skyColor: "#082243",
|
|
|
|
|
|
zoom: 11,
|
|
|
|
|
|
...this.ops
|
|
|
|
|
|
})
|
|
|
|
|
|
this.amap.on('complete', () => {
|
|
|
|
|
|
this.amap.setFitView();//视口自适应
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
this.$emit('update:map', this.amap)
|
|
|
|
|
|
this.$emit("loaded")
|
|
|
|
|
|
this.mapLoaded()
|
|
|
|
|
|
}
|
2022-11-29 18:27:14 +08:00
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
getMapArea() {
|
|
|
|
|
|
const {mapLib: AMap} = this
|
|
|
|
|
|
if (!!AMap) {
|
|
|
|
|
|
new AMap.DistrictSearch({
|
|
|
|
|
|
subdistrict: 0, //获取边界不需要返回下级行政区
|
|
|
|
|
|
extensions: 'all', //返回行政区边界坐标组等具体信息
|
|
|
|
|
|
level: 'district' //查询行政级别为 市
|
|
|
|
|
|
}).search(this.areaId.substring(0, 6), (status, result) => {
|
|
|
|
|
|
const area = result?.districtList?.[0],
|
|
|
|
|
|
bounds = area?.boundaries || [];
|
|
|
|
|
|
let polygons = []
|
|
|
|
|
|
if (this.onlyShowArea) {
|
|
|
|
|
|
const mask = bounds.map(e => [e])
|
|
|
|
|
|
polygons = bounds.map(path => new AMap.Polygon({
|
|
|
|
|
|
path: path.map(e => [e.lng, e.lat]),
|
|
|
|
|
|
strokeWeight: 1,
|
|
|
|
|
|
fillOpacity: 0,
|
|
|
|
|
|
strokeStyle: 'dashed',
|
|
|
|
|
|
strokeColor: '#0091ea'
|
|
|
|
|
|
}))
|
|
|
|
|
|
this.amap.setMask(mask)
|
|
|
|
|
|
this.amap.setPitch(65)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
polygons = bounds.map(path => new AMap.Polygon({
|
|
|
|
|
|
strokeWeight: 1,
|
|
|
|
|
|
path: path.map(e => [e.lng, e.lat]),
|
|
|
|
|
|
strokeStyle: 'dashed',
|
|
|
|
|
|
fillOpacity: 0.1,
|
|
|
|
|
|
fillColor: '#80d8ff',
|
|
|
|
|
|
strokeColor: '#0091ea'
|
|
|
|
|
|
}))
|
|
|
|
|
|
}
|
|
|
|
|
|
this.amap.add(polygons)
|
|
|
|
|
|
this.amap.setCenter(area.center, true)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
mapLoaded() {
|
|
|
|
|
|
this.areaId && this.getMapArea()
|
|
|
|
|
|
this.addPulseLines(this.areaId?.substring(0, 6))
|
|
|
|
|
|
this.addMarkers()
|
|
|
|
|
|
},
|
|
|
|
|
|
addMarkers() {
|
|
|
|
|
|
if (this.markers.length > 0 && this.mapLib && this.amap) {
|
|
|
|
|
|
let markers = this.markers.map(e => {
|
|
|
|
|
|
let {label, icon = "https://cdn.cunwuyun.cn/dvcp/h5/Location2.png"} = e
|
|
|
|
|
|
return new this.mapLib.Marker({
|
|
|
|
|
|
content: e.content || `<div class="marker">
|
|
|
|
|
|
<img src="${icon}"/>
|
|
|
|
|
|
<span>${label}</span>
|
|
|
|
|
|
</div>`,
|
|
|
|
|
|
position: [e.lng, e.lat]
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
this.amap.add(markers)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
addPulseLines(city) {
|
|
|
|
|
|
let {amap: map, mapLib: lib, pulseLines} = this
|
|
|
|
|
|
if (pulseLines && lib && map) {
|
|
|
|
|
|
this.loca = new Loca.Container({map: this.amap})
|
|
|
|
|
|
let ls = new lib.LineSearch({pageSize: 1, pageNum: 1, city}), lines = {
|
|
|
|
|
|
type: "FeatureCollection",
|
|
|
|
|
|
features: []
|
|
|
|
|
|
}
|
|
|
|
|
|
Promise.all(Array.from("0123456789").map(i => new Promise((resolve) => {
|
|
|
|
|
|
ls.search(i, (e, res) => {
|
|
|
|
|
|
if (e == "complete" && res.info == "OK") {
|
|
|
|
|
|
res.lineInfo?.map(line => {
|
|
|
|
|
|
lines.features.push({
|
|
|
|
|
|
type: "Feature",
|
|
|
|
|
|
properties: {},
|
|
|
|
|
|
geometry: {
|
|
|
|
|
|
type: "LineString",
|
|
|
|
|
|
coordinates: line.path?.map(p => [p.lng, p.lat]) || []
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
resolve()
|
|
|
|
|
|
})
|
|
|
|
|
|
}))).then(() => {
|
|
|
|
|
|
let layer = new Loca.PulseLineLayer({
|
|
|
|
|
|
zIndex: 10,
|
|
|
|
|
|
opacity: 1,
|
|
|
|
|
|
visible: true,
|
|
|
|
|
|
zooms: [2, 22],
|
|
|
|
|
|
})
|
|
|
|
|
|
let geo = new Loca.GeoJSONSource({data: lines})
|
|
|
|
|
|
layer.setSource(geo)
|
|
|
|
|
|
layer.setStyle({
|
|
|
|
|
|
altitude: 0,
|
|
|
|
|
|
lineWidth: 2,
|
|
|
|
|
|
// 脉冲头颜色
|
|
|
|
|
|
headColor: "#B5FBFF",
|
|
|
|
|
|
// 脉冲尾颜色
|
|
|
|
|
|
trailColor: 'rgba(0,0,0,0)',
|
|
|
|
|
|
// 脉冲长度,0.25 表示一段脉冲占整条路的 1/4
|
|
|
|
|
|
interval: 0.25,
|
|
|
|
|
|
// 脉冲线的速度,几秒钟跑完整段路
|
|
|
|
|
|
duration: 15000,
|
|
|
|
|
|
})
|
|
|
|
|
|
this.loca.add(layer)
|
|
|
|
|
|
this.loca.animate.start()
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
mounted() {
|
|
|
|
|
|
this.initMap()
|
|
|
|
|
|
},
|
|
|
|
|
|
destroyed() {
|
|
|
|
|
|
this.amap?.destroy()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.AiMap {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
min-height: 0;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
&.mask {
|
|
|
|
|
|
box-shadow: 0 0 40px 20px rgba(#000, .8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.map {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mask {
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
z-index: 8;
|
|
|
|
|
|
background: radial-gradient(rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .6) 40%, #000 100%);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-09 17:28:30 +08:00
|
|
|
|
:deep( .marker ) {
|
2022-11-29 18:27:14 +08:00
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
& > img {
|
|
|
|
|
|
width: 50px;
|
|
|
|
|
|
height: 50px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
& > span {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:hover > span {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: 50%;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
transform: translate(-50%, 100%);
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-09 17:28:30 +08:00
|
|
|
|
:deep( .amap-logo), :deep( .amap-copyright ) {
|
2022-11-29 18:27:14 +08:00
|
|
|
|
display: none !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-09 17:28:30 +08:00
|
|
|
|
:deep( .amap-icon ) {
|
2022-11-29 18:27:14 +08:00
|
|
|
|
width: 40px !important;
|
|
|
|
|
|
height: 40px !important;
|
|
|
|
|
|
|
|
|
|
|
|
img {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|