|
|
@@ -1,5 +1,5 @@
|
|
|
<template>
|
|
|
- <div class="map-wrapper">
|
|
|
+ <div class="map-wrapper" :style="mapCssVars">
|
|
|
<div ref="mapContainer" class="map-container"></div>
|
|
|
|
|
|
<div class="map-legend" :style="privateStyle.legend" v-if="(!mode || mode === '路口')"
|
|
|
@@ -83,7 +83,8 @@ export default {
|
|
|
{ name: "故障", color: "#FF3938", type: "abnormal" }
|
|
|
],
|
|
|
intersectionData: [],
|
|
|
- statusIntersections: {}
|
|
|
+ statusIntersections: {},
|
|
|
+ currentZoomSize: 14, // 保存当前的动态尺寸
|
|
|
};
|
|
|
},
|
|
|
mounted() {
|
|
|
@@ -177,6 +178,18 @@ export default {
|
|
|
return this.statusConfig.filter(item => !['干线协调', '勤务路线'].includes(item.name));
|
|
|
}
|
|
|
return [];
|
|
|
+ },
|
|
|
+ // 自动计算并下发给所有 CSS 的变量字典
|
|
|
+ mapCssVars() {
|
|
|
+ const size = this.currentZoomSize;
|
|
|
+ const specialSize = Math.max(16, size * 1.5);
|
|
|
+ return {
|
|
|
+ '--dot-size': `${size}px`,
|
|
|
+ '--dot-padding': size >= 14 ? '2px' : '0px',
|
|
|
+ '--text-display': size >= 14 ? 'flex' : 'none',
|
|
|
+ '--text-size': `${Math.max(10, size - 2)}px`,
|
|
|
+ '--special-size': `${specialSize}px`
|
|
|
+ };
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
@@ -299,6 +312,12 @@ export default {
|
|
|
this.drawStaticRoutes();
|
|
|
}
|
|
|
});
|
|
|
+
|
|
|
+ this.map.on('zoomchange', () => {
|
|
|
+ if (!this.isComponentDestroyed) {
|
|
|
+ this.currentZoomSize = this.getDotSizeByZoom();
|
|
|
+ }
|
|
|
+ });
|
|
|
} catch (err) {
|
|
|
console.error('地图加载失败:', err);
|
|
|
}
|
|
|
@@ -915,30 +934,9 @@ export default {
|
|
|
getDotSizeByZoom() {
|
|
|
if (!this.map) return 14;
|
|
|
const zoom = this.map.getZoom();
|
|
|
- const base = 14;
|
|
|
- const extra = Math.max(0, zoom - 15) * 3;
|
|
|
- return Math.min(base + extra, 28);
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 遍历所有已注册的普通圆点 marker,更新其 content 和 offset
|
|
|
- */
|
|
|
- updateDotMarkerSizes() {
|
|
|
- if (!this.isMapReady()) return;
|
|
|
- const size = this.getDotSizeByZoom();
|
|
|
- const half = Math.round(size / 2) + 2;
|
|
|
- this.dotMarkers.forEach(({ marker, config, isRoute }) => {
|
|
|
- if (!marker || typeof marker.setContent !== 'function') return;
|
|
|
- const displayText = config.name ? config.name.charAt(0) : '';
|
|
|
- const border = isRoute ? 'none' : '1.5px solid rgba(255,255,255,0.7)';
|
|
|
- const boxShadow = isRoute ? 'none' : `0 0 8px ${config.color}`;
|
|
|
- marker.setContent(`
|
|
|
- <div class="pure-light-node ${isRoute ? 'route-node' : ''}" style="width:${size}px;height:${size}px;background:${config.color || '#999'};box-shadow:${boxShadow};border:${border};box-sizing:content-box;display:flex;justify-content:center;align-items:center;color:#fff;border-radius:50%;cursor:pointer;padding:2px;">
|
|
|
- <span style="transform:scale(0.8);font-weight:bold;font-size:${Math.max(10, size - 2)}px;">${displayText}</span>
|
|
|
- </div>
|
|
|
- `);
|
|
|
- marker.setOffset(new this.AMap.Pixel(-half, -half));
|
|
|
- });
|
|
|
+ // 基准:zoom=15时是14px。每缩小一级减小3px。
|
|
|
+ const size = 14 + (zoom - 15) * 3;
|
|
|
+ return Math.min(Math.max(6, size), 28); // 最小值设为 6px
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
@@ -965,30 +963,12 @@ export default {
|
|
|
const isStartEnd = type === 'start' || type === 'end';
|
|
|
const isPassed = type === 'passed';
|
|
|
|
|
|
- const markerStyle = isStartEnd ? {
|
|
|
- size: '24px',
|
|
|
- height: '30px',
|
|
|
- offset: [-12, -30],
|
|
|
- zIndex: 120,
|
|
|
- border: '2px solid #fff'
|
|
|
- } : (isAbnormal ? {
|
|
|
- size: '30px',
|
|
|
- height: '30px',
|
|
|
- offset: [-15, -15],
|
|
|
- zIndex: 110,
|
|
|
- border: 'none'
|
|
|
- } : {
|
|
|
- size: '18px',
|
|
|
- height: '18px',
|
|
|
- offset: [-11, -11],
|
|
|
- zIndex: 100,
|
|
|
- border: isRoute ? 'none' : '1.5px solid rgba(255,255,255,0.7)'
|
|
|
- });
|
|
|
-
|
|
|
let markerContent = '';
|
|
|
+
|
|
|
+ // --- 核心优化:尺寸全部使用 var(--xxx) CSS变量接管 ---
|
|
|
if (isStartEnd) {
|
|
|
markerContent = `
|
|
|
- <div class="pure-light-node start-end-node" style="width: ${markerStyle.size}; height: ${markerStyle.height}; background: transparent; border: none; display: flex; justify-content: center; align-items: flex-end; cursor: pointer; transform-origin: bottom center;">
|
|
|
+ <div class="pure-light-node start-end-node" style="width: var(--special-size); height: calc(var(--special-size) + 6px); background: transparent; border: none; display: flex; justify-content: center; align-items: flex-end; cursor: pointer; transform-origin: bottom center;">
|
|
|
<img src="${require(`@/assets/map/${type}.png`)}" style="width: 100%; height: auto; object-fit: contain; pointer-events: none;" />
|
|
|
</div>
|
|
|
`;
|
|
|
@@ -1001,23 +981,24 @@ export default {
|
|
|
} else if (isAbnormal) {
|
|
|
const iconName = config.name === '离线' ? 'lixian' : config.name === '降级' ? 'jiangji' : 'guzhang';
|
|
|
markerContent = `
|
|
|
- <div class="pure-light-node breathe" style="width: ${markerStyle.size}; height: ${markerStyle.height}; background: transparent; border: none; box-sizing: content-box; display: flex; justify-content: center; align-items: center; cursor: pointer; padding: 0;">
|
|
|
+ <div class="pure-light-node breathe" style="width: var(--special-size); height: var(--special-size); background: transparent; border: none; display: flex; justify-content: center; align-items: center; cursor: pointer; padding: 0;">
|
|
|
<img src="${require(`@/assets/images/icon_${iconName}.png`)}" style="width: 100%; height: 100%; object-fit: contain;" />
|
|
|
</div>
|
|
|
`;
|
|
|
} else {
|
|
|
markerContent = `
|
|
|
- <div class="pure-light-node ${isRoute ? 'route-node' : ''}" style="width: ${markerStyle.size}; height: ${markerStyle.height}; background: ${config.color || '#999'}; box-shadow: ${isRoute ? 'none' : `0 0 8px ${config.color}`}; border: ${markerStyle.border}; box-sizing: content-box; display: flex; justify-content: center; align-items: center; color: #fff; border-radius: 50%; cursor: pointer; padding: 2px;">
|
|
|
- <span style="transform: scale(0.8); font-weight: bold; font-size: 14px;">${displayText}</span>
|
|
|
+ <div class="pure-light-node ${isRoute ? 'route-node' : ''}" style="width: var(--dot-size); height: var(--dot-size); background: ${config.color || '#999'}; box-shadow: ${isRoute ? 'none' : `0 0 8px ${config.color}`}; border: ${isRoute ? 'none' : '1.5px solid rgba(255,255,255,0.7)'}; box-sizing: border-box; display: flex; justify-content: center; align-items: center; color: #fff; border-radius: 50%; cursor: pointer; padding: var(--dot-padding);">
|
|
|
+ <span style="display: var(--text-display); transform: scale(0.8); font-weight: bold; font-size: var(--text-size);">${displayText}</span>
|
|
|
</div>
|
|
|
`;
|
|
|
}
|
|
|
|
|
|
const marker = new this.AMap.Marker({
|
|
|
position: [lng, lat],
|
|
|
- zIndex: markerStyle.zIndex,
|
|
|
+ zIndex: isStartEnd ? 120 : (isAbnormal ? 110 : 100),
|
|
|
content: markerContent,
|
|
|
- offset: new this.AMap.Pixel(...markerStyle.offset),
|
|
|
+ // 核心优化:高德 2.0 原生支持 anchor 属性。代替手动计算 Offset!
|
|
|
+ anchor: isStartEnd ? 'bottom-center' : 'center',
|
|
|
extData: {
|
|
|
...config,
|
|
|
position: [lng, lat],
|
|
|
@@ -1029,11 +1010,6 @@ export default {
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- if (!isStartEnd && !isAbnormal && !isPassed) {
|
|
|
- const isRoute = ["干线协调", "勤务路线"].includes(config.name);
|
|
|
- this.dotMarkers.push({ marker, config, isRoute });
|
|
|
- }
|
|
|
-
|
|
|
marker.on('click', (e) => {
|
|
|
if (this.isComponentDestroyed) return;
|
|
|
const extData = e.target.getExtData();
|