Skip to content

Commit c945b49

Browse files
committed
fix MassPoints
Signed-off-by: CoderJ <550106786@qq.com>
1 parent e8f80ef commit c945b49

File tree

5 files changed

+106
-17
lines changed

5 files changed

+106
-17
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
## v1.4.2
2+
3+
- feature: [MassPoints](https://github.com/Coder-JJ/rc-leaflet/blob/master/docs/MassPoints.md) new props.
4+
5+
- throttleThreshold
6+
7+
- type: `number`
8+
9+
- required: `false`
10+
11+
- default `20480`
12+
13+
- when `points.length` > `throttleThreshold`, `MassPoints` will use throttled draw function
14+
15+
- throttleDuration default
16+
17+
- type: `number`
18+
19+
- required: `false`
20+
21+
- default `60`
22+
23+
- used in throttled draw function, draw points per `throttleDuration` ms
24+
25+
- fix: [MassPoints](https://github.com/Coder-JJ/rc-leaflet/blob/master/docs/MassPoints.md) layer drift when zoom is small.
26+
27+
- fix: [MassPoints](https://github.com/Coder-JJ/rc-leaflet/blob/master/docs/MassPoints.md) is static duration zoom animation.
28+
129
## v1.4.1
230

331
- feature: totally rewrite [MassPoints](https://github.com/Coder-JJ/rc-leaflet/blob/master/docs/MassPoints.md), now it supports multi icons, mouse events, and `DivOverlay` render props.

docs/MassPoints.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## MassPoints `v2.2.0+`
1+
## MassPoints `v1.1.0+`
22

33
### Examples
44

@@ -29,7 +29,7 @@
2929
return (
3030
<RCMap crs center>
3131
<TileLayer />
32-
<MassPoints points iconUrl iconSize iconAnchor popupAnchor tooltipAnchor>
32+
<MassPoints points iconUrl iconSize iconAnchor popupAnchor tooltipAnchor throttleThreshold throttleDuration>
3333
<Popup>
3434
{ target => <div /> }
3535
</Popup>
@@ -57,6 +57,26 @@
5757

5858
### Props
5959

60+
- throttleThreshold `v1.4.2+`
61+
62+
- type: `number`
63+
64+
- required: `false`
65+
66+
- default: `20480`
67+
68+
- 当点位数量大于设定的阈值时, 将使用节流的渲染函数
69+
70+
- throttleDuration `v1.4.2+`
71+
72+
- type: `number`
73+
74+
- required: `false`
75+
76+
- default: `60`
77+
78+
- 节流渲染函数的渲染时间间隔
79+
6080
- points
6181

6282
- type: `MassPoint[]`

src/components/MassPoints/MassLayer.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import L from 'leaflet'
22
import { distinct } from '../../util/Array'
3+
import throttle from '../../util/throttle'
34
import { defaultOptions as defaultIconOptions } from '../Icon/creator'
45

56
export type Icon = Partial<{
@@ -29,10 +30,14 @@ export interface EventTarget {
2930

3031
export interface MassLayerOptions extends L.InteractiveLayerOptions, Icon {
3132
points: MassPoint[]
33+
throttleThreshold?: number
34+
throttleDuration?: number
3235
}
3336

34-
const defaultOptions: MassLayerOptions = {
35-
points: []
37+
export const defaultOptions: MassLayerOptions = {
38+
points: [],
39+
throttleThreshold: 20480,
40+
throttleDuration: 60
3641
}
3742

3843
export default class MassLayer extends L.Layer {
@@ -52,12 +57,21 @@ export default class MassLayer extends L.Layer {
5257

5358
private click: EventTarget
5459

60+
private throttledReset: () => void
61+
5562
public constructor (options?: MassLayerOptions) {
5663
super(options)
5764
L.Util.setOptions(this, L.Util.extend(defaultOptions, options))
5865
this.canvas = L.DomUtil.create('canvas', 'leaflet-zoom-animated') as HTMLCanvasElement
5966
this.ctx = this.canvas.getContext('2d')
6067
this.prepareIcons()
68+
this.setThrottledReset(this.options)
69+
}
70+
71+
private setThrottledReset (options: MassLayerOptions): void {
72+
const threshold = options.throttleThreshold || defaultOptions.throttleThreshold
73+
const duration = options.throttleDuration || defaultOptions.throttleDuration
74+
this.throttledReset = options.points.length <= threshold ? this.reset : throttle(this.reset, duration)
6175
}
6276

6377
public onAdd (map: L.Map): this {
@@ -67,6 +81,7 @@ export default class MassLayer extends L.Layer {
6781

6882
map.on('click', this.onClick, this)
6983
map.on('mousemove', this.onMouseMove, this)
84+
map.on('move', this.throttledReset, this)
7085
map.on('moveend', this.reset, this)
7186
map.on('zoomanim', this.zoomAnim, this)
7287
this.on('popupclose', this.onPopupClose)
@@ -78,6 +93,7 @@ export default class MassLayer extends L.Layer {
7893
public onRemove (map: L.Map): this {
7994
map.off('click', this.onClick, this)
8095
map.off('mousemove', this.onMouseMove, this)
96+
map.off('move', this.throttledReset, this)
8197
map.off('moveend', this.reset, this)
8298
map.off('zoomanim', this.zoomAnim, this)
8399
this.off()
@@ -97,17 +113,17 @@ export default class MassLayer extends L.Layer {
97113
public setOptions (options: MassLayerOptions): void {
98114
this.closePopup()
99115
L.Util.setOptions(this, options)
116+
this._map.off('move', this.throttledReset, this)
117+
this.setThrottledReset(options)
118+
this._map.on('move', this.throttledReset, this)
100119
this.prepareIcons()
101120
this.draw()
102121
}
103122

104123
public getOptions = (): MassLayerOptions => this.options
105124

106125
public setPoints (points: MassPoint[]): void {
107-
this.closePopup()
108-
this.options.points = points
109-
this.prepareIcons()
110-
this.draw()
126+
this.setOptions({ points })
111127
}
112128

113129
public getPoints = (): MassPoint[] => this.options.points
@@ -298,8 +314,13 @@ export default class MassLayer extends L.Layer {
298314

299315
private zoomAnim = (e: L.LeafletEvent & { center: L.LatLng, zoom: number }): void => {
300316
const scale = this._map.getZoomScale(e.zoom, this._map.getZoom())
301-
const offset = (this._map as any)._latLngBoundsToNewLayerBounds(this._map.getBounds(), e.zoom, e.center).min
302-
L.DomUtil.setTransform(this.canvas, offset, scale)
317+
const position = L.DomUtil.getPosition(this.canvas)
318+
const viewHalf = this._map.getSize().multiplyBy(0.5)
319+
const currentCenterPoint = this._map.project(this._map.getCenter(), e.zoom)
320+
const destCenterPoint = this._map.project(e.center, e.zoom)
321+
const centerOffset = destCenterPoint.subtract(currentCenterPoint)
322+
const topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add(viewHalf).subtract(centerOffset)
323+
L.DomUtil.setTransform(this.canvas, topLeftOffset, scale)
303324
}
304325

305326
private onPopupClose = (): void => { this.click = undefined }

src/components/MassPoints/index.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ContextType } from '../RCMap/Context'
66
import Layer from '../Layer'
77
import Popup from '../Popup'
88
import Tooltip from '../Tooltip'
9-
import MassLayer, { EventTarget, MassLayerOptions } from './MassLayer'
9+
import MassLayer, { EventTarget, MassLayerOptions, defaultOptions } from './MassLayer'
1010

1111
type Props = Readonly<MassLayerOptions>
1212

@@ -35,6 +35,11 @@ export default class MassPoints extends Layer<MassLayer, Props, State> {
3535
...Icon
3636
}
3737

38+
public static defaultProps = {
39+
throttleThreshold: defaultOptions.throttleThreshold,
40+
throttleDuration: defaultOptions.throttleDuration
41+
}
42+
3843
protected constructor (props: Props, context: ContextType) {
3944
super(props, context)
4045
this.state = { clickPoint: undefined, hoverPoint: undefined }
@@ -44,8 +49,8 @@ export default class MassPoints extends Layer<MassLayer, Props, State> {
4449
}
4550

4651
public componentDidUpdate (prevProps: Props): void {
47-
const { points: prevPoints, iconUrl: prevIconUrl, iconSize: prevIconSize, iconAnchor: prevIconAnchor, popupAnchor: prevPopupAnchor, tooltipAnchor: prevTooltipAnchor } = prevProps
48-
const { points, iconUrl, iconSize, iconAnchor, popupAnchor, tooltipAnchor } = this.props
52+
const { points: prevPoints, iconUrl: prevIconUrl, iconSize: prevIconSize, iconAnchor: prevIconAnchor, popupAnchor: prevPopupAnchor, tooltipAnchor: prevTooltipAnchor, throttleThreshold: prevThrottleThreshold, throttleDuration: prevThrottleDuration } = prevProps
53+
const { points, iconUrl, iconSize, iconAnchor, popupAnchor, tooltipAnchor, throttleThreshold, throttleDuration } = this.props
4954

5055
if (points !== prevPoints) {
5156
this.setState({ clickPoint: undefined, hoverPoint: undefined })
@@ -56,15 +61,15 @@ export default class MassPoints extends Layer<MassLayer, Props, State> {
5661
if (tooltipAnchor !== prevTooltipAnchor) {
5762
this.instance.setTooltipAnchor(tooltipAnchor)
5863
}
59-
if (points !== prevPoints || iconUrl !== prevIconUrl || iconSize !== prevIconSize || iconAnchor !== prevIconAnchor) {
60-
this.instance.setOptions({ points, iconUrl, iconSize, iconAnchor })
64+
if (points !== prevPoints || iconUrl !== prevIconUrl || iconSize !== prevIconSize || iconAnchor !== prevIconAnchor || throttleThreshold !== prevThrottleThreshold || throttleDuration !== prevThrottleDuration) {
65+
this.instance.setOptions({ points, iconUrl, iconSize, iconAnchor, throttleThreshold, throttleDuration })
6166
}
6267
super.componentDidUpdate(prevProps)
6368
}
6469

6570
protected createInstance (props: Props): MassLayer {
66-
const { points, iconUrl, iconSize, iconAnchor, popupAnchor, tooltipAnchor } = props
67-
return new MassLayer({ points, iconUrl, iconSize, iconAnchor, popupAnchor, tooltipAnchor })
71+
const { points, iconUrl, iconSize, iconAnchor, popupAnchor, tooltipAnchor, throttleThreshold, throttleDuration } = props
72+
return new MassLayer({ points, iconUrl, iconSize, iconAnchor, popupAnchor, tooltipAnchor, throttleThreshold, throttleDuration })
6873
}
6974

7075
private onPopupClose = (): void => this.setState({ clickPoint: undefined })

src/util/throttle.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export type Func<T = any> = (...args: any) => T
2+
3+
const throttle = (func: Func, wait: number): Func => {
4+
let prevCallTime: number | undefined
5+
return (...args: Parameters<Func>): ReturnType<Func> | void => {
6+
const now = new Date().getTime()
7+
if (prevCallTime && now - prevCallTime < wait) {
8+
return
9+
}
10+
prevCallTime = now
11+
return func(...args)
12+
}
13+
}
14+
15+
export default throttle

0 commit comments

Comments
 (0)