Commit 948cd75bff727a1307e00637bc0ccf0e78daa14e
Merge branch 'fix/3D-map-select-sacle' into 'main_dev'
perf(src/views/chart): 优化三维地图右侧区块配置项,并且修复兼容之前旧地图 See merge request yunteng/thingskit-view!185
Showing
5 changed files
with
269 additions
and
210 deletions
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> | ... | ... |