|
|
@@ -0,0 +1,252 @@
|
|
|
+<template>
|
|
|
+ <div class="map-wrapper">
|
|
|
+ <div ref="mapContainer" class="map-container"></div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import AMapLoader from '@amap/amap-jsapi-loader';
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "EvaluationTrafficMap",
|
|
|
+ props: {
|
|
|
+ amapKey: { type: String, required: true },
|
|
|
+ securityJsCode: { type: String, required: true },
|
|
|
+ mode: {
|
|
|
+ type: String,
|
|
|
+ default: 'overview',
|
|
|
+ validator: (val) => ['overview', 'singlePoint', 'trunkLine', 'area'].includes(val)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ AMap: null,
|
|
|
+ map: null,
|
|
|
+ overlays: [], // 统一管理当前地图上的所有覆盖物
|
|
|
+ };
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ // 监听模式变化,重新绘制地图元素
|
|
|
+ mode(newMode) {
|
|
|
+ this.updateMapDisplay();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.initAMap();
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ if (this.map) {
|
|
|
+ this.map.destroy();
|
|
|
+ this.map = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async initAMap() {
|
|
|
+ window._AMapSecurityConfig = { securityJsCode: this.securityJsCode };
|
|
|
+ try {
|
|
|
+ const AMap = await AMapLoader.load({
|
|
|
+ key: this.amapKey,
|
|
|
+ version: "2.0",
|
|
|
+ });
|
|
|
+ this.AMap = AMap;
|
|
|
+ this.map = new AMap.Map(this.$refs.mapContainer, {
|
|
|
+ zoom: 13,
|
|
|
+ mapStyle: "amap://styles/darkblue",
|
|
|
+ center: [116.66, 39.91], // 通州区
|
|
|
+ });
|
|
|
+
|
|
|
+ this.map.on('complete', () => {
|
|
|
+ this.updateMapDisplay();
|
|
|
+ });
|
|
|
+ } catch (err) {
|
|
|
+ console.error('地图加载失败:', err);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ clearOverlays() {
|
|
|
+ if (this.map && this.overlays.length > 0) {
|
|
|
+ this.map.remove(this.overlays);
|
|
|
+ this.overlays = [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ updateMapDisplay() {
|
|
|
+ if (!this.map || !this.AMap) return;
|
|
|
+ this.clearOverlays();
|
|
|
+
|
|
|
+ switch (this.mode) {
|
|
|
+ case 'overview':
|
|
|
+ this.drawOverview();
|
|
|
+ break;
|
|
|
+ case 'singlePoint':
|
|
|
+ this.drawSinglePoint();
|
|
|
+ break;
|
|
|
+ case 'trunkLine':
|
|
|
+ this.drawTrunkLine();
|
|
|
+ break;
|
|
|
+ case 'area':
|
|
|
+ this.drawArea();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 1. 绘制总览:简单的红黄绿圆点
|
|
|
+ drawOverview() {
|
|
|
+ const mockData = [
|
|
|
+ { pos: [116.65, 39.90], color: '#00FF00' }, { pos: [116.66, 39.91], color: '#FF0000' },
|
|
|
+ { pos: [116.67, 39.89], color: '#FFA500' }, { pos: [116.69, 39.92], color: '#00FF00' },
|
|
|
+ { pos: [116.64, 39.93], color: '#FF0000' }, { pos: [116.70, 39.90], color: '#FFA500' },
|
|
|
+ { pos: [116.68, 39.91], color: '#00FF00' }, { pos: [116.66, 39.93], color: '#FF0000' },
|
|
|
+ ];
|
|
|
+
|
|
|
+ mockData.forEach(item => {
|
|
|
+ const marker = new this.AMap.Marker({
|
|
|
+ position: item.pos,
|
|
|
+ content: `<div style="width: 12px; height: 12px; background-color: ${item.color}; border-radius: 50%; box-shadow: 0 0 5px ${item.color}; border: 1px solid #fff;"></div>`,
|
|
|
+ offset: new this.AMap.Pixel(-6, -6),
|
|
|
+ });
|
|
|
+ this.overlays.push(marker);
|
|
|
+ });
|
|
|
+ this.map.add(this.overlays);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 2. 绘制评价监测-单点:带 A-F 字母和对应颜色的点
|
|
|
+ drawSinglePoint() {
|
|
|
+ const colors = { A: '#8fc31f', B: '#d7df23', C: '#fff200', D: '#f39c12', E: '#e74c3c', F: '#c0392b' };
|
|
|
+ const mockData = [
|
|
|
+ { pos: [116.63, 39.90], level: 'A' }, { pos: [116.65, 39.91], level: 'B' },
|
|
|
+ { pos: [116.66, 39.89], level: 'C' }, { pos: [116.68, 39.88], level: 'D' },
|
|
|
+ { pos: [116.70, 39.91], level: 'E' }, { pos: [116.71, 39.90], level: 'F' },
|
|
|
+ { pos: [116.67, 39.90], level: 'B' }, { pos: [116.69, 39.89], level: 'C' },
|
|
|
+ { pos: [116.65, 39.88], level: 'A' }, { pos: [116.69, 39.87], level: 'D' },
|
|
|
+ ];
|
|
|
+
|
|
|
+ mockData.forEach(item => {
|
|
|
+ const marker = new this.AMap.Marker({
|
|
|
+ position: item.pos,
|
|
|
+ content: `
|
|
|
+ <div style="width: 20px; height: 20px; background-color: ${colors[item.level]}; border-radius: 50%; display: flex; justify-content: center; align-items: center; color: #fff; font-weight: bold; font-size: 12px; border: 2px solid rgba(255,255,255,0.5);">
|
|
|
+ ${item.level}
|
|
|
+ </div>
|
|
|
+ `,
|
|
|
+ offset: new this.AMap.Pixel(-10, -10),
|
|
|
+ });
|
|
|
+ this.overlays.push(marker);
|
|
|
+ });
|
|
|
+ this.map.add(this.overlays);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 3. 绘制评价监测-干线:绿色波段线段
|
|
|
+ drawTrunkLine() {
|
|
|
+ const lines = [
|
|
|
+ [[116.65, 39.91], [116.69, 39.92]],
|
|
|
+ [[116.64, 39.90], [116.70, 39.91]],
|
|
|
+ [[116.65, 39.89], [116.70, 39.89]],
|
|
|
+ [[116.66, 39.88], [116.68, 39.85]],
|
|
|
+ ];
|
|
|
+
|
|
|
+ lines.forEach(path => {
|
|
|
+ // 画线
|
|
|
+ const polyline = new this.AMap.Polyline({
|
|
|
+ path: path,
|
|
|
+ isOutline: true,
|
|
|
+ outlineColor: '#fff',
|
|
|
+ borderWeight: 1,
|
|
|
+ strokeColor: "#a6ce39",
|
|
|
+ strokeOpacity: 0.9,
|
|
|
+ strokeWeight: 5,
|
|
|
+ });
|
|
|
+ this.overlays.push(polyline);
|
|
|
+
|
|
|
+ // 在线段两端或中间画点作为路口标识
|
|
|
+ path.forEach(pos => {
|
|
|
+ const marker = new this.AMap.Marker({
|
|
|
+ position: pos,
|
|
|
+ content: `<div style="width: 10px; height: 10px; background-color: #fff; border-radius: 50%; border: 2px solid #a6ce39;"></div>`,
|
|
|
+ offset: new this.AMap.Pixel(-5, -5),
|
|
|
+ });
|
|
|
+ this.overlays.push(marker);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.map.add(this.overlays);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 4. 绘制评价监测-区域:半透明多边形 + 中心文字
|
|
|
+ drawArea() {
|
|
|
+ const areas = [
|
|
|
+ {
|
|
|
+ path: [[116.67, 39.94], [116.70, 39.94], [116.71, 39.92], [116.70, 39.91], [116.67, 39.91]],
|
|
|
+ color: '#d35400', label: '6.2', center: [116.69, 39.925]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ path: [[116.68, 39.90], [116.72, 39.90], [116.72, 39.88], [116.68, 39.88]],
|
|
|
+ color: '#c0392b', label: '4.5', center: [116.70, 39.89]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ path: [[116.67, 39.87], [116.71, 39.87], [116.71, 39.85], [116.67, 39.85]],
|
|
|
+ color: '#c0392b', label: '4.8', center: [116.69, 39.86]
|
|
|
+ }
|
|
|
+ ];
|
|
|
+
|
|
|
+ areas.forEach(area => {
|
|
|
+ // 绘制多边形
|
|
|
+ const polygon = new this.AMap.Polygon({
|
|
|
+ path: area.path,
|
|
|
+ fillColor: area.color,
|
|
|
+ fillOpacity: 0.4,
|
|
|
+ strokeColor: area.color,
|
|
|
+ strokeWeight: 2,
|
|
|
+ });
|
|
|
+ this.overlays.push(polygon);
|
|
|
+
|
|
|
+ // 绘制中心数字标识
|
|
|
+ const textMarker = new this.AMap.Marker({
|
|
|
+ position: area.center,
|
|
|
+ content: `<div style="color: rgba(255,255,255,0.8); font-size: 24px; font-weight: bold; text-shadow: 1px 1px 2px #000;">${area.label}</div>`,
|
|
|
+ offset: new this.AMap.Pixel(-15, -15),
|
|
|
+ });
|
|
|
+ this.overlays.push(textMarker);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 画一个圆形的区域 (对应图中的绿色 9.1)
|
|
|
+ const circle = new this.AMap.Circle({
|
|
|
+ center: [116.64, 39.88],
|
|
|
+ radius: 1800,
|
|
|
+ fillColor: '#27ae60',
|
|
|
+ fillOpacity: 0.4,
|
|
|
+ strokeColor: '#27ae60',
|
|
|
+ strokeWeight: 2,
|
|
|
+ });
|
|
|
+ this.overlays.push(circle);
|
|
|
+
|
|
|
+ const circleText = new this.AMap.Marker({
|
|
|
+ position: [116.64, 39.88],
|
|
|
+ content: `<div style="color: rgba(255,255,255,0.8); font-size: 24px; font-weight: bold; text-shadow: 1px 1px 2px #000;">9.1</div>`,
|
|
|
+ offset: new this.AMap.Pixel(-15, -15),
|
|
|
+ });
|
|
|
+ this.overlays.push(circleText);
|
|
|
+
|
|
|
+ this.map.add(this.overlays);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.map-wrapper {
|
|
|
+ width: 100%;
|
|
|
+ height: 100vh;
|
|
|
+ position: relative;
|
|
|
+ background: #010813;
|
|
|
+}
|
|
|
+.map-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+/* 隐藏高德Logo等 */
|
|
|
+::v-deep .amap-logo,
|
|
|
+::v-deep .amap-copyright,
|
|
|
+::v-deep .amap-copyright-logo {
|
|
|
+ display: none !important;
|
|
|
+}
|
|
|
+</style>
|