当渲染层 JS 资源加载完成后 , 直接省略反序列化、初始化 Model、计算排版数据等阶段 , 将 FVG 转换成 Widget 进行 Canvas 渲染 , 这一步非常接近于 React 的 hydrate , 很巧妙 。用过 Canvas 的都知道它的 API 比较多 , 使用起来也很麻烦 , 比如我想绘制一个圆形就要调一堆 API , 对开发算不上友好 。
为了解决这个痛点 , 诞生了例如 PIXI、ZRender、Fabric 等 Canvas 库 , 对 Canvas API 进行了一系列的封装 。
今天主要介绍一下社区几个比较有代表性的 Canvas 渲染引擎的设计原理 。
这篇文中不会从源码讲起 , 更像是一篇科普文章 , 介绍 Canvas 一些有趣的点 。
1. 特性Canvas 渲染引擎一般包括下面几个特点:
- 封装
比如想画一个圆 , 直接调用封装好的绘制方法就行了 , 我们不需要关心是如何绘制的 。
- 性能
常见的性能优化手段有离屏渲染、脏区渲染、异步渲染等等 。
- 跨平台
针对底层的渲染流程和类进行抽象化 , 在不同平台具象化去实现具体的渲染逻辑 , 从而可以一套代码 , 只要切换渲染器就能实现多平台渲染 。
2. 封装2.1 虚拟节点Canvas 是一张画布 , 里面的内容都是自己调用 API 绘制的 , 所以更像是我们拿起画笔来作画 。
目前主流的 Canvas 渲染引擎都会将要绘制的图形封装成类 , 以方便开发者去调用 , 复用性也比较强 。调用方式类似于 DOM , 每个实例可以当做一个虚拟节点 。
使用 AntV/g 的例子:
import { Circle, Canvas, CanvasEvent } from '@antv/g';import { Renderer as CanvasRenderer } from '@antv/g-canvas';// or// import { Renderer as WebGLRenderer } from '@antv/g-webgl';// import { Renderer as SVGRenderer } from '@antv/g-svg';// 创建画布const canvas = new Canvas({container: 'container',width: 500,height: 500,renderer: new CanvasRenderer(), // 选择一个渲染器});// 创建一个圆const circle = new Circle({style: {cx: 100,cy: 100,r: 50,fill: 'red',stroke: 'blue',lineWidth: 5,},});canvas.addEventListener(CanvasEvent.READY, function () {// 加入画布canvas.AppendChild(circle);// 监听 `click` 事件circle.addEventListener('click', function () {this.style.fill = 'green';});});
在此基础上 , 可以进一步针对 React/Vue 语法进行封装 , 让用户对底层的实现无感知 。使用 React-Konva 的例子(通过 react-reconciler 实现):
import React, { Component } from 'react';import { render } from 'react-dom';import { Stage, Layer, Rect, Text } from 'react-konva';import Konva from 'konva';class ColoredRect extends React.Component {state = {color: 'green',};handleClick = () => {this.setState({color: Konva.Util.getRandomColor(),});};render() {return (<Rectx={20}y={20}width={50}height={50}fill={this.state.color}shadowBlur={5}onClick={this.handleClick}/>);}}class App extends Component {render() {return (<Stage width={window.innerWidth} height={window.innerHeight}><Layer><Text text="Try click on rect" /><ColoredRect /></Layer></Stage>);}}render(<App />, document.getElementById('root'));
除了内置的图形类 , 很多渲染引擎还会提供自定义绘制图形类的能力 。以 Konva 为例 , 每个图形类都需要实现 sceneFunc 方法 , 在这个方法里面去调用 Canvas API 来进行绘制 。
如果需要自定义新的图形 , 就可以继承 Shape 来实现 sceneFunc 方法 。
Konva 里面圆形绘制类的实现:
export class Circle extends Shape<CircleConfig> {_sceneFunc(context) {context.beginPath();context.arc(0, 0, this.attrs.radius || 0, 0, Math.PI * 2, false);context.closePath();context.fillStrokeShape(this);}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 浅谈前端组件设计
- |浅谈抛竿最重要的配件
- 浅谈味精最大使用量的标准 味精的主要成分是什么
- 浅谈这个风情万种的国度 土耳其的首都是什么名字
- 浅谈华硕笔记本电脑电池价格 华硕笔记本电池怎么取下来
- 浅谈班级管理的几点策略 班级管理论文
- 饵料|浅谈仲春野钓天气,好天气反而渔获差,这种时机别错过
- |浅谈职场中的沟通的重要性
- |仲春野钓鲫鱼思路浅谈,找草不是最优解,这种钓法渔获才好
- 浅谈一年级识字教学论文 识字教学论文