zoukankan      html  css  js  c++  java
  • 高德地图实现一个比例圆环形聚合点缩放

    前言:碰到一个需求,效果实现一个该范围不同点数的圆环比例以及总数。比例按照对应的区域内不同内容的数量实现比例圆环比例。

    查看高德api只有点聚合效果,我们可以根据他的基础api来增加实现更高级的效果改造。

    先上效果图

    1、最低层级时候效果:(这里就是打点而已)

    2、缩放时候:(这时候将红色和蓝色圆环缩放在一个区域,我们绘制出来圆环显示对应数值3个红色和4个蓝色)

    3、继续缩放时候效果(注意:红色和蓝色是该区域内的比例,所占比例是一样的,总数是7)

     附上代码:可以直接复制黏贴使用

    该功能核心是将canvas绘制的圆环通过base64转为图片,然后传给高德api渲染

    (比较粗略,但是这个实现基础,有其他需求可以自行修改。点个赞评论再走,不要白嫖)

    import React from 'react';
    import { connect } from 'dva';
    import styles from './index.less';
    import iconAddress from '../../static/dir-marker.png';
    import { Button } from 'antd';
    
    /**
     * 全局变量
     * **/
    const AMap = window.AMap;
    
    class LBSMap extends React.Component {
    
      state = {
        mapLang: (localStorage.getItem('lang') === 'TC' || localStorage.getItem('lang') === 'CHS') ? 'zh_cn' : 'en',   //en:英文,zh_en:中英文对照
        aaa: null,
        blueIconArr: [],
        redIconArr: [],
        markers: [],
      };
    
      componentDidMount() {
        this.renderRing();
      }
    
      /********************************************使用renderClusterMarker属性实现聚合点的完全自定义绘制*****************************************/
      renderRing = (blueIconArr = []) => {
        const markers = [];
        /***
         * 创建地图实例
         * **/
        const map = new AMap.Map('lbsMap', {
          zoom: 13,//级别
          center: [113.55891, 22.17059],//中心点坐标
          // lang: this.state.mapLang,
          expandZoomRange: true,
        });
        /***
         * 异步同时加载多个插件
         * AMap.MarkerClusterer点聚合插件、AMap.CircleEditor圆编辑插件、AMap.ElasticMarker灵活点标记,
         * 可以随着地图级别改变样式和大小的 Marker、AMap.AdvancedInfoWindow高级信息窗体
         * **/
        AMap.plugin(['AMap.ToolBar', 'AMap.MarkerClusterer'], function() {
          var toolbar = new AMap.ToolBar();
          map.addControl(toolbar);
        });
    
        /******
         *  蓝色的点模拟数据
         * ****/
          // 创建一个 蓝色Icon
        const blueIcon_3d93fd = new AMap.Icon({
            size: new AMap.Size(25, 34),// 图标尺寸
            image: iconAddress, // 图标的取图地址
            imageSize: new AMap.Size(135, 40),// 图标所用图片大小
            imageOffset: new AMap.Pixel(-9, -3), // 图标取图偏移量
          });
        for (let i = 0; i < 7; i++) {
          if (i % 2 === 0) {
            this.state.blueIconArr.push({ x: `113.57${i}41`, y: `22.164${i}32` });
          } else {
            this.state.blueIconArr.push({ x: `113.56${i}11`, y: `22.132${i}59` });
          }
        }
        const redIcon_f34234 = new AMap.Icon({
          size: new AMap.Size(25, 34),
          image: iconAddress,
          imageSize: new AMap.Size(135, 40),
          imageOffset: new AMap.Pixel(-96, -3),
        });
    
        for (let i = 0; i < 6; i++) {
          if (i % 2 === 0) {
            this.state.redIconArr.push({ x: `113.55${i}71`, y: `22.167${i}42` });
          } else {
            this.state.redIconArr.push({ x: `113.54${i}91`, y: `22.122${i}59` });
          }
        }
    
        this.state.blueIconArr.forEach(item => {
          markers.push(new AMap.Marker({
            position: new AMap.LngLat(item.x, item.y),
            icon: blueIcon_3d93fd,
            offset: new AMap.Pixel(-15, -20),
            type: 'blueIcon_3d93fd',
          }));
        });
        this.state.redIconArr.forEach(item => {
          markers.push(new AMap.Marker({
            position: new AMap.LngLat(item.x, item.y),
            icon: redIcon_f34234,
            offset: new AMap.Pixel(-15, -20),
            type: 'redIcon_f34234',
          }));
        });
    
    
        var _renderClusterMarker = function(mapContext) {
          console.log('context', mapContext.markers);
          /*************计算颜色在圆的比例为多少*************/
          const orangeColorRing = [];
          const yellowColorRing = [];
          const greenColorRing = [];
          mapContext.markers.forEach(item => {
            const itemColorType = item.De.type;
            if (itemColorType === 'greenBlueIcon_0ccae7') {
              orangeColorRing.push(itemColorType);
            }
            if (itemColorType === 'redIcon_f34234') {
              yellowColorRing.push(itemColorType);
            }
            if (itemColorType === 'blueIcon_3d93fd') {
              greenColorRing.push(itemColorType);
            }
          });
          const orangeNumber = orangeColorRing.length;
          const yellowNumber = yellowColorRing.length;
          const greenNumber = greenColorRing.length;
          const total = orangeNumber + yellowNumber + greenNumber;
          const orangePer = orangeNumber / total;
          const yellowPer = yellowNumber / total;
          const greenPer = greenNumber / total;
          const ringPerInTotal = orangePer + yellowPer + greenPer;
          const perInTotal1 = (orangePer / ringPerInTotal) * 2;
          const perInTotal2 = (yellowPer / ringPerInTotal) * 2;
          const perInTotal3 = (greenPer / ringPerInTotal) * 2;
    
          function process() {
            const ring = arguments[0];
            const canvas = document.getElementById(ring.canvasId);
            const context = canvas.getContext('2d');
            const centerX = ring.canvasW / 2;
            const centerY = ring.canvasH / 2;
            const borderWidth = ring.bdWidth;
            const radius = ring.canvasW / 2 - borderWidth / 2;
            canvas.width = ring.canvasW;
            canvas.height = ring.canvasH;
            //绘制内圈
            context.save();
            context.beginPath();
            context.arc(centerX, centerY, radius, 0, 360, false);
            context.fillStyle = 'rgba(255, 255, 255, 0.75)';
            context.fill();
            context.stroke();
            context.restore();
            //圆环中文字
            context.save();
            context.beginPath();
            context.font = '18px Georgia';
            context.textAlign = 'center';
            context.fillStyle = 'black';
            context.fillText(mapContext.count, centerX, centerY + 6);
            context.restore();
    
            const ringFunction1 = (start, end, color) => {
              context.save();
              context.beginPath();
              context.lineWidth = borderWidth;
              context.arc(centerX, centerY, radius, start, end, false);
              context.strokeStyle = color;
              context.stroke();
              context.closePath(); //路径结束
              context.restore();
            };
    
            const rad = Math.PI;
            const rad1 = -Math.PI / 2 + perInTotal1 * rad;
            const rad2 = -Math.PI / 2 + (perInTotal1 + perInTotal2) * rad;
            const rad3 = -Math.PI / 2 + (perInTotal1 + perInTotal2 + perInTotal3) * rad;
    
            ringFunction1(-Math.PI / 2, rad1, '#0ccae7');
            ringFunction1(rad1, rad2, '#f34234');
            ringFunction1(rad2, rad3, '#3d93fd');
          }
    
          /*********************调用方法*************************/
          const canvasDiv = document.getElementById('canvasDiv');
          const canvasW = canvasDiv.offsetWidth;
          const canvasH = canvasDiv.offsetWidth;
          process({
            canvasId: 'canvasDiv',  //canvas的Id
            canvasW: canvasW,        //canvas的width
            canvasH: canvasH,        //canvas的height
            bdWidth: 6,          //圆环的宽
          });
          /***************将绘制的canvas转化为img交给高德***********/
          const dataURL = canvasDiv.toDataURL();
          const img = document.createElement('img');
          img.src = dataURL;
          img.alt = '';
          const count = markers.length;
          const size = Math.round(30 + Math.pow(mapContext.count / count, 1 / 5) * 20);   //设置图像偏移量
          mapContext.marker.setOffset(new AMap.Pixel(-size / 2, -size / 2));
          mapContext.marker.setContent(img);
        };
        /**********************运行高德地图自定义实例***************/
        var cluster = new AMap.MarkerClusterer(map, markers, {
          gridSize: 80,
          renderClusterMarker: _renderClusterMarker,
        });
      };
    
    
      addRed = () => {
        this.setState({ blueIconArr: [] });
        //this.state.blueIconArr.push({x: `113.53331`, y: `22.1644332`})
        // 创建一个红色 icon
        const redIcon_f34234 = new AMap.Icon({
          size: new AMap.Size(25, 34),
          image: iconAddress,
          imageSize: new AMap.Size(135, 40),
          imageOffset: new AMap.Pixel(-96, -3),
        });
        // 创建一个青色 icon
        const greenBlueIcon_0ccae7 = new AMap.Icon({
          size: new AMap.Size(25, 34),
          image: iconAddress,
          imageSize: new AMap.Size(135, 40),
          imageOffset: new AMap.Pixel(-51, -3),
        });
      };
    
      render() {
        console.log('state', this.state.blueIconArr);
        return (
          <React.Fragment>
            <div id="lbsMap" className={styles.LBSMap}>
              <canvas id="canvasDiv" width="56" height="56"></canvas>
            </div>
          </React.Fragment>
        );
      }
    }
    
    export default LBSMap;
  • 相关阅读:
    bind 与Eval的区别
    GDI+
    文件读写
    “六度分离”和 洪泛(Search flooding)搜索
    Internet streaming 现在谁是霸主?
    苹果提供高清HD下载SO贵
    关于Youtube 的平均文件尺寸与GFS
    [笔记+整理]随机网络和无标度网络
    2008年中国广播电视广告额增长超15%
    笔记:Mobile CDN 和IPTV CDN有哪些不同
  • 原文地址:https://www.cnblogs.com/seemoon/p/12916516.html
Copyright © 2011-2022 走看看