像写 React Native(RN)一样,完成 canvas 海报绘图任务,让海报绘制更加简单~

546 阅读5分钟

跟大家分享一下我实现的一个小工具:@sketchjs

小程序使用的话占用包体积比较大,taro主包体积优化插件已经在路上了

给大家介绍一个我实现的一个小工具 ——@sketchjs。它能实现像写 React Native(RN)一样,相对轻松地完成绘图任务。接下来,就详细跟大家唠唠它。

一、安装轻松上手

  • 要是你习惯 npm,在命令行输入下面这行就行:
npm install @sketchjs/react
  • 喜欢 yarn 的话,就执行:
yarn add @sketchjs/react
  • 用 pnpm 的朋友,输入:
pnpm add @sketchjs/react

二、多平台支持

不管是 H5 页面,还是 Taro 小程序,都能稳稳地发挥作用。

(一)H5环境中

codesandbox 中打开

image.png

在 H5 环境里,可以通过以下代码进行简单的Canvas绘制:

import React, { useEffect } from 'react'
import { StyleSheet, Sketch } from '@sketchjs/react'
import logo from './logo.png'
import './App.css'

const style = StyleSheet.create({
  root: {
    width: 500,
    height: 500,
    backgroundColor: '#282c34'
  },
  view: {
    width: 500,
    height: 500,
    justifyContent: 'center',
    alignItems: 'center'
  },
  logo: {
    width: 200,
    height: 200
  },
  text: {
    width: 500,
    marginTop: 20,
    color: '#ffffff',
    fontSize: 50,
    fontWeight: 400,
    lineHeight: 50,
    textAlign: 'center'
  }
})

function App () {
  const sketch = Sketch.useSketch()

  const canvasRef = React.useRef<HTMLCanvasElement>(null)

  const handleToDataURL = () => {
    const dataUrl = sketch.toDataURL('image/png', 1)
    console.log({ dataUrl })
  }

  const handleSketchUpdate = () => {
    console.log('sketch update')
  }

  const handleSketchInitialized = () => {
    console.log('sketch initialized')
  }

  const initCanvas = () => {
    const canvas = canvasRef.current
    const ctx = canvas?.getContext('2d')
    if (!canvas || !ctx) return
    return sketch.init({ canvas, ctx })
  }

  useEffect(() => {
    initCanvas()
  }, [])

  return (
    <div className="App" onClick={handleToDataURL}>
      <canvas className="sketch-canvas" ref={canvasRef}/>
      <Sketch.Root style={style.root} sketch={sketch} onReady={handleSketchInitialized} onUpdate={handleSketchUpdate}>
        <Sketch.View style={style.view}>
          <Sketch.Image src={logo} style={style.logo}/>
          <Sketch.Text text="Hello  World!" style={style.text}/>
        </Sketch.View>
      </Sketch.Root>
    </div>
  )
}

export default App

(二)Taro 小程序中

在 Taro 小程序这边,@sketchjs/react 同样没让人失望。

image.png

  • 首先,得在taro项目 config/index.ts 中配置下环境变量:
import { defineConfig } from '@tarojs/cli';

export default defineConfig({
    defineConstants: {
        'process.env.SKETCH_PLATFORM': '"APPLET"',  // 使用小程序端 sketch 实现
        'process.env.YOGA_USE_WASM': 'false',  // 不使用 WASM 实现
    },
});
  • 接着就是具体的示例代码,和 H5 那边有些类似:
import { View, Canvas } from '@tarojs/components'
import { StyleSheet, Sketch } from '@sketchjs/react'
import logo from '@/assets/logo.png'
import React, { useEffect } from 'react'
import Taro from '@tarojs/taro'
import './index.less'

Sketch.debug = true

const style = StyleSheet.create({
  root: {
    width: 500,
    height: 500,
    backgroundColor:'#282c34'
  },
  rootView: {
    width: 500,
    height: 500,
    justifyContent: 'center',
    alignItems: 'center',
  },
  logo: {
    width: 200,
    height: 200
  },
  text: {
    width: 500,
    marginTop: 20,
    color: '#ffffff',
    fontSize: 50,
    fontWeight: 400,
    lineHeight: 50,
    textAlign: 'center'
  }
})

const Index: React.FC = () => {

  const sketch = Sketch.useSketch()

  const handleSketchUpdate = () => {
    console.log('sketch update')
  }

  const handleSketchInitialized = () => {
    console.log('sketch initialized')
  }


  const initCanvas = async () => {
    const canvasNode: HTMLCanvasElement = await new Promise((resolve) => {
      const selectorQuery = Taro.createSelectorQuery()
      const callback = (res:any) => resolve(res?.node)
      selectorQuery.select('#sketch-canvas').fields({ node: true },callback).exec()
    })
    const canvasCtx = canvasNode.getContext('2d')
    if (!canvasNode || !canvasCtx) return
    return sketch.init({canvas:canvasNode, ctx: canvasCtx}).then(()=>sketch.render())
  }

  useEffect(() => {
    initCanvas()
  }, [])

  return (
    <View className='index-view'>
      <Canvas id='sketch-canvas' type='2d' className='sketch-canvas' />
      <Sketch.Root sketch={sketch} style={style.root} onReady={handleSketchInitialized} onUpdate={handleSketchUpdate}>
        <Sketch.View style={style.rootView}>
          <Sketch.Image src={logo} style={style.logo} />
          <Sketch.Text text='Hello  World!' style={style.text} />
        </Sketch.View>
      </Sketch.Root>
    </View>
  )
}
export default Index

