前言:碰到一个需求,效果实现一个该范围不同点数的圆环比例以及总数。比例按照对应的区域内不同内容的数量实现比例圆环比例。
查看高德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;