Commit 948cd75bff727a1307e00637bc0ccf0e78daa14e

Authored by xp.Huang
2 parents 1aa17ab8 1b052dfc

Merge branch 'fix/3D-map-select-sacle' into 'main_dev'

perf(src/views/chart): 优化三维地图右侧区块配置项,并且修复兼容之前旧地图

See merge request yunteng/thingskit-view!185
1 1 <script lang="ts" setup name="SelectCity">
2   -import { onMounted, reactive } from 'vue'
  2 +import { onMounted, reactive, nextTick } from 'vue'
3 3 import { getAreaList } from '@/api/external/common/index'
4 4 import { areaEnum } from '../config'
5 5
... ... @@ -25,7 +25,8 @@ const selectValues = reactive({
25 25 provinceValue: 'china',
26 26 cityValue: null,
27 27 countyValue: null,
28   - levelStr: areaEnum.COUNTRY
  28 + levelStr: areaEnum.COUNTRY,
  29 + areaName: ''
29 30 })
30 31
31 32 const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => {
... ... @@ -34,36 +35,40 @@ const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => {
34 35 parentId
35 36 })
36 37 if (!resp) return []
37   - return resp.map((item: any) => ({ label: item.name, value: item.code }))
  38 + return resp.map((item: Recordable) => ({ label: item.name, value: item.code }))
