使用echarts绘制中国地图根据不同的省份划分到指定区域里面中

发布于:2024-07-07 ⋅ 阅读:(48) ⋅ 点赞:(0)

需求:我们在开发过程中会遇到使用中国地图来划分不同区域省份下面的数量统计情况,但是有时候使用Echarts里面地图功能和我们实际业务需求不匹配的,这个时候就需要我们手动自定义进行划分不同区域下面的省份数据。例如大区1下面有哪些省份,大区2对应哪些的省份进行划分显示的。

1,实现效果图如下:

在这里插入图片描述
2,关键代码如下:

【1】后端返回数据格式如下:
在这里插入图片描述

在这里插入图片描述

【2】把需要合并的省份的经纬度数据合并起来。

function mergeProvinces(chinaJson, regionMap) {
    //合并大区里省份的coordinates
    var oldFeatures = chinaJson.features

    var featuress = regionMap.map((item) => {
      var polygonsCoordinates: any[] = []
      for (var z = 0; z < item.provinces.length; z++) {
        for (var j = 0; j < oldFeatures.length; j++) {
          if (oldFeatures[j].properties.name.includes(item.provinces[z].slice(0, 2))) {
            const coordinates = oldFeatures[j].geometry.coordinates
            if (coordinates[0].length !== 1) {
              polygonsCoordinates = polygonsCoordinates.concat(coordinates)
            } else {
              polygonsCoordinates = polygonsCoordinates.concat(
                coordinates.reduce((r, e) => {
                  return r.concat(e)
                }, []),
              )
            }

            oldFeatures[j].ok = 1
            break
          }
        }
      }
      return {
        id: 'xx',
        type: 'MultiPolygon',
        geometry: {
          type: 'Polygon',
          coordinates: polygonsCoordinates,
        },
        properties: {
          name: item.regionName || '',
          childNum: polygonsCoordinates.length,
        },
      }
    })
    const others = oldFeatures.filter((item: any) => !item.ok)
    featuress = featuress.concat(others)
    chinaJson.features = featuress
    return chinaJson
  }

3- 具体代码组件如下所示:

<template>
  <div class="chinamapContentbox">
    <div id="chinaMap" ref="chinaMap"></div>
  </div>
</template>

