今天尝试使用 canvaskit 第一次使用就翻了车。因为 umi 不支持 wasm 格式的解析,因此安装好 canvaskit-wasm 后无法直接使用,报了错。
正确安装方法
官方的指南是在 config 里添加配置:
config.plugins.push(new CopyWebpackPlugin([{ from: 'node_modules/canvaskit-wasm/bin/canvaskit.wasm' }]));
但是在 umi 中不能这么用。因为 webpack 的配置项没有被暴露出来,所以使用 chainwebpack 进行修改。使用 CopyWebpackPlugin 插件加载 wasm 文件。
// webpackChain.tsimport IWebpackChainConfig from 'webpack-chain';import CopyWebpackPlugin from 'copy-webpack-plugin';export default (config: IWebpackChainConfig) => {config.plugin('wasm').use(CopyWebpackPlugin, [{ patterns: [{ from: 'node_modules/canvaskit-wasm/bin/canvaskit.wasm' }] },]);};// config.tsimport { defineConfig } from 'umi';import webpackPlugin from './plugin.config';export default defineConfig({// ...chainWebpack: webpackPlugin,});
虽然项目使用了TS,且 canvaskit-wasm 也有 ts 定义文件(由 Alexander Shilov 老哥编写),但是他写的应该是有点问题的,我自己做了点调整。
网上已有的案例
测试代码使用了官网的的涂写案例:
import React, { useEffect } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { CanvasKit as CanvasKitType } from 'canvaskit-wasm';
const CanvasKitInit = require('canvaskit-wasm');
function preventScrolling(canvas) {
canvas.addEventListener('touchmove', e => {
// Prevents touch events in the canvas from scrolling the canvas.
e.preventDefault();
e.stopPropagation();
});
}
function InkExample(CanvasKit) {
const surface = CanvasKit.MakeCanvasSurface('ink');
if (!surface) {
console.error('Could not make surface');
return;
}
let paint = new CanvasKit.SkPaint();
paint.setAntiAlias(true);
paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
paint.setStyle(CanvasKit.PaintStyle.Stroke);
paint.setStrokeWidth(4.0);
paint.setPathEffect(CanvasKit.SkPathEffect.MakeCorner(50));
// Draw I N K
let path = new CanvasKit.SkPath();
path.moveTo(80, 30);
path.lineTo(80, 80);
path.moveTo(100, 80);
path.lineTo(100, 15);
path.lineTo(130, 95);
path.lineTo(130, 30);
path.moveTo(150, 30);
path.lineTo(150, 80);
path.moveTo(170, 30);
path.lineTo(150, 55);
path.lineTo(170, 80);
let paths = [path];
let paints = [paint];
function drawFrame(canvas) {
canvas.clear(CanvasKit.Color(255, 255, 255, 1.0));
for (let i = 0; i < paints.length && i < paths.length; i++) {
canvas.drawPath(paths[i], paints[i]);
}
surface.requestAnimationFrame(drawFrame);
}
let hold = false;
let interact = e => {
let type = e.type;
if (type === 'lostpointercapture' || type === 'pointerup' || !e.pressure) {
hold = false;
return;
}
if (hold) {
path.lineTo(e.offsetX, e.offsetY);
} else {
paint = paint.copy();
paint.setColor(
CanvasKit.Color(
Math.random() * 255,
Math.random() * 255,
Math.random() * 255,
Math.random() + 0.2,
),
);
paints.push(paint);
path = new CanvasKit.SkPath();
paths.push(path);
path.moveTo(e.offsetX, e.offsetY);
}
hold = true;
};
document.getElementById('ink').addEventListener('pointermove', interact);
document.getElementById('ink').addEventListener('pointerdown', interact);
document.getElementById('ink').addEventListener('lostpointercapture', interact);
document.getElementById('ink').addEventListener('pointerup', interact);
preventScrolling(document.getElementById('ink'));
surface.requestAnimationFrame(drawFrame);
}
export default (): React.ReactNode => {
useEffect(() => {
CanvasKitInit().then((CanvasKit: CanvasKitType) => {
InkExample(CanvasKit);
});
}, []);
return (
<PageHeaderWrapper>
<canvas id="ink" width="1024" height="1024" />
</PageHeaderWrapper>
);
};
渲染效果如下:
同样的画面在手机端的表现如下:
整体表现感觉还不错,下一步应该就是找地方了解 CanvasKit 的 api 和基本使用方法了。