三、关键绘图组件

@sketchjs/react 和 RN 开发模式相似,用起来比较容易上手。

(一)<Sketch.Root> 组件

在代码里,咱们用 StyleSheet.create 来定义样式赋予它宽高。比如说:

import React from'react';
import { StyleSheet, Sketch } from '@sketchjs/react';

const style = StyleSheet.create({
    root: {
        width: 500,
        height: 500
    }
});

function MySketch() {
    return (
        <Sketch.Root style={style.root}>
            {/* 这里面放其他绘图子组件,像 <Sketch.View> 等 */}
        </Sketch.Root>
    );
}

(二)<Sketch.View> 组件

<Sketch.View> 在绘图区域内划分出一个个子区域,用于对绘图元素进行分组管理。通过 style 属性,我们能运用熟悉的 CSS 布局技巧对其进行调控。以常见的居中布局为例,在代码中:

import React from'react';
import { StyleSheet, Sketch } from '@sketchjs/react';

const style = StyleSheet.create({
    rootView: {
        width: 500,
        height: 500,
        justifyContent: 'center',
        alignItems: 'center',
    },
});

function MySketch() {
    return (
        <Sketch.Root>
            <Sketch.View style={style.rootView}>
                {/* 这里面放图片、文本等绘图子组件,它们就能按设定布局展示 */}
            </Sketch.View>
        </Sketch.Root>
    );
}
  • style.rootView 样式对象定义了子区域的宽度与高度均为 500justifyContent: 'center' 使得子组件在水平方向上居中对齐,alignItems: 'center' 让子组件在垂直方向上也居中对齐。
  • 这样一来,不管是 <Sketch.Image> 展示的图片,还是 <Sketch.Text> 呈现的文本,都能在这个子区域内找到合适的展示位置,布局整整齐齐的。

(三)<Sketch.Image> 组件

<Sketch.Image> 功能很明确,就是把图片展示在 Canvas 绘图区域里。咱们只要给 src 属性指定图片的路径就行,超级简单。

结合 StyleSheet.create 定义样式来看个例子:

import React from'react';
import { StyleSheet, Sketch } from '@sketchjs/react';
import myImage from './myImage.png'; // 这里引入实际的图片资源

const style = StyleSheet.create({
    imageStyle: {
        width: 200,
        height: 200,
        marginLeft: 50, // 还可以设置图片的边距等样式,按需调整
    },
});

function MySketch() {
    return (
        <Sketch.Root>
            <Sketch.View>
                <Sketch.Image src={myImage} style={style.imageStyle} />
            </Sketch.View>
        </Sketch.Root>
    );
}
  • 通过 src 属性把 myImage(指向实际图片文件的路径)传给 <Sketch.Image> 组件,
  • 然后用 StyleSheet.create 生成的 style.imageStyle 来设置图片尺寸,像这里设置宽度 200 像素,高度 200 像素,
  • 还可以通过其他属性调整图片位置,这样图片就能以咱们想要的样子出现在绘图区域,给画面添彩。

(四)<Sketch.Text> 组件

<Sketch.Text> 组件负责在绘图区域里显示文字内容。咱们用 text 属性写上要显示的文字,再用 style 属性设置字体、大小、颜色、对齐方式这些,文字就能自然融入绘图。

比如这个例子:

import React from'react';
import { StyleSheet, Sketch } from '@sketchjs/react';

const style = StyleSheet.create({
    textStyle: {
        width: 500,
        marginTop: 20,
        color: '#ffffff',
        fontSize: 50,
        fontWeight: 400,
        lineHeight: 50,
        textAlign: 'center'
    },
});

function MySketch() {
    return (
        <Sketch.Root>
            <Sketch.View>
                <Sketch.Text text="Hello  World!" style={style.textStyle} />
            </Sketch.View>
        </Sketch.Root>
    );
}
  • 在这个例子里,text 属性写上 “Hello World!”
  • style.textStyle 样式对象里设置了文字颜色为白色、字体大小 50 像素、居中对齐等
  • 这样文字就能在绘图区域里以合适的样子出现,和图片等其他元素搭配起来,共同完成绘图效果。

四、总结

总的来说,@sketchjs/react 开发体验还不错,能让咱们像写 RN 代码一样相对轻松地搞定 Canvas 2D 绘图。要是你在绘图开发上也遇到难题,不妨试试它,说不定能帮你省不少事儿,让你的项目绘图功能实现得更顺利。希望对大家的Canvas绘图开发有点帮助。

目前@sketchjs/react还是alpha版本。要是在使用的过程中有什么问题,欢迎提issues随时交流。

如果这个库在canvas开发中帮到了你,请给个赞或者githubstar

本文由豆包AI生成如有错漏,辛苦指正。

链接地址

npm 地址

github 仓库地址