38 39 }
39 40
40 41 onMounted(async () => {
41 42 selectOptions.provinceOptions = await getAreaLists()
42   - ;(selectOptions.provinceOptions as never as any).unshift({
  43 + ;(selectOptions.provinceOptions as never as Recordable[]).unshift({
43 44 label: '中国',
44 45 value: 'china'
45 46 })
46   - onHandleSelectProvince(props.optionData?.mapRegion.saveSelect['provinceValue'])
  47 + onHandleSelectProvince(props.optionData?.mapRegion.saveSelect['provinceValue'], {})
47 48 for (let i in selectValues) Reflect.set(selectValues, i, props.optionData?.mapRegion.saveSelect[i])
48 49 })
49 50
50   -const onHandleSelectProvince = async (value: number | string) => {
  51 +const onHandleSelectProvince = async (value: number | string, options: Recordable) => {
51 52 selectValues.cityValue = null
52 53 selectValues.countyValue = null
53 54 if (value === 'china') return (selectValues.levelStr = areaEnum.COUNTRY)
54   - selectOptions.cityOptions = await getAreaLists(areaEnum.CITY, value as any)
  55 + selectOptions.cityOptions = await getAreaLists(areaEnum.CITY, value as number)
55 56 selectValues.levelStr = areaEnum.PROVINCE
  57 + selectValues.areaName = options.label
56 58 }
57 59
58   -const onHandleSelectCity = async (value: number) => {
  60 +const onHandleSelectCity = async (value: number, options: Recordable) => {
59 61 selectValues.countyValue = null
60 62 selectOptions.countryOptions = await getAreaLists(areaEnum.COUNTY, value)
61 63 selectValues.levelStr = areaEnum.CITY
  64 + selectValues.areaName = options.label
62 65 }
63 66
64   -const onHandleSubmit = () => {
  67 +const onHandleSubmit = async () => {
  68 + await nextTick()
65 69 emits('submit', selectValues)
66 70 }
  71 +
67 72 const resetValue = () => {
68 73 selectValues.provinceValue = 'china'
69 74 selectValues.cityValue = null
... ... @@ -72,6 +77,7 @@ const resetValue = () => {
72 77 selectOptions.cityOptions = []
73 78 selectOptions.countryOptions = []
74 79 }
  80 +
75 81 defineExpose({
76 82 resetValue
77 83 })
... ...
... ... @@ -20,6 +20,7 @@ export interface regionInfo {
20 20 cityValue: string | null
21 21 countyValue: string | null
22 22 levelStr: areaEnum
  23 + areaName: string
23 24 }
24 25
25 26 type itemOption = {
... ... @@ -36,6 +37,7 @@ export interface regionOption {
36 37 export interface historyParentType {
37 38 adcode: number
38 39 level: string
  40 + areaName: string
39 41 }
40 42
41 43 export interface backMapLevel {
... ... @@ -50,6 +52,7 @@ export interface levelFunc {
50 52 //数据源接口
51 53 export interface dataPointI {
52 54 name: string
  55 + city_name: string
53 56 value: number[]
54 57 adcode: number
55 58 height: number
... ... @@ -69,6 +72,70 @@ export const regionMapParentArea = {
69 72 TOWN: areaEnum.COUNTY //镇的上一级 县或者区
70 73 }
71 74
  75 +// 缩放配置文件
  76 +export const setScale = (adcode: string | number) => {
  77 + switch (adcode) {
  78 + case 'china':
  79 + return { distance: 100, zoom: 1, alpha: 45 }
  80 + case '110000':
  81 + return { distance: 150, zoom: 0.8, alpha: 45 }
  82 + case '120000':
  83 + return { distance: 190, zoom: 0.8, alpha: 45 }
  84 + case '130000':
  85 + return { distance: 165, zoom: 0.8, alpha: 45 }
  86 + case '140000':
  87 + return { distance: 216, zoom: 0.8, alpha: 45 }
  88 + case '150000':
  89 + return { distance: 130, zoom: 0.8, alpha: 45 }
  90 + case '210000':
  91 + return { distance: 130, zoom: 0.8, alpha: 45 }
  92 + case '310000':
  93 + return { distance: 135, zoom: 0.8, alpha: 45 }
  94 + case '320000':
  95 + return { distance: 145, zoom: 0.8, alpha: 45 }
  96 + case '330000':
  97 + return { distance: 135, zoom: 0.8, alpha: 45 }
  98 + case '340000':
  99 + return { distance: 170, zoom: 0.8, alpha: 45 }
  100 + case '350000':
  101 + return { distance: 150, zoom: 0.8, alpha: 45 }
  102 + case '360000':
  103 + return { distance: 190, zoom: 0.8, alpha: 45 }
  104 + case '370000':
  105 + return { distance: 135, zoom: 0.8, alpha: 45 }
  106 + case '420000':
  107 + return { distance: 145, zoom: 0.8, alpha: 45 }
  108 + case '430000':
  109 + return { distance: 165, zoom: 0.8, alpha: 45 }
  110 + case '440000':
  111 + return { distance: 165, zoom: 0.8, alpha: 45 }
  112 + case '500000':
  113 + return { distance: 145, zoom: 0.8, alpha: 45 }
  114 + case '520000':
  115 + return { distance: 135, zoom: 0.8, alpha: 45 }
  116 + case '530000':
  117 + return { distance: 145, zoom: 0.8, alpha: 45 }
  118 + case '540000':
  119 + return { distance: 140, zoom: 0.8, alpha: 45 }
  120 + case '610000':
  121 + return { distance: 210, zoom: 0.8, alpha: 45 }
  122 + case '620000':
  123 + return { distance: 135, zoom: 0.8, alpha: 45 }
  124 + case '640000':
  125 + return { distance: 195, zoom: 0.8, alpha: 45 }
  126 + case '650000':
  127 + return { distance: 135, zoom: 0.8, alpha: 45 }
  128 + case '710000':
  129 + return { distance: 135, zoom: 0.8, alpha: 45 }
  130 + case '810000':
  131 + return { distance: 145, zoom: 0.8, alpha: 45 }
  132 + case '820000':
  133 + return { distance: 240, zoom: 0.8, alpha: 45 }
  134 + default:
  135 + return { distance: 125, zoom: 1, alpha: 45 }
  136 + }
  137 +}
  138 +
72 139 export const includes = []
73 140
74 141 // 特殊处理安徽省的下钻
... ... @@ -105,11 +172,13 @@ export const option = {
105 172 mapRegion: {
106 173 adcode: 'china',
107 174 showHainanIsLands: true,
  175 + areaName: '',
108 176 saveSelect: {
109 177 levelStr: areaEnum.COUNTRY,
110 178 cityValue: null,
111 179 countyValue: null,
112   - provinceValue: 'china'
  180 + provinceValue: 'china',
  181 + areaName: ''
113 182 }
114 183 },
115 184 tooltip: {
... ... @@ -118,30 +187,30 @@ export const option = {
118 187 //三维地图有两种,一种是geo3D,另一种是map3D,但是如果使用geo3D,地图点击获取不到点击区域name
119 188 geo3D: {
120 189 show: false, // 隐藏该层,为true时会导致出现两个地图
121   - map: 'centerMap',
  190 + map: '',
122 191 roam: true
123 192 },
124 193 series: [
125 194 {
126 195 type: 'map3D',
127   - map: 'centerMap',
128   - name: 'centerMap',
129   - regionHeight: 3,
  196 + map: '',
  197 + name: '',
  198 + regionHeight: 0,
130 199 label: {
131 200 show: true,
132 201 formatter: function (params: Recordable) {
133 202 return params.data.name ? params.data.name : ' '
134 203 },
135 204 textStyle: {
136   - color: '#fff',
  205 + color: '#ffffffff',
137 206 fontSize: 14
138 207 }
139 208 },
140 209 itemStyle: {
141   - color: '#4482B1FF', //背景颜色
  210 + color: '#3c7effff', //背景颜色
142 211 opacity: 1,
143 212 borderWidth: 0.8,
144   - borderColor: '#4482B1FF'
  213 + borderColor: '#51d6a9FF'
145 214 },
146 215 emphasis: {
147 216 // 鼠标hover 高亮时图形和标签的样式 (当鼠标放上去时 label和itemStyle 的样式)
... ... @@ -149,12 +218,12 @@ export const option = {
149 218 // label高亮时的配置
150 219 show: true,
151 220 textStyle: {
152   - color: 'green',
  221 + color: '#57c3c2ff',
153 222 fontSize: 14
154 223 }
155 224 },
156 225 itemStyle: {
157   - color: 'red'
  226 + color: '#1ba784ff'
158 227 }
159 228 },
160 229 data: [],
... ... @@ -163,28 +232,19 @@ export const option = {
163 232 }
164 233 },
165 234 {
166   - name: 'scatter3D',
167   - type: 'scatter3D',
168   - coordinateSystem: 'geo3D',
169   - symbol: 'circle',
170   - symbolSize: 20,
171   - animation: true,
172   - data: []
173   - },
174   - {
175 235 name: 'bar3D',
176 236 type: 'bar3D',
177 237 coordinateSystem: 'geo3D',
178 238 // 倒角尺寸
179 239 bevelSize: 0,
180   - minHeight: 12,
  240 + minHeight: 5,
181 241 shading: 'lambert',
182 242 barSize: 1,
183 243 itemStyle: {
184 244 color: '#4482B1FF'
185 245 },
186 246 data: []
187   - },
  247 + }
188 248 ]
189 249 }
190 250
... ...
... ... @@ -43,7 +43,7 @@
43 43 />
44 44 <div style="height: 30px"></div>
45 45 <n-tag type="primary">若配置无响应,请在预览页面查看效果</n-tag>
46   - <SettingItemBox name="区块配置">
  46 + <SettingItemBox name="地图配置">
47 47 <SettingItem name="区域颜色">
48 48 <n-color-picker size="small" :modes="['hex']" v-model:value="seriesList[0].itemStyle.color"></n-color-picker>
49 49 </SettingItem>
... ... @@ -126,24 +126,10 @@
126 126 ></n-color-picker>
127 127 </SettingItem>
128 128 </SettingItemBox>
129   - <SettingItemBox name="散点配置">
130   - <SettingItem name="大小">
131   - <n-input-number
132   - v-model:value="seriesList[1].symbolSize"
133   - :min="0"
134   - :step="1"
135   - size="small"
136   - placeholder="请输入"
137   - ></n-input-number>
138   - </SettingItem>
139   - <SettingItem name="形状">
140   - <n-select :options="symbolOption" v-model:value="seriesList[1].symbol"></n-select>
141   - </SettingItem>
142   - </SettingItemBox>
143 129 <SettingItemBox name="柱状配置">
144 130 <SettingItem name="最小高度">
145 131 <n-input-number
146   - v-model:value="seriesList[2].minHeight"
  132 + v-model:value="seriesList[1].minHeight"
147 133 :min="0"
148 134 :step="1"
149 135 size="small"
... ... @@ -152,7 +138,7 @@
152 138 </SettingItem>
153 139 <SettingItem name="大小">
154 140 <n-input-number
155   - v-model:value="seriesList[2].barSize"
  141 + v-model:value="seriesList[1].barSize"
156 142 :min="0"
157 143 :step="1"
158 144 size="small"
... ... @@ -161,7 +147,7 @@
161 147 </SettingItem>
162 148 <SettingItem name="倒角尺寸">
163 149 <n-input-number
164   - v-model:value="seriesList[2].bevelSize"
  150 + v-model:value="seriesList[1].bevelSize"
165 151 :min="0"
166 152 :max="1"
167 153 :step="0.1"
... ... @@ -170,15 +156,22 @@
170 156 ></n-input-number>
171 157 </SettingItem>
172 158 </SettingItemBox>
173   - <SettingItemBox name="区块配置">
  159 + </CollapseItem>
  160 + <CollapseItem name="地区配置" :expanded="true">
  161 + <SettingItemBox name="地区配置" :alone="true">
174 162 <template v-for="(item, map3DIndex) in optionData.dataset.map3D" :key="map3DIndex">
175   - <setting-item name="地区名称">
176   - <n-input v-model:value="item.name"> </n-input>
  163 + <setting-item name="省份名称">
  164 + <n-select
  165 + @change="(v:number,o:Recordable,w:Recordable,s1:number)=> onHandleSelectProvince(v,o,item, map3DIndex)"
  166 + placeholder="请选择省份"
  167 + v-model:value="item.name"
  168 + :options="item.provinceOptions"
  169 + />
177 170 </setting-item>
178   - <setting-item name="地区代码">
179   - <n-input v-model:value="item.adcode"> </n-input>
  171 + <setting-item name="城市名称">
  172 + <n-select placeholder="请选择城市" v-model:value="item.city_name" :options="item.cityOptions" />
180 173 </setting-item>
181   - <setting-item name="离地高度">
  174 + <setting-item name="区块厚度">
182 175 <n-input-number v-model:value="item.height"> </n-input-number>
183 176 </setting-item>
184 177 <setting-item name="区块颜色">
... ... @@ -187,71 +180,27 @@
187 180 <setting-item name="区块透明度">
188 181 <n-input-number v-model:value="item.itemStyle.opacity"> </n-input-number>
189 182 </setting-item>
  183 + <setting-item></setting-item>
190 184 <setting-item>
191 185 <n-button size="small" @click="optionData.dataset.map3D.splice(map3DIndex, 1)"> - </n-button>
192 186 </setting-item>
193 187 </template>
194   - <n-button
195   - style="float: right"
196   - size="small"
197   - @click="optionData.dataset.map3D.push(cloneDeep(STATIC_SCATTER_CONFIG))"
198   - >
199   - +
200   - </n-button>
  188 + <div class="h-space"></div>
  189 + <n-button size="small" @click="handleAddRegion"> + </n-button>
201 190 </SettingItemBox>
202   - <SettingItemBox name="散点配置">
203   - <template v-for="(item, scatterIndex) in optionData.dataset.scatter3D" :key="scatterIndex">
204   - <setting-item name="地区名称">
205   - <n-input v-model:value="item.name"> </n-input>
206   - </setting-item>
207   - <setting-item name="地区代码">
208   - <n-input v-model:value="item.adcode"> </n-input>
209   - </setting-item>
210   - <setting-item name="离地高度">
211   - <n-input-number v-model:value="item.height"> </n-input-number>
212   - </setting-item>
  191 + </CollapseItem>
  192 + <CollapseItem name="柱状配置" :expanded="true">
  193 + <SettingItemBox name="柱状配置" :alone="true">
  194 + <template v-for="(item, barIndex) in optionData.dataset.bar3D" :key="barIndex">
213 195 <setting-item name="经度">
214 196 <n-input-number v-model:value="item.value[0]"> </n-input-number>
215 197 </setting-item>
216 198 <setting-item name="纬度">
217 199 <n-input-number v-model:value="item.value[1]"> </n-input-number>
218 200 </setting-item>
219   - <setting-item name="散点颜色">
220   - <n-color-picker size="small" :modes="['hex']" v-model:value="item.itemStyle.color"></n-color-picker>
221   - </setting-item>
222   - <setting-item name="散点透明度">
223   - <n-input-number v-model:value="item.itemStyle.opacity"> </n-input-number>
224   - </setting-item>
225   - <setting-item> </setting-item>
226   - <setting-item>
227   - <n-button size="small" @click="optionData.dataset.scatter3D.splice(scatterIndex, 1)"> - </n-button>
228   - </setting-item>
229   - </template>
230   - <n-button
231   - style="float: right"
232   - size="small"
233   - @click="optionData.dataset.scatter3D.push(cloneDeep(STATIC_SCATTER_CONFIG))"
234   - >
235   - +
236   - </n-button>
237   - </SettingItemBox>
238   - <SettingItemBox name="柱状配置">
239   - <template v-for="(item, barIndex) in optionData.dataset.bar3D" :key="barIndex">
240   - <setting-item name="地区名称">
241   - <n-input v-model:value="item.name"> </n-input>
242   - </setting-item>
243   - <setting-item name="地区代码">
244   - <n-input v-model:value="item.adcode"> </n-input>
245   - </setting-item>
246 201 <setting-item name="离地高度">
247 202 <n-input-number v-model:value="item.height"> </n-input-number>
248 203 </setting-item>
249   - <setting-item name="经度">
250   - <n-input-number v-model:value="item.value[0]"> </n-input-number>
251   - </setting-item>
252   - <setting-item name="纬度">
253   - <n-input-number v-model:value="item.value[1]"> </n-input-number>
254   - </setting-item>
255 204 <setting-item name="柱状颜色">
256 205 <n-color-picker size="small" :modes="['hex']" v-model:value="item.itemStyle.color"></n-color-picker>
257 206 </setting-item>
... ... @@ -262,6 +211,7 @@
262 211 <n-button size="small" @click="optionData.dataset.bar3D.splice(barIndex, 1)"> - </n-button>
263 212 </setting-item>
264 213 </template>
  214 + <div class="h-space"></div>
265 215 <n-button
266 216 style="float: right"
267 217 size="small"
... ... @@ -274,13 +224,15 @@
274 224 </template>
275 225
276 226 <script setup lang="ts">
277   -import { PropType, computed, ref } from 'vue'
  227 +import { PropType, computed, ref, onMounted } from 'vue'
278 228 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
279 229 import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
280 230 import { GlobalSetting } from '@/components/Pages/ChartItemSetting'
281 231 import SelectCity from './components/SelectCity.vue'
282 232 import { regionInfo } from './config'
283 233 import { cloneDeep } from 'lodash'
  234 +import { getAreaList } from '@/api/external/common/index'
  235 +import { areaEnum } from '../../../Decorates/Mores/Weather/config'
284 236
285 237 const props = defineProps({
286 238 optionData: {
... ... @@ -293,67 +245,83 @@ const seriesList = computed(() => {
293 245 return props.optionData.series
294 246 })
295 247
  248 +const datasetMap3DList = computed(() => {
  249 + return props.optionData.dataset['map3D']
  250 +})
  251 +
296 252 const STATIC_SCATTER_CONFIG = {
297   - name: '',
  253 + name: null,
  254 + adcode: 510000,
  255 + city_name:null,
298 256 value: [0, 0, 0],
299   - adcode: 0,
300   - height: 0,
  257 + height: 2,
301 258 itemStyle: {
302   - color: '',
  259 + color: '#4482B1FF',
303 260 opacity: 1
304 261 }
305 262 }
306 263
307   -const symbolOption = ref([
308   - {
309   - label: 'circle',
310   - value: 'circle'
311   - },
312   - {
313   - label: 'rect',
314   - value: 'rect'
315   - },
316   - {
317   - label: 'roundRect',
318   - value: 'roundRect'
319   - },
320   - {
321   - label: 'triangle',
322   - value: 'triangle'
323   - },
324   - {
325   - label: 'diamond',
326   - value: 'diamond'
327   - },
328   - {
329   - label: 'pin',
330   - value: 'pin'
331   - },
332   - {
333   - label: 'arrow',
334   - value: 'arrow'
335   - },
336   - {
337   - label: 'none',
338   - value: 'none'
339   - }
340   -])
341   -
342 264 const SelectCityRef = ref<InstanceType<typeof SelectCity>>()
343 265
  266 +const getAreaLists = async (level = areaEnum.PROVINCE, parentId = 1) => {
  267 + const resp = await getAreaList({
  268 + level,
  269 + parentId
  270 + })
  271 + if (!resp) return []
  272 + return resp.map((item: Recordable) => ({ label: item.name, value: item.name, adcode: item.code }))
  273 +}
  274 +
  275 +onMounted(async () => {
  276 + datasetMap3DList.value.forEach(async (item: Recordable) => {
  277 + item.provinceOptions = await getAreaLists()
  278 + item.cityOptions = await getAreaLists(areaEnum.CITY, !item.adcode ? mapRegionCache.value.adcode : item.adcode)
  279 + item.adcode = !item.adcode ? mapRegionCache.value.adcode : item.adcode
  280 + })
  281 +})
  282 +
  283 +const onHandleSelectProvince = async (value: number, option: Recordable, item: Recordable, mapIndex: number) => {
  284 + const findIndex = datasetMap3DList.value.findIndex((findItem: Recordable) => findItem.name === item.name)
  285 + datasetMap3DList.value[findIndex].city_name = null
  286 + datasetMap3DList.value[findIndex].adcode = option.adcode
  287 + datasetMap3DList.value[findIndex].cityOptions = await getAreaLists(areaEnum.CITY, option.adcode)
  288 +}
  289 +
  290 +const handleAddRegion = () => {
  291 + props.optionData.dataset.map3D.push(cloneDeep(STATIC_SCATTER_CONFIG))
  292 + datasetMap3DList.value.forEach(async (item: Recordable) => {
  293 + item.provinceOptions = await getAreaLists()
  294 + })
  295 +}
  296 +
  297 +const mapRegionCache = computed(() => {
  298 + return props.optionData.mapRegion
  299 +})
  300 +
344 301 const onHandleSelectValues = (values: regionInfo) => {
345   - const { cityValue, countyValue, provinceValue } = values
346   - props.optionData.mapRegion.saveSelect = values
347   - props.optionData.mapRegion.adcode = countyValue
  302 + const { cityValue, countyValue, provinceValue, areaName } = values
  303 + mapRegionCache.value.areaName = areaName
  304 + mapRegionCache.value.saveSelect = values
  305 + mapRegionCache.value.adcode = countyValue
348 306 ? countyValue
349 307 : cityValue
350 308 ? cityValue
351 309 : provinceValue === 'china'
352 310 ? 'china'
353 311 : provinceValue
  312 + props.optionData.mapRegion = mapRegionCache.value
354 313 }
355 314
356 315 const handleChangeDrillingIn = () => {
357 316 SelectCityRef.value?.resetValue()
  317 + props.optionData.mapRegion.adcode = 'china'
  318 + props.optionData.mapRegion.areaName = ''
  319 + props.optionData.mapRegion.saveSelect.areaName = ''
358 320 }
359 321 </script>
  322 +
  323 +<style scoped>
  324 +.h-space {
  325 + height: 10px;
  326 +}
  327 +</style>
... ...
... ... @@ -2,37 +2,9 @@
2 2 "map3D": [
3 3 {
4 4 "name": "四川省",
5   - "height": 5,
6   - "adcode": "510000",
7   - "itemStyle": {
8   - "color": "#4482B1FF",
9   - "opacity": 1,
10   - "borderWidth": 0.4,
11   - "borderColor": "#5F9EA0"
12   - }
13   - },
14   - {
15   - "name": "山西省",
16   - "height": 6,
17   - "adcode": "140000",
18   - "itemStyle": {
19   - "color": "#4482B1FF",
20   - "opacity": 1,
21   - "borderWidth": 0.4,
22   - "borderColor": "#5F9EA0"
23   - }
24   - }
25   - ],
26   - "scatter3D": [
27   - {
28   - "name": "广东省",
29   - "value": [
30   - 113.2592945,
31   - 23.1301964,
32   - 20000
33   - ],
34   - "adcode": "440000",
35   - "height": 5,
  5 + "adcode": 510000,
  6 + "city_name": "成都市",
  7 + "height": 2,
36 8 "itemStyle": {
37 9 "color": "#4482B1FF",
38 10 "opacity": 1,
... ... @@ -43,14 +15,12 @@
43 15 ],
44 16 "bar3D": [
45 17 {
46   - "name": "安徽省",
47 18 "value": [
48 19 117.283042,
49 20 31.86119,
50 21 20000
51 22 ],
52   - "adcode": "340000",
53   - "height": 5,
  23 + "height": 2,
54 24 "itemStyle": {
55 25 "color": "#4482B1FF",
56 26 "opacity": 1,
... ... @@ -59,4 +29,4 @@
59 29 }
60 30 }
61 31 ]
62   -}
\ No newline at end of file
  32 +}
... ...
... ... @@ -20,10 +20,12 @@ import config, {
20 20 backMapLevel,
21 21 levelFunc,
22 22 regionMapParentArea,
23   - specialTreatmentAnhui
  23 + specialTreatmentAnhui,
  24 + setScale
24 25 } from './config'
25 26 import { getGeoJsonMap } from '@/api/external/common'
26 27 import { ThreeMapEnum } from '@/enums/external/mapEnum'
  28 +import cloneDeep from 'lodash/cloneDeep'
27 29
28 30 const props = defineProps({
29 31 chartConfig: {
... ... @@ -115,13 +117,14 @@ props.chartConfig.option = {
115 117
116 118 //地图点击返回
117 119 const handleBack = async () => {
  120 + stopWatch()
118 121 if (drillingIn.value) {
119 122 //如果是从右边配置里设置的,比如点击四川省,然后点击返回
120 123 const savePopParent = saveHistoryParent.value.pop()
121 124 let saveAdcode = savePopParent?.adcode as string | number
122 125 saveLevelStr.level = savePopParent?.level as string
123 126 if (!savePopParent) {
124   - saveAdcode = getParentAdcode(mapRegion.value.adcode)
  127 + saveAdcode = getParentAdcode(mapRegion.value.adcode).adcodeNum
125 128 saveLevelStr.level = (regionMapParentArea as Recordable)[mapRegion.value.saveSelect.levelStr]
126 129 }
127 130 if (saveAdcode === 0) {
... ... @@ -132,6 +135,7 @@ const handleBack = async () => {
132 135 const adcode = saveAdcode === 100000 ? 'china' : saveAdcode
133 136 saveClickRegion.value.level = saveLevelStr.level
134 137 if (exist) {
  138 + mapRegion.value.areaName = getParentAdcode(mapRegion.value.adcode).areaName
135 139 //fix 解决点击下钻返回后页面为空问题
136 140 mapRegion.value.adcode = adcode
137 141 }
... ... @@ -142,20 +146,24 @@ const handleBack = async () => {
142 146 const handleMap3DClick = async (params: Recordable) => {
143 147 if (drillingIn.value) {
144 148 const { name } = params
145   - saveGeojson.value?.features.forEach((item: Recordable) => {
  149 + const geoJson = JSON.parse(saveGeojson.value?.geoJson)
  150 + geoJson?.features.forEach((item: Recordable) => {
146 151 if (item.properties.name === name) {
147 152 const level = item.properties.level.toUpperCase()
148 153 const adcode = item.properties.adcode
  154 + const areaName = item.properties.name
149 155 if (level === 'DISTRICT') return //下钻暂且不支持地区
150 156 if (String(adcode).startsWith('15') && level === areaEnum.CITY) return //特殊处理地区码15开头的
151 157 mapRegion.value.adcode = adcode
  158 + mapRegion.value.areaName = areaName
152 159 saveClickRegion.value.level = level
153 160 saveLevelStr.level = level
154 161 saveHistoryParent.value.push({
155 162 adcode: specialTreatmentAnhui.includes(item.properties.name)
156 163 ? JSON.parse(item.properties.parent)?.adcode
157 164 : item.properties.parent.adcode,
158   - level: (regionMapParentArea as Recordable)[level]
  165 + level: (regionMapParentArea as Recordable)[level],
  166 + areaName: saveGeojson.value.name
159 167 })
160 168 }
161 169 })
... ... @@ -182,18 +190,22 @@ const getGeojson = (regionId: number | string) => {
182 190 regionId === 'china' ? chinaDefaultRegionId.value : regionId,
183 191 !saveLevelStr.level ? levelStr : saveLevelStr.level //没有则获取右侧配置的行政级别
184 192 ).then(res => {
185   - const { geoJson, name, code, level } = res.data
  193 + saveGeojson.value = res.data //保存一份服务端返回的数据
  194 + const { geoJson, name, level, code } = res.data
186 195 const geoJsonFile = JSON.parse(geoJson)
187 196 if (!geoJsonFile) return
188   - saveGeojson.value = geoJsonFile //保存一份服务端返回的geojson
189 197 const nameChina = name === '中国' ? 'china' : name //为中国的话,registerMap第一个必须是china,否则显示不出来
190 198 /**
191 199 * 主要注意的点,registerMap中的第一个参数需要和series中的map匹配,否则渲染不出地图,
192 200 * 比如map: '北京市' echarts.registerMap('北京市', beijingGeoJSON);
193 201 */
194   - registerMap(level === areaEnum.COUNTRY ? nameChina : code, { geoJSON: geoJsonFile, specialAreas: {} }) //注册geoJSON
  202 + registerMap(level === areaEnum.COUNTRY ? nameChina : !mapRegion.value.areaName ? code : name, {
  203 + geoJSON: geoJsonFile,
  204 + specialAreas: {}
  205 + }) //注册geoJSON
195 206 resolve(true)
196 207 show.value = false
  208 + changeOption.value = true
197 209 })
198 210 })
199 211 } catch (error) {
... ... @@ -210,12 +222,15 @@ registerMap(mapRegion.value.adcode, { geoJSON: {} as any, specialAreas: {} })
210 222 //传adcode 获取上级
211 223 const getParentAdcode = (adcode: number) => {
212 224 let adcodeNum = 100000
213   - saveGeojson.value?.features.forEach((item: Recordable) => {
  225 + let areaName = ''
  226 + const geoJson = JSON.parse(saveGeojson.value?.geoJson)
  227 + geoJson.features.forEach((item: Recordable) => {
214 228 if (item.properties.adcode === adcode) {
215 229 adcodeNum = item.properties.parent.adcode
  230 + areaName = saveGeojson.value.name
216 231 }
217 232 })
218   - return adcodeNum
  233 + return { adcodeNum, areaName }
219 234 }
220 235
221 236 // 初始化三维地图
... ... @@ -224,7 +239,7 @@ const initMap3D = async () => {
224 239 await nextTick()
225 240 await getGeojson(mapRegion.value.adcode)
226 241 await nextTick().then(() => {
227   - handleRegisterMapNameAndData(mapRegion.value.adcode, dataset.value)
  242 + handleRegisterMapNameAndData(mapRegion.value.adcode, dataset.value, 'china')
228 243 })
229 244 chartInstance.value?.on('click', (e: Recordable) => {
230 245 if (!e) return
... ... @@ -235,16 +250,13 @@ const initMap3D = async () => {
235 250 onMounted(() => initMap3D())
236 251
237 252 // 动态注册 series中的map必须和registerMap的第一个参数匹配,否则渲染不出
238   -const handleRegisterMapNameAndData = (adcode: string | number, data: Recordable) => {
239   - geo3D.value.map = adcode // coordinateSystem使用了geo3D,不能删除这一行
  253 +const handleRegisterMapNameAndData = (adcode: string | number, data: Recordable, areaName: string) => {
  254 + geo3D.value.map = !areaName ? adcode : areaName // coordinateSystem使用了geo3D,不能删除这一行
240 255 series.value.forEach((item: Recordable) => {
241 256 if (item.type === ThreeMapEnum.MAP3D) {
242   - item.map = adcode
  257 + item.map = !areaName ? adcode : areaName
243 258 item.data = data[ThreeMapEnum.MAP3D]
244 259 }
245   - if (item.type === ThreeMapEnum.SCATTER3D) {
246   - item.data = data[ThreeMapEnum.SCATTER3D]
247   - }
248 260 if (item.type === ThreeMapEnum.BAR3D) {
249 261 item.data = data[ThreeMapEnum.BAR3D]
250 262 }
... ... @@ -274,18 +286,27 @@ watch(
274 286 )
275 287
276 288 //处理数据标点
277   -const handleDataPoint = (newData: string | number) => {
  289 +const handleDataPoint = (newData: string | number, areaName: string) => {
278 290 if (newData === 'china') {
279 291 // 全国则展示所有的标点
280   - handleRegisterMapNameAndData(newData, dataset.value)
  292 + handleRegisterMapNameAndData(newData, dataset.value, 'china')
281 293 } else {
282 294 // 展示对应区域的标点
283 295 series.value.forEach((item: Recordable) => {
284 296 if (item.type === ThreeMapEnum.MAP3D) {
285   - item.data = [] //置空,否则鼠标移上去点击不了,不知道原因!
286   - }
287   - if (item.type === ThreeMapEnum.SCATTER3D) {
288   - item.data = dataset.value[ThreeMapEnum.SCATTER3D].filter((dataItem: dataPointI) => dataItem.adcode === newData)
  297 + item.map = !areaName ? newData : areaName
  298 + item.data = dataset.value[ThreeMapEnum.MAP3D].filter((dataItem: dataPointI) => {
  299 + if (String(dataItem.adcode) === String(!areaName ? newData : areaName)) {
  300 + return dataItem
  301 + } else if (dataItem.name === String(!areaName ? newData : areaName)) {
  302 + return dataItem
  303 + }
  304 + })
  305 + const cloneDeepData = cloneDeep(item.data)
  306 + cloneDeepData.forEach((item: dataPointI) => {
  307 + item.name = item.city_name
  308 + })
  309 + item.data = cloneDeepData.filter((item: Recordable) => item.name !== null) || []
289 310 }
290 311 if (item.type === ThreeMapEnum.BAR3D) {
291 312 item.data = dataset.value[ThreeMapEnum.BAR3D].filter((dataItem: dataPointI) => dataItem.adcode === newData)
... ... @@ -293,22 +314,56 @@ const handleDataPoint = (newData: string | number) => {
293 314 })
294 315 }
295 316 }
  317 +const changeOption = ref(false)
296 318
297 319 // 监听地图展示区域发生变化
298 320 watch(
299 321 () => `${props.chartConfig.option.mapRegion.adcode}`,
300   - async (newData: string | number) => {
  322 + async (newData: number | string) => {
301 323 try {
302 324 await getGeojson(newData)
303   - handleRegisterMapNameAndData(newData, dataset.value)
304   - handleDataPoint(newData)
305   - handleSetOption(chartInstance.value!, props.chartConfig.option)
  325 + const { distance, zoom, alpha } = setScale(String(newData))
  326 + const option = props.chartConfig.option
  327 + // 修复缩放
  328 + const { series } = option || {}
  329 + series?.forEach((item: Recordable) => {
  330 + if (item.type === 'map3D') {
  331 + item.viewControl = {
  332 + ...item?.viewControl,
  333 + distance,
  334 + zoom,
  335 + alpha
  336 + }
  337 + }
  338 + })
  339 + handleRegisterMapNameAndData(newData, dataset.value, mapRegion.value.areaName)
  340 + handleDataPoint(newData, mapRegion.value.areaName)
  341 + changeOption.value = true
  342 + handleSetOption(chartInstance.value!, { ...option, series })
306 343 } catch (error) {
307 344 console.error('展示区域发生变化出错,出错原因->', error)
308 345 }
309 346 },
310 347 {
311   - immediate: true
  348 + immediate: true,
  349 + deep: true
  350 + }
  351 +)
  352 +
  353 +// 实时监听地图右侧配置项变化
  354 +const stopWatch = watch(
  355 + props.chartConfig.option,
  356 + async newData => {
  357 + try {
  358 + if (changeOption.value) {
  359 + // handleSetOption(chartInstance.value!, newData)
  360 + }
  361 + } catch (error) {
  362 + console.error('监听地图右侧配置项变化,出错原因->', error)
  363 + }
  364 + },
  365 + {
  366 + deep: true
312 367 }
313 368 )
314 369 </script>
... ...