react+高德地图实现热力地图及海量点加载

之前研究过研究过百度地图配合echarts实现热力地图和大量标注点加载,有兴趣可查看博客https://www.cnblogs.com/class1/p/13691867.html。结果效果不是太理想,进而转战高德地图。

最终效果图先展示一波。

 

图上效果图的实现主要有五点:

一,高德地图的引入。

引入地图,和百度地图一样,还是要申请自己使用的key值,网上讲解很多,这里不再细述。有了key值以后,在全局的入口html文件中引入高德地图,我使用的是antd pro框架,入口文件是document.ejs。如果不想申请key值,直接复制粘贴下面的就可以行。

<script type="text/javascript" src="http://webapi.amap.com/maps?v=1.3&key=4611f58483d79aa58bf6d2b508078f9c&plugin=AMap.Autocomplete,AMap.PlaceSearch"></script>

然后直接在项目里创建页面文件,写你的地图就完了,非常方便。这里我创建的地图文件命名为guidemap.js.

二,热力地图的实现。

关键部分代码:

// 创建地图,gaoDe为地图容器标签的id名
const map = new AMap.Map('gaoDe', {   
      resizeEnable: true,   // 允许缩放地图
      center: [108.5, 34.3],  // 地图中心点经纬度
      zoom: 4   // 地图的等级,范围是3~18级
    });

    let heatmap;
    map.plugin(["AMap.Heatmap"], function () {
      // 初始化heatmap对象
      heatmap = new AMap.Heatmap(map, {
        radius: 25, // 给定半径
        opacity: [0, 0.8],
        gradient:{    // 热力值的颜色设置,范围是0-1,可以分段设置颜色
            0.5: 'blue',
            0.65: 'rgb(117,211,248)',
            0.7: 'rgb(0, 255, 0)',
            0.9: '#ffea00',
            1.0: 'red'
        }
      });
      heatmap.setDataSet({
        data: gaoData,  // heatmapData 热力地图的数据,这里的数据格式 [ {"lng": 116.191031,	"lat": 39.988585,	"count": 10},{...}]
        max: 10   // 热力最大范围值
      })
    });

  

效果图如下:

 

三,控件的添加。

关键部分代码:

  const scale = new AMap.Scale({
        visible: true,
        offset: new AMap.Pixel(70,20),   // 控件的偏移位置
      });
      map.addControl(scale);   // 添加比例尺控件
      map.addControl(new AMap.ToolBar());   // 添加缩放控件

  

因为是热力图,一般图上会有个热力标尺,但是高德地图没有,可以将高德地图引入echarts图表中,通过配置项加热力标尺(visualMap属性)。但是考虑到高德地图的功能比较完备,为了一个属性引入echarts,太大费周章。今天我决定手写个热力标尺:

<div 
  style={{
      height:200,
       width:30 }}
   >
          10
          <div
            style={{
              width:20,
              height: 170,
              background: `linear-gradient(to top,blue,green 33%, yellow 66%, red)`,  // css写渐变色,这里是重点
            }}
          />
          0
    </div>

  

这个是在react项目里写的html,css样式这么写没问题的。

看下添加的控件效果:这个手写的热力标尺毫无违和感是不是。

 

四,海量点标记的添加。

// 海量点标记
    const mass = new AMap.MassMarks(massData, {
      opacity: 0.8,
      zIndex: 111,
      cursor: 'pointer',
      style: {
        url: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',   // 点标注用的图片,可自定义
        anchor: new AMap.Pixel(6, 6),   // 位置偏移
        size: new AMap.Size(15, 15)   // 标注的大小
      }
    });

  mass.setMap(map);

  

此时就是页面标注点和热力图结合了,但是标注点还没有添加信息窗,点击是没有效果的。如果标注点不是太多,也可以不用海量点,直接创建mark,每一个依次添加就行

 const allLength=gaoData.length;    // 获取标注点的个数
     for(let i = 0; i < allLength; i += 1){    // 把每个点都添加在地图上
     const marker = new AMap.Marker({
        position: [gaoData[i].lng, gaoData[i].lat],
      map:map
       });
     }

  

