npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@duxapp/react-native-canvas

v0.1.1

Published

Pure JavaScript canvas-like API for React Native powered by react-native-skia

Readme

@duxapp/react-native-canvas

@duxapp/react-native-canvas 是一个基于 @shopify/react-native-skia 的 React Native canvas 绘图库,提供 CanvasPath2DOffscreenCanvasImage 以及接近 Canvas 2D 的绘制 API。当前只支持 2d,不支持 WebGL 或其他 3D 渲染上下文。

目录

主要特性

  • React Native Canvas 组件
  • 类 Canvas 2D context API
  • 仅支持 2D,不支持 WebGL / 3D 上下文
  • Path2D
  • OffscreenCanvas
  • Image
  • useClickable
  • 文本绘制与测量
  • 变换、状态栈
  • 渐变、图案、阴影、混合模式
  • toDataURL()
  • 推荐开启 picture 模式,可明显提升大多数绘制场景下的帧率
  • 内部已经处理 DPI,不要再额外做 PixelRatio / devicePixelRatio 缩放

安装

yarn add @duxapp/react-native-canvas @shopify/react-native-skia

npm install @duxapp/react-native-canvas @shopify/react-native-skia

必须安装的依赖:

  • @shopify/react-native-skia

这个包本身是纯 JS,但宿主工程必须正确安装 @shopify/react-native-skia

快速开始

import { useEffect } from 'react'
import { Canvas, useCanvasRef } from '@duxapp/react-native-canvas'

export default function Demo() {
  const ref = useCanvasRef()

  useEffect(() => {
    let mounted = true

    ref.current?.getCanvas().then(({ canvas, size }) => {
      if (!mounted) return

      const ctx = canvas.getContext('2d')

      ctx.fillStyle = '#f5f5f5'
      ctx.fillRect(0, 0, size.width, size.height)

      ctx.beginPath()
      ctx.moveTo(20, 20)
      ctx.lineTo(180, 20)
      ctx.lineTo(100, 120)
      ctx.closePath()

      ctx.fillStyle = '#2f80ed'
      ctx.strokeStyle = '#0f4aa1'
      ctx.lineWidth = 4
      ctx.fill()
      ctx.stroke()

      ctx.font = 'bold 20px sans-serif'
      ctx.fillStyle = '#111'
      ctx.fillText('Hello Canvas', 20, 170)
    })

    return () => {
      mounted = false
    }
  }, [ref])

  return <Canvas ref={ref} style={{ flex: 1, minHeight: 240 }} />
}

示例

import { useEffect } from 'react'
import { Canvas, Path2D, useCanvasRef } from '@duxapp/react-native-canvas'

export default function Example() {
  const ref = useCanvasRef()

  useEffect(() => {
    ref.current?.getCanvas().then(({ canvas }) => {
      const ctx = canvas.getContext('2d')
      const path = new Path2D()

      path.moveTo(40, 40)
      path.lineTo(160, 40)
      path.lineTo(100, 140)
      path.closePath()

      ctx.fillStyle = '#e8f1ff'
      ctx.fillRect(0, 0, canvas.width, canvas.height)

      ctx.fillStyle = '#2f80ed'
      ctx.strokeStyle = '#1456b8'
      ctx.lineWidth = 3
      ctx.fill(path)
      ctx.stroke(path)
    })
  }, [ref])

  return <Canvas ref={ref} style={{ flex: 1 }} />
}

Picture + 动画示例

import { useEffect } from 'react'
import { Canvas, useCanvasRef } from '@duxapp/react-native-canvas'

export default function PictureAnimationExample() {
  const ref = useCanvasRef()

  useEffect(() => {
    let frameId = 0
    let active = true

    ref.current?.getCanvas().then(({ canvas, size }) => {
      if (!active) return

      const ctx = canvas.getContext('2d')
      let x = 30
      let direction = 1

      const render = () => {
        if (!active) return

        ctx.fillStyle = '#f7f8fa'
        ctx.fillRect(0, 0, size.width, size.height)

        ctx.beginPath()
        ctx.arc(x, size.height / 2, 24, 0, Math.PI * 2)
        ctx.fillStyle = '#2f80ed'
        ctx.fill()

        x += direction * 2
        if (x >= size.width - 30 || x <= 30) {
          direction *= -1
        }

        frameId = requestAnimationFrame(render)
      }

      render()
    })

    return () => {
      active = false
      cancelAnimationFrame(frameId)
    }
  }, [ref])

  return <Canvas ref={ref} picture style={{ flex: 1, minHeight: 240 }} />
}

