Vue + Echarts + 高德地图 实现点击下探图表

效果图:

1. 高德地图 Key 申请

参考文章传送门

2. 引入使用AMapJS

AMapJS 是 AMap高德地图API加载器。
帮助开发者快速加载高德地图相关API,在模块化应用、异步编程中使用API更加灵活便捷。
安装:

npm i amap-js -S

完整引入:

import AMapJS from 'amap-js';

本文仅使用AMapUILoader

3. Vue 中实现效果图完整代码

<template>
  <div class="app-container">
    <div id="chinaMap"></div>
    <div class="mapChoose">
      <span v-for="(item,index) in parentInfo" :key="item.code">
        <span
          class="title"
          @click="chooseArea(item,index)"
        >{
     {
     item.cityName=='全国'?'中国':item.cityName}}</span>
        <span class="icon" v-show="index+1!=parentInfo.length">></span>
      </span>
    </div>
  </div>
</template>

<script>
import AMapJS from 'amap-js'
import resize from '@/mixins/resize'

export default {
     
  name: 'home',
  components: {
     },
  data() {
     
    return {
     
      // 创建AMapJSAPI Loader
      amapLoader: new AMapJS.AMapLoader({
     
        key: '申请的高德地图key',
        version: '1.4.15',
        plugins: [],
      }),
      // 创建AMapUI Loader
      amapuiLoader: new AMapJS.AMapUILoader({
      version: '1.0' }),
      timeTitle: ['2016', '2017', '2018', '2019', '2020'],
      parentInfo: [
        {
     
          cityName: '全国',
          code: 100000,
        },
      ],
      geoJson: {
     
        features: [],
      },
    }
  },
  mixins: [resize],
  methods: {
     
    async getGeoJson(adcode) {
     
      await this.amapLoader.load()
      await this.amapuiLoader.load()

      let that = this
      AMapUI.loadUI(['geo/DistrictExplorer'], DistrictExplorer => {
     
        var districtExplorer = new DistrictExplorer()
        districtExplorer.loadAreaNode(adcode, function(error, areaNode) {
     
          if (error) {
     
            console.error(error)
            return
          }
          let Json = areaNode.getSubFeatures()
          if (Json.length > 0) {
     
            that.geoJson.features = Json
          } else if (Json.length === 0) {
     
            that.geoJson.features = that.geoJson.features.filter(
              item => item.properties.adcode == adcode
            )
            if (that.geoJson.features.length === 0) return
          }
          that.getMapData()
        })
      })
    },
    // 获取数据
    getMapData() {
     
      let mapData = {
     },
        pointData = {
     },
        sum = {
     }
      for (let i = 0; i < this.timeTitle.length; i++) {
     
        mapData[this.timeTitle[i]] = []
        pointData[this.timeTitle[i]] = []
        sum[this.timeTitle[i]] = 0
        for (let j = 0; j < this.geoJson.features.length; j++) {
     
          let value = Math.random() * 3000
          mapData[this.timeTitle[i]].push({
     
            name: this.geoJson.features[j].properties.name,
            value: value,
            level: this.geoJson.features[j].properties.level,
            cityCode: this.geoJson.features[j].properties.adcode,
          })
          pointData[this.timeTitle[i]].push({
     
            name: this.geoJson.features[j].properties.name,
            value: [
              this.geoJson.features[j].properties.center[0],
              this.geoJson.features[j].properties.center[1],
              value,
            ],
            cityCode: this.geoJson.features[j].properties.adcode,
          })
          sum[this.timeTitle[i]] += value
        }
        mapData[this.timeTitle[i]] = mapData[this.timeTitle[i]].sort(function(
          a,
          b
        ) {
     
          return b.value - a.value
        })
      }
      this.drawChinaMap(mapData, pointData, sum)
    },

    drawChinaMap(mapData, pointData, sum) {
     
      var echarts = require('echarts')
      var mapChart = echarts.init(document.getElementById('chinaMap'))
      //这里做个切换,全国的时候才显示南海诸岛  只有当注册的名字为china的时候才会显示南海诸岛
      if (this.parentInfo.length === 1) {
     
        echarts.registerMap('china', this.geoJson) //注册
      } else {
     
        echarts.registerMap('map', this.geoJson) //注册
      }

      var option = {
     
        timeline: {
     
          data: this.timeTitle,
          axisType: 'category',
          autoPlay: true,
          playInterval: 3000,
          left: '10%',
          right: '10%',
          bottom: '2%',
          width: '80%',
          label: {
     
            normal: {
     
              textStyle: {
     
                color: 'rgb(179, 239, 255)',
              },
            },
            emphasis: {
     
              textStyle: {
     
                color: '#fff',
              },
            },
          },
          symbolSize: 10,
          lineStyle: {
     
            color: '#8df4f4',
          },
          checkpointStyle: {
     
            borderColor: '#8df4f4',
            color: '#53D9FF',
            borderWidth: 2,
          },
          controlStyle: {
     
            showNextBtn: true,
            showPrevBtn: true,
            normal: {
     
              color: '#53D9FF',
              borderColor: '#53D9FF',
            },
            emphasis: {
     
              color: 'rgb(58,115,192)',
              borderColor: 'rgb(58,115,192)',
            },
          },
        },
        baseOption: {
     
          animation: true,
          animationDuration: 900,
          animationEasing: 'cubicInOut',
          animationDurationUpdate: 900,
          animationEasingUpdate: 'cubicInOut',
          tooltip: {
     
            trigger: 'axis',
            axisPointer: {
     
              type: 'shadow',
            },
          },
          grid: {
     
            right: '2%',
            top: '12%',
            bottom: '8%',
            width: '20%',
          },
          toolbox: {
     
            feature: {
     
              restore: {
     
                show: false,
              },
              dataView: {
     
                optionToContent: function(opt) {
     
                  let series = opt.series[0].data //折线图数据
                  //表头
                  let tdHeads =
                    '所在地区销售额' 
                  let tdBodys = '' //数据
                  let table = `${
       tdHeads} `for(let i =0; i < series.length; i++){
     
                    table +=``}
                  table +='
${ series[i].name} ${ series[ i ].value.toFixed(2)}
'
return table }, }, saveAsImage: { name: this.parentInfo[this.parentInfo.length - 1].cityName + '销售额统计图', }, dataZoom: { show: false, }, magicType: { show: false, }, }, iconStyle: { normal: { borderColor: '#1990DA', }, }, top: 15, right: 35, }, // 地理坐标系组件 geo: { map: this.parentInfo.length === 1 ? 'china' : 'map', zoom: 1.1, // 当前视角的缩放比例 roam: true, // 鼠标缩放和平移 center: this.parentInfo.length === 1 ? ['118.83531246', '32.0267395887'] : false, tooltip: { trigger: 'item', formatter: p => { let val = p.value[2] if (window.isNaN(val)) { val = 0 } let txtCon = "
" + p.name + ':
销售额:'
+ val.toFixed(2) + '万
'
return txtCon }, }, label: { normal: { show: true, color: 'rgb(249, 249, 249)', //省份标签字体颜色 formatter: p => { switch (p.name) { case '内蒙古自治区': p.name = '内蒙古' break case '西藏自治区': p.name = '西藏' break case '新疆维吾尔自治区': p.name = '新疆' break case '宁夏回族自治区': p.name = '宁夏' break case '广西壮族自治区': p.name = '广西' break case '香港特别行政区': p.name = '香港' break case '澳门特别行政区': p.name = '澳门' break default: break } return p.name }, }, emphasis: { show: true, color: '#f75a00', }, }, itemStyle: { normal: { areaColor: '#24CFF4', borderColor: '#53D9FF', borderWidth: 1.3, shadowBlur: 15, shadowColor: 'rgb(58,115,192)', shadowOffsetX: 7, shadowOffsetY: 6, }, emphasis: { areaColor: '#8dd7fc', borderWidth: 1.6, shadowBlur: 25, }, }, }, }, options: [], } this.timeTitle.forEach(item => { var xData = [], yData = [] var min = mapData[item][mapData[item].length - 1].value var max = mapData[item][0].value if (mapData[item].length === 1) { min = 0 } mapData[item].forEach(c => { xData.unshift(c.name) yData.unshift(c.value) }) option.options.push({ backgroundColor: '#012248', title: [ { left: 'center', top: 10, text: item + this.parentInfo[this.parentInfo.length - 1].cityName + '销售额统计图(可点击下钻到县)', textStyle: { color: 'rgb(179, 239, 255)', fontSize: 16, }, }, { text: '销售总额:' + sum[item].toFixed(2) + '万', left: 'center', top: '6.5%', textStyle: { color: '#FFAC50', fontSize: 26, }, }, ], // 视觉映射组件 visualMap: { min: min, max: max, left: '3%', bottom: '5%', calculable: true, // 显示拖拽手柄 seriesIndex: [0], inRange: { color: ['#24CFF4', '#2E98CA', '#1E62AC'], }, textStyle: { color: '#24CFF4', }, }, // 柱状图横轴 xAxis: { type: 'value', scale: true, position: 'top', boundaryGap: false, splitLine: { show: false, }, axisLine: { show: true, lineStyle: { color: '#455B77', }, }, axisTick: { show: false, }, axisLabel: { margin: 2, textStyle: { color: '#c0e6f9', }, }, }, // 柱状图纵轴 yAxis: { type: 'category', nameGap: 16, axisLine: { show: true, lineStyle: { color: '#455B77', }, }, axisTick: { show: false, }, axisLabel: { interval: 0, textStyle: { color: '#c0e6f9', }, }, data: xData, }, series: [ { name: item + '销售额度', type: 'map', geoIndex: 0, map: this.parentInfo.length === 1 ? 'china' : 'map', roam: true, zoom: 1.3, tooltip: { trigger: 'item', formatter: p => { let val = p.value if (p.name == '南海诸岛') return if (window.isNaN(val)) { val = 0 } let txtCon = "
" + p.name + ':
销售额:'
+ val.toFixed(2) + '万
'
return txtCon }, }, label: { normal: { show: false, }, emphasis: { show: false, }, }, data: mapData[item], }, { name: '散点', type: 'effectScatter', coordinateSystem: 'geo', rippleEffect: { brushType: 'fill', }, label: { normal: { formatter: p => { return p.value[2].toFixed() }, position: 'center', //地图上是否有文字 show: true, textStyle: { color: '#fff' } }, emphasis: { show: false } }, itemStyle: { normal: { color: '#F4E925', shadowBlur: 10, shadowColor: '#333', }, }, data: pointData[item], symbolSize: function(val) { let value = val[2] if (value == max) { return 27 } return 10 }, showEffectOn: 'render', //加载完毕显示特效 }, { type: 'bar', barGap: '-100%', barCategoryGap: '60%', itemStyle: { normal: { color: '#11AAFE', }, emphasis: { show: false, }, }, data: yData, }, ], }) }) mapChart.setOption(option, true) //点击前解绑,防止点击事件触发多次 mapChart.off('click') mapChart.on('click', this.echartsMapClick) }, //echarts点击事件 echartsMapClick(params) { if (!params.data) { return } else { //如果当前是最后一级,那就直接return if ( this.parentInfo[this.parentInfo.length - 1].code == params.data.cityCode ) { return } let data = params.data this.parentInfo.push({ cityName: data.name, level: data.level, code: data.cityCode, }) this.getGeoJson(data.cityCode) } }, //选择切换市县 chooseArea(val, index) { if (this.parentInfo.length === index + 1) { return } this.parentInfo.splice(index + 1) this.getGeoJson(this.parentInfo[this.parentInfo.length - 1].code) }, }, mounted() { this.getGeoJson(100000) }, } </script> <style lang="scss" scoped> .app-container { #chinaMap { width: 1400px; height: 800px; } .mapChoose { position: absolute; left: 20px; top: 55px; color: #eee; .title { padding: 5px; border-top: 1px solid rgba(147, 235, 248, 0.8); border-bottom: 1px solid rgba(147, 235, 248, 0.8); cursor: pointer; } .icon { font-family: 'simsun'; font-size: 25px; margin: 0 11px; } } } </style>

resize.js

import {
     
  debounce
} from "@/utils/index.js"

export default {
     
  data() {
     
    return {
     
      myChart: null,
      resizeHandler: null
    }
  },
  mounted() {
     
    this.resizeHandler = debounce(() => {
     
      if (this.myChart) {
     
        this.myChart.resize()
      }
    }, 200)
    this.initResizeEvent();
  },

  beforeDestroy() {
     
    this.destroyResizeEvent()
    if (!this.myChart) {
     
      return
    }
    this.myChart.dispose()
    this.myChart.off('click')
    this.myChart = null
  },

  activated() {
     
    this.initResizeEvent()
  },

  deactivated() {
     
    this.destroyResizeEvent()
  },

  methods: {
     
    //监听resize
    initResizeEvent() {
     
      window.addEventListener('resize', this.resizeHandler)
    },
    //移除resize
    destroyResizeEvent() {
     
      window.removeEventListener('resize', this.resizeHandler);
    }
  }
}

index.js

/**
 *  函数防抖
 *  @param {Function} func  包装的函数
 *  @param {num} delay      延迟时间
 *  @param {boolean} immediate 第一次滚动会执行两次  开始滚动和结束滚动的时候
 *  @return {*}      
 */

export function debounce(func, delay, immediate = false) {
     
  let timer, context = this
  return (...args) => {
     
    if (immediate) {
     
      func.apply(context, args)
      immediate = false
      return
    }
    clearTimeout(timer)
    timer = setTimeout(() => {
     
      func.apply(context, args)
    }, delay)
  }
}

参考echarts图表(侵删)

你可能感兴趣的:(Canvas,SVG,WebGL,前端,echarts)