262 lines
6.7 KiB
Vue
262 lines
6.7 KiB
Vue
<template>
|
||
<section class="AiMap" :class="{mask}">
|
||
<div ref="amap" class="map"/>
|
||
<div v-if="mask" class="mask"/>
|
||
<slot/>
|
||
</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,
|
||
satellite: Boolean
|
||
},
|
||
data() {
|
||
return {
|
||
amap: null,
|
||
mapLib: null,
|
||
loca: null,
|
||
}
|
||
},
|
||
watch: {
|
||
markers: {
|
||
deep: true, handler() {
|
||
this.addMarkers()
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
initMap(c = 0) {
|
||
let {plugins, 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)
|
||
if (this.$refs.amap) {
|
||
this.amap = new AMap.Map(this.$refs.amap, {
|
||
mapStyle,
|
||
viewMode: "3D",
|
||
terrain: true,
|
||
resizeEnable: true,
|
||
skyColor: "#082243",
|
||
zoom: 11,
|
||
...this.ops
|
||
})
|
||
this.amap.on('complete', () => {
|
||
this.amap.setFitView();//视口自适应
|
||
})
|
||
/*增加卫星图层*/
|
||
if (this.satellite) {
|
||
this.amap.add([new AMap.TileLayer.RoadNet({zIndex: 11}), new AMap.TileLayer.Satellite({zIndex: 10})])
|
||
}
|
||
/* end */
|
||
this.$emit('update:map', this.amap)
|
||
this.$emit("loaded")
|
||
this.mapLoaded()
|
||
}
|
||
}).catch(() => c < 10 ? this.initMap(++c) : new Error("地图加载有问题"))
|
||
},
|
||
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.is3d && 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 && city) {
|
||
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%);
|
||
}
|
||
|
||
:deep( .marker ) {
|
||
position: relative;
|
||
|
||
& > img {
|
||
width: 30px;
|
||
height: 30px;
|
||
}
|
||
|
||
& > 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;
|
||
}
|
||
}
|
||
|
||
:deep( .amap-logo), :deep( .amap-copyright ) {
|
||
display: none !important;
|
||
}
|
||
|
||
:deep( .amap-icon ) {
|
||
width: 40px !important;
|
||
height: 40px !important;
|
||
|
||
img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
}
|
||
</style>
|