-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3e141cd
commit 841fa09
Showing
9 changed files
with
215 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,92 +1,57 @@ | ||
import { useRef, useEffect } from 'react'; | ||
import { useDeepCompareEffect, useUnmount } from '@pansy/react-hooks'; | ||
import { isEqual } from 'lodash-es'; | ||
|
||
export interface Instance extends Record<string, any> { | ||
on(type: string, handle: (...args: any[]) => void): void; | ||
off(type: string, handle: (...args: any[]) => void): void; | ||
} | ||
|
||
export type Listeners<Events extends Record<string, string>> = { | ||
[T in keyof Events]: (evt: any) => void; | ||
}; | ||
|
||
export const useEvents = <Ins extends Instance, Events extends Record<string, string>>( | ||
ins: Ins, | ||
events: Events, | ||
props: Record<string, any> = {}, | ||
import { useUnmount } from '@pansy/react-hooks'; | ||
import { useTrackedEffect } from './useTrackedEffect'; | ||
|
||
import type { Instance } from '../types'; | ||
|
||
export const useEvents = <Ins extends Instance, Props extends Record<string, any>>( | ||
map: Ins, | ||
props: Props, | ||
options: { | ||
eventMap: Record<string, any>; | ||
eventList: string[]; | ||
}, | ||
) => { | ||
const listeners = useRef<Partial<Listeners<Events>>>({}); | ||
|
||
useEffect(() => { | ||
if (ins) { | ||
listeners.current = listenEvents(events, props, ins); | ||
} | ||
}, [ins]); | ||
|
||
useDeepCompareEffect(() => { | ||
if (ins) { | ||
listeners.current = updateEvents(listeners.current, props, ins); | ||
} | ||
}, [props]); | ||
|
||
useUnmount(() => { | ||
unlistenEvents(listeners.current, ins); | ||
listeners.current = {}; | ||
}); | ||
const { eventMap = {}, eventList = [] } = options; | ||
|
||
const listenEvents = ( | ||
partialEvents: Record<string, string> = {}, | ||
props: Record<string, any> = {}, | ||
ins: Ins, | ||
) => | ||
Object.keys(partialEvents).reduce((listeners, event) => { | ||
const eventCallback = props[event]; | ||
const eventName = partialEvents[event]; | ||
|
||
if (eventName && eventCallback) { | ||
ins.on(eventName, eventCallback); | ||
// @ts-ignore | ||
listeners[event] = eventCallback; | ||
useTrackedEffect<[Ins, ...any[]]>( | ||
(changeIndexList = [], previousDeps, currentDeps) => { | ||
if (!map) { | ||
return; | ||
} | ||
// 需要更新的事件对应到 deps 的数组下标,但是不包含 scene 实例的更新 | ||
let eventIndexList = changeIndexList.filter((index) => !!index).map((index) => index - 1); | ||
|
||
return listeners; | ||
}, {}); | ||
|
||
const updateEvents = ( | ||
listeners: Partial<Listeners<Events>> = {}, | ||
currentProps: Record<string, any> = {}, | ||
ins: Ins, | ||
) => { | ||
const toListenOff = Object.keys(events).filter( | ||
(eventKey) => | ||
(listeners[eventKey] && typeof currentProps[eventKey] !== 'function') || | ||
!isEqual(listeners[eventKey], currentProps[eventKey]), | ||
); | ||
|
||
toListenOff.forEach((key) => { | ||
if (listeners[key]) { | ||
ins.off(events[key], listeners[key] as any); | ||
delete listeners[key]; | ||
// 如果本次变化为实例化则无差别遍历所有事件类型 | ||
if (changeIndexList.includes(0)) { | ||
eventIndexList = eventList.map((_, index) => index); | ||
} | ||
}); | ||
|
||
const toListenOn = Object.keys(events) | ||
.filter((key) => !listeners[key] && typeof currentProps[key] === 'function') | ||
// @ts-ignore | ||
.reduce((acc, next) => ((acc[next] = events[next]), acc), {}); | ||
|
||
const newListeners = listenEvents(toListenOn, currentProps, ins); | ||
|
||
return { ...listeners, ...newListeners }; | ||
}; | ||
eventIndexList.forEach((index) => { | ||
const eventName = eventMap[eventList[index]] as string; | ||
const previousCallback = previousDeps?.[index + 1] as any; | ||
const currentCallback = currentDeps?.[index + 1] as any; | ||
// 分别注销旧的事件回调并绑定新的事件 | ||
if (previousCallback) { | ||
map.off(eventName, previousCallback); | ||
} | ||
if (currentCallback) { | ||
map.on(eventName, currentCallback); | ||
} | ||
}); | ||
}, | ||
[map, ...eventList.map((eventName) => props[eventName])], | ||
); | ||
|
||
const unlistenEvents = (listeners: Partial<Listeners<Events>> = {}, ins: Ins) => { | ||
const toListenOff = Object.keys(events).filter((eventKey) => listeners[eventKey]); | ||
|
||
toListenOff.forEach((key) => { | ||
// @ts-ignore | ||
ins.off(events[key], listeners[key]); | ||
useUnmount(() => { | ||
if (!map) { | ||
return; | ||
} | ||
eventList.forEach((key) => { | ||
const eventName = eventMap[key]; | ||
const callback = props[key]; | ||
if (eventName && callback) { | ||
map.off(eventName, callback); | ||
} | ||
}); | ||
}; | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import type { EventMapping } from './types'; | ||
import type { KeysOfUnion } from '../types'; | ||
|
||
export const MapEventMap: EventMapping = { | ||
onError: 'error', | ||
|
||
onLoad: 'load', | ||
onIdle: 'idle', | ||
onRemove: 'remove', | ||
onRender: 'render', | ||
onResize: 'resize', | ||
|
||
onWebglContextLost: 'webglcontextlost', | ||
onWebglContextRestored: 'webglcontextrestored', | ||
|
||
onDataloading: 'dataloading', | ||
onData: 'data', | ||
onTileDataLoading: 'tiledataloading', | ||
onSourceDataLoading: 'sourcedataloading', | ||
onStyleDataLoading: 'styledataloading', | ||
onSourceData: 'sourcedata', | ||
onStyleData: 'styledata', | ||
|
||
onBoxZoomCancel: 'boxzoomcancel', | ||
onBoxZoomStart: 'boxzoomstart', | ||
onBoxZoomEnd: 'boxzoomend', | ||
|
||
onTouchCancel: 'touchcancel', | ||
onTouchMove: 'touchmove', | ||
onTouchEnd: 'touchend', | ||
onTouchStart: 'touchstart', | ||
|
||
onClick: 'click', | ||
onContextMenu: 'contextmenu', | ||
onDoubleClick: 'dblclick', | ||
onMouseMove: 'mousemove', | ||
onMouseUp: 'mouseup', | ||
onMouseDown: 'mousedown', | ||
onMouseOut: 'mouseout', | ||
onMouseOver: 'mouseover', | ||
|
||
onMoveStart: 'movestart', | ||
onMove: 'move', | ||
onMoveEnd: 'moveend', | ||
|
||
onZoomStart: 'zoomstart', | ||
onZoom: 'zoom', | ||
onZoomEnd: 'zoomend', | ||
|
||
onRotateStart: 'rotatestart', | ||
onRotate: 'rotate', | ||
onRotateEnd: 'rotateend', | ||
|
||
onDragStart: 'dragstart', | ||
onDrag: 'drag', | ||
onDragEnd: 'dragend', | ||
|
||
onPitchStart: 'pitchstart', | ||
onPitch: 'pitch', | ||
onPitchEnd: 'pitchend', | ||
|
||
onWheel: 'wheel', | ||
}; | ||
|
||
export const MapEventList = Object.keys(MapEventMap) as KeysOfUnion<EventMapping>[]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { useUnmount } from '@pansy/react-hooks'; | ||
import { useTrackedEffect } from '../../hooks/useTrackedEffect'; | ||
|
||
import type { Map } from 'mapbox-gl'; | ||
import type { Instance } from '../../types'; | ||
|
||
export const useMapEvent = <Ins extends Instance, Props extends Record<string, any>>( | ||
map: Ins, | ||
props: Props, | ||
options: { | ||
eventMap: Record<string, any>; | ||
eventList: string[]; | ||
}, | ||
) => { | ||
const { eventMap = {}, eventList = [] } = options; | ||
|
||
useTrackedEffect<any>( | ||
(changeIndexList = [], previousDeps: [Map, ...any[]], currentDeps: [Map, ...any[]]) => { | ||
if (!map) { | ||
return; | ||
} | ||
// 需要更新的事件对应到 deps 的数组下标,但是不包含 scene 实例的更新 | ||
let eventIndexList = changeIndexList.filter((index) => !!index).map((index) => index - 1); | ||
|
||
// 如果本次变化为实例化则无差别遍历所有事件类型 | ||
if (changeIndexList.includes(0)) { | ||
eventIndexList = eventList.map((_, index) => index); | ||
} | ||
|
||
eventIndexList.forEach((index) => { | ||
const eventName = eventMap[eventList[index]] as string; | ||
const previousCallback = previousDeps[index + 1] as any; | ||
const currentCallback = currentDeps[index + 1] as any; | ||
// 分别注销旧的事件回调并绑定新的事件 | ||
if (previousCallback) { | ||
map.off(eventName, previousCallback); | ||
} | ||
if (currentCallback) { | ||
map.on(eventName, currentCallback); | ||
} | ||
}); | ||
}, | ||
[map, ...eventList.map((eventName) => props[eventName])], | ||
); | ||
|
||
useUnmount(() => { | ||
if (!map) { | ||
return; | ||
} | ||
eventList.forEach((key) => { | ||
const eventName = eventMap[key]; | ||
const callback = props[key]; | ||
if (eventName && callback) { | ||
map.off(eventName, callback); | ||
} | ||
}); | ||
}); | ||
}; |
Oops, something went wrong.