性能说明

当前性能大致可以这样理解:

  • 和现有的 React Native canvas 插件,例如 react-native-canvasreact-native-gcanvas 相比,在相同类型的绘制场景下,这个库通常会有非常明显的性能提升
  • 但和原生 canvas 相比,仍然还有很大的差距
  • 在相同场景下,目前的表现通常还是明显低于原生 canvas 的一半

这意味着:

  • 如果你现在使用的是较旧的 RN canvas 方案,迁移过来通常会有很明显的收益
  • 如果你的目标是接近原生 canvas 性能,目前仍然要预期存在较大的差距
  • 在渲染模型允许的情况下,强烈建议开启 picture 模式,以尽可能发挥当前实现的帧率表现

详细文档说明

下面的章节会继续说明这个包的 API、渲染模式、支持的绘制源、兼容性说明以及已知限制。

基本使用方式

1. 使用 useCanvasRef 创建 ref

const ref = useCanvasRef()

这个 ref 直接传给 Canvas

<Canvas ref={ref} style={{ flex: 1 }} />

2. 获取 canvas 实例

const { canvas, size } = await ref.current.getCanvas()

返回值说明:

  • canvas:canvas 风格对象
  • size:当前布局信息 { width, height, x, y }

3. 获取 2D context

const ctx = canvas.getContext('2d')

导出内容

import {
  Canvas,
  Image,
  OffscreenCanvas,
  Path2D,
  defineCanvas,
  defineCanvasContext,
  useCanvasRef,
  useClickable
} from '@duxapp/react-native-canvas'

说明:

  • Canvas:React Native canvas 组件
  • useCanvasRef:返回 Canvas 所需 ref 的 hook
  • Path2D:路径对象
  • OffscreenCanvas:离屏画布
  • Image:用于 drawImage() 的图片对象
  • useClickable:独立的 hook,用于在 React Native 上模拟网页端触摸事件
  • defineCanvas / defineCanvasContext:为了兼容保留下来的 identity helper

useClickable

useClickable 是从原始 RN 实现中抽出来的独立 hook,它的作用是在 React Native 上模拟网页端触摸事件,让一些库可以更少改动地运行。它没有接入 Canvas 内部。

import { Canvas, useCanvasRef, useClickable } from '@duxapp/react-native-canvas'

export default function Demo() {
  const ref = useCanvasRef()
  const clickable = useClickable({
    onClick: e => {
      console.log('click', e.detail.x, e.detail.y)
    },
    onLongPress: e => {
      console.log('longpress', e)
    }
  })

  return <Canvas ref={ref} {...clickable} style={{ flex: 1, minHeight: 240 }} />
}

支持这些回调:

  • onClick
  • onLongPress
  • onTouchStart
  • onTouchMove
  • onTouchEnd
  • onTouchCancel

API 概览

Canvas 组件

Props:

  • style
  • onLayout
  • picture

picture 用于启用 React Native 的 picture 渲染路径,并且在大多数场景下都推荐开启。

Canvas Ref

ref.current.getCanvas(): Promise<{
  canvas: CanvasElement
  size: {
    width: number
    height: number
    x: number
    y: number
  }
}>

Canvas Element

返回的 canvas 支持:

  • getContext('2d')
  • createImageData(width, height)
  • toDataURL(type?, encoderOptions?)
  • width
  • height

当前只支持 getContext('2d')。不支持 WebGL、WebGL2 以及其他 3D 渲染上下文。

DPI 处理说明

设备像素比已经在内部处理完成。

不要再手动对 canvas 尺寸、坐标或变换额外乘这些值:

  • PixelRatio.get()
  • window.devicePixelRatio
  • 自己定义的 DPR 缩放系数

正常情况下,直接按逻辑布局尺寸进行绘制即可。

2D Context

当前支持的能力分组:

  • 状态:saverestore
  • 变换:translatescalerotatetransformsetTransformresetTransformgetTransform
  • 路径:beginPathclosePathmoveTolineToarcarcTobezierCurveToquadraticCurveTorectroundRectellipse
  • 绘制:fillstrokeclipisPointInPath
  • 矩形:fillRectstrokeRectclearRect
  • 文本:fillTextstrokeTextmeasureText
  • 图像:drawImage
  • 像素:getImageDataputImageData
  • 样式:fillStylestrokeStylelineWidthlineCaplineJoinmiterLimitsetLineDashlineDashOffset
  • 透明度与阴影:globalAlphashadowColorshadowBlurshadowOffsetXshadowOffsetY
  • 文本样式:fonttextAligntextBaselinedirection
  • 合成:globalCompositeOperation
  • 渐变与图案:createLinearGradientcreateRadialGradientcreatePattern

