UNPKG

@wayz/react-gl

Version:

React Component for DeckGL, Base on AMap, Mapbox GL

101 lines (100 loc) 3.43 kB
// @ts-nocheck import TagMap from './CustomTagMap'; import RBush from 'rbush'; import { lngLatToWorld, worldToLngLat } from '@math.gl/web-mercator'; function getDrawingContext() { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); ctx.font = '10px "Lucida Console", Monaco, monospace'; ctx.fillStyle = '#000'; ctx.textBaseline = 'hanging'; ctx.textAlign = 'left'; return ctx; } class TextMapWrapper { constructor() { this.tagMap = null; this.ctx = getDrawingContext(); this.measureText = this.measureText.bind(this); this.textSizes = {}; this.weightThreshold = 1; // cache of layout results this.clusterCache = {}; } setData(data, { getLabel, getPosition, getWeight }) { this.textSizes = {}; data.forEach((d) => { const label = getLabel(d); this.textSizes[label] = this.ctx.measureText(label).width; }); this.tagMap = new TagMap(); this.tagMap.buildHierarchy(data, { getLabel, getPosition, getWeight }); this.clusterCache = {}; } extractCluster({ scale, weightThreshold }) { const project = (lngLat) => { const p = lngLatToWorld(lngLat); p[0] *= scale; p[1] *= scale; return p; }; const tagList = this.tagMap.extractCluster({ project, weightThreshold }); tagList.forEach((tag) => { tag.minX = tag.center[0]; tag.minY = tag.center[1]; tag.maxX = tag.center[0]; tag.maxY = tag.center[1]; }); const cluster = new RBush(); cluster.load(tagList); return cluster; } layout({ tagList, scale, minFontSize, maxFontSize }) { const tags = this.tagMap.layout({ tagList, minFontSize, maxFontSize, maxNumOfTags: 150, sizeMeasurer: this.measureText, }); // transform tags to the format that are used to be visualized as icons in the deckgl layer tags.forEach((tag) => { tag.position = worldToLngLat([tag.center[0] / scale, tag.center[1] / scale]); }); return tags; } getTags({ zoom, bbox, minFontSize, maxFontSize, weightThreshold }) { if (weightThreshold !== this.weightThreshold) { this.weightThreshold = weightThreshold; this.clusterCache = {}; } const scale = Math.pow(2, zoom); const cluster = this.clusterCache[zoom] || this.extractCluster({ scale, weightThreshold }); this.clusterCache[zoom] = cluster; let tagList; if (bbox) { const sw = lngLatToWorld([bbox.minX, bbox.minY]); const ne = lngLatToWorld([bbox.maxX, bbox.maxY]); tagList = cluster.search({ minX: sw[0] * scale, minY: sw[1] * scale, maxX: ne[0] * scale, maxY: ne[1] * scale, }); } else { tagList = cluster.all(); } return this.layout({ tagList, scale, minFontSize, maxFontSize, }); } measureText(label, fontSize) { const width = this.textSizes[label]; return { width: (width / 10) * fontSize, height: fontSize }; } } export default TextMapWrapper;