五,点标记的信息窗的添加。

点标记应该和上面的四合起来用的。如果是海量点,加信息窗如下:

const mass = new AMap.MassMarks(massData, {
      opacity: 0.8,
      zIndex: 111,
      cursor: 'pointer',
      style: {
        url: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
        anchor: new AMap.Pixel(6, 6),
        size: new AMap.Size(15, 15)
      }
    });

   //  这部分是label标签,使用label就是这样写的,使用这部分就要注释掉下面信息窗的代码
    // var marker = new AMap.Marker({content: ' ', map: map});
    // mass.on('mouseover', function (e) {
    //   marker.setPosition(e.data.lnglat);
    //   marker.setLabel({content: e.data.lnglat})
    // });


    const infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -10)});
    mass.on('click', function (e) {
      infoWindow.setContent(`<div>
      标题:热点详细信息
      <br/>地理位置:${e.data.lnglat.lng}, ${e.data.lnglat.lat}
      <br/>最近三个月热力值:${e.data.val}
    </div>`);
      infoWindow.open(map, e.data.lnglat);
    });

    mass.setMap(map);

  

这个是使用label标签的效果,鼠标放在mark标注上就展示当前点的地理位置坐标:

 

如果点数不多这里提供了两种写法:

 const allLength=gaoData.length;
    for(let i = 0; i < allLength; i += 1){
      const marker = new AMap.Marker({
        position: [gaoData[i].lng, gaoData[i].lat],
        map:map
      });

      const infoWindow = new AMap.InfoWindow({
        anchor: 'bottom-center',
        content:`<div><p>这是信息窗体!这是信息窗体!</p><p>${gaoData[i].lng}</p></div>` ,
      });
      // 鼠标点击marker弹出自定义的信息窗体
      marker.on('click', function () {
        infoWindow.open(map,[gaoData[i].lng, gaoData[i].lat])
      });
    }

  

 var infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -30)});
    const allLength=gaoData.length;
    function markerClick(e) {
      infoWindow.setContent(e.target.content);
      infoWindow.open(map, e.target.getPosition());
    }
    for(let i = 0; i < allLength; i += 1){
      const marker = new AMap.Marker({
        position: [gaoData[i].lng, gaoData[i].lat],
        map:map
      });
      marker.content = '我是第' + (i + 1) + '个Marker';
      marker.on('click', markerClick);
    }

  

最后附上完整的代码// guidemap.js

import React, { Component,Fragment } from 'react';

const {AMap} = window;

class Guide extends Component {

  constructor(props) {
    super(props);
    this.state = {
      data: props.data,
    };
  }

  componentDidMount() {
      this.getCharts();
  }

  // eslint-disable-next-line no-unused-vars
  componentWillReceiveProps(nextProps, nextContext) {
    if (nextProps.data.length > 0) {
      this.setState({
        data: nextProps.data,
      });
      setTimeout(() => {
        this.getCharts();
      }, 500);
    }else{ this.setState({data:[]})}
  }

