Commit 1b052dfc269f85221389c413a577131b0dbbbf6b
Committed by
xp.Huang
1 parent
1aa17ab8
perf(src/views/chart): 优化三维地图右侧区块配置项,并且修复兼容之前旧地图
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> | ... | ... |