<script lang="ts" setup>
  import { onMounted, onBeforeUnmount, ref, watch } from 'vue'
  import china from './china.json'
  import { cloneDeep, debounce } from 'lodash-es'
  import { nextTick } from 'vue'
  import * as echarts from 'echarts/core'
  import {
    TooltipComponent,
    TooltipComponentOption,
    VisualMapComponent,
    VisualMapComponentOption,
    GeoComponent,
    GeoComponentOption,
  } from 'echarts/components'
  import { MapChart, MapSeriesOption } from 'echarts/charts'
  import { CanvasRenderer } from 'echarts/renderers'

  echarts.use([TooltipComponent, VisualMapComponent, GeoComponent, MapChart, CanvasRenderer])

  type EChartsOption = echarts.ComposeOption<
    TooltipComponentOption | VisualMapComponentOption | GeoComponentOption | MapSeriesOption
  >

  function mergeProvinces(chinaJson, regionMap) {
    //合并大区里省份的coordinates
    var oldFeatures = chinaJson.features

    var featuress = regionMap.map((item) => {
      var polygonsCoordinates: any[] = []
      for (var z = 0; z < item.provinces.length; z++) {
        for (var j = 0; j < oldFeatures.length; j++) {
          if (oldFeatures[j].properties.name.includes(item.provinces[z].slice(0, 2))) {
            const coordinates = oldFeatures[j].geometry.coordinates
            if (coordinates[0].length !== 1) {
              polygonsCoordinates = polygonsCoordinates.concat(coordinates)
            } else {
              polygonsCoordinates = polygonsCoordinates.concat(
                coordinates.reduce((r, e) => {
                  return r.concat(e)
                }, []),
              )
            }

            oldFeatures[j].ok = 1
            break
          }
        }
      }
      return {
        id: 'xx',
        type: 'MultiPolygon',
        geometry: {
          type: 'Polygon',
          coordinates: polygonsCoordinates,
        },
        properties: {
          name: item.regionName || '',
          childNum: polygonsCoordinates.length,
        },
      }
    })
    const others = oldFeatures.filter((item: any) => !item.ok)
    featuress = featuress.concat(others)
    chinaJson.features = featuress
    return chinaJson
  }

  const chinaMap = ref()
  let myChart: echarts.ECharts
  const resize = debounce(() => myChart && myChart.resize(), 200)
  const props = defineProps({
    type: {
      type: String,
      default: '1',
    },
    areaDataInfo: {
      type: Array,
      default: () => [],
    },
    regionMap: {
      type: Array,
      default: () => [],
    },
  })

  watch(
    () => ({
      areaDataInfo: props.areaDataInfo,
      chinaMap: chinaMap.value,
      regionMap: props.regionMap,
    }),
    ({ areaDataInfo, chinaMap, regionMap }) => {
      if (chinaMap && areaDataInfo) {
        const getvlaueList = areaDataInfo.map((item: any) => {
          return item.value
        })
        let maxNum = 100
        if (getvlaueList && getvlaueList.length > 0) {
          maxNum = Math.max(...getvlaueList)
        }
        echarts.registerMap('china', mergeProvinces(cloneDeep(china), regionMap))
        if (!myChart) {
          myChart = echarts.init(chinaMap)
        }
        nextTick(() => {
          setOptions(maxNum, areaDataInfo)
        })
      }
    },
    { immediate: true, deep: true },
  )

  onMounted(() => {
    window.addEventListener('resize', resize)
  })

  onBeforeUnmount(() => {
    window.removeEventListener('resize', resize)
  })

  function setOptions(maxNum, areaDataInfo) {
    const options: EChartsOption = {
      tooltip: {
        formatter(params) {
          if (!areaDataInfo.some((e) => e.name === params.name)) {
            return ''
          }
          const htmlStr1 = `<div style='font-size:14px; margin-bottom:10px;'> ${params.name} </div>
              <p style='text-align:left;margin-top:-4px;'>联斯达覆盖省份:${
                params.data?.liansidaCoverProvinceCount || 0
              }
                <br/>联斯达覆盖城市:${params.data?.liansidaCoverCityCount || 0}
                <br/>斯联达覆盖中心:${params.data?.liansidaCoverCenterCount || 0}
                <br/>联斯达未覆盖中心:${params.data?.liansidaUnCoverCenterCount || 0}
                <br/>联斯达中心覆盖率:${params.data?.liansidaCoverCenterRate || 0}
              </p>`
          const htmlStr2 = `<div style='font-size:14px; margin-bottom:10px;'> ${params.name} </div>
              <p style='text-align:left;margin-top:-4px;'>项目数:${params.data?.projectCount || 0}
                <br/>提前启动项目:${params.data?.preProjectCount || 0}
                <br/>入组数:${params.data?.enrollmentCount || 0}
              </p>`
          return props.type === '1' ? htmlStr1 : htmlStr2
        },
        backgroundColor: 'rgba(0,0,0,.6)', //提示标签背景颜色
        textStyle: { color: '#fff' }, //提示标签字体颜色
      },
      visualMap: {
        show: false,
        max: maxNum,
        color: ['#356191', '#1890ff', '#EBEBEB'],
      },
      geo: {
        map: 'china',
        roam: false,
        zoom: 1.2,
        label: {
          show: false,
          color: '#fff',
          textShadowColor: '#000',
          textShadowBlur: 10,
          textShadowOffsetX: 3,
        },
        itemStyle: {
          areaColor: '#d5e8f3',
          borderColor: '#fcfdfe',
          borderWidth: 1,
        },
        center: [104.114129, 37.550339],
        emphasis: {
          label: {
            color: '#fff',
            textShadowColor: '#000',
            textShadowBlur: 10,
            textShadowOffsetX: 0,
          },
          itemStyle: {
            areaColor: '#55D187',
          },
        },
      },
      series: [
        {
          name: '地图', // 浮动框的标题(上面的formatter自定义了提示框数据,所以这里可不写)
          type: 'map',
          map: 'china',
          geoIndex: 0,
          label: {
            show: true,
          },
          data: areaDataInfo,
        },
      ],
    }
    myChart.clear()
    myChart.setOption(options)
  }
</script>

<style lang="less">
  .chinamapContentbox {
    width: 100%;

    #chinaMap {
      width: 100%;
      height: 430px;
    }
  }
</style>


网站公告

今日签到

点亮在社区的每一天
去签到