You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
5.3 KiB
188 lines
5.3 KiB
<template> |
|
<div style="position: relative; height: 100%; width: 100%; overflow: hidden"> |
|
<div id="map" style="height: 100%; width: 100%; overflow: hidden"></div> |
|
<div v-if="darkMask" class="dark-mask"></div> |
|
</div> |
|
</template> |
|
|
|
<script> |
|
import AMapLoader from '@amap/amap-jsapi-loader'; |
|
|
|
/** |
|
* props.rectangles: Array<{ id, name, status, geomWkt }> |
|
* - geomWkt: "POLYGON((lng lat,lng lat,...))" |
|
* - status: 施工中 | 已施工 | 未施工 | 故障 | 运行中 | 停机 |
|
*/ |
|
const STATUS_STYLE = { |
|
施工中: { stroke: 'rgba(41,169,253,1)', fill: 'rgba(41,169,253,0.45)' }, |
|
已施工: { stroke: 'rgba(82,196,26,1)', fill: 'rgba(82,196,26,0.45)' }, |
|
未施工: { stroke: 'rgba(250,173,20,1)', fill: 'rgba(250,173,20,0.45)' }, |
|
故障: { stroke: 'rgba(219,77,77,1)', fill: 'rgba(219,77,77,0.6)' }, |
|
运行中: { stroke: 'rgba(19,194,194,1)', fill: 'rgba(19,194,194,0.45)' }, |
|
停机: { stroke: 'rgba(99,99,99,1)', fill: 'rgba(0,0,0,0.45)' } |
|
}; |
|
|
|
export default { |
|
name: 'TaskMapPolygon', |
|
props: { |
|
rectangles: { |
|
type: Array, |
|
default: () => [] |
|
}, |
|
// 进一步压暗卫星底图的遮罩 |
|
darkMask: { |
|
type: Boolean, |
|
default: true |
|
} |
|
}, |
|
data() { |
|
return { |
|
map: null, |
|
AMapIns: null, |
|
polygons: [], |
|
texts: [], |
|
pointAll: { lng: [], lat: [] } |
|
}; |
|
}, |
|
watch: { |
|
rectangles: { |
|
immediate: true, |
|
deep: true, |
|
handler(val) { |
|
if (this.map && val?.length) { |
|
this.clearLayers(); |
|
this.formatData(val); |
|
} |
|
} |
|
} |
|
}, |
|
mounted() { |
|
this.initAMap(); |
|
}, |
|
beforeUnmount() { |
|
this.map?.destroy(); |
|
}, |
|
methods: { |
|
initAMap() { |
|
const map_center = JSON.parse(this.$storage.get('map_center') || 'null'); |
|
let defaultCenterPoint = [121.5563, 32.107]; |
|
if (map_center) { |
|
defaultCenterPoint = map_center.find((el) => el.key == 'default')?.value || defaultCenterPoint; |
|
} |
|
|
|
window._AMapSecurityConfig = { securityJsCode: '5869fe06ab3640b49006f4ec5e595e9f' }; |
|
AMapLoader.load({ |
|
key: '3758e4530242ba6282c77f96ea69262d', |
|
version: '2.0', |
|
plugins: ['AMap.MouseTool', 'AMap.Scale', 'AMap.Text'] |
|
}) |
|
.then((AMap) => { |
|
this.AMapIns = AMap; |
|
// 使用卫星图层(不叠加道路线) |
|
const satellite = new AMap.TileLayer.Satellite(); |
|
this.map = new AMap.Map('map', { |
|
viewMode: '2D', |
|
zoom: 12, |
|
center: defaultCenterPoint, |
|
layers: [satellite] |
|
}); |
|
if (this.rectangles?.length) { |
|
this.formatData(this.rectangles); |
|
} |
|
}) |
|
.catch(console.error); |
|
}, |
|
clearLayers() { |
|
if (!this.map) return; |
|
this.map.remove(this.polygons); |
|
this.map.remove(this.texts); |
|
this.polygons = []; |
|
this.texts = []; |
|
this.pointAll = { lng: [], lat: [] }; |
|
}, |
|
formatData(data = []) { |
|
// 解析 WKT -> AMap path,并着色绘制(使用原始坐标,不做偏移转换) |
|
const list = (data || []).map((item, index) => { |
|
const raw = (item.geomWkt || '') |
|
.replace(/POLYGON\(\(/i, '') |
|
.replace(/\)\)$/i, '') |
|
.trim(); |
|
const points = raw.split(','); |
|
const path = []; |
|
for (let i = 0; i < points.length; i++) { |
|
const parts = points[i].trim().split(/\s+/); |
|
const lng = Number(parts[0]); |
|
const lat = Number(parts[1]); |
|
if (isNaN(lng) || isNaN(lat)) continue; |
|
this.pointAll.lng.push(lng); |
|
this.pointAll.lat.push(lat); |
|
path.push([lng, lat]); |
|
} |
|
return { ...item, path, index }; |
|
}); |
|
|
|
list.forEach((it) => this.createPolygon(it)); |
|
|
|
// 视野自适配:基于多边形覆盖物 |
|
if (this.polygons.length) { |
|
// padding: [top, right, bottom, left] |
|
this.map.setFitView(this.polygons, false, [60, 60, 60, 60]); |
|
} |
|
}, |
|
createPolygon(item) { |
|
const { path, status, name } = item; |
|
const style = STATUS_STYLE[status] || STATUS_STYLE['未施工']; |
|
const polygon = new this.AMapIns.Polygon({ |
|
path, |
|
strokeColor: style.stroke, |
|
strokeWeight: 2, |
|
strokeOpacity: 1, |
|
strokeStyle: 'solid', |
|
fillColor: style.fill, |
|
fillOpacity: 0.45, |
|
cursor: 'pointer', |
|
zIndex: 50 |
|
}); |
|
console.log(polygon, 'polygon'); |
|
this.map.add(polygon); |
|
this.polygons.push(polygon); |
|
|
|
// 居中名称标签 |
|
const text = new this.AMapIns.Text({ |
|
text: name || '', |
|
anchor: 'center', |
|
style: { 'background-color': 'transparent', border: 'none', color: '#ffffff', 'font-size': '12px' } |
|
}); |
|
// 计算简单中心点 |
|
const mid = path[Math.floor(path.length / 2)] || path[0]; |
|
if (mid) text.setPosition(mid); |
|
text.setMap(this.map); |
|
this.texts.push(text); |
|
|
|
// hover 高亮 |
|
polygon.on('mouseover', () => { |
|
polygon.setOptions({ fillOpacity: 0.55 }); |
|
}); |
|
polygon.on('mouseout', () => { |
|
polygon.setOptions({ fillOpacity: 0.35 }); |
|
}); |
|
} |
|
} |
|
}; |
|
</script> |
|
|
|
<style scoped lang="scss"> |
|
#map { |
|
width: 100%; |
|
height: 100%; |
|
} |
|
.dark-mask { |
|
position: absolute; |
|
left: 0; |
|
top: 0; |
|
right: 0; |
|
bottom: 0; |
|
background: rgba(0, 10, 26, 0.25); |
|
pointer-events: none; |
|
} |
|
</style>
|
|
|