Skip to content

konva 开源项目解读

项目信息

  • 项目名称:Konva

  • 项目描述:Konva 是一个 HTML5 Canvas 2D 图形框架(v10.3.0),采用保留模式图形树架构,提供 Stage → Layer → Group → Shape 的四层抽象。支持 19 种内置形状、20 种滤镜、拖拽、动画和事件系统。

  • 项目地址:https://github.com/konvajs/konva

  • 官方文档:

  • 解决的核心痛点

    • Canvas API 的底层复杂性: 原生 Canvas API 是无状态的"立即模式",Konva 提供"保留模式"的树形节点抽象
    • 高性能互动图形的工程化需求: 内置图层批量渲染、离屏 Hit Canvas 命中检测、节点变换与嵌套
    • 跨平台 2D 图形一致性: 通过抽象渲染后端(canvas-backend / skia-backend),浏览器和 Node.js 共用同一套 API
  • 核心亮点

    • 保留模式图形树: Stage → Layer → Group → Shape 树形结构,类 DOM 操作体验;
    • 像素级命中检测: 颜色编码 HitCanvas,GPU 加速,O(1) 查找;
    • 图层系统: 每个 Layer 独立 Canvas,支持批量渲染和图层级性能优化;
    • 滤镜管道: 20 种内置滤镜,支持 CSS filter 和 JS 滤镜函数双模式;
    • 变换系统: 综合位置/旋转/缩放/倾斜/偏移的仿射变换矩阵;
    • 动画引擎: RAF 循环 + 补间动画(Tween),支持 yoyo/play/pause/reverse;
    • Tree-shaking: 支持 Core(~26KB)和 Full 两种导入方式;
    • 跨平台: 浏览器 + Node.js(canvas/skia 双后端);

1. 项目概览

1.1 项目定位与核心价值

一句话定位:Konva 是一个面向前端开发者的高性能 HTML5 Canvas 2D 图形框架,通过树形节点结构提供对 Canvas 元素的高级抽象,使得在 Web 上构建交互式图形、编辑器和图表变得简单高效。

核心痛点解决

  1. Canvas API 的底层复杂性 — 原生 Canvas API 是无状态的"立即模式",Konva 提供"保留模式"的树形节点抽象
  2. 高性能互动图形的工程化需求 — 内置图层批量渲染、离屏 Hit Canvas 命中检测、节点变换与嵌套
  3. 跨平台 2D 图形一致性 — 通过抽象渲染后端(canvas-backend / skia-backend),浏览器和 Node.js 共用同一套 API

1.2 目标用户与使用场景

  • 前端 Web 开发者 — 图形编辑器、画布应用、数据可视化图表
  • 图形编辑器/设计工具开发者 — Polotno 等设计编辑器 SDK 基于 Konva 构建
  • 游戏开发者 — 2D 精灵、动画和交互的轻量级方案
  • Node.js 开发者 — 服务端渲染 Canvas 图像(缩略图生成、PDF/图片合成)

1.3 核心技术亮点

特性说明
保留模式图形树Stage → Layer → Group → Shape 树形结构,类 DOM 操作体验
像素级命中检测颜色编码 HitCanvas,GPU 加速,O(1) 查找
图层系统每个 Layer 独立 Canvas,支持批量渲染和图层级性能优化
滤镜管道20 种内置滤镜,支持 CSS filter 和 JS 滤镜函数双模式
变换系统综合位置/旋转/缩放/倾斜/偏移的仿射变换矩阵
动画引擎RAF 循环 + 补间动画(Tween),支持 yoyo/play/pause/reverse
Tree-shaking支持 Core(~26KB)和 Full 两种导入方式
跨平台浏览器 + Node.js(canvas/skia 双后端)

1.4 技术栈与选型对比

决策点选择替代方案权衡
渲染范式保留模式(Retained Mode)立即模式(Immediate Mode)牺牲了一定底层灵活性,换取了声明式 API 和自动重绘管理
命中检测颜色编码 HitCanvas几何碰撞计算像素级精度 + GPU 加速,但需要额外 Canvas 和内存开销
属性管理Factory 元编程手动属性声明极大减少样板代码,但 IDE 智能提示依赖类型导出
包设计Core/Full 分包单一打包支持按需加载和 Tree-shaking,但增加了构建配置复杂度
Node.js 后端canvas + skia 双后端单一后端提供兼容性(canvas/Cairo)和性能(skia/Chrome 引擎)两种选择

2. 整体架构设计

2.1 架构概述

Konva 采用分层图形树架构(Layered Scene Graph Architecture),核心设计理念是"保留模式"(Retained Mode)——所有图形对象以树形节点组织,每个节点独立维护自身属性状态,渲染引擎遍历树进行绘制。

系统分为四个层次:

  • 用户接口层:Konva 全局对象,提供创建 Stage/Shape/Animation/Tween 的入口
  • 图形树管理层:Stage -> Layer -> Group -> Shape 的四层节点树
  • 渲染引擎层:Canvas双缓冲(SceneCanvas + HitCanvas)、Context 包装、滤镜管线
  • 事件与交互层:指针事件系统、拖拽引擎、命中检测

2.2 整体架构图

text
+=======================================================================+
|                        Konva 全局对象 (Namespace)                      |
|  [Stage] [Layer] [Shape] [Tween] [Animation] [Filters] [Easings]      |
+=====================================+=================================+
                                      | (create/configure)
                                      v
