Skip to content

Commit

Permalink
feat: add 用于视角动画的 useViewAnimation hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
yue1123 committed Nov 9, 2022
1 parent 42e7c07 commit 1fd4912
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 5 deletions.
11 changes: 6 additions & 5 deletions packages/hooks/useTrackAnimation.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { Component, onUnmounted, Ref, ref, watch } from 'vue'
import Map from '../components/bm-map/index.vue'
import { onUnmounted, Ref, ref, watch } from 'vue'

type MapComponent = typeof Map
export type PathPoint = {
lng: number
lat: number
}
export type UseTrackAnimationOptions = {
export type TrackAnimationOptions = {
/**
* 动画持续时常,单位ms
* @default 10000
Expand Down Expand Up @@ -45,7 +43,7 @@ const statusMap: Record<number, AnimationStatus> = {
* @param {UseTrackAnimationOptions} options 轨迹动画配置
* @returns { setPath, start, stop}
*/
export function useTrackAnimation(map: any, options: UseTrackAnimationOptions) {
export function useTrackAnimation(map: any, options: TrackAnimationOptions) {
let instance: BMapGLLib.TrackAnimation
let pl: BMapGL.Polyline | null
let mapComponentInstance: any
Expand Down Expand Up @@ -106,6 +104,9 @@ export function useTrackAnimation(map: any, options: UseTrackAnimationOptions) {
})
}
onUnmounted(() => {
if (instance && status.value !== 'INITIAL') {
instance.cancel()
}
// 手动回收内存
if (mapInstance) {
mapInstance.removeOverlay(pl!)
Expand Down
169 changes: 169 additions & 0 deletions packages/hooks/useViewAnimation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import { onUnmounted, ref, Ref, watch } from 'vue'
import { Point } from './usePoint'

export interface ViewAnimationKeyFrames {
/**
* 地图中心点,默认值为地图当前状态中心点
*/
center: Point
/**
* 地图缩放级别,默认值为地图当前状态缩放级别
*/
zoom?: number
/**
* 地图倾斜角度,默认值为地图当前状态倾斜角度
*/
tilt?: number
/**
* 地图旋转角度,默认值为地图当前旋转角度
*/
heading?: number
/**
* 表示当前关键帧处于动画过程的百分比,取值范围0~1
*/
percentage: RangeOf2<0, 1>
}

export interface ViewAnimationOptions {
/**
* 动画开始延迟时间,单位ms,默认0
*/
delay: number
/**
* 动画持续时间,单位ms,默认1000
*/
duration: number
/**
* 循环次数,参数类型为数字时循环固定次数,参数为'INFINITE'无限循环,默认为1
*/
loop: number | 'INFINITE'
/**
* 动画播放时禁止鼠标拖动
*/
disableDragging: boolean
}

type AnimationListenerType = 'animationstart' | 'animationiterations' | 'animationend' | 'animationcancel'

type AnimationStatus = 'PLAYING' | 'STOPPING' | 'INITIAL'
export function useViewAnimation(map: any, options: ViewAnimationOptions) {
options = options || {}
options.disableDragging = options.disableDragging !== undefined ? false : true
const status = ref<AnimationStatus>('INITIAL')
// 保存未初始化前的事件监听
const eventListener: Partial<Record<AnimationListenerType, BMapGL.Callback[]>> = {
animationcancel: [() => (status.value = 'INITIAL')],
animationend: [() => (status.value = 'INITIAL')],
animationstart: [() => (status.value = 'PLAYING')]
}

let mapComponentInstance: any
let mapInstance: BMapGL.Map
let initd = false
watch(
() => map.value,
(n) => {
mapComponentInstance = n
}
)

const syncDragging = () => {
const { enableDragging } = mapComponentInstance.getBaseMapOptions()
mapComponentInstance.setDragging(enableDragging)
}

const defaultValue = {
addEventListener(event: AnimationListenerType, cal: BMapGL.Callback) {
if (!eventListener[event]) {
eventListener[event] = []
}
eventListener[event]!.push(cal)
},
removeEventListener(event: AnimationListenerType, cal: BMapGL.Callback) {
const subs = eventListener[event]
if (subs) {
if (!cal) {
eventListener[event] = []
} else {
for (let i = subs.length; i >= 0; i--) {
if (subs[i] === cal) {
subs.splice(i, 1)
}
}
}
}
}
}
let viewAnimation: BMapGL.ViewAnimation | typeof defaultValue = defaultValue

const createViewAnimation = (keyFrames: ViewAnimationKeyFrames[]) => {
const { loop, duration, delay } = options
for (const keyFrame of keyFrames) {
if (keyFrame.center) {
const { lng, lat } = keyFrame.center
keyFrame.center = new BMapGL.Point(lng, lat)
}
}
viewAnimation = new BMapGL.ViewAnimation(keyFrames, {
duration,
delay,
interation: loop
})
for (const eventKey of Object.keys(eventListener)) {
const events = eventListener[eventKey]
if (events && events.length) {
events.forEach((cal: (...arg: []) => void) => {
viewAnimation.addEventListener(eventKey as AnimationListenerType, cal)
})
}
}
initd = true
}
const start = () => {
if (initd) {
mapInstance = mapComponentInstance.getMapInstance()
mapInstance.startViewAnimation(viewAnimation as BMapGL.ViewAnimation)
mapComponentInstance.setDragging(!options.disableDragging)
}
}
const cancel = () => {
if (initd) {
;(viewAnimation as BMapGL.ViewAnimation)._cancel(mapInstance)
syncDragging()
}
}
const stop = () => {
if (initd && status.value === 'PLAYING') {
;(viewAnimation as BMapGL.ViewAnimation)._pause()
status.value = 'STOPPING'
}
}
const proceed = () => {
if (initd && status.value === 'STOPPING') {
;(viewAnimation as BMapGL.ViewAnimation)._continue()
status.value = 'PLAYING'
}
}

onUnmounted(() => {
try {
if ((viewAnimation as BMapGL.ViewAnimation) && status.value == 'INITIAL') {
mapInstance = mapComponentInstance.getMapInstance()
;(viewAnimation as BMapGL.ViewAnimation)._cancel(mapInstance)
syncDragging()
}
} catch (e) {
return false
}
})

return {
viewAnimation,
start,
cancel,
stop,
proceed,
status,
setKeyFrames: createViewAnimation
}
}
1 change: 1 addition & 0 deletions packages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface InitOptions {
export * from './hooks/useAreaBoundary'
export * from './hooks/useTrackAnimation'
export * from './hooks/usePoint'
export * from './hooks/useViewAnimation'

// components
import Map from './components/map/index.vue'
Expand Down

0 comments on commit 1fd4912

Please sign in to comment.