Konva.js 基础绘图教程:矩形、圆形及自定义路径绘制
本教程详细讲解如何使用 Konva.js 进行基础图形绘制,涵盖环境初始化、舞台与图层构建,以及 Konva.Rect 矩形、Konva.Circle 圆形和 Konva.Path 自定义路径的完整参数配置与代码实战。
Konva.Rect、Konva.Circle 与 Konva.Path 绘制基础几何图形及任意矢量路径的标准步骤与关键参数。
一、Konva.js 的层次渲染架构认知
在原生 HTML5 Canvas 开发中,绘制图形通常依赖 CanvasRenderingContext2D 的即时模式(Immediate Mode)。一旦执行 ctx.rect() 并填充颜色,像素就会直接固化到缓冲区,开发者无法在后续流程中单独拾取这个矩形、修改它的坐标或监听鼠标悬浮点击。
Konva.js 采用保留模式(Retained Mode),在底层维护了一套严格的树形层级(Scene Graph)。开发者无需手动操作底层绘图上下文,只需实例化相应的节点并将其逐级挂载。完整的显示对象树分为四个主要层级:
- 舞台(Stage):整个画布的顶层容器,直接绑定页面中的某一个 DOM 节点(如
<div>),负责监听全局事件并管理视口尺寸。 - 图层(Layer):独立的 Canvas 载体。一个 Stage 下可以承载多个 Layer,每个 Layer 在底层对应独立的
<canvas>DOM 元素。这种设计允许把频繁变化的图形与静止的背景分置在不同图层,避免全量重绘。 - 组(Group):可选的逻辑集合节点,用于把若干图形打包统一管理,支持统一变换坐标、缩放与批量隐藏。
- 图形(Shape):最底层的具体可视单元,包括矩形、圆形、文本、图片以及自定义路径等。
二、标准绘图执行流程与容器初始化
在 Konva.js 中绘制任何图元,都必须遵循严格的 5 个步骤。理解这套操作时序能够避免“图形未出现在屏幕上”或“事件监听无响应”等最常见的开发错误:
- 准备宿主 DOM 容器:在 HTML 中定义具有明确 ID 的
<div>元素。 - 创建舞台实例(Stage):传入
container选择器或 DOM 对象,并设定宽与高。 - 创建图层实例(Layer):实例化
Konva.Layer,随后通过stage.add(layer)挂载到舞台。 - 声明并配置图元对象(Shape):调用
new Konva.Rect(...)、new Konva.Circle(...)或new Konva.Path(...)定义几何参数与颜色。 - 挂载与绘制(Add & Draw):调用
layer.add(shape)将图元加入图层,并显式执行layer.draw()刷新画布。
环境安装与初始化代码非常轻量。在现代 Web 应用中,可通过 NPM 安装或在 HTML 中直接引入 UMD 脚本:
<!-- 通过 CDN 方式引入 -->
<script src="https://unpkg.com/konva@9/konva.min.js"></script>
<div id="canvas-container" style="width: 800px; height: 500px; border: 1px solid #ccc;"></div>
<script>
// 1. 初始化舞台
const stage = new Konva.Stage({
container: 'canvas-container',
width: 800,
height: 500
});
// 2. 初始化图层并挂载
const layer = new Konva.Layer();
stage.add(layer);
</script>
三、绘制矩形(Konva.Rect)
矩形是界面布局中最常用的图元。在 Konva.js 中,使用 Konva.Rect 构造函数创建矩形。需要特别注意的是,矩形的定位锚点 (x, y) 默认位于矩形的左上角,矩形的体积沿 X 轴向右延伸 width,沿 Y 轴向下延伸 height。
1. 矩形关键配置属性
| 配置属性 | 类型 | 说明与默认值 |
|---|---|---|
x, y |
Number | 矩形左上角在父容器(Layer/Group)中的绝对坐标,默认 0。 |
width, height |
Number | 矩形的横向宽度与纵向高度,必填正数。 |
fill |
String | 填充色彩,支持 HEX(如 #AD8B58)、RGB、RGBA 或 CSS 颜色名。 |
stroke, strokeWidth |
String, Number | 边框颜色与线宽(单位 px)。边框会居中覆盖在几何轮廓上。 |
cornerRadius |
Number | Array | 圆角半径。可传单一数值,或传入包含 4 个值的数组 [top-left, top-right, bottom-right, bottom-left]。 |
draggable |
Boolean | 是否开启拖拽移动,设置为 true 即自动激活拖拽交互。 |
2. 矩形绘制代码实例
下面的代码演示了包含填充、高对比度边框、阴影效果以及独立圆角半径的矩形配置:
// 创建一个带圆角与阴影的矩形
const rect = new Konva.Rect({
x: 60,
y: 50,
width: 200,
height: 120,
fill: '#FAF7F1',
stroke: '#394957',
strokeWidth: 3,
// 分别指定 [左上, 右上, 右下, 左下] 圆角
cornerRadius: [16, 4, 16, 4],
// 投影配置
shadowColor: 'rgba(57, 73, 87, 0.25)',
shadowBlur: 10,
shadowOffset: { x: 5, y: 5 },
shadowOpacity: 0.8,
draggable: true // 允许鼠标拖拽
});
// 加入图层并渲染
layer.add(rect);
layer.draw();
四、绘制圆形(Konva.Circle)与原点差异
绘制圆形使用 Konva.Circle 构造函数。很多从矩形绘制转来的开发者容易在此产生坐标偏移的误区:
Konva.Rect 的 (x, y) 位于图形的左上角,而 Konva.Circle 的 (x, y) 严格对应圆形的几何中心(圆心)。圆形没有 width 和 height 属性,其体积由单一的 radius(半径)参数向四周扩散决定。
掌握了圆心原点机制后,编写圆形代码便能精确控制其在屏幕上的排版居中:
// 创建一个圆形节点
const circle = new Konva.Circle({
x: 400, // 圆心位于画布水平中点
y: 200, // 圆心位于画布垂直位置
radius: 70, // 半径 70px (直径为 140px)
fill: '#394957', // 深灰蓝填充
stroke: '#AD8B58', // 暗金色描边
strokeWidth: 4,
draggable: true // 支持拖拽
});
layer.add(circle);
layer.draw();
如果需要让矩形也像圆形一样“以中心点为 (x, y) 放置”,可以通过设置 offsetX: width / 2, offsetY: height / 2 来调整矩形的内部变换原点。
五、绘制自定义路径(Konva.Path)
当界面需要非规则图形、折线图、图标、气泡对话框或设计软件导出的多边形时,Konva.Rect 与 Konva.Circle 无法满足需求。此时应当使用 Konva.Path。
Konva.Path 的核心是 data 属性。它直接兼容 W3C 标准的 SVG Path Data 语法规范。只要熟悉 SVG 路径指令,就可以将 Illustrator、Figma 或 SVG 文件中的 d="..." 属性直接粘贴使用。
1. 常用 SVG Path 指令速查
| 指令 | 名称与语法 | 执行行为说明 |
|---|---|---|
M / m |
Moveto: M x y |
将当前画笔抬起并移动到指定坐标点,不产生描边。 |
L / l |
Lineto: L x y |
从当前点画一条直线到目标 (x, y) 坐标。 |
H / h, V / v |
水平 / 垂直线 | H x 绘制水平直线到横坐标 x;V y 绘制垂直直线到纵坐标 y。 |
C / c |
三次贝塞尔曲线 | C x1 y1, x2 y2, x y,由两个控制点与终点生成平滑的立体曲线。 |
Q / q |
二次贝塞尔曲线 | Q x1 y1, x y,单一控制点生成的简易平滑曲线。 |
Z / z |
Closepath | 从当前画笔位置向路径的起点拉一条闭合直线,形成封闭多边形。 |
2. 自定义路径实战代码
在下面的实例中,我们通过两段 SVG 路径指令,分别绘制一个等腰三角形徽章和一个带平滑三次贝塞尔曲线的书签图形:
// 1. 绘制一个封闭三角形徽标
const trianglePath = new Konva.Path({
x: 100,
y: 80,
// 路径以 (0,0) 为起点,向右画到 (80,0),再到底部中间 (40,70),最后 Z 闭合
data: 'M 0 0 L 80 0 L 40 70 Z',
fill: '#AD8B58',
stroke: '#394957',
strokeWidth: 2,
draggable: true
});
// 2. 绘制包含三次贝塞尔曲线(C 指令)的波浪勋章
const waveBadge = new Konva.Path({
x: 240,
y: 80,
data: 'M 10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80 L 180 120 L 10 120 Z',
fill: '#394957',
stroke: '#AD8B58',
strokeWidth: 2,
opacity: 0.9,
draggable: true
});
layer.add(trianglePath);
layer.add(waveBadge);
layer.draw();
Konva.Path 的一个显著优势是事件命中的无缝继承。虽然路径形状复杂多样,但 Konva 会在离屏 Hit Canvas 上同步栅格化该路径的填充与轮廓,无论是点击三角形空隙还是贝塞尔曲面边缘,鼠标事件都能做到像素级精确拾取。
六、综合实战:多图元组合与动态属性更新
在真实业务场景中,图元绝非静态存在。开发者需要组合不同图元构建UI组件,并在用户交互(如点击、悬停、拖拽)时动态修改图元参数。
Konva.js 遵循统一的 Getter/Setter 机制。修改任意属性时直接调用 shape.setAttr('fill', value) 或便捷方法 shape.fill(value)。需要注意的是,修改属性后必须调用 layer.draw() 或 layer.batchDraw() 触发重绘,视图才会同步刷新。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Konva 综合绘图交互示例</title>
<script src="https://unpkg.com/konva@9/konva.min.js"></script>
<style>
#container {
width: 700px;
height: 350px;
background: #FAF7F1;
border: 1px solid #E6DFD5;
margin: 20px auto;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
const stage = new Konva.Stage({
container: 'container',
width: 700,
height: 350
});
const layer = new Konva.Layer();
stage.add(layer);
// 1. 矩形底板
const cardBg = new Konva.Rect({
x: 50,
y: 50,
width: 260,
height: 180,
fill: '#FFFFFF',
stroke: '#394957',
strokeWidth: 2,
cornerRadius: 8,
shadowColor: 'rgba(0,0,0,0.1)',
shadowBlur: 10,
shadowOffset: { x: 4, y: 4 },
draggable: true
});
// 2. 状态指示圆点
const statusIndicator = new Konva.Circle({
x: 80,
y: 80,
radius: 12,
fill: '#AD8B58',
stroke: '#FFFFFF',
strokeWidth: 2
});
// 3. 矢量箭头图标 (使用 Konva.Path)
const arrowIcon = new Konva.Path({
x: 120,
y: 72,
data: 'M 0 8 L 24 8 L 16 0 L 24 8 L 16 16',
stroke: '#394957',
strokeWidth: 3,
lineCap: 'round',
lineJoin: 'round'
});
// 交互逻辑:悬浮改变矩形高亮色
cardBg.on('mouseenter', () => {
stage.container().style.cursor = 'pointer';
cardBg.stroke('#AD8B58');
cardBg.strokeWidth(3);
layer.batchDraw(); // 批量优化重绘
});
cardBg.on('mouseleave', () => {
stage.container().style.cursor = 'default';
cardBg.stroke('#394957');
cardBg.strokeWidth(2);
layer.batchDraw();
});
// 点击指示圆点切换填充状态
statusIndicator.on('click', () => {
const isGold = statusIndicator.fill() === '#AD8B58';
statusIndicator.fill(isGold ? '#394957' : '#AD8B58');
layer.batchDraw();
});
// 依次挂载到图层
layer.add(cardBg);
layer.add(statusIndicator);
layer.add(arrowIcon);
// 初次渲染
layer.draw();
</script>
</body>
</html>
七、基础图元特性对比与性能优化建议
为了帮助读者在不同业务场景中做出最合理的图元选型,下表对三种基础图形在计算开销、坐标原点、变换特性和适用场景上进行了综合归纳:
掌握了矩形、圆形和自定义路径的绘制原理与原点特性后,读者已经具备了构建绝大多数复杂 2D 画布界面的基础。后续进阶开发中,可以结合 Konva.Group 实现多图元编组,利用 Konva.Transformer 实现图形的交互式拉伸旋转,并结合 layer.batchDraw() 保证复杂场景下的流畅绘制体验。
JavaScript 事件循环与浏览器渲染帧(requestAnimationFrame)的协作关系
2026-11-06 17:19:31
Chart.js 快速上手:引入库并绘制第一个折线图
2026-11-06 08:26:13
不用安装环境,怎么在线运行和调试JavaScript代码
2026-11-05 21:51:53
JS事件委托中stopPropagation失效的原因与解决
2026-11-05 19:57:55
JS在setTimeout或Ajax回调中打开新标签页失败怎么处理
2026-11-05 15:50:12








