前言
- 最近在类taro框架中小程序端使用最新版f2。(这里我使用rax)并封装了库,特此记录一下。
使用
- 想直接用的同学直接在你的rax项目中安装
rax-my-f2
这个包,他依赖@antv/f2
与@antv/f2-context
这2个包。
import { MyCanvas } from 'rax-my-f2';
- 导入之后和官方文档一样直接使用:
const LineChart = (props) => (
<Chart data={props.data}>
<Axis
field="date"
tickCount={3}
style={{
label: { align: 'between' },
}}
/>
<Axis field="value" tickCount={5} />
<Line x="date" y="value" />
<Tooltip />
</Chart>
);
function Index() {
const [datas, setData] = useState(data);
useEffect(() => {
setTimeout(() => {
console.log('over');
setData(data2);
}, 5000);
}, []);
return (
<view id="aaa">
<MyCanvas id='ddd' width={375} height={260} data={datas} onRender={LineChart} />
</view>
);
}
export default Index;
- 如果需要封装taro或者其他类taro框架或者非阿里小程序,需要看一下下面的封装思路自行封装。
封装思路
- 首先有些背景知识需要知道下。
- 小程序的canvas和web的canvas有一些区别,不同平台的小程序之间canvas也有区别。f2是基于canvas绘图的,所以需要有个东西抹平canvas的差异。这里f2团队已经做好了使用
@antv/f2-context
就可以。这个包的用法很简单,你给他个小程序canvas的context做参数,他还你个做过兼容的context。 - 阿里小程序主要分为支付宝小程序与钉钉小程序。钉钉小程序基础库目前只能使用1版本的,而阿里小程序可以切换1版本或者2版本。而canvas这个在1版本和2版本的使用都不一样,需要做两者的兼容。
- 阿里小程序中2版本的canvas在加载完成后会触发onReady方法,在onReady方法中可以拿到该canvas的node,从而能获取到context。这个context是已经兼容过的,只需要做一下分辨率然后转给f2渲染即可:
const onCanvasReady = () => {
const query = my.createSelectorQuery();
query
.select(`#${id}`)
.node()
.exec((res) => {
if (!res[0]) {
return;
}
const canvas = res[0].node;
const { width, height } = canvas;
const pixelRatio = getPixelRatio();
canvas.width = width * pixelRatio;
canvas.height = height * pixelRatio;
const context = canvas.getContext("2d");
canvasRender({ width, height, pixelRatio, context });
});
};
const canvasRender = ({ width, height, pixelRatio, context }) => {
if (!width || !height) {
return;
}
const children = props.onRender(props);
const pix = isAppX2CanvasEnv() ? pixelRatio : 1;
const canvas = new Canvas({
pixelRatio: pix,
width,
height,
context,
children,
});
canvas.render();
setCtx(canvas);
setEl(canvas.canvas.get("el"));
};
- 2版本的判断使用,一个就是onReady用来拿context,一个是return node用来拿canvas的node。
// 判断是否是新版 canvas 所支持的调用方法(AppX 2.7.0 及以上)
const isAppX2CanvasEnv = () =>
my.canIUse("canvas.onReady") && my.canIUse("createSelectorQuery.return.node");
- 1版本由于不会触发onReady且也拿不到node,需要使用
createSelectorQuery
去查找。实测发现这里在useEffect后还需要setTimeout不然很可能找不到。拿到宽高后使用createCanvasContext
进行创建context,这个context则是没有兼容的,需要使用@antv/f2-context
进行兼容。最后这个传给f2渲染的pixelRatio
应该为1,否则这个图像显示会不太正常。 - 最后对移动端常见的事件进行封装,因为已经拿到element了,直接canvas派发对应事件即可:
const click = (e) => {
if (!el) {
return;
}
const event = wrapEvent(e);
const { detail, target } = e;
const { x, y } = detail;
const { offsetLeft = 0, offsetTop = 0 } = target;
// 包装成 touch 对象
event.touches = [{ x: x - offsetLeft, y: y - offsetTop }];
el.dispatchEvent("click", event);
};
const touchStart = (e) => {
if (!el) {
return;
}
el.dispatchEvent("touchstart", wrapEvent(e));
};
const touchMove = (e) => {
if (!el) {
return;
}
el.dispatchEvent("touchmove", wrapEvent(e));
};
const touchEnd = (e) => {
if (!el) {
return;
}
el.dispatchEvent("touchend", wrapEvent(e));
};
faq
1、 按照官网的示例写原生canvas怎么着都出不来效果
- 官网示例:https://opendocs.alipay.com/mini/api/createimage
包括onCanvasReady函数不会正常运行。createSelectorQuery没有node方法。 - 原因:未使用高版本基础库。(低版本基础库也能显示f2,但是不会触发onCanvasReady方法,钉钉小程序只能使用低版本基础库)。
需要在设置里勾上启用2.0构建。
可以查看下版本号:
错误的版本号1开头的就不会显示。
高版本则正常。
2、rax小程序报找不到jsx
- 找不到jsx一般有2种情况:
一种是使用的组件没有保留rax的createElement函数导致。
还有一种是在该Rax页面中保留了rax的默认导出(这个坑坑了我挺久的)比如:
import Rax, { createElement, useEffect, useRef, useState } from 'rax';
- 这个默认导出Rax如果存在,就会报这个错。