Picture 模式

开启方式:

<Canvas ref={ref} picture style={{ flex: 1 }} />

这个模式通常可以明显提升绘制帧率,建议默认开启,除非你的场景强依赖持久 canvas 状态下的增量更新语义。

推荐使用方式

  • 大多数 canvas 绘制场景都建议默认开启
  • 特别适合图表、海报、预览、编辑器整帧刷新这类场景
  • 只有在你依赖持久画布状态做局部增量更新时,才建议评估是否关闭

默认优点

  • 通常可以获得更高的绘制帧率
  • 特别适合动画和整帧重绘场景
  • 当每一帧都从头计算时,渲染模型会更简单

需要注意的问题

  • picture 绘制不会保留历史内容
  • 只会保留当前这一帧绘制出来的内容
  • 到下一个时刻开始绘制时,上一帧的内容会自动被清除
  • 绘制状态不会在帧之间自动保留
  • 变换状态不会在帧之间自动保留
  • clearRect() 不再等价于持久画布上的增量擦除

如果你的场景依赖基于历史内容的局部更新,通常不适合使用这个模式。

Path2D

import { Path2D } from '@duxapp/react-native-canvas'

const path = new Path2D()
path.moveTo(20, 20)
path.lineTo(100, 20)
path.lineTo(60, 80)
path.closePath()

ctx.fill(path)
ctx.stroke(path)

也支持通过另一个 Path2D 或 SVG path 字符串初始化。

OffscreenCanvas

import { OffscreenCanvas } from '@duxapp/react-native-canvas'

const offscreen = new OffscreenCanvas(200, 120)
const ctx = offscreen.getContext('2d')

ctx.fillStyle = '#000'
ctx.fillRect(0, 0, 200, 120)

const dataUrl = offscreen.toDataURL()

适合场景:

  • 预渲染
  • 生成纹理或缩略图
  • 作为 drawImage() 的绘制源
  • 用于 createPattern() 图案源

Image

import { Image } from '@duxapp/react-native-canvas'

const image = new Image()
image.onload = () => {
  ctx.drawImage(image, 0, 0, 120, 120)
}
image.onerror = err => {
  console.error(err)
}
image.src = 'https://example.com/example.png'

支持的 src 类型:

  • 远程 URL 字符串
  • data: URL 字符串
  • require(...) 返回的本地资源 id

当前支持的成员:

  • src
  • onload
  • onerror
  • onabort
  • alt
  • complete
  • currentSrc
  • width
  • height
  • decode()
  • addEventListener()
  • removeEventListener()

drawImage() 支持的 source

当前类型和运行时都支持:

  • Image
  • OffscreenCanvas

例如:

const offscreen = new OffscreenCanvas(100, 100)
const offscreenCtx = offscreen.getContext('2d')
offscreenCtx.fillStyle = 'red'
offscreenCtx.fillRect(0, 0, 100, 100)

ctx.drawImage(offscreen, 20, 20)

toDataURL()

主 canvas 对象和 OffscreenCanvas 都支持 toDataURL()

const url = canvas.toDataURL()
const jpeg = canvas.toDataURL('image/jpeg', 0.9)

支持的输出类型:

  • image/png
  • image/jpeg
  • image/webp

兼容性说明

这个库是 canvas-like,不是浏览器完整的 HTMLCanvasElement 实现。

和浏览器相比,有一些有意保留的差异:

  • 没有 DOM API
  • 没有完整浏览器图片加载行为
  • 没有浏览器事件系统
  • 这个包版本不包含小程序兼容 API

如果某些浏览器 API 在 React Native 里没有实际意义,就不会强行暴露。

已知限制

  • 某些边界场景下行为可能与浏览器 canvas 存在差异
  • 文本测量依赖 Skia 的字体行为
  • 图片加载依赖 React Native / Skia 运行环境
  • picture 模式针对整帧重绘优化,不适合增量更新
  • 不是所有浏览器 canvas API 都已实现

类型文件

包内提供 TypeScript 类型:

  • 英文注释版本:src/index.d.ts
  • 中文注释版本:src/index.zh-CN.d.ts

License

MIT