首页 前端知识 基于echarts实现地图撒点、飞线等功能

基于echarts实现地图撒点、飞线等功能

2024-03-02 09:03:32 前端知识 前端哥 38 537 我要收藏
  • 获取echarts
npm install echarts --save
  • 引入echarts
import * as echarts from 'echarts';
  • 基于准备好的dom,初始化echarts实例
this.myChart = echarts.init(document.getElementById('main'))
  • 注册地图。echarts中注册地图只在 geo 组件或者 map 图表类型中使用,可以选择SVG 格式或者GeoJson格式(编码各种地理数据结构的格式,用来作为地图的轮廓)的数据。这个可以按需选择,该项目使用的GeoJson格式。
    提供一个可以获取到国内各区域地理数据的网站:http://datav.aliyun.com/portal/school/atlas/area_selector#&lat=31.769817845138945&lng=104.29901249999999&zoom=4
var geoJson = require('../utils/310106.json')
echarts.registerMap('JINGAN', geoJson);
  • 配置飞线和删除撒点按钮
    本demo中地图状态分为展示状态、配置状态,通过代码中的isConfig控制。在展示状态中,展示撒好的点以及点到点之间飞线。在配置状态,可以撒点以及删除撒点。

飞线使用eacharts中的路径图系列,用于带有起点和终点信息的线数据的绘制,主要用于地图上的航线,路线的可视化。在这里可以帮助我们实现点到点的飞线效果

// 飞线配置
var lineSeries = {
type:'lines',
name: 'line',
coordinateSystem:'geo',
zlevel: 15,
effect: {
  show: true,
  period: 5,
  trailLength: 0.3,
  symbol: 'circle',
  color:'#e4dfa9',symbolSize: 5,
},
lineStyle: {
  normal: {width: 1.2, opacity: 0.6, curveness: 0.2, color: '#FFB800'}
},
data: []
}

配置删除撒点按钮。这里使用的是eachrts的custom自定义系列,可以自定义系列中的图形元素渲染,从而能扩展出不同的图表

var closeSeries = {
type: 'custom',
id: 'close',
name: 'close',
coordinateSystem: 'geo',
selectedMode: 'single',
datasetIndex: 2,
renderItem: function (params, api) {
  return {
      type: 'group',
      children: [
      {
          type: 'rect',
          invisible: true,
          textContent: {
             style: {
              text: 'X',
              font: '1.5em',
              fill: '#fff',
              x: api.coord([parseFloat(self.data[params.dataIndex] ? self.data[params.dataIndex].longitude : self.education[0].longitude), parseFloat(self.data[params.dataIndex] ? self.data[params.dataIndex].latitude : self.education[0].latitude)])[0] + 20,
              y: api.coord([parseFloat(self.data[params.dataIndex] ? self.data[params.dataIndex].longitude : self.education[0].longitude), parseFloat(self.data[params.dataIndex] ?  self.data[params.dataIndex].latitude : self.education[0].latitude)])[1] - 50
          }
      },
      fill: 'rtgba(65,105,225, 1)',
      style: {
          fill: '#FFC0CB',
          x: api.coord([parseFloat(self.data[params.dataIndex] ? self.data[params.dataIndex].longitude : self.education[0].longitude), parseFloat(self.data[params.dataIndex] ?self.data[params.dataIndex].latitude : self.education[0].latitude)])[0] - 0,
          y: api.coord([parseFloat(self.data[params.dataIndex] ? self.data[params.dataIndex].longitude : self.education[0].longitude), parseFloat(self.data[params.dataIndex] ? self.data[params.dataIndex].latitude : self.education[0].latitude)])[1] - 0,
      },
      z: 3
      }
  ]}
}
}
  • 设置地图配置并绘制。
    点位也是用custom系列,主要由三部分组成,区域个数(文字)、点位图片(图片)以及点位名称(文字)。custom 系列需要开发者自己提供图形渲染的逻辑,这个渲染逻辑一般命名为 renderItem,renderItem 函数须返回根据此 dataItem 绘制出的图形元素的定义信息,图形元素可以是图片、文字、图形等等。而group 是唯一的可以有子节点的容器,可以用来整体定位一组图形元素,能满足我们点位元素组成的需求。