+=====================================+=================================+
|                       图形树管理层 (Scene Graph)                        |
|                                                                        |
|  +-----------------------------+                                       |
|  |          Stage              |  DOM 绑定、事件分发、resize           |
|  |  (root of scene graph)      |                                       |
|  +-------------+---------------+                                       |
|                | children[]                                            |
|                v                                                       |
|  +-------------+---------------+                                       |
|  |    Layer / FastLayer         |  批量绘制、离屏缓存、Hit检测          |
|  |  (rendering surface)         |                                       |
|  +-------------+---------------+                                       |
|                | children[]                                            |
|                v                                                       |
|  +-------------+---------------+                                       |
|  |    Group (container)         |  组织结构/变换层级、裁剪             |
|  |  (spatial grouping)          |                                       |
|  +-------------+---------------+                                       |
|                | children[]                                            |
|       +--------+--------+                                             |
|       v                  v                                            |
|  +---------+        +---------+                                       |
|  |  Group   |        |  Shape  |  具体渲染单元                         |
|  | (nested) |        |         |                                       |
|  +---------+        +---------+                                       |
+=======================================================================+

+=====================================+=================================+
|                        渲染引擎层 (Rendering Engine)                    |
|                                                                        |
|  +-------------------+     +-------------------+                       |
|  |   SceneCanvas     |     |    HitCanvas       |                      |
|  |  (visible drawing) |     | (color-coded hit)  |                     |
|  +--------+----------+     +--------+----------+                       |
|           |                          |                                 |
|           v                          v                                 |
|  +--------+----------+     +--------+----------+                       |
|  |  SceneContext     |     |   HitContext       |                      |
|  +-------------------+     +-------------------+                       |
|                                                                        |
|  +----------------------------------------------------+               |
|  |              滤镜管线 (Filter Pipeline)             |               |
|  |  Blur | Brightness | Contrast | HSL | Invert ...   |               |
|  +----------------------------------------------------+               |
+=======================================================================+

+=====================================+=================================+
|                      事件与交互层 (Events & Interaction)               |
|                                                                        |
|  +-------------------+     +-------------------+                       |
|  |  PointerEvents     |     |  DragAndDrop (DD)  |                     |
|  |  (hit detection)   |     | (drag constraints)  |                    |
|  +-------------------+     +-------------------+                       |
|                                                                        |
|  +-------------------+     +-------------------+                       |
|  |  Animation         |     |  Tween             |                     |
|  |  (RAF loop)        |     | (property easing)  |                     |
|  +-------------------+     +-------------------+                       |
+=======================================================================+

2.3 目录结构

