From 20281a184829329a2abbc6919b5aa4ac6a06752b Mon Sep 17 00:00:00 2001 From: hi2hi Date: Sun, 8 Dec 2024 16:39:02 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E4=B8=96=E7=95=8C?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E7=82=B9=E7=9A=84=E8=AE=A1=E7=AE=97=E9=80=BB?= =?UTF-8?q?=E8=BE=91=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=88=86=E7=BB=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=B9=B6=E9=87=8D=E6=9E=84=E7=9B=B8=E5=85=B3=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/world-map/world-map-point.vue | 25 +++++ src/components/world-map/world-map.vue | 111 ++++++++++++++++--- src/utils/world-map-location.js | 35 ------ src/utils/world-map.js | 61 ++++++++++ src/views/detail.vue | 3 +- src/views/home.vue | 13 ++- 6 files changed, 189 insertions(+), 59 deletions(-) delete mode 100644 src/utils/world-map-location.js create mode 100644 src/utils/world-map.js diff --git a/src/components/world-map/world-map-point.vue b/src/components/world-map/world-map-point.vue index e500d2d..4755eb3 100644 --- a/src/components/world-map/world-map-point.vue +++ b/src/components/world-map/world-map-point.vue @@ -2,6 +2,7 @@
diff --git a/src/components/world-map/world-map.vue b/src/components/world-map/world-map.vue index f8ce7fc..50c8281 100644 --- a/src/components/world-map/world-map.vue +++ b/src/components/world-map/world-map.vue @@ -37,10 +37,14 @@ import { ref, computed, + watch, } from 'vue'; import validate from '@/utils/validate'; import WorldMapPoint from './world-map-point.vue'; +import { + findIntersectingGroups, +} from '@/utils/world-map'; const props = defineProps({ width: { @@ -100,16 +104,75 @@ const mapStyle = computed(() => { return style; }); -const mapPoints = computed(() => props.locations.map((i) => { - const item = { - key: i.key, - left: (computedSize.value.width / 1280) * i.x, - top: (computedSize.value.height / 621) * i.y, - size: i.size || 4, - label: i.label, - }; - return item; -})); +const mapPoints = ref([]); +let computeMapPointsTimer = null; +function computeMapPoints() { + if (computeMapPointsTimer) { + clearTimeout(computeMapPointsTimer); + } + if (props.locations.length === 0) { + mapPoints.value = []; + return; + } + computeMapPointsTimer = setTimeout(() => { + const points = props.locations.map((i) => { + const item = { + key: i.key, + left: (computedSize.value.width / 1280) * i.x, + top: (computedSize.value.height / 621) * i.y, + size: i.size || 4, + label: i.label, + servers: i.servers, + type: 'single', + }; + const halfSize = (item.size + 8) / 2; + item.topLeft = { + left: item.left - halfSize, + top: item.top - halfSize, + }; + item.bottomRight = { + left: item.left + halfSize, + top: item.top + halfSize, + }; + return item; + }); + const groups = findIntersectingGroups(points); + Object.entries(groups).forEach(([key, group]) => { + const item = points.find((i) => i.key === key); + if (item.parent) { + return; + } + item.size = 4; + item.type = 'group'; + item.children = group; + let label = item.label || ''; + let servers = [...(item.servers || [])]; + group.forEach((i) => { + if (!i.parent && !i.children) { + i.parent = item; + label += `\n${i.label}`; + servers = servers.concat((i.servers || [])); + } + }); + item.label = label; + item.servers = servers; + }); + mapPoints.value = points.filter((i) => !i.parent); + }, 100); +} + +watch(() => props.locations, () => { + computeMapPoints(); +}, { + immediate: true, +}); + +watch(() => computedSize.value, () => { + computeMapPoints(); +}, { + immediate: true, + deep: true, +}); /** * 提示框 @@ -125,7 +188,7 @@ const tipsContentStyle = computed(() => { if (window.innerWidth > 500) { style.top = `${activeTipsXY.value.y}px`; style.left = `${activeTipsXY.value.x}px`; - style.transform = 'translate(-50%, 100%)'; + style.transform = 'translate(-50%, 20px)'; } else { style.bottom = '10px'; style.left = '50%'; @@ -133,18 +196,18 @@ const tipsContentStyle = computed(() => { } return style; }); -let timer = null; +let handlePointTapTimer = null; function handlePointTap(e) { tipsContent.value = e.label; activeTipsXY.value = { - x: e.left - (e.size / 2), - y: e.top - e.size, + x: e.left, + y: e.top - 10, }; tipsShow.value = true; - if (timer) { - clearTimeout(timer); + if (handlePointTapTimer) { + clearTimeout(handlePointTapTimer); } - timer = setTimeout(() => { + handlePointTapTimer = setTimeout(() => { tipsShow.value = false; }, 5000); } @@ -173,6 +236,20 @@ function handlePointTap(e) { background: rgba(#000, 0.8); box-shadow: 1px 4px 8px rgba(#303841, 0.4); z-index: 100; + white-space: pre; + + // 向上的尖角 + &::before { + content: ''; + position: absolute; + bottom: 100%; + left: 50%; + width: 0; + height: 0; + border: 5px solid transparent; + border-bottom-color: rgba(#000, 0.8); + transform: translateX(-50%); + } } } diff --git a/src/utils/world-map-location.js b/src/utils/world-map-location.js deleted file mode 100644 index e154314..0000000 --- a/src/utils/world-map-location.js +++ /dev/null @@ -1,35 +0,0 @@ -import config from '@/config'; -import CODE_MAPS, { - countryCodeMapping, - aliasMapping, -} from '@/data/code-maps'; - -export const ALIAS_CODE = { - ...aliasMapping, - ...countryCodeMapping, -}; - -export const alias2code = (code) => ALIAS_CODE[code]; - -export const locationCode2Info = (code) => { - const maps = { - ...CODE_MAPS, - ...(config.nazhua.customCodeMap || {}), - }; - let info = maps[code]; - const aliasCode = aliasMapping[code]; - if (!info && aliasCode) { - info = maps[aliasCode]; - } - return info; -}; - -export const count2size = (count) => { - if (count < 3) { - return 4; - } - if (count < 5) { - return 6; - } - return 8; -}; diff --git a/src/utils/world-map.js b/src/utils/world-map.js new file mode 100644 index 0000000..9dd9deb --- /dev/null +++ b/src/utils/world-map.js @@ -0,0 +1,61 @@ +import config from '@/config'; +import CODE_MAPS, { + countryCodeMapping, + aliasMapping, +} from '@/data/code-maps'; + +export const ALIAS_CODE = { + ...aliasMapping, + ...countryCodeMapping, +}; + +export const alias2code = (code) => ALIAS_CODE[code]; + +export const locationCode2Info = (code) => { + const maps = { + ...CODE_MAPS, + ...(config.nazhua.customCodeMap || {}), + }; + let info = maps[code]; + const aliasCode = aliasMapping[code]; + if (!info && aliasCode) { + info = maps[aliasCode]; + } + return info; +}; + +export const count2size = (count) => { + if (count < 3) { + return 4; + } + if (count < 5) { + return 6; + } + return 8; +}; + +export function findIntersectingGroups(coordinates) { + const groups = {}; + + coordinates.forEach((coordinate, index) => { + const intersects = []; + const n = 2; + coordinates.forEach((otherCoordinate, otherIndex) => { + if (index !== otherIndex) { + if ( + coordinate.topLeft.top - otherCoordinate.bottomRight.top < n + && coordinate.topLeft.left - otherCoordinate.bottomRight.left < n + && coordinate.bottomRight.top - otherCoordinate.topLeft.top > -n + && coordinate.bottomRight.left - otherCoordinate.topLeft.left > -n + ) { + intersects.push(otherCoordinate); + } + } + }); + if (intersects.length > 0) { + groups[coordinate.key] = intersects; + } + }); + + return groups; +} diff --git a/src/views/detail.vue b/src/views/detail.vue index 3b11eb3..6f6c77c 100644 --- a/src/views/detail.vue +++ b/src/views/detail.vue @@ -53,7 +53,7 @@ import config from '@/config'; import { alias2code, locationCode2Info, -} from '@/utils/world-map-location'; +} from '@/utils/world-map'; import WorldMap from '@/components/world-map/world-map.vue'; import ServerName from './components/server-detail/server-name.vue'; @@ -99,6 +99,7 @@ const locations = computed(() => { code, size: 4, label: `${name}`, + servers: [info.value], }); } return arr; diff --git a/src/views/home.vue b/src/views/home.vue index b25eaf0..b70f11d 100644 --- a/src/views/home.vue +++ b/src/views/home.vue @@ -64,7 +64,7 @@ import { alias2code, locationCode2Info, count2size, -} from '@/utils/world-map-location'; +} from '@/utils/world-map'; import uuid from '@/utils/uuid'; import WorldMap from '@/components/world-map/world-map.vue'; @@ -149,13 +149,13 @@ const serverLocations = computed(() => { const code = alias2code(aliasCode) || locationCode; if (code) { if (!locationMap[code]) { - locationMap[code] = 0; + locationMap[code] = []; } - locationMap[code] += 1; + locationMap[code].push(i); } }); const locations = []; - Object.entries(locationMap).forEach(([code, count]) => { + Object.entries(locationMap).forEach(([code, servers]) => { const { x, y, @@ -167,8 +167,9 @@ const serverLocations = computed(() => { x, y, code, - size: count2size(count), - label: `${name},${count}台`, + size: count2size(servers.length), + label: `${name},${servers.length}台`, + servers, }); } });