前言:碰到一個需求,效果實現一個該范圍不同點數的圓環比例以及總數。比例按照對應的區域內不同內容的數量實現比例圓環比例。
查看高德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;