sell
konva/
├── src/                                       # 【核心基建】源代码主目录
│   ├── index.ts                               # 【核心基建】完整版入口(导入 _FullInternals,export default Konva)
│   ├── Core.ts                                # 【核心基建】精简版入口(导入 _CoreInternals,不含形状和滤镜)
│   ├── _CoreInternals.ts                      # 【核心基建】核心模块组装器 — 将核心基建类注入 Konva 全局对象
│   ├── _FullInternals.ts                      # 【核心基建】完整模块组装器 — 继承 Core 并注入所有 shapes 和 filters
│   ├── Global.ts                              # 【核心基建】全局 Konva 命名空间初始化 + _registerNode 注册机制
│   ├── Node.ts                                # 【核心基建】所有图形对象的抽象基类 — 事件系统、变换、缓存、滤镜管道
│   ├── Container.ts                           # 【核心基建】容器抽象类 — 子节点管理、树遍历、查找、裁剪
│   ├── Stage.ts                               # 【核心基建】舞台根节点 — DOM 容器绑定、原生事件→Konva事件转换、resize
│   ├── Layer.ts                               # 【核心基建】图层 — 维护 SceneCanvas+HitCanvas、批量绘制、Hit检测
│   ├── FastLayer.ts                           # 【核心基建】快速图层 — 继承 Layer,不维护 HitCanvas(无交互图层优化)
│   ├── Group.ts                               # 【核心基建】分组容器 — 嵌套变换层级、支持 clip
│   ├── Shape.ts                               # 【核心基建】形状抽象基类 — 填充/描边/阴影样式、sceneFunc/hitFunc 模板
│   ├── Factory.ts                             # 【核心基建】属性工厂 — 泛型 addGetterSetter/getterSetter/overloadedGetterSetter
│   ├── Validators.ts                          # 【工具集】属性校验器 — getNumberValidator、getStringValidator、getBooleanValidator 等
│   ├── Util.ts                                # 【工具集】通用工具函数 — Transform 矩阵类、颜色解析、Canvas 元素管理
│   ├── Canvas.ts                              # 【核心基建】画布抽象 — SceneCanvas(可见绘制) + HitCanvas(颜色编码命中)
│   ├── Context.ts                             # 【核心基建】渲染上下文包装 — SceneContext、HitContext 封装 CanvasRenderingContext2D
│   ├── DragAndDrop.ts                         # 【核心基建】拖拽引擎 — DD 单例、位置追踪、边界约束、事件触发
│   ├── Animation.ts                           # 【核心基建】动画引擎 — 全局 RAF 循环、animations[] 管理、帧计时
│   ├── Tween.ts                               # 【核心基建】补间动画 — TweenEngine 属性缓动、yoyo、play/pause/reverse
│   ├── PointerEvents.ts                       # 【核心基建】指针事件系统 — 相对坐标计算、事件对象构建、按钮/指针类型映射
│   ├── BezierFunctions.ts                     # 【工具集】贝塞尔曲线计算 — 点插值、长度、导数
│   ├── types.ts                               # 【核心基建】全局类型定义 — GetSet、IRect、Vector2d、AnimationFn 等
│   ├── canvas-backend.ts                      # 【配置】Node.js canvas 后端 — 注册 node-canvas 为默认渲染引擎
│   ├── skia-backend.ts                        # 【配置】Node.js skia-canvas 后端 — 注册 skia 为渲染引擎
│   ├── shapes/                                # 【业务模块】19 个具体形状实现(均继承 Shape)
│   │   ├── Arc.ts                            # 【业务模块】弧形路径
│   │   ├── Arrow.ts                          # 【业务模块】箭头(基于 Line,添加箭头头部计算)
│   │   ├── Circle.ts                         # 【业务模块】圆形
│   │   ├── Ellipse.ts                        # 【业务模块】椭圆
│   │   ├── Image.ts                          # 【业务模块】图像 — 图片加载、裁剪、DPI 感知
│   │   ├── Label.ts                          # 【业务模块】标签 — Group + Tag 组合
│   │   ├── Line.ts                           # 【业务模块】线段/折线/多边形/贝塞尔曲线
│   │   ├── Path.ts                           # 【业务模块】SVG 路径解析和渲染
│   │   ├── Rect.ts                           # 【业务模块】矩形
│   │   ├── RegularPolygon.ts                 # 【业务模块】正多边形(三角形/五边形/六边形等)
│   │   ├── Ring.ts                           # 【业务模块】环形/同心圆
│   │   ├── Sprite.ts                         # 【业务模块】精灵动画 — spritesheet 帧播放
│   │   ├── Star.ts                           # 【业务模块】星形(内/外半径+顶点数)
│   │   ├── Text.ts                           # 【业务模块】文本渲染 — 多行、对齐、换行、文字装饰
│   │   ├── TextPath.ts                       # 【业务模块】沿路径排列文本
│   │   ├── Transformer.ts                    # 【业务模块】变换控件 — 选择框、旋转锚点、缩放手柄、边界保持
│   │   └── Wedge.ts                          # 【业务模块】楔形/扇形
│   └── filters/                               # 【业务模块】20 个图像滤镜(操作 ImageData)
│       ├── Blur.ts                           # 【业务模块】模糊(Stack Blur 算法)
│       ├── Brighten.ts                       # 【业务模块】增亮
│       ├── Brightness.ts                     # 【业务模块】亮度调整
│       ├── Contrast.ts                       # 【业务模块】对比度调整
│       ├── Emboss.ts                         # 【业务模块】浮雕效果
│       ├── Enhance.ts                        # 【业务模块】增强
│       ├── Grayscale.ts                      # 【业务模块】灰度化
│       ├── HSL.ts                            # 【业务模块】HSL 色彩空间调整
│       ├── HSV.ts                            # 【业务模块】HSV 色彩空间调整
│       ├── Invert.ts                         # 【业务模块】反色
│       ├── Kaleidoscope.ts                   # 【业务模块】万花筒效果
│       ├── Mask.ts                           # 【业务模块】蒙版
│       ├── Noise.ts                          # 【业务模块】噪点
│       ├── Pixelate.ts                       # 【业务模块】像素化
│       ├── Posterize.ts                      # 【业务模块】色调分离
│       ├── RGB.ts                            # 【业务模块】RGB 通道调整
│       ├── RGBA.ts                           # 【业务模块】RGBA 通道调整
│       ├── Sepia.ts                          # 【业务模块】复古棕褐色
│       ├── Solarize.ts                       # 【业务模块】曝光过度
│       └── Threshold.ts                      # 【业务模块】二值化阈值
├── test/                                       # 【质量保证】测试文件目录
│   ├── unit/                                 # 【质量保证】单元测试(~45 个 .ts 文件,覆盖所有模块)
│   ├── manual/                               # 【质量保证】手动滤镜测试(~20 个 .ts 文件)
│   ├── performance/                          # 【质量保证】性能测试(创建元素、bunnies、jump-shape 等 HTML)
│   ├── typescript/                           # 【质量保证】TypeScript 类型推导正确性测试
│   ├── assets/                               # 【质量保证】测试资源(darth-vader.jpg、lion.png、bunny.png、SVG 数据)
│   ├── unit-tests.html                       # 【配置】Parcel 打包的单元测试入口
│   ├── manual-tests.html                     # 【配置】手动测试入口
│   └── sandbox.html                          # 【配置】开发沙盒
├── resources/                                  # 【配置】文档生成资源
│   ├── jsdoc.conf.json                       # 【配置】JSDoc 配置
│   └── doc-includes/                         # 【配置】JSDoc 模板片段(NodeParams、ContainerParams、ShapeParams)
├── .github/                                    # 【配置】GitHub Actions CI/CD
│   ├── workflows/test-browser.yml            # 【配置】浏览器端 CI 测试
│   ├── workflows/test-node.yml               # 【配置】Node.js CI 测试
│   ├── workflows/build.yml                   # 【配置】构建验证
│   ├── workflows/release.yml                 # 【配置】自动发布流程
│   └── workflows/prettier.yml                # 【配置】代码格式检查
├── rollup.config.mjs                          # 【配置】Rollup 打包配置
├── gulpfile.mjs                               # 【配置】Gulp 构建脚本(文档生成、构建 pipeline)
├── tsconfig.json                              # 【配置】TypeScript 编译配置(target: ES2015, module: ESNext)
├── tsconfig.test.json                         # 【配置】测试用 TypeScript 配置
├── package.json                               # 【配置】NPM 包配置(v10.3.0, MIT license)
├── release.sh                                 # 【工具集】发布流程脚本
├── CHANGELOG.md                               # 【配置】版本变更日志
├── LICENSE                                    # 【配置】MIT 许可证
└── README.md                                  # 【配置】英文项目说明文档