this.myChart.setOption({
geo: [{
  // 引用注册过的底图
  map: 'JINGAN',
  zoom: 1,
  top: 50,
  id: 'jingan',
  itemStyle: {
      areaColor: self.isConfig
      ? {
          type: 'linear',
          x: 0,
          y: 0,
          x2: 0,
          y2: 1,
          colorStops: [{
              offset: 0, color: 'rgba(2,116,159,0.45)'
          }, {
              offset: 0.2, color: 'rgba(0,140,168,0.24)'
          }, {
              offset: 0.4, color: 'rgba(0,91,155,0.11)'
          },{
              offset: 0.6, color: 'rgba(0,129,158,0.28)'
          },{
              offset: 0.8, color: 'rgba(0,141,159,0.49)'
          },{
              offset: 1, color: 'rgb(2,147,156,0.45)'
          }],
          global: false
      }
      : 'rgba(255,255,255,0)'
   },
  emphasis: {
      itemStyle: {
          areaColor: self.isConfig
          ? {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 0,
              y2: 1,
              colorStops: [{
                  offset: 0, color: 'rgba(2,116,159,0.45)'
              }, {
                  offset: 0.2, color: 'rgba(0,140,168,0.24)'
              }, {
                  offset: 0.4, color: 'rgba(0,91,155,0.11)'
              },{
                  offset: 0.6, color: 'rgba(0,129,158,0.28)'
              },{
                  offset: 0.8, color: 'rgba(0,141,159,0.49)'
              },{
                    offset: 1, color: 'rgb(2,147,156,0.45)'
              }],
              global: false
          }
          : 'rgba(255,255,255,0)'
      },
      label: {
          show: false
      }
  },
  backgroundColor: 'rgba(255, 255, 255, 0)'
}],
dataset: [
  {
      source: []
  },
  {
      source: []
  },
  {
      source: []
  },
  {
      source: []
  }],
series: [
  {
      type: 'custom',
      name: 'area',
      coordinateSystem: 'geo',
      selectedMode: 'single',
      datasetIndex: 0,
      // geoIndex: 0,
      renderItem: function (params, api) {
        return {
          type: 'group',
          children: [
            {
              type: 'image',
              style: {
                image: icon,
                x: api.coord([parseFloat(self.data[params.dataIndex].longitude), parseFloat(self.data[params.dataIndex].latitude)])[0] - 54,
                y: api.coord([parseFloat(self.data[params.dataIndex].longitude), parseFloat(self.data[params.dataIndex].latitude)])[1] -54
              }
            },
            {
              type: 'text',
              style: {
                text: self.data[params.dataIndex].orgName,
                fill: 'rgba(255, 255, 255, 0.9)',
                x: api.coord([parseFloat(self.data[params.dataIndex].longitude), parseFloat(self.data[params.dataIndex].latitude)])[0] - self.data[params.dataIndex].orgName.length * self.fontSize,
                y: api.coord([parseFloat(self.data[params.dataIndex].longitude), parseFloat(self.data[params.dataIndex].latitude)])[1] + 23
              }
            },
            {
              type: 'text',
              style: {
                text: self.data[params.dataIndex].subOrgNum || 0,
                fill: 'rgba(255, 255, 255, 0.9)',
                x: api.coord([parseFloat(self.data[params.dataIndex].longitude), parseFloat(self.data[params.dataIndex].latitude)])[0] - (self.data[params.dataIndex].subOrgNum || '').toString().length * self.fontSize,
                y: api.coord([parseFloat(self.data[params.dataIndex].longitude), parseFloat(self.data[params.dataIndex].latitude)])[1] - 38
              }
            }
          ]
        }
      }
    },{
      type: 'custom',
      id: 'edu',
      name: 'edu',
      coordinateSystem: 'geo',
      datasetIndex: 1,
      renderItem: function (params, api) {
        return {
          type: 'group',
          children: [
            {
              type: 'image',
              style: {
                image: iconEdu,
                x: api.coord([parseFloat(self.education[params.dataIndex].longitude), parseFloat(self.education[params.dataIndex].latitude)])[0] - 46,
                y: api.coord([parseFloat(self.education[params.dataIndex].longitude), parseFloat(self.education[params.dataIndex].latitude)])[1] - 60
              }
            }
          ]
        }
      }
    }
  ]
  .concat(self.isConfig ? [closeSeries] : [lineSeries])
})
  • 拿到后台数据,转化为我们需要的格式后,更新地图。
this.myChart.setOption({
        dataset: [
          {
            source: this.data
          },
          {
            source: this.education
          },
          {
            source: this.data.concat(this.education)
          }
        ],
        series:[
        {
          name: 'area',
          datasetIndex: 0
        },
        {
          name: 'edu',
          datasetIndex: 1
        },
        {
          name: 'close',
          datasetIndex: 2
        },
        {
          name: 'line',
          data: line
        }]
      })
  • 获取地图的监听事件,本demo主要用于实现:
    1.展示状态,点击点位后,显示点位详情弹框。
    2.配置状态,点击地图任意区域,进行撒点功能;点击关闭按钮,删除该点位;
this.myChart.on('click', function(params) {
  console.log(params)
  let componentType = params.componentType;
  if (!self.isConfig) {
      if (componentType === 'series' && params.seriesName !== 'edu') {
          self.$emit('handleClick', params)
      }
  } else {
      if (componentType === 'geo') {
          let offsetX = params.event.offsetX;
          let offsetY = params.event.offsetY;
          let lonlat = self.myChart.convertFromPixel('geo', [offsetX, offsetY]); // 转换成坐标
          self.$emit('handleClick', {type:'add', data: {}, lonlat:lonlat})
      }
      if (componentType === 'series') {
          if (params.seriesName === 'close') {
            self.$emit('close', params)
          }
          if (params.seriesName === 'area' || params.seriesName === 'edu') {
            self.$emit('handleClick', {type:'edit', data: params.data})
          }
      }
  }
})
转载请注明出处或者链接地址:https://www.qianduange.cn//article/3086.html
标签
评论
会员中心 联系我 留言建议 回顶部
复制成功!