mirror of https://gitee.com/antv-l7/antv-l7
improvement(markerlayer): 支持根据缩放范围动态获取聚合数据
This commit is contained in:
parent
8424e17dc4
commit
94a563b25e
|
@ -143,7 +143,7 @@
|
||||||
"release-cdn": "antv-bin upload -n @antv/l7",
|
"release-cdn": "antv-bin upload -n @antv/l7",
|
||||||
"storybook": "start-storybook -p 6006",
|
"storybook": "start-storybook -p 6006",
|
||||||
"test": "cross-env BABEL_ENV=test jest",
|
"test": "cross-env BABEL_ENV=test jest",
|
||||||
"test-live": "cross-env BABEL_ENV=test DEBUG_MODE=1 jest --watch packages/scene/__tests__/index.spec.ts ",
|
"test-live": "cross-env BABEL_ENV=test DEBUG_MODE=1 jest --watch",
|
||||||
"coveralls": "jest --coverage && cat ./tests/coverage/lcov.info | coveralls",
|
"coveralls": "jest --coverage && cat ./tests/coverage/lcov.info | coveralls",
|
||||||
"tsc": "tsc",
|
"tsc": "tsc",
|
||||||
"watch": "yarn clean && lerna exec --parallel -- cross-env BABEL_ENV=cjs babel --watch src --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
|
"watch": "yarn clean && lerna exec --parallel -- cross-env BABEL_ENV=cjs babel --watch src --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
import { IMapService, IMarker, TYPES } from '@antv/l7-core';
|
import { IMapService, IMarker, TYPES } from '@antv/l7-core';
|
||||||
import { bindAll, DOM, Satistics } from '@antv/l7-utils';
|
import {
|
||||||
|
bindAll,
|
||||||
|
boundsContains,
|
||||||
|
DOM,
|
||||||
|
IBounds,
|
||||||
|
padBounds,
|
||||||
|
Satistics,
|
||||||
|
} from '@antv/l7-utils';
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import { Container } from 'inversify';
|
import { Container } from 'inversify';
|
||||||
import { merge } from 'lodash';
|
import { merge } from 'lodash';
|
||||||
|
@ -39,6 +46,7 @@ export default class MarkerLayer extends EventEmitter {
|
||||||
private mapsService: IMapService<unknown>;
|
private mapsService: IMapService<unknown>;
|
||||||
private scene: Container;
|
private scene: Container;
|
||||||
private zoom: number;
|
private zoom: number;
|
||||||
|
private bbox: IBounds;
|
||||||
|
|
||||||
constructor(option?: Partial<IMarkerLayerOption>) {
|
constructor(option?: Partial<IMarkerLayerOption>) {
|
||||||
super();
|
super();
|
||||||
|
@ -141,11 +149,7 @@ export default class MarkerLayer extends EventEmitter {
|
||||||
this.clusterIndex.load(this.points);
|
this.clusterIndex.load(this.points);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getClusterMarker(zoom: number) {
|
private getClusterMarker(viewBounds: IBounds, zoom: number) {
|
||||||
// 之前的参数为 [-180, -85, 180, 85],基本等于全地图的范围
|
|
||||||
// 优化后的逻辑为:
|
|
||||||
// 取当前视野范围 * 2,只渲染视野内 * 2 范围的点
|
|
||||||
const viewBounds = this.mapsService.getBounds();
|
|
||||||
const viewBBox = viewBounds[0].concat(viewBounds[1]) as GeoJSON.BBox;
|
const viewBBox = viewBounds[0].concat(viewBounds[1]) as GeoJSON.BBox;
|
||||||
const clusterPoint = this.clusterIndex.getClusters(viewBBox, zoom);
|
const clusterPoint = this.clusterIndex.getClusters(viewBBox, zoom);
|
||||||
this.clusterMarkers.forEach((marker: IMarker) => {
|
this.clusterMarkers.forEach((marker: IMarker) => {
|
||||||
|
@ -168,14 +172,10 @@ export default class MarkerLayer extends EventEmitter {
|
||||||
const column = Satistics.getColumn(columnData as any, field);
|
const column = Satistics.getColumn(columnData as any, field);
|
||||||
const stat = Satistics.getSatByColumn(method, column);
|
const stat = Satistics.getSatByColumn(method, column);
|
||||||
const fieldName = 'point_' + method;
|
const fieldName = 'point_' + method;
|
||||||
feature.properties[fieldName] = stat;
|
feature.properties[fieldName] = stat.toFixed(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const marker = this.clusterMarker(feature);
|
const marker = this.clusterMarker(feature);
|
||||||
// feature.properties && feature.properties.hasOwnProperty('point_count')
|
|
||||||
// ? this.clusterMarker(feature)
|
|
||||||
// : this.normalMarker(feature);
|
|
||||||
|
|
||||||
this.clusterMarkers.push(marker);
|
this.clusterMarkers.push(marker);
|
||||||
marker.addTo(this.scene);
|
marker.addTo(this.scene);
|
||||||
});
|
});
|
||||||
|
@ -211,14 +211,15 @@ export default class MarkerLayer extends EventEmitter {
|
||||||
|
|
||||||
private update() {
|
private update() {
|
||||||
const zoom = this.mapsService.getZoom();
|
const zoom = this.mapsService.getZoom();
|
||||||
// 在 zoom 变化的时候,通过控制触发的阈值 (0.4),减少小层级的 zoom 变化引起的频繁重绘
|
const bbox = this.mapsService.getBounds();
|
||||||
if (zoom !== this.zoom && Math.abs(zoom - this.zoom) > 0.4) {
|
if (
|
||||||
// 按照当前地图的放大层级向下取整,进行聚合点的绘制
|
!this.bbox ||
|
||||||
|
Math.abs(zoom - this.zoom) >= 1 ||
|
||||||
|
!boundsContains(this.bbox, bbox)
|
||||||
|
) {
|
||||||
|
this.bbox = padBounds(bbox, 0.5);
|
||||||
this.zoom = Math.floor(zoom);
|
this.zoom = Math.floor(zoom);
|
||||||
this.getClusterMarker(Math.floor(zoom));
|
this.getClusterMarker(this.bbox, this.zoom);
|
||||||
} else if (zoom === this.zoom) {
|
|
||||||
// 如果 zoom 没有变化,只是平移,进行重新计算渲染加载s
|
|
||||||
this.getClusterMarker(Math.floor(zoom));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,14 +235,6 @@ export default class MarkerLayer extends EventEmitter {
|
||||||
? feature.properties['point_' + method] || feature.properties[field]
|
? feature.properties['point_' + method] || feature.properties[field]
|
||||||
: feature.properties.point_count;
|
: feature.properties.point_count;
|
||||||
span.textContent = text;
|
span.textContent = text;
|
||||||
// const elStyle = isFunction(style)
|
|
||||||
// ? style(feature.properties.point_count)
|
|
||||||
// : style;
|
|
||||||
|
|
||||||
// Object.keys(elStyle).forEach((key: string) => {
|
|
||||||
// // @ts-ignore
|
|
||||||
// el.style[key] = elStyle[key];
|
|
||||||
// });
|
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,39 @@
|
||||||
import { aProjectFlat, lngLatToMeters, project } from '../src/geo';
|
import {
|
||||||
describe('aProjectFlat', () => {
|
aProjectFlat,
|
||||||
it('aProjectFlat', () => {
|
boundsContains,
|
||||||
// console.log(aProjectFlat([112, 32]));
|
IBounds,
|
||||||
// console.log(lngLatToMeters([112, 32]));
|
lngLatToMeters,
|
||||||
// console.log(project([112, 32]));
|
padBounds,
|
||||||
|
project,
|
||||||
|
} from '../src/geo';
|
||||||
|
|
||||||
|
describe('geo', () => {
|
||||||
|
it('padBounds', () => {
|
||||||
|
const bounds: IBounds = [
|
||||||
|
[112, 30],
|
||||||
|
[116, 34],
|
||||||
|
];
|
||||||
|
const bounds2 = padBounds(bounds, 0.5);
|
||||||
|
expect(bounds2).toEqual([
|
||||||
|
[110, 28],
|
||||||
|
[118, 36],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('boundContain', () => {
|
||||||
|
const bounds: IBounds = [
|
||||||
|
[112, 30],
|
||||||
|
[116, 34],
|
||||||
|
];
|
||||||
|
const b2: IBounds = [
|
||||||
|
[113, 30],
|
||||||
|
[115, 33],
|
||||||
|
];
|
||||||
|
const b3: IBounds = [
|
||||||
|
[110, 30],
|
||||||
|
[115, 33],
|
||||||
|
];
|
||||||
|
expect(boundsContains(bounds, b2)).toEqual(true);
|
||||||
|
expect(boundsContains(bounds, b3)).toEqual(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,15 @@ import {
|
||||||
Units,
|
Units,
|
||||||
} from '@turf/helpers';
|
} from '@turf/helpers';
|
||||||
|
|
||||||
|
export type IBounds = [[number, number], [number, number]];
|
||||||
|
export interface ILngLat {
|
||||||
|
lng: number;
|
||||||
|
lat: number;
|
||||||
|
}
|
||||||
|
export interface IPoint {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
const originShift = (2 * Math.PI * 6378137) / 2.0;
|
const originShift = (2 * Math.PI * 6378137) / 2.0;
|
||||||
export type Point = number[];
|
export type Point = number[];
|
||||||
/**
|
/**
|
||||||
|
@ -207,3 +216,26 @@ export function project(lnglat: [number, number]) {
|
||||||
|
|
||||||
return [x, y];
|
return [x, y];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function padBounds(b: IBounds, bufferRatio: number): IBounds {
|
||||||
|
const heightBuffer = Math.abs(b[1][1] - b[0][1]) * bufferRatio;
|
||||||
|
const widthBuffer = Math.abs(b[1][0] - b[0][0]) * bufferRatio;
|
||||||
|
|
||||||
|
return [
|
||||||
|
[b[0][0] - widthBuffer, b[0][1] - heightBuffer],
|
||||||
|
[b[1][0] + widthBuffer, b[1][1] + heightBuffer],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* b1 包含 b2 返回 true 否则false
|
||||||
|
* @param b1 bounds1
|
||||||
|
* @param b2 bounds2
|
||||||
|
*/
|
||||||
|
export function boundsContains(b1: IBounds, b2: IBounds): boolean {
|
||||||
|
return (
|
||||||
|
b1[0][0] <= b2[0][0] &&
|
||||||
|
b1[0][1] <= b2[0][1] &&
|
||||||
|
b1[1][0] >= b2[1][0] &&
|
||||||
|
b1[1][1] >= b2[1][1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue