|
|
@@ -86,7 +86,7 @@
|
|
|
lonlat: [91.132212, 29.660361]
|
|
|
}
|
|
|
]
|
|
|
- const fullOptions = ref({ options: {} })
|
|
|
+ const fullOptions = shallowRef({ options: {} })
|
|
|
// 判断当前经纬度是否在规定区域内
|
|
|
function isPointInMultiPolygon(point, multiPolygons) {
|
|
|
for (let polygon of multiPolygons) {
|
|
|
@@ -140,65 +140,139 @@
|
|
|
let mapType = 0
|
|
|
let currentMap = { name: 'china', code: 100000 }
|
|
|
let optionConfig = null
|
|
|
+ // const setData = async (code = 100000, name = 'china') => {
|
|
|
+ // const geoJSON = await API_GET_GEO_JSON_GET({ code })
|
|
|
+ // const data = []
|
|
|
+ // loading.value = false
|
|
|
+ // const newGeojson = formatJson(geoJSON)
|
|
|
+ // newGeojson.features.forEach((item) => {
|
|
|
+ // data.push({
|
|
|
+ // name: item.properties.name,
|
|
|
+ // adcode: item.properties.adcode,
|
|
|
+ // level: item.properties.level,
|
|
|
+ // lonlat: item.properties.center
|
|
|
+ // })
|
|
|
+ // })
|
|
|
+
|
|
|
+ // // 过滤出当前地图的点位,过滤掉不属于改地图区域的点位
|
|
|
+ // // let currentData = toolTipData.filter((v) => {
|
|
|
+ // // return isPointInMultiPolygon([v.lonlat[0], v.lonlat[1]], newGeojson.features)
|
|
|
+ // // })
|
|
|
+
|
|
|
+ // // echartsRef.value.destroyed()
|
|
|
+ // optionConfig = chartOptions.setMapOption(
|
|
|
+ // data,
|
|
|
+ // geoJSON,
|
|
|
+ // code === 100000 ? toolTipData : [],
|
|
|
+ // name
|
|
|
+ // )
|
|
|
+ // optionConfig.option.geo.layoutSize = name == 'china' ? '140%' : '100%'
|
|
|
+ // currentMap = { name, code }
|
|
|
+ // const series =
|
|
|
+ // mapType === 0
|
|
|
+ // ? optionConfig.getSeries1()
|
|
|
+ // : mapType === 1
|
|
|
+ // ? optionConfig.getSeries2()
|
|
|
+ // : optionConfig.getSeries1()
|
|
|
+
|
|
|
+ // console.log(optionConfig)
|
|
|
+ // console.log(series)
|
|
|
+
|
|
|
+ // optionConfig.option.series.splice(1, 0, ...series)
|
|
|
+ // // fullOptions.value.options = optionConfig.option
|
|
|
+ // echartsRef.value.myChart.setOption(optionConfig.option, { notMerge: false })
|
|
|
+ // // echartsRef.value.myChart.on('georoam', function (params) {
|
|
|
+ // // var option = echartsRef.value.myChart.getOption() //获得option对象
|
|
|
+ // // if (params.zoom != null && params.zoom != undefined) {
|
|
|
+ // // //捕捉到缩放时
|
|
|
+ // // option.geo[1].zoom = option.geo[0].zoom //下层geo的缩放等级跟着上层的geo一起改变
|
|
|
+ // // option.geo[1].center = option.geo[0].center //下层的geo的中心位置随着上层geo一起改变
|
|
|
+ // // } else {
|
|
|
+ // // //捕捉到拖曳时
|
|
|
+ // // option.geo[1].center = option.geo[0].center //下层的geo的中心位置随着上层geo一起改变
|
|
|
+ // // }
|
|
|
+ // // echartsRef.value.myChart.dispatchAction({
|
|
|
+ // // type: 'restore'
|
|
|
+ // // })
|
|
|
+ // // echartsRef.value.myChart.setOption(option) //设置option
|
|
|
+ // // })
|
|
|
+ // }
|
|
|
+
|
|
|
+ // 保存事件监听器的引用,以便在组件销毁时移除
|
|
|
+
|
|
|
const setData = async (code = 100000, name = 'china') => {
|
|
|
- const geoJSON = await API_GET_GEO_JSON_GET({ code })
|
|
|
- const data = []
|
|
|
- loading.value = false
|
|
|
- const newGeojson = formatJson(geoJSON)
|
|
|
- newGeojson.features.forEach((item) => {
|
|
|
- data.push({
|
|
|
- name: item.properties.name,
|
|
|
- adcode: item.properties.adcode,
|
|
|
- level: item.properties.level,
|
|
|
- lonlat: item.properties.center
|
|
|
+ if (echartsRef.value?.myChart) {
|
|
|
+ // 如果是从 3D 饼图切回地图,或者地图 adcode 变化大
|
|
|
+ // 强制清理一次画布可以缓解 WebGL 压力
|
|
|
+ echartsRef.value.myChart.clear()
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ // 1. 开启 Loading 并锁定逻辑,防止重复触发
|
|
|
+ loading.value = true
|
|
|
+
|
|
|
+ const geoJSON = await API_GET_GEO_JSON_GET({ code })
|
|
|
+ if (!geoJSON) return
|
|
|
+
|
|
|
+ // 2. 格式化数据
|
|
|
+ const data = []
|
|
|
+ const newGeojson = formatJson(geoJSON)
|
|
|
+ newGeojson.features.forEach((item) => {
|
|
|
+ data.push({
|
|
|
+ name: item.properties.name,
|
|
|
+ adcode: item.properties.adcode,
|
|
|
+ level: item.properties.level,
|
|
|
+ lonlat: item.properties.center
|
|
|
+ })
|
|
|
})
|
|
|
- })
|
|
|
|
|
|
- // 过滤出当前地图的点位,过滤掉不属于改地图区域的点位
|
|
|
- // let currentData = toolTipData.filter((v) => {
|
|
|
- // return isPointInMultiPolygon([v.lonlat[0], v.lonlat[1]], newGeojson.features)
|
|
|
- // })
|
|
|
+ // 3. 释放旧的 optionConfig 引用
|
|
|
+ let optionConfig = chartOptions.setMapOption(
|
|
|
+ data,
|
|
|
+ geoJSON,
|
|
|
+ code === 100000 ? toolTipData : [],
|
|
|
+ name
|
|
|
+ )
|
|
|
|
|
|
- echartsRef.value.myChart?.clear()
|
|
|
- optionConfig = chartOptions.setMapOption(
|
|
|
- data,
|
|
|
- geoJSON,
|
|
|
- code === 100000 ? toolTipData : [],
|
|
|
- name
|
|
|
- )
|
|
|
- optionConfig.option.geo.forEach((v) => {
|
|
|
- v.layoutSize = name == 'china' ? '140%' : '100%'
|
|
|
- })
|
|
|
- currentMap = { name, code }
|
|
|
- optionConfig.option.series.splice(
|
|
|
- 1,
|
|
|
- 0,
|
|
|
- ...(mapType === 0
|
|
|
- ? optionConfig.getSeries1()
|
|
|
- : mapType === 1
|
|
|
- ? optionConfig.getSeries2()
|
|
|
- : optionConfig.getSeries1())
|
|
|
- )
|
|
|
- fullOptions.value.options = optionConfig.option
|
|
|
- // echartsRef.value.myChart.on('georoam', function (params) {
|
|
|
- // var option = echartsRef.value.myChart.getOption() //获得option对象
|
|
|
- // if (params.zoom != null && params.zoom != undefined) {
|
|
|
- // //捕捉到缩放时
|
|
|
- // option.geo[1].zoom = option.geo[0].zoom //下层geo的缩放等级跟着上层的geo一起改变
|
|
|
- // option.geo[1].center = option.geo[0].center //下层的geo的中心位置随着上层geo一起改变
|
|
|
- // } else {
|
|
|
- // //捕捉到拖曳时
|
|
|
- // option.geo[1].center = option.geo[0].center //下层的geo的中心位置随着上层geo一起改变
|
|
|
- // }
|
|
|
- // echartsRef.value.myChart.dispatchAction({
|
|
|
- // type: 'restore'
|
|
|
- // })
|
|
|
- // echartsRef.value.myChart.setOption(option) //设置option
|
|
|
- // })
|
|
|
+ // 4. 适配不同层级的缩放
|
|
|
+ optionConfig.option.geo.forEach((g) => {
|
|
|
+ g.layoutSize = name === 'china' ? '140%' : '100%'
|
|
|
+ // 关键:强制关闭缩放,防止多层 geo 错位
|
|
|
+ g.roam = false
|
|
|
+ })
|
|
|
+
|
|
|
+ currentMap = { name, code }
|
|
|
+
|
|
|
+ // 5. 获取 Series 逻辑
|
|
|
+ const seriesData = mapType === 1 ? optionConfig.getSeries2() : optionConfig.getSeries1()
|
|
|
+
|
|
|
+ // 清理并重新组合 series
|
|
|
+ // 建议:不要用 splice,直接重新赋值以保证数据的纯净
|
|
|
+ optionConfig.option.series = [optionConfig.option.series[0], ...seriesData]
|
|
|
+
|
|
|
+ // 6. 执行渲染
|
|
|
+ if (echartsRef.value && echartsRef.value.myChart) {
|
|
|
+ // 关键优化:使用 notMerge: true 彻底释放旧地图显存
|
|
|
+ echartsRef.value.myChart.setOption(optionConfig.option, {
|
|
|
+ notMerge: true,
|
|
|
+ lazyUpdate: false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('地图数据加载失败', error)
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const eventListeners = {
|
|
|
+ dblclick: null,
|
|
|
+ click: null
|
|
|
}
|
|
|
+
|
|
|
const init = async () => {
|
|
|
setData()
|
|
|
- echartsRef.value.myChart.on('dblclick', async function (params) {
|
|
|
+
|
|
|
+ // 保存dblclick事件监听器
|
|
|
+ eventListeners.dblclick = async function (params) {
|
|
|
if (params.data) {
|
|
|
const { adcode, name, level } = params.data
|
|
|
if (level === 'district' || params.componentSubType != 'map') {
|
|
|
@@ -207,66 +281,71 @@
|
|
|
useHomeStore.setCode({ code: adcode, name })
|
|
|
setData(adcode, name)
|
|
|
}
|
|
|
- })
|
|
|
- echartsRef.value.myChart.on('click', async function (params) {
|
|
|
+ }
|
|
|
+ echartsRef.value.myChart.on('dblclick', eventListeners.dblclick)
|
|
|
+
|
|
|
+ // 保存click事件监听器
|
|
|
+ eventListeners.click = async function (params) {
|
|
|
console.log(params)
|
|
|
if (params.seriesType === 'scatter') {
|
|
|
visible.value = true
|
|
|
}
|
|
|
- })
|
|
|
+ }
|
|
|
+ echartsRef.value.myChart.on('click', eventListeners.click)
|
|
|
|
|
|
+ // mitt事件监听器
|
|
|
$mitt.on('onPreLevel', (item) => {
|
|
|
if (useHomeStore.codes[useHomeStore.codes.length - 1].code === item.code) return
|
|
|
useHomeStore.codes = useHomeStore.codes.slice(
|
|
|
0,
|
|
|
useHomeStore.codes.findIndex((v) => v.name === item.name) + 1
|
|
|
)
|
|
|
+
|
|
|
setData(item.code, item.name === '中国' ? 'china' : item.name)
|
|
|
})
|
|
|
- const toolsIndex = (i) => {
|
|
|
- const series = fullOptions.value.options.series
|
|
|
- let newSeries = [series[0]]
|
|
|
- const index = series.findIndex((v) => v.name === '热力图')
|
|
|
- if (typeof i === 'number') {
|
|
|
- mapType = i
|
|
|
- if (i === 0) {
|
|
|
- if (index != -1) {
|
|
|
- newSeries = [...newSeries, series[index], ...optionConfig.getSeries1()]
|
|
|
- } else {
|
|
|
- newSeries = [...newSeries, ...optionConfig.getSeries1()]
|
|
|
- }
|
|
|
- } else if (i === 1) {
|
|
|
- if (index != -1) {
|
|
|
- newSeries = [...newSeries, series[index], ...optionConfig.getSeries2()]
|
|
|
- } else {
|
|
|
- newSeries = [...newSeries, ...optionConfig.getSeries2()]
|
|
|
- }
|
|
|
- }
|
|
|
- fullOptions.value.options.series = newSeries
|
|
|
- } else {
|
|
|
- if (i.type === 'rlt') {
|
|
|
- if (i.selected) {
|
|
|
- series.push(...optionConfig.getSeries3())
|
|
|
- } else {
|
|
|
- if (index == -1) return
|
|
|
- delete fullOptions.value.options.visualMap
|
|
|
- series.splice(
|
|
|
- series.findIndex((v) => v.name === '热力图'),
|
|
|
- 1
|
|
|
- )
|
|
|
- }
|
|
|
- }
|
|
|
- // else if (i.type === 'xs') {
|
|
|
- // if (i.selected) {
|
|
|
- // toolsIndex(mapType)
|
|
|
- // toolsIndex({ type: 'rlt' })
|
|
|
- // } else {
|
|
|
- // fullOptions.value.options.series = [series[0]]
|
|
|
- // }
|
|
|
- // }
|
|
|
- }
|
|
|
- }
|
|
|
- $mitt.on('onToolsIndex', toolsIndex)
|
|
|
+ // const toolsIndex = (i) => {
|
|
|
+ // const series = fullOptions.value.options.series
|
|
|
+ // let newSeries = [series[0]]
|
|
|
+ // const index = series.findIndex((v) => v.name === '热力图')
|
|
|
+ // if (typeof i === 'number') {
|
|
|
+ // mapType = i
|
|
|
+ // if (i === 0) {
|
|
|
+ // if (index != -1) {
|
|
|
+ // newSeries = [...newSeries, series[index], ...optionConfig.getSeries1()]
|
|
|
+ // } else {
|
|
|
+ // newSeries = [...newSeries, ...optionConfig.getSeries1()]
|
|
|
+ // }
|
|
|
+ // } else if (i === 1) {
|
|
|
+ // if (index != -1) {
|
|
|
+ // newSeries = [...newSeries, series[index], ...optionConfig.getSeries2()]
|
|
|
+ // } else {
|
|
|
+ // newSeries = [...newSeries, ...optionConfig.getSeries2()]
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // fullOptions.value.options.series = newSeries
|
|
|
+ // } else {
|
|
|
+ // if (i.type === 'rlt') {
|
|
|
+ // if (i.selected) {
|
|
|
+ // series.push(...optionConfig.getSeries3())
|
|
|
+ // } else {
|
|
|
+ // if (index == -1) return
|
|
|
+ // delete fullOptions.value.options.visualMap
|
|
|
+ // series.splice(
|
|
|
+ // series.findIndex((v) => v.name === '热力图'),
|
|
|
+ // 1
|
|
|
+ // )
|
|
|
+ // }
|
|
|
+ // } else if (i.type === 'xs') {
|
|
|
+ // // if (i.selected) {
|
|
|
+ // // toolsIndex(mapType)
|
|
|
+ // // toolsIndex({ type: 'rlt' })
|
|
|
+ // // } else {
|
|
|
+ // // fullOptions.value.options.series = [series[0]]
|
|
|
+ // // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // $mitt.on('onToolsIndex', toolsIndex)
|
|
|
}
|
|
|
|
|
|
watch(
|
|
|
@@ -277,9 +356,20 @@
|
|
|
}
|
|
|
}
|
|
|
)
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
init()
|
|
|
})
|
|
|
+
|
|
|
+ onUnmounted(() => {
|
|
|
+ // 移除echarts事件监听器
|
|
|
+ if (echartsRef.value?.myChart) {
|
|
|
+ echartsRef.value.myChart.off('dblclick', eventListeners.dblclick)
|
|
|
+ echartsRef.value.myChart.off('click', eventListeners.click)
|
|
|
+ }
|
|
|
+ // 移除mitt事件监听器
|
|
|
+ $mitt.off('onPreLevel')
|
|
|
+ })
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss">
|