3. 模块依赖与调用关系

3.1 全局入口与核心路由

  • 逻辑说明:Konva 提供了两个入口:index.ts(完整版)和 Core.ts(精简版)。两者都通过 _assign 将模块注入全局 Konva 对象,保证全局单例。用户通过 new Konva.Stage() 创建根节点后,整个应用以树形结构组织。

  • 调用拓扑 (plainText)

text
index.ts (完整版入口)
 +--> _FullInternals.ts
       +--> _CoreInternals.ts
       |     +--> Global.ts .............. Konva 全局命名空间初始化
       |     +--> Util.ts / Transform .... 工具函数和矩阵变换
       |     +--> Node.ts ................ 基类节点(事件、缓存、变换)
       |     +--> Container.ts ........... 容器抽象(子节点管理)
       |     +--> Stage.ts ............... 舞台(DOM绑定、事件分发)
       |     +--> Layer.ts ............... 图层(批量渲染)
       |     +--> FastLayer.ts ........... 快速图层(跳过Hit检测)
       |     +--> Group.ts ............... 分组(空间组织)
       |     +--> Shape.ts ............... 形状基类(Canvas绘制)
       |     +--> Canvas.ts .............. 画布抽象(Scene/Hit双缓冲)
       |     +--> Context.ts ............. 渲染上下文包装
       |     +--> Factory.ts ............. 属性工厂(getter/setter生成)
       |     +--> Validators.ts .......... 属性校验
       |     +--> DragAndDrop.ts ......... 拖拽引擎
       |     +--> Animation.ts ........... 动画引擎(RAF管理)
       |     +--> Tween.ts ............... 补间动画引擎
       |     +--> PointerEvents.ts ....... 指针事件系统
       |     +--> BezierFunctions.ts ..... 贝塞尔曲线
       |     +--> types.ts ............... 全局类型
       |
       +--> shapes/
       |     +--> Arc.ts
       |     +--> Arrow.ts
       |     +--> Circle.ts
       |     +--> Ellipse.ts
       |     +--> Image.ts
       |     +--> Label.ts / Tag
       |     +--> Line.ts
       |     +--> Path.ts
       |     +--> Rect.ts
       |     +--> RegularPolygon.ts
       |     +--> Ring.ts
       |     +--> Sprite.ts
       |     +--> Star.ts
       |     +--> Text.ts
       |     +--> TextPath.ts
       |     +--> Transformer.ts
       |     +--> Wedge.ts
       |
       +--> filters/
             +--> Blur.ts, Brighten.ts, Brightness.ts, Contrast.ts
             +--> Emboss.ts, Enhance.ts, Grayscale.ts, HSL.ts, HSV.ts
             +--> Invert.ts, Kaleidoscope.ts, Mask.ts, Noise.ts
             +--> Pixelate.ts, Posterize.ts, RGB.ts, RGBA.ts
             +--> Sepia.ts, Solarize.ts, Threshold.ts

Core.ts (精简版入口)
 +--> _CoreInternals.ts (仅核心基建,不含 shapes/ 和 filters/)

3.2 核心业务实体与关联

  • 实体定义
实体描述
Node所有图形对象的抽象基类。维护位置、旋转、缩放、透明度等变换属性;提供事件监听系统;支持缓存和滤镜。
Container继承自 Node,抽象出"可以有子节点"的语义。维护 children[] 数组,提供树的遍历、查找、增删改能力。
Stage场景图的根节点。绑定 HTML DOM 容器,创建 SceneCanvas/HitCanvas,协调所有事件(鼠标/触摸/指针)的分发。
Layer渲染表面。拥有独立的 SceneCanvas 和 HitCanvas,执行批量绘制(batchDraw)。每个 Stage 可以包含多个 Layer。
FastLayerLayer 的子类,不维护 HitCanvas,适合不需要交互的纯展示图层(性能优化)。
Group组织容器。提供坐标系变换的嵌套,支持裁剪(clip)。本身不进行绘制,但影响子节点的渲染状态。
Shape所有可渲染形状的基类。定义 sceneFunc()hitFunc() 模板方法,子类实现具体绘制逻辑。管理填充/描边/阴影等样式。
Transformer特殊的 Shape,提供可视化的锚点控件,用于选中和变换其他节点(缩放/旋转/倾斜)。
  • 实体引用拓扑 (plainText)
text
[Konva Global Namespace]
  |
  +-- 1 -----> 1 [Stage] (根容器)
                   |
                   +-- 1 -----> N [Layer/FastLayer] (渲染图层)
                                    |
                                    +-- 1 -----> N [Group] (组织容器)
                                                   |
                                                   +-- 1 -----> N [Group] (可递归嵌套)
                                                   |              |
                                                   |              +-- 1 -----> N [Shape] (渲染单元)
                                                   |
                                                   +-- 1 -----> N [Shape] (渲染单元)