  getCharts = () => {
    const { data } = this.state;
    const gaoData=[];
    const massData=[];
    // eslint-disable-next-line array-callback-return
      data.map(item=>{
        gaoData.push({ lng:item.longitude, lat:item.latitude, count:item.number})
        massData.push({lnglat:[item.longitude,item.latitude],val:item.number})
      });
    console.log("高德地图",gaoData);
    const map = new AMap.Map('gaoDe', {
      resizeEnable: true,
      center: [108.5, 34.3],
      zoom: 4
    });

    let heatmap;
    map.plugin(["AMap.Heatmap","AMap.Scale",'AMap.ToolBar',], function () {
      // 初始化heatmap对象
      heatmap = new AMap.Heatmap(map, {
        radius: 25, // 给定半径
        opacity: [0, 0.8],
        gradient:{
            0.5: 'blue',
            0.65: 'rgb(117,211,248)',
            0.7: 'rgb(0, 255, 0)',
            0.9: '#ffea00',
            1.0: 'red'
        }
      });
      heatmap.setDataSet({
        data: gaoData,// heatmapData
        max: 10
      });
      const scale = new AMap.Scale({
        visible: true,
        offset: new AMap.Pixel(70,20),
      });
      map.addControl(scale);
      map.addControl(new AMap.ToolBar());
    });

  // 海量点标记
    const mass = new AMap.MassMarks(massData, {
      opacity: 0.8,
      zIndex: 111,
      cursor: 'pointer',
      style: {
        url: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
        anchor: new AMap.Pixel(6, 6),
        size: new AMap.Size(15, 15)
      }
    });

    // var marker = new AMap.Marker({content: ' ', map: map});
    // mass.on('mouseover', function (e) {
    //   marker.setPosition(e.data.lnglat);
    //   marker.setLabel({content: e.data.lnglat})
    // });

    const infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -10)});
    mass.on('click', function (e) {
      infoWindow.setContent(`<div>
      标题:热点详细信息
      <br/>地理位置:${e.data.lnglat.lng}, ${e.data.lnglat.lat}
      <br/>最近三个月热力值:${e.data.val}
    </div>`);
      infoWindow.open(map, e.data.lnglat);
    });

    mass.setMap(map);
   // map.setFitView();// 自适应所有的点

    // 点不多,添加mark和信息窗(方案一)
    // const allLength=gaoData.length;
    // for(let i = 0; i < allLength; i += 1){
    //   const marker = new AMap.Marker({
    //     position: [gaoData[i].lng, gaoData[i].lat],
    //     map:map
    //   });
    //
    //   const infoWindow = new AMap.InfoWindow({
    //     anchor: 'bottom-center',
    //     content:`<div><p>这是信息窗体!这是信息窗体!</p><p>${gaoData[i].lng}</p></div>` ,
    //   });
    //   // 鼠标点击marker弹出自定义的信息窗体
    //   marker.on('click', function () {
    //     infoWindow.open(map,[gaoData[i].lng, gaoData[i].lat])
    //   });
    // }

       // 点不多,添加mark和信息窗(方案二)
    // var infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -30)});
    // const allLength=gaoData.length;
    // function markerClick(e) {
    //   infoWindow.setContent(e.target.content);
    //   infoWindow.open(map, e.target.getPosition());
    // }
    // for(let i = 0; i < allLength; i += 1){
    //   const marker = new AMap.Marker({
    //     position: [gaoData[i].lng, gaoData[i].lat],
    //     map:map
    //   });
    //   marker.content = '我是第' + (i + 1) + '个Marker';
    //   marker.on('click', markerClick);
    // }
  };

  render(){
    return (
      <Fragment>
        <div id="gaoDe" style={{ width: '100%', height: 600 }}>
          {' '}
        </div>
        <div
          style={{
            height:200,
            width:30,
            position:"relative",
            left:20,
            top: -230,
        }}
        >
          10
          <div
            style={{
              width:20,
              height: 170,
              background: `linear-gradient(to top,blue,green 33%, yellow 66%, red)`,
            }}
          />
          0
        </div>
      </Fragment>

    );
  }
}

export default Guide;

  

然后在其他页面引入这个地图:

import Guidemap from './guidemap';  //引入自己写好的热力地图
const arry=[
  {longitude:120.328789,latitude:34.876575,number:10},
 {longitude:120.328789,latitude:34.876575,number:10},
];           
<Guidemap data={arry} />   //直接在页面引入标签使用  arry的数据格式你可以有自己的格式,不过你的格式改了的话,guide.js参数使用也得自己改下。

  文章转载请标明出处,谢谢配合。

posted @ 2020-12-11 15:49  荷风伊夏  阅读(1304)  评论(0编辑  收藏  举报