参照 DOM 树的结构 , 每个 Konva 应用包括一个舞台 Stage、多个画布 Layer、多个分组 Group , 以及若干的叶子节点 Shape , 这些虚拟节点关联起来最终形成了一棵树 。
文章插图
在 Konva 中 , 一个 Stage 就是根节点 , Layer 对应一个 Canvas 画布 , Group 是指多个 Shape 的集合 , 它本身不会进行绘制 , 但同一个 Group 里面的 Shape 可以一起应用旋转、缩放等变换 。
Shape 则是指具体的绘制节点 , 比如 Rect、Circle、Text 等等 。
2.2 包围盒既然有了虚拟节点 , 那知道每个虚拟节点的位置和大小也比较重要 , 它会涉及到判断两个图形是否相交、事件等等 。
有时候元素的形状不是很规则 , 如果直接对不规则元素进行碰撞检测会比较麻烦 , 所以就有了一个近似的算法 , 就是在物体外侧加上包围盒 , 如图:
目前主流的包围盒有 AABB 和 OBB 两种 。
AABB 包围盒:
实现方式简单 , 直接用最大最小的横纵坐标来生成包围盒 , 但不会跟着元素旋转 , 因此空白区域比较多 , 也不够准确 。
也是目前 Konva 和 AntV 使用的方式 。(适合表格业务)
OBB 包围盒:
实现方式相对复杂 , 通过构建协方差矩阵来计算出新的坐标轴方向 , 将其顶点投射到坐标轴上面来得到新的包围盒 。
所以 OBB 包围盒更加准确一些 , 也是 cocos2d 使用的方式 。
碰撞检测:
两个包围盒在所有轴(与边平行)上的投影都发生重叠 , 则判定为碰撞;否则 , 没有发生碰撞 。
2.3 排版系统绘制 Canvas 的时候一般是通过相对坐标来确定当前要绘制的位置 , 所以都是通过各种计算来拿到 x、y 。
即使是 Konva 也是依赖于 x、y 来做相对定位 。
因此 , 在 AntV 和 SpriteJS 这类 Canvas 渲染引擎里面 , 都内置支持了盒模型的语法糖 , 底层会将盒模型属性进行一次计算转换成 x、y 。
以 AntV 为例子 , 排版能力是基于 Facebook 开源的 Yoga 排版引擎(React Native)来实现的 , 支持一套非常完整的盒模型和 Flex 布局语法 。
const container = new Rect({style: {width: 500, // Sizeheight: 300,display: 'flex', // Declaring the use of flex layoutsjustifyContent: 'center',alignItems: 'center',x: 0,y: 0,fill: '#C6E5FF',},});
在腾讯开源的 Hippy 里面自己实现了一套类似 Yoga 的排版引擎 , 叫做 Titank 。在飞书文档多维表格里面 , 排版语法更加接近于 Flutter , 实现了 Padding、Column、Row、Margin、Expanded、Flex、GridView 等 Widget 。
下面的示例是 Flutter 的:
Row(mainAxisSize: MainAxisSize.min,mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 对齐方式children: [Icon(Icons.star, color: Colors.green[500]),Icon(Icons.star, color: Colors.green[500]),Icon(Icons.star, color: Colors.green[500]),const Icon(Icons.star, color: Colors.black),const Icon(Icons.star, color: Colors.black),],);Align(alignment: Alignment.bottomRight,child: Container(width: 100, height: 100, color: red),)Padding(padding: EdgeInsets.fromLTRB(30, 30, 0, 30),child: Image.NETwork("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581413255772&di=52021e3e656744094d0339e7016994bb&imgtype=0&src=https://www.isolves.com/it/cxkf/bk/2023-02-28/http%3A%2F%2Fimg8.zol.com.cn%2Fbbs%2Fupload%2F19571%2F19570481.jpg",fit: BoxFit.cover,),)Widget _buildGrid() => GridView.extent(maxCrossAxisExtent: 150,padding: const EdgeInsets.all(4),mainAxisSpacing: 4,crossAxisSpacing: 4,children: _buildGridTileList(30));
实现了盒模型和 Flex 布局 , 可以让 Canvas 的排版能力更上一层楼 。不仅可以减少代码中的大量计算 , 也可以让大家从 DOM 开发无缝衔接进来 , 值得我们参考 。
canvas-flexbox - CodeSandbox
3. 事件Canvas 本身是一块画布 , 所以里面的内容都是画出来的 , 在 DOM 树里面也只是一个 Canvas 的节点 , 所以如何才能知道当前点击的是哪个图形呢?
由于 Canvas 渲染引擎都会封装虚拟节点 , 每个节点都有自己的包围盒 , 所以为实现 Canvas 的事件系统提供了可能性 。
主流的 Canvas 渲染引擎都是针对 Canvas 节点或者上层节点进行事件委托 , 监听用户相关的事件(mouseDown、click、touch等等)之后 , 匹配到当前触发的元素 , 将事件分发出去 , 并且拥有一套向上冒泡的机制 。
推荐阅读
- 浅谈前端组件设计
- |浅谈抛竿最重要的配件
- 浅谈味精最大使用量的标准 味精的主要成分是什么
- 浅谈这个风情万种的国度 土耳其的首都是什么名字
- 浅谈华硕笔记本电脑电池价格 华硕笔记本电池怎么取下来
- 浅谈班级管理的几点策略 班级管理论文
- 饵料|浅谈仲春野钓天气,好天气反而渔获差,这种时机别错过
- |浅谈职场中的沟通的重要性
- |仲春野钓鲫鱼思路浅谈,找草不是最优解,这种钓法渔获才好
- 浅谈一年级识字教学论文 识字教学论文