[Node] <|------- [Container] <|------- [Stage]
        |                   |
        |                   +------- [Layer] <|---- [FastLayer]
        |
        +------- [Shape] <|------- [Rect, Circle, Arc, Ellipse, ...]
                |           |------- [Image, Sprite, Text, TextPath]
                |           |------- [Line, Path, Arrow]
                |           |------- [Label, Transformer, ...]
                |
                +------- [Group]

[Shape].sceneFunc() --> [SceneContext] --> CanvasRenderingContext2D
[Shape].hitFunc()   --> [HitContext]   --> CanvasRenderingContext2D
[Shape].filters[]   --> [Filter Pipeline] --> ImageData processing

[Stage] --> [PointerEvents] --> getIntersection() --> [HitCanvas]
[Node]   --> [DD (DragAndDrop)] --> 拖拽位置计算
[Node]   --> [Animation] --> requestAnimationFrame 循环
[Node]   --> [Tween] --> TweenEngine (属性补间)

4. 核心模块详解

模块一:Node(所有节点的抽象基类)

  • 模块名称:Node — 图形对象基类

  • 设计说明: Node 是整个框架的基石,继承自 EventEmitter 模式(自定义实现),提供:

    1. 属性系统:通过 Factory.addGetterSetter 动态生成属性的 getter/setter,setter 中自动触发变更通知和脏标记
    2. 变换系统:维护 Transform 矩阵(位置 x/y、缩放 scaleX/scaleY、旋转 rotation、偏移 offsetX/offsetY、倾斜 skewX/skewY)
    3. 缓存系统:支持将节点的渲染结果缓存到离屏 Canvas,提高复杂图形的重绘性能
    4. 滤镜管道:支持对缓存结果应用多个滤镜(CSS filter 或 JS 滤镜函数)
    5. 事件系统:完整的事件监听/触发/取消机制,支持命名空间(如 click.konva
  • 内部结构图 (plainText)

text
+=======================================================================+
|                           Node (基类)                                  |
+=======================================================================+
|                                                                        |
|  +---------------------+    +---------------------+                    |
|  |   属性系统           |    |   变换系统           |                   |
|  | (Factory.getter/     |    | (Transform Matrix)   |                   |
|  |  setter 动态生成)    |    |  - x, y              |                   |
|  |  - attrs: {}         |    |  - scaleX, scaleY    |                   |
|  |  - onChange()        |    |  - rotation          |                   |
|  |  - _setAttr()        |    |  - offsetX, offsetY  |                   |
|  +----------+-----------+    |  - skewX, skewY      |                   |
|             |                +----------+-----------+                   |
|             v                           v                              |
|  +----------+-----------+    +----------+-----------+                  |
|  |   脏标记系统           |    |   缓存系统           |                 |
|  |  - _dirty: boolean    |    |  - cache()           |                 |
|  |  - batchDraw 触发     |    |  - clearCache()      |                 |
|  +----------+-----------+    |  - _cacheCanvas       |                 |
|             |                +----------+-----------+                  |
|             v                           v                              |
|  +----------+-----------+    +----------+-----------+                  |
|  |   事件系统             |    |   滤镜管道           |                 |
|  |  - on/off/fire()      |    |  - filters[]         |                 |
|  |  - namespace support  |    |  - _applyFilter()    |                 |
|  |  - event bubbling     |    |  - CSS filter parse  |                 |
|  +---------------------+    +---------------------+                    |
|                                                                        |
+=======================================================================+

模块二:Shape(形状渲染基类)

  • 模块名称:Shape — Canvas 2D 绘制核心

  • 设计说明: Shape 是渲染的关键模块。采用模板方法模式

    1. 子类实现 _sceneFunc(context) 定义场景绘制逻辑
    2. 子类实现 _hitFunc(context) 定义命中检测绘制逻辑
    3. Shape 基类的 sceneFunc(context) 包装了填充/描边/阴影等样式处理
    4. 颜色编码的命中检测:每个 Shape 实例在 HitCanvas 上用一个唯一颜色绘制,通过 getIntersection() 采样像素颜色来定位命中的节点
  • 内部结构图 (plainText)

text
+=======================================================================+
|                           Shape (渲染基类)                             |
+=======================================================================+
|                                                                        |
|  绘制管线:                                                             |
|                                                                        |
|  draw()                                                               |
|    |                                                                   |
|    v                                                                   |
|  drawHit(can, top) ---------> HitCanvas (颜色编码)                     |
|    |                             |                                     |
|    |                             v                                     |
|    |                        hitFunc()                                  |
|    |                        - _hitFunc(context) [子类实现]             |
|    |                        - 填充唯一颜色 key                          |
|    |                                                                   |
|    v                                                                   |
|  drawScene(can, top) ------> SceneCanvas (可见绘制)                    |
|    |                             |                                     |
|    |                             v                                     |
|    |                        sceneFunc()                                |
|    |                        - 填充样式处理                              |
|    |                        - 描边样式处理                              |
|    |                        - 阴影处理                                  |
|    |                        - _sceneFunc(context) [子类实现]           |
|    |                                                                   |
|    v                                                                   |
|  drawHitFromCache(can, top) (缓存命中时)                               |
|                                                                        |
+=======================================================================+
|                                                                        |
|  命中检测:                                                             |
|                                                                        |
|  getIntersection(point)                                               |
|    |                                                                   |
|    v                                                                   |
|  HitCanvas.getContext().getImageData(x, y, 1, 1)                      |
|    |                                                                   |
|    v                                                                   |
|  colors['#' + r + g + b] --> shape instances (颜色→形状映射)           |
|                                                                        |
+=======================================================================+

模块三:Stage(舞台根节点与事件中枢)

  • 模块名称:Stage — 整个场景图的入口

  • 设计说明: Stage 是唯一直接与 DOM 交互的模块:

    1. 创建 HTML Canvas 元素并绑定到用户指定的 DOM 容器
    2. 管理 content div 及其子 Canvas 元素的生命周期
    3. 监听所有原生 DOM 事件(mouse/touch/pointer/wheel),转换为 Konva 内部事件
    4. 通过 PointerEvents 模块进行坐标转换和命中检测
    5. 维护全局 stages[] 数组(用于全局事件分发和资源管理)
  • 内部结构图 (plainText)

text
+=======================================================================+
|                         Stage (根容器)                                 |
+=======================================================================+
|                                                                        |
|  DOM 绑定层:                                                           |
|  +--------------------------------------------------+                 |
|  |  container (HTMLDivElement)                       |                 |
|  |    +-- content (HTMLDivElement)                   |                 |
|  |         +-- <canvas> SceneCanvas                  |                 |
|  |         +-- <canvas> HitCanvas (hidden)           |                 |
|  +--------------------------------------------------+                 |
|                                                                        |
|  事件管道:                                                             |
|  +--------------------------------------------------+                 |
|  |  DOM Events (mouse/touch/pointer/wheel)           |                 |
|  |    |                                               |                 |
|  |    v                                               |                 |
|  |  _pointerdown / _pointermove / _pointerup...      |                 |
|  |    |                                               |                 |
|  |    v                                               |                 |
|  |  PointerEvents.createEvent()                       |                 |
|  |    |                                               |                 |
|  |    v                                               |                 |
|  |  getIntersection() --> 从 HitCanvas 获取命中节点   |                 |
|  |    |                                               |                 |
|  |    v                                               |                 |
|  |  targetNode.fire('eventName', evt)                 |                 |
|  |    |                                               |                 |
|  |    v                                               |                 |
|  |  Event Bubbling (向上冒泡至 Layer/Stage)           |                 |
|  +--------------------------------------------------+                 |
|                                                                        |
+=======================================================================+

模块四:Factory(属性系统工厂)

  • 模块名称:Factory — getter/setter 生成引擎
  • 设计说明: Factory 使用了元编程技术,通过 addGetterSetter() 方法动态为类添加属性的 getter/setter:
    1. 在类的原型链上定义属性访问器
    2. setter 中自动触发:值变更检测 -> 校验器执行 -> 属性存储 -> 变更回调
    3. 支持components(复合属性自动拆分,如 position 自动分解为 x, y
    4. addGetterSetterafter 回调支持在 setter 后执行额外逻辑(如触发重绘)
text
+=======================================================================+
|                      Factory (属性工厂)                                |
+=======================================================================+
|                                                                        |
|  addGetterSetter(NodeClass, 'x', 0, getNumberValidator(), afterFn)    |
|    |                                                                   |
|    v                                                                   |
|  Object.defineProperty(NodeClass.prototype, 'x', {                     |
|    get: function() { return this._attrs.x; },                          |
|    set: function(val) {                                                |
|      val = validator(val, 'x');       // 校验                           |
|      if (val === this._attrs.x) return; // 去重                        |
|      this._attrs.x = val;             // 存储                           |
|      this._dirty = true;              // 标记脏                         |
|      if (afterFn) afterFn.call(this); // 后置处理                       |
|    }                                                                   |
|  });                                                                   |
|                                                                        |
|  overloadedGetterSetter(NodeClass, 'position', ['x', 'y'])              |
|    --> 自动生成 position({x, y}) 形式的复合 setter                     |
|                                                                        |
+=======================================================================+

模块五:Animation + Tween(动画引擎)

  • 模块名称:Animation & Tween — 帧循环与补间动画
  • 设计说明: Animation 管理 requestAnimationFrame 循环,维护全局动画列表。Tween 基于 Animation 实现属性的缓动过渡:
    1. Animation:构造函数接收 func 和 layers,start() 后将自身注册到全局动画列表,通过 RAF 循环每帧调用 func
    2. Tween:为每个被补间的属性创建独立的 TweenEngine 实例,支持 yoyo(往复)、play/pause/reverse/reset 控制
    3. TweenEngine 使用 easing 函数计算每帧的进度位置
    4. colorAttrs(fill, stroke, shadowColor)支持颜色空间的平滑过渡
text
+=======================================================================+
|                    动画引擎 (Animation + Tween)                         |
+=======================================================================+
|                                                                        |
|  Animation (RAF 管理)                                                  |
|  +--------------------------------------------------+                 |
|  |  Animation.animations[]  (全局动画列表)           |                 |
|  |  Animation._animationLoop()                       |                 |
|  |    |--> requestAnimationFrame(_animationLoop)     |                 |
|  |    |--> 遍历 animations[]                         |                 |
|  |    |--> 对每个 anim:                              |                 |
|  |    |     anim.func(anim.frame)                    |                 |
|  |    |     if layers: layers.forEach(l => l.draw())  |                |
|  +--------------------------------------------------+                 |
|                                                                        |
|  Tween (补间管理器)                                                    |
|  +--------------------------------------------------+                 |
|  |  Node.to(config)                                  |                 |
|  |    |--> 解析 config (duration, easing, onFinish)  |                 |
|  |    |--> 为每个属性创建 TweenEngine                |                 |
|  |    |     TweenEngine(prop, propFunc, easing)       |                |
|  |    |        |--> setTime() / setPosition()         |                |
|  |    |        |--> play/pause/reverse/reset          |                |
|  |    |                                               |                 |
|  |    |--> 创建 Animation(func, layers)               |                 |
|  |    |--> Animation.start()                          |                 |
|  +--------------------------------------------------+                 |
|                                                                        |
+=======================================================================+

5. 关键数据流程

场景一:用户点击一个 Shape 的完整事件流程

场景说明:用户鼠标点击一个矩形 Shape,从 DOM 事件触发到 Konva 事件回调执行的完整链路。

流转时序图

场景二:形状属性变更到屏幕渲染的完整流程

  • 场景说明:用户调用 rect.x(200) 修改属性,到最终屏幕更新(包括脏标记、自动绘制)的完整链路。

  • 流转时序图 (Mermaid)

场景三:拖拽操作的完整事件链

  • 场景说明:用户拖拽一个形状从起点移动到终点。

  • 流转时序图 (Mermaid)

6. 接口与契约规范

6.1 核心内部模块契约 (TypeScript)

typescript
// ============================================================
// Node.ts — 所有图形对象的基类契约
// ============================================================

export interface NodeConfig {
  x?: number;
  y?: number;
  width?: number;
  height?: number;
  visible?: boolean;
  listening?: boolean;
  id?: string;
  name?: string;
  opacity?: number;
  scale?: Vector2d;
  scaleX?: number;
  scaleY?: number;
  rotation?: number;
  rotationDeg?: number;
  offset?: Vector2d;
  offsetX?: number;
  offsetY?: number;
  draggable?: boolean;
  dragDistance?: number;
  dragBoundFunc?: (pos: Vector2d) => Vector2d;
  preventDefault?: boolean;
}

export type KonvaEventListener<This, EventType> = (
  this: This,
  evt: KonvaEventObject<EventType>
) => void;

export interface KonvaEventObject<EventType> {
  type: string;
  target: Shape;
  evt: EventType;
  pointerId?: number;
  currentTarget: Node;
  cancelBubble: boolean;
}

// ============================================================
// Container.ts — 容器契约
// ============================================================

export interface ContainerConfig extends NodeConfig {
  clearBeforeDraw?: boolean;
  clipFunc?: (ctx: SceneContext) => ClipFuncOutput;
  clipX?: number;
  clipY?: number;
  clipWidth?: number;
  clipHeight?: number;
}

export abstract class Container<
  ChildType extends Node = Node,
  Config extends ContainerConfig = ContainerConfig
> extends Node<Config> {
  children: Array<ChildType>;
  getChildren(filterFunc?: (item: Node) => boolean): ChildType[];
  hasChildren(): boolean;
  removeChildren(): void;
  destroyChildren(): void;
  add(...children: ChildType[]): this;
  find(selector: string | ((node: Node) => boolean)): Node[];
  findOne(selector: string | ((node: Node) => boolean)): Node | undefined;
  getClientRect(config?: { skipTransform?: boolean; skipShadow?: boolean; skipStroke?: boolean }): IRect;
  draw(): this;
  batchDraw(): this;
}

// ============================================================
// Stage.ts — 舞台契约
// ============================================================

export interface StageConfig extends ContainerConfig {
  container?: HTMLDivElement | string;
}

export class Stage extends Container<Layer> {
  container(): HTMLDivElement;
  content: HTMLDivElement;
  getPointerPosition(): Vector2d | null;
  getIntersection(pos: Vector2d, children?: Node[]): Shape | undefined;
  getAllIntersections(pos: Vector2d): Shape[];
  setPointersPositions(evt: Event): void;
  container(): HTMLDivElement;
  draw(): this;
  toDataURL(config?: object): string;
  toBlob(config?: object): Promise<Blob>;
  toCanvas(config?: object): HTMLCanvasElement;
  toImage(config?: object): HTMLImageElement;
  setSize(config: { width: number; height: number }): void;
  getSize(): { width: number; height: number };
}

// ============================================================
// Layer.ts — 图层契约
// ============================================================

export interface LayerConfig extends ContainerConfig {
  clearBeforeDraw?: boolean;
  hitGraphEnabled?: boolean;
  imageSmoothingEnabled?: boolean;
}

export class Layer extends Container<Group | Shape> {
  canvas: SceneCanvas;
  hitCanvas: HitCanvas;
  batchDraw(): this;
  getIntersection(pos: Vector2d): Shape | undefined;
  enableHitGraph(): this;
  disableHitGraph(): this;
  drawScene(can?: SceneCanvas): this;
  drawHit(can?: HitCanvas): this;
}

// ============================================================
// Shape.ts — 形状基类契约
// ============================================================

export type LineJoin = 'round' | 'bevel' | 'miter';
export type LineCap = 'butt' | 'round' | 'square';

export interface ShapeConfig extends NodeConfig {
  fill?: string | CanvasGradient;
  fillEnabled?: boolean;
  fillPriority?: string;
  fillRule?: CanvasFillRule;
  stroke?: string | CanvasGradient;
  strokeWidth?: number;
  strokeScaleEnabled?: boolean;
  strokeHitEnabled?: boolean;
  strokeEnabled?: boolean;
  lineJoin?: LineJoin;
  lineCap?: LineCap;
  miterLimit?: number;
  dash?: number[];
  dashEnabled?: boolean;
  dashOffset?: number;
  shadowColor?: string;
  shadowBlur?: number;
  shadowOffset?: Vector2d;
  shadowOffsetX?: number;
  shadowOffsetY?: number;
  shadowEnabled?: boolean;
  shadowOpacity?: number;
  shadowForStrokeEnabled?: boolean;
  perfectDrawEnabled?: boolean;
  hitFunc?: ShapeConfigHandler<Shape>;
}

export class Shape<
  Config extends ShapeConfig = ShapeConfig
> extends Node<Config> {
  sceneFunc(context: SceneContext): void;
  draw(): this;
  drawHit(can?: HitCanvas, top?: Node): void;
  drawScene(can?: SceneCanvas, top?: Node): void;
  getSelfRect(): IRect;
  getClientRect(config?: { skipTransform?: boolean }): IRect;
  hasFill(): boolean;
  hasStroke(): boolean;
  hasShadow(): boolean;
  fillStrokeScene(context: SceneContext): void;
  getHitFunc(): ShapeConfigHandler<Shape>;
  static getShapeKey(): string;
}

// ============================================================
// Animation.ts — 动画引擎契约
// ============================================================

export interface IFrame {
  time: number;
  timeDiff: number;
  lastTime: number;
  frameRate: number;
}

export type AnimationFn = (frame?: IFrame) => boolean | undefined | void;

export class Animation {
  func: AnimationFn;
  id: number;
  layers: Layer[];
  frame: IFrame;
  constructor(func: AnimationFn, layers?: Layer | Layer[]);
  start(): this;
  stop(): this;
  setLayers(layers?: Layer | Layer[]): void;
  isRunning(): boolean;
}

// ============================================================
// Tween.ts — 补间动画契约
// ============================================================

export interface TweenConfig extends NodeConfig {
  duration: number;
  easing?: (t: number, b: number, c: number, d: number) => number;
  onFinish?: () => void;
  yoyo?: boolean;
  node?: Node; // 额外属性注入
}

export class Tween {
  constructor(config: TweenConfig);
  play(): this;
  pause(): this;
  reverse(): this;
  reset(): this;
  finish(): this;
  destroy(): void;
  seek(t: number): this;
}

6.2对外 API 契约(公共 API 导出)

typescript
// Konva 全局命名空间导出契约
declare namespace Konva {
  // 核心类
  export class Stage extends Container<Layer> { }
  export class Layer extends Container<Group | Shape> { }
  export class FastLayer extends Layer { }
  export class Group extends Container<Shape> { }
  export class Shape<Config> extends Node<Config> { }

  // 形状
  export class Rect extends Shape<RectConfig> { }
  export class Circle extends Shape<CircleConfig> { }
  export class Ellipse extends Shape<EllipseConfig> { }
  export class Line extends Shape<LineConfig> { }
  export class Path extends Shape<PathConfig> { }
  export class Text extends Shape<TextConfig> { }
  export class Image extends Shape<ImageConfig> { }
  export class Arrow extends Shape<ArrowConfig> { }
  export class Arc extends Shape<ArcConfig> { }
  export class Ring extends Shape<RingConfig> { }
  export class Star extends Shape<StarConfig> { }
  export class Wedge extends Shape<WedgeConfig> { }
  export class RegularPolygon extends Shape<RegularPolygonConfig> { }
  export class Label extends Group { }
  export class Tag extends Shape<TagConfig> { }
  export class Sprite extends Shape<SpriteConfig> { }
  export class TextPath extends Shape<TextPathConfig> { }
  export class Transformer extends Group { }

  // 滤镜
  export namespace Filters {
    export function Blur(imageData: ImageData): void;
    export function Brighten(imageData: ImageData): void;
    // ... 其余滤镜
  }

  // 工具
  export namespace Util {
    export function haveIntersection(r1: IRect, r2: IRect): boolean;
    export function getRandomColor(): string;
    // ...
  }

  // 动画
  export class Animation { }
  export class Tween { }
  export const Easings: Record<string, EasingFunction>;

  // 类型
  export type Vector2d = { x: number; y: number };
  export type IRect = { x: number; y: number; width: number; height: number };
}

export default Konva;

7. 快速开始

7.1 安装与运行

bash
# NPM 安装
npm install konva

# 开发模式
git clone https://github.com/konvajs/konva.git
cd konva
npm install
npm start  # 启动开发服务器 + 测试 watcher

7.2 最简示例

html
<script src="https://unpkg.com/konva@10/konva.min.js"></script>
<div id="container"></div>
<script>
  const stage = new Konva.Stage({
    container: 'container',
    width: window.innerWidth,
    height: window.innerHeight,
  });
  const layer = new Konva.Layer();
  stage.add(layer);

  const rect = new Konva.Rect({
    x: 50, y: 50, width: 100, height: 50,
    fill: '#00D2FF', stroke: 'black', strokeWidth: 4,
    draggable: true,
  });
  layer.add(rect);
  layer.draw();
</script>

7.3 构建命令

命令说明
npm run build完整构建(编译+打包+压缩)
npm test运行所有测试
npm start开发模式(parcel serve + watch)
npm run fmt代码格式化(prettier)