echarts实现地图下钻

本文介绍了使用Echarts实现地图下钻功能的详细步骤,包括加载地图JSON数据、设置地图纹理和阴影、地图下钻与回钻的实现方法。此外,还分享了如何自定义div实现tooltip框并防止超出屏幕,以及地图下钻组件的设计思路,支持多级下钻、自定义纹理和事件监听等特性。
摘要由CSDN通过智能技术生成

公司的新项目需要写这样的地图,还要能两级下钻到省,下面是我写好了的样子,我今天就是复一下盘:

如何用echarts显示地图

首先需要下载map的Json数据,我放到这里:mapJson
然后使用echarts的geo配置,或者series的type = 'map’就可以加载地图了:

import chinaMapJson from "./china.json"

echarts.registerMap('china', chinaMapJson)

var options = {
  tooltip:{
    show:false
  },
  geo: {
    map: 'china',
    roam:false,
    label: {
        emphasis: {
            show: false
        }
    }
  }
}


const el = document.getElementById("chart")
const chart = echart.init(el)
chart.setOption(options)

这样就可以显示中国地图。

第二种是series的type设置为map:

import chinaMapJson from "./china.json"

echarts.registerMap('china', chinaMapJson)

var options = {
  tooltip:{
    show:false
  },
  series: [
    {
        type: 'map',
        map: 'china'
    }
  ]
}

const el = document.getElementById("chart")
const chart = echart.init(el)
chart.setOption(options)
  • 注意
    中国地图的名字叫china才会显示南海诸岛,别的名字不会显示

如何设置地图的纹理

itemStyle.areaColor的配置文档中,写着:

  • 提示
    支持使用rgb(255,255,255),rgba(255,255,255,1),#fff等方式设置为纯色,也支持设置为渐变色和纹理填充

    // 纹理填充
    {
    image: imageDom, // 支持为 HTMLImageElement, HTMLCanvasElement,不支持路径字符串
    repeat: ‘repeat’ // 是否平铺,可以是 ‘repeat-x’, ‘repeat-y’, ‘no-repeat’
    }

可以使用这种方式来实现地图的纹理以及高亮状态的纹理

如何给地图设置阴影

地图阴影其实我使用了geo和series的两种地图叠加起来,第一层geo设置了阴影,第二层series的地图使用了描边。

const imageDom = document.createElement("img")
imageDom.src = "./texture.png"
const lightDom = document.createElement("img")
lightDom.src = "./light.png"

let options = {
  tooltip:{
    show:false
  },
  geo: {
      map: '',
      roam:false,
      label: {
          emphasis: {
              show: false
          }
      },
      itemStyle: {
          shadowColor: '#C3F4F4',
          shadowOffsetX:'-2px',
          shadowOffsetY: '10px',
          shadowBlur: '5px'
      }
  },
  series: [
      {
          type: 'map',
          map: 'china',
          roam: false,
          tooltip:{
            show:false
          },
          label: {
              show:false,
              color:'#fff'
          },
          itemStyle: {
              areaColor:imageDom,
              borderColor: '#C3F4F4',
              borderWidth:'2px'
          },
          emphasis: {
              itemStyle: {
                  areaColor:lightDom
              },
              label:{
                  show:false
              }
          }
      }
  ]
}

这样就可以绘制出效果来了

地图下钻实现

地图下钻其实就是,在地图的点击事件回调中,加载了另一份地图的json并注册地图,然后再setOption中更改了地图名字。

chart.on('click', (params) => {
    if (params.componentSubType == 'map') {
        goDown(params.name)
    }
})

//用来存放当前的地图名字
let currentName = ''
//用来存放下钻的历史记录
let history = []

async function goDown(name){
    //获取地图数据之后,修改地图options
    const mapname = name
    if (!echarts.getMap(name)) {
        const newMapJson = await getMapJson(name)
        echarts.registerMap(mapname, newMapJson)
    }
    options.geo.map = mapname
    options.series[0].map = mapname
    //然后重新绘制地图
    history.push(currentName)
    chart.setOption(this.options)
    currentName = name
}

async function getMapJson(name) {
  const jsonData = await import('./map/'+name+'.json')
  return jsonData.default
}

地图回钻实现

刚刚在下钻时保存了名字和历史记录,所以回钻就是把历史记录中的最后一项弹出

function returnUpLevel() {
    //先判断history有没有数据,能不能返回
    if(history.length == 0){
        return false
    }
    //取出要返回的那个名字
    const name = history.pop()
    const currentJson = echarts.getMap(mapname).geoJson
    //修改地图配置重新绘制地图
    options.geo.map = mapname
    options.series[0].map = mapname
    chart.setOption(options)
    //修改当前的层级,名字
    currentName = name
}

如何判定点是否在地图中

地图上我打了一些散点,但是在地图下钻后,有一些散点会显示在地图外,所以需要判断哪些点是需要显示的,哪些不要,具体方法我用的射线法,射线法的解释我写在另一篇里了:
射线法判断一个点是否在多边形内部

结合地图json的数据结构,我放一下判断点是否在当前地图中的代码:

function isPointInMaps(p, mapJson) {
    const areas = mapJson.features 
    let flag = false
    for(let i = 0;i < areas.length; i++) {
        if(rayCasting(p, areas[i].geometry.coordinates[0])) {
            flag = true
            break
        }
    }
    return flag
}

function rayCasting(p, poly) {
    let px = p[0],
        py = p[1],
        flag = false

    for(let i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) {
        let sx = poly[i][0],
            sy = poly[i][1],
            tx = poly[j][0],
            ty = poly[j][1]

        // 点与多边形顶点重合
        if((sx === px && sy === py) || (tx === px && ty === py)) {
            return true
        }

        // 点的射线和多边形的一条边重合,并且点在边上
        if((sy === ty && sy === py) && ((sx > px && tx < px) || (sx < px && tx > px))) {
            return true
        }

        // 判断线段两端点是否在射线两侧
        if((sy < py && ty >= py) || (sy >= py && ty < py)) {
            // 线段上与射线 Y 坐标相同的点的 X 坐标
            let x = sx + (py - sy) * (tx - sx) / (ty - sy)

            // 点在多边形的边上
            if(x === px) {
                return true
            }

            // 射线穿过多边形的边界
            if(x > px) {
                flag = !flag
            }
        }
    }

    // 射线穿过多边形边界的次数为奇数时点在多边形内
    return flag ? true : false
}

如何自定义div写的tooltip框

echarts中的tooltip框其实很容易实现,但是我们UI小姐姐设计的。。我短时间内翻echarts配置翻不出来,所以用一个更绝的方法——div来写这个tooltip框,代码我后续会贴,思路是这样的:

  1. 写一个绝对定位的隐藏起来的div,写好样式
  2. echarts的散点触发 mouseover 事件的时候,更新div位置,更新其中的数据,并显示div
  3. echarts的散点触发 mouseout 事件的时候,隐藏d
  • 14
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值