diff --git a/examples/point/cluster/demo/cluster2.js b/examples/point/cluster/demo/cluster2.js new file mode 100644 index 0000000000..707602eb42 --- /dev/null +++ b/examples/point/cluster/demo/cluster2.js @@ -0,0 +1,62 @@ +import { Scene, PointLayer, Source } from '@antv/l7'; +import { GaodeMap } from '@antv/l7-maps'; + +const scene = new Scene({ + id: 'map', + map: new GaodeMap({ + center: [ 120.19382669582967, 30.258134 ], + pitch: 0, + style: 'dark', + zoom: 3 + }) +}); +scene.on('loaded', () => { + fetch('https://gw.alipayobjects.com/os/bmw-prod/87e40417-a5da-4fdb-8313-c796ea15f982.csv') + .then(res => res.text()) + .then(data => { + const dataSource = new Source(data, { + parser: { + type: 'csv', + x: 'lng', + y: 'lat' + + }, + cluster: true + }); + const pointLayer = new PointLayer({ + autoFit: true + }) + .source(dataSource) + .shape('circle') + .scale('point_count', { + type: 'quantile' + }) + .size('point_count', [ 5, 10, 15, 20, 25 ]) + .active(true) + .color('rgb(73,167,86)') + .style({ + opacity: 1, + strokeWidth: 1, + stroke: '#fff' + }); + + // 聚合图标注 + const pointLayerText = new PointLayer({ + autoFit: false + }) + .source(dataSource) + .shape('point_count', 'text') + .size(15) + .active(true) + .color('#fff') + .style({ + opacity: 1, + strokeWidth: 0, + stroke: '#fff' + + }); + + scene.addLayer(pointLayer); + scene.addLayer(pointLayerText); + }); +}); diff --git a/examples/point/cluster/demo/meta.json b/examples/point/cluster/demo/meta.json index bad1f1d0a9..de8727def5 100644 --- a/examples/point/cluster/demo/meta.json +++ b/examples/point/cluster/demo/meta.json @@ -7,7 +7,12 @@ { "filename": "cluster.js", "title": "聚合图", - "screenshot": "https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*MowATbzWK_QAAAAAAAAAAAAAARQnAQ" + "screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*paQsRKykjL4AAAAAAAAAAABkARQnAQ" + }, + { + "filename": "cluster2.js", + "title": "充电桩分布聚合图", + "screenshot": "https://gw.alipayobjects.com/mdn/rms_08cc33/afts/img/A*dy0NSJHoRSYAAAAAAAAAAAAAARQnAQ" } ] diff --git a/packages/core/src/services/layer/ILayerService.ts b/packages/core/src/services/layer/ILayerService.ts index ca5fd3e58e..d2281ea830 100644 --- a/packages/core/src/services/layer/ILayerService.ts +++ b/packages/core/src/services/layer/ILayerService.ts @@ -98,6 +98,7 @@ export interface ILayer { name: string; // inited: boolean; // 是否初始化完成 zIndex: number; + clusterZoom: number; plugins: ILayerPlugin[]; layerModelNeedUpdate: boolean; styleNeedUpdate: boolean; diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index 0efa449d2d..73c748248a 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -73,6 +73,7 @@ export default class BaseLayer extends EventEmitter public selectedFeatureID: number | null = null; public styleNeedUpdate: boolean = false; public rendering: boolean; + public clusterZoom: number = 0; // 聚合等级标记 public dataState: IDataState = { dataSourceNeedUpdate: false, @@ -491,6 +492,7 @@ export default class BaseLayer extends EventEmitter data, options, }; + this.clusterZoom = 0; return this; } public setData(data: any, options?: ISourceCFG) { @@ -862,6 +864,7 @@ export default class BaseLayer extends EventEmitter } this.layerSource = source; + this.clusterZoom = 0; // 已 inited 且启用聚合进行更新聚合数据 if (this.inited && this.layerSource.cluster) { @@ -1093,7 +1096,7 @@ export default class BaseLayer extends EventEmitter if (autoFit) { this.fitBounds(fitBoundsOptions); } - + // 对外暴露事件 this.emit('dataUpdate'); this.reRender(); }; diff --git a/packages/layers/src/plugins/DataSourcePlugin.ts b/packages/layers/src/plugins/DataSourcePlugin.ts index 77d97be588..737a9933ef 100644 --- a/packages/layers/src/plugins/DataSourcePlugin.ts +++ b/packages/layers/src/plugins/DataSourcePlugin.ts @@ -46,10 +46,14 @@ export default class DataSourcePlugin implements ILayerPlugin { // 如果 dataSource 有更新,跳过 zoom 的判断,直接更新一次 if ( cluster && - (dataSourceNeedUpdate || Math.abs(zoom - newZoom) > 1) && - maxZoom > zoom + (dataSourceNeedUpdate || Math.abs(layer.clusterZoom - newZoom) >= 1) && + maxZoom > layer.clusterZoom ) { - source.updateClusterData(Math.floor(newZoom)); + // TODO 判断数据是否更新 + if (zoom !== Math.floor(newZoom)) { + source.updateClusterData(Math.round(newZoom)); + } + layer.clusterZoom = newZoom; return true; } return false; diff --git a/stories/Layers/Layers.stories.tsx b/stories/Layers/Layers.stories.tsx index 91fbecadc5..8656d6c58b 100644 --- a/stories/Layers/Layers.stories.tsx +++ b/stories/Layers/Layers.stories.tsx @@ -5,6 +5,7 @@ import Arc2DLineDemo from './components/Arc2DLine'; import ArcLineDemo from './components/Arcline'; import CityBuildingLayerDemo from './components/citybuilding'; import ClusterDemo from './components/cluster'; +import ClusterDemo2 from './components/cluster2'; import Column from './components/column'; import DashLineDemo from './components/dash'; import DataUpdate from './components/data_update'; @@ -31,6 +32,7 @@ import TextLayerDemo from './components/Text'; storiesOf('图层', module) .add('点图层', () => ) .add('聚合图', () => ) + .add('聚合图标注', () => ) .add('数据更新', () => ) .add('点动画', () => ) .add('3D点', () => ) diff --git a/stories/Layers/components/cluster2.tsx b/stories/Layers/components/cluster2.tsx new file mode 100644 index 0000000000..f95dddee87 --- /dev/null +++ b/stories/Layers/components/cluster2.tsx @@ -0,0 +1,95 @@ +import { PointLayer, Scene, Source } from '@antv/l7'; +import { GaodeMap, Mapbox } from '@antv/l7-maps'; +import * as React from 'react'; +// @ts-ignore +import data from '../data/data.json'; +export default class Point3D extends React.Component { + // @ts-ignore + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const scene = new Scene({ + id: 'map', + pickBufferScale: 3.0, + map: new GaodeMap({ + style: 'light', + center: [-121.24357, 37.58264], + pitch: 0, + zoom: 10.45, + }), + }); + scene.on('loaded', () => { + const fontFamily = 'iconfont'; + const fontPath = + '//at.alicdn.com/t/font_2534097_fcae9o2mxbv.woff2?t=1622200439140'; + scene.addFontFace(fontFamily, fontPath); + scene.addIconFont('icon1', ''); + fetch( + 'https://gw.alipayobjects.com/os/bmw-prod/87e40417-a5da-4fdb-8313-c796ea15f982.csv', + ) + .then((res) => res.text()) + .then((data) => { + const dataSource = new Source(data, { + parser: { + type: 'csv', + x: 'lng', + y: 'lat', + }, + cluster: true, + }); + const pointLayer = new PointLayer({ + autoFit: true, + }) + .source(dataSource) + .shape('circle') + .scale('point_count', { + type: 'quantile', + }) + .size('point_count', [5, 10, 15, 20, 25]) + .active(true) + .color('rgb(73,167,86)') + .style({ + opacity: 1, + strokeWidth: 1, + stroke: '#333', + }); + + const pointLayerText = new PointLayer({ + autoFit: true, + }) + .source(dataSource) + .shape('point_count', 'text') + .size(15) + .active(true) + .color('#fff') + .style({ + opacity: 1, + strokeWidth: 0, + stroke: '#fff', + }); + + scene.addLayer(pointLayer); + scene.addLayer(pointLayerText); + }); + }); + } + + public render() { + return ( +
+ ); + } +} diff --git a/stories/Map/components/cluster.tsx b/stories/Map/components/cluster.tsx new file mode 100644 index 0000000000..3909bdc832 --- /dev/null +++ b/stories/Map/components/cluster.tsx @@ -0,0 +1,70 @@ +import { PointLayer, Marker, Scene } from '@antv/l7'; +import { GaodeMap } from '@antv/l7-maps'; +import * as React from 'react'; +export default class Cluster extends React.Component { + // @ts-ignore + private scene: Scene; + + public componentWillUnmount() { + // this.scene.destroy(); + } + + public async componentDidMount() { + const scene = new Scene({ + id: 'map', + map: new GaodeMap({ + center: [110.19382669582967, 30.258134], + pitch: 0, + zoom: 3, + }), + }); + + scene.on('loaded', () => { + fetch( + 'https://gw.alipayobjects.com/os/basement_prod/d3564b06-670f-46ea-8edb-842f7010a7c6.json', + ) + .then((res) => res.json()) + .then((data) => { + const pointLayer = new PointLayer({}) + .source(data, { + cluster: true, + }) + .shape('circle') + .scale('point_count', { + type: 'quantile', + }) + .size('point_count', [5, 10, 15, 20, 25]) + .active(true) + .color('yellow') + .style({ + opacity: 0.5, + strokeWidth: 1, + }); + + scene.addLayer(pointLayer); + + scene.on('zoomchange', () => { + const d = pointLayer.getSource(); + // console.log('ddd', d.data.dataArray) + }); + }); + }); + } + + public render() { + return ( + <> +
+ + ); + } +} diff --git a/stories/Map/map.stories.tsx b/stories/Map/map.stories.tsx index 6cff7420af..7cca30b3b7 100644 --- a/stories/Map/map.stories.tsx +++ b/stories/Map/map.stories.tsx @@ -74,6 +74,7 @@ import SimplePoint from './components/simplePoint'; import LineWall from './components/linewall' import GridTile from './components/gridTile' import GridTile2 from './components/gridTile2' +import Cluster from './components/cluster' // @ts-ignore storiesOf('地图方法', module) @@ -152,3 +153,4 @@ storiesOf('地图方法', module) .add('BusLine', () => ) .add('GridTile', () => ) .add('GridTile2', () => ) + .add('Cluster', () => )