useFrameIcon

View source
注册帧动画图标的底层原语,处理样式重载补回与缺图兜底,由 SpriteImage / AnimatedImage 共用。

简介

useFrameIcon 是帧动画图标的底层原语:把一组逐帧 ImageData 注册为 StyleImageInterface,按 fps 或每帧 durations 循环播放,并自动处理样式重载补回、styleimagemissing 兜底与卸载清理。MapboxSpriteImageMapboxAnimatedImage 即基于它实现。

<MapboxMap> 子树内调用(内部依赖 useMap)。frames / durations 为取值函数,返回值变化即生效,便于异步解码后再填充。多数场景直接用 SpriteImage / AnimatedImage 组件即可,仅在自定义帧来源时才需此原语。

用法

子组件用 canvas 逐帧绘制扩散圆环,经 useFrameIcon 注册为 symbol 图标:

<template>
  <div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MapboxMap
      :options="{ style: 'mapbox://styles/mapbox/dark-v11', center: [116.397, 39.908], zoom: 13 }"
    >
      <UseFrameIconLayerExample />
    </MapboxMap>
  </div>
</template>

子组件实现(位于 <MapboxMap> 子树内):

<script setup lang="ts">
import type { FeatureCollection } from 'geojson'

const size = 64
const FRAME_COUNT = 30
const data: FeatureCollection = {
  type: 'FeatureCollection',
  features: [{ type: 'Feature', properties: {}, geometry: { type: 'Point', coordinates: [116.397, 39.908] } }]
}

function buildFrames(): ImageData[] {
  const canvas = document.createElement('canvas')
  canvas.width = size
  canvas.height = size
  const context = canvas.getContext('2d')!
  return Array.from({ length: FRAME_COUNT }, (_, i) => {
    const t = i / FRAME_COUNT
    context.clearRect(0, 0, size, size)
    context.beginPath()
    context.arc(size / 2, size / 2, (size / 2 - 3) * t, 0, Math.PI * 2)
    context.strokeStyle = `rgba(34, 211, 238, ${1 - t})`
    context.lineWidth = 3
    context.stroke()
    return context.getImageData(0, 0, size, size)
  })
}

const { map } = useMap()
const frames = ref<ImageData[]>([])
onMounted(() => {
  frames.value = buildFrames()
  map.value?.triggerRepaint()
})

useFrameIcon({ imageName: 'pulse-ring', size, frames: () => frames.value, fps: 24 })
</script>

<template>
  <MapboxSource source-id="pulse-pts" :source="{ type: 'geojson', data }">
    <MapboxLayer layer-id="pulse-pts" type="symbol" source="pulse-pts" :layout="{ 'icon-image': 'pulse-ring', 'icon-allow-overlap': true }" />
  </MapboxSource>
</template>

API

useFrameIcon()

注册帧动画图标,无返回值(副作用型)。

options.imageName
string required
注册到样式的图片名(symbol 图层 icon-image 引用)。
options.size
number required
纹理边长(像素)。
options.frames
() => ImageData[] required
当前帧序列(响应式取值)。
options.fps
number
固定帧率,durations 缺省时生效。
options.durations
() => number[] | undefined
每帧时长 ms(响应式取值),优先于 fps

Changelog

No recent changes
Copyright © 2026 - 2026 YiXuan - MIT License