用JSX写Canvas

做为一个非专业游戏和可视化开发方向的前端,我对canvas的使用经验是颇有限的,可是在某些状况又须要用到canvas,好比图片合成。 这个时候咱们一般会借助于已有的类库来完成咱们的需求, 好比上面提到的图片合成需求,可使用html2canvas来完成。 可是html2canvas的原理是将整个渲染树给解析一遍,所以会解析不少我不须要的东西。 另外,html2canvas的性能我是不能接受的,合成一个图片要花费数秒的时间。html

一个很直观的方式就是使用原生canvas去写,可是这又有以下三个问题。前端

第一是canvas对我来讲的写起来不顺手。 第二是为了跨端的能力,canvas的语法写出来必需要在支持canvas的容器中运行。 第三是对于咱们团队来讲,有不少人不熟悉canavs,强行推可能会不顺利。git

所以我动手造了一个轮子,这个轮子不只很好地解决了上面三个问题, 而且因为其是基于编译时声称可执行的代码, 所以它在性能上也有很大的优点。github

为了你们可以更好地理解我说的,咱们先来复习一下简单的canavs知识, 若是已经了解的能够快速看一下或者跳过。canvas

canvas基本概念

画布

canvas元素和普通的元素看起来没有什么不一样,而且canvas更加简单,只有两个属性width和height。 没有设置宽度和高度的时候,canvas会初始化宽度为300像素和高度为150像素。async

和其余元素不一样的是,canvas元素会建立一个固定大小的画布,它公开了一个或多个渲染上下文,其能够用来绘制和处理要展现的内容。布局

<canvas id="tutorial" width="150" height="150"></canvas>
复制代码

画笔

var canvas = document.getElementById('tutorial');
var ctx = canvas.getContext('2d'); // 这个方法是用来得到渲染上下文和它的绘画功能

复制代码

有了画笔, 咱们就能够画画了。 你须要指挥画笔,从哪开始,画到哪,用什么颜色的笔。性能

function draw(canvas) {
  if (canvas.getContext) {
    var ctx = canvas.getContext("2d");

    ctx.fillStyle = "rgb(200,0,0)"; // 笔的颜色
    ctx.fillRect (10, 10, 55, 50); // 画一个矩形

    ctx.fillStyle = "rgba(0, 0, 200, 0.5)";// 笔的颜色
    ctx.fillRect (30, 30, 55, 50); // 画一个矩形
  }
}

var canvas = document.getElementById("canvas");

draw(canvas)

复制代码

看起来就是这样的:flex

对于使用jsx2canvas来讲,有了这些知识就足够了,是否是很简单?动画

图片合成为例

刚才咱们反复提到了图片合成,是所以这个项目的灵感来自这个需求。那么咱们就拿图片合成来举例子。 个人需求是能够将多行图片按照某种形式组合起来。 传统的方式咱们能够直接使用canvas的API去一个个绘制图片,并本身计算布局。 所以canavs是 没有相似盒模型或者flex布局这种概念的,所以须要本身去计算布局,固然你能够本身封装。 还有一个问题就是层级,若是 用canvas去作的话,须要控制绘制顺序来控制层级。 若是合成的动画能够动呢? 咱们可能还要写逻辑来控制每一帧的变化等等。

JSX2canvas

貌似上面有不少问题,或大或小,而且均可以解决。 可是,咱们可否跳出这个思惟,用别的方式来解决这个问题呢?若是使用JSX2Canavs会是怎么样呢?

若是使用JSX2Canavs 可能会是这样的:

import { Canvas, CImage, CText, jsx2canvas } from "@duiba/jsx2canvas";

function getCTX() {
 const c = document.getElementById("canvas");
 return c.getContext("2d");
}

function render(commands) {
 const ctx = getCTX();

 commands.map(command => {
   return command.run(ctx);
 });
}

async function canvas({ backgroundImage, text, QRCode }) {
 const commands = await (
   <Canvas>
     <CImage zIndex={9} center middle src={backgroundImage} />
     <CText fontSize={60} center middle text={text} />
     <CImage center src={QRCode} />
   </Canvas>
 );

 return render(commands);
}

canvas({
 backgroundImage: "http://www.duiba.com.cn/_nuxt/img/huan.16841d6.png",
 text: "我是动态生成的文本!",
 QRCode: "http://www.duiba.com.cn/_nuxt/img/cainiao.f7032a9.png"
});

复制代码

渲染结果是:

能够看出它实际上是将两个图片和一个文本按照某种布局方式组织起来。 若是你的合成更复杂,其简洁性和直观性会表现地更加明显。

仓库地址:github.com/azl39798585… 详细文档你们能够去仓库查看。

固然这个仓库还在alpha版本,后续会考虑加入更多的功能, 好比borderonClick动画等。

相关文章
相关标签/搜索