前端使用 Konva 实现可视化设计器(1)
使用 konva 实现一个设计器交互,首先考虑实现设计器的画布。
一个基本的画布:
【展示】网格、比例尺
【交互】拖拽、缩放
“拖拽”是无尽的,“缩放”是基于鼠标焦点的。
最终效果:



基本思路:
设计区域 HTML 由两个节点构成,内层挂载一个 Konva.stage 作为画布的开始。
<template>
<div class="page">
<header></header>
<section>
<header></header>
<section ref="boardElement">
<div ref="stageElement"></div>
</section>
<footer></footer>
</section>
<footer></footer>
</div>
</template>

Konva.stage 暂时先设计3个 Konva.Layer,分别用于绘制背景、所有素材、比例尺。

通过 ResizeObserver 使 Konva.stage 的大小与外层 boardElement 保持一致。
为了显示“比例尺” Konva.stage 默认会偏移一些距离,这里定义“比例尺”尺寸为 40px。
this.stage = new Konva.Stage({
container: stageEle,
x: this.rulerSize,
y: this.rulerSize,
width: config.width,
height: config.height
})
关于“网格背景”,是按照当前设计区域大小、缩放大小、偏移量,计算横向、纵向分别需要绘制多少条 Konva.Line(横向、纵向分别多加1条),同时根据 Konva.stage 的 x,y 进行偏移,用有限的 Konva.Line 模拟无限的网格画布。
// 格子大小
const cellSize = this.option.size
//
const width = this.stage.width()
const height = this.stage.height()
const scaleX = this.stage.scaleX()
const scaleY = this.stage.scaleY()
const stageX = this.stage.x()
const stageY = this.stage.y()
// 列数
const lenX = Math.ceil(width / scaleX / cellSize)
// 行数
const lenY = Math.ceil(height / scaleY / cellSize)
const startX = -Math.ceil(stageX / scaleX / cellSize)
const startY = -Math.ceil(stageY / scaleY / cellSize)
const group = new Konva.Group()
group.add(
new Konva.Rect({
name: this.constructor.name,
x: 0,
y: 0,
width: width,
height: height,
stroke: 'rgba(255,0,0,0.1)',
strokeWidth: 2 / scaleY,
listening: false,
dash: [4, 4]
})
)
// 竖线
for (let x = startX; x < lenX + startX + 1; x++) {
group.add(
new Konva.Line({
name: this.constructor.name,
points: _.flatten([
[cellSize * x, -stageY / scaleY],
[cellSize * x, (height - stageY) / scaleY]
]),
stroke: '#ddd',
strokeWidth: 1 / scaleY,
listening: false
})
)
}
// 横线
for (let y = startY; y < lenY + startY + 1; y++) {
group.add(
new Konva.Line({
name: this.constructor.name,
points: _.flatten([
[-stageX / scaleX, cellSize * y],
[(width - stageX) / scaleX, cellSize * y]
]),
stroke: '#ddd',
strokeWidth: 1 / scaleX,
listening: false
})
)
}
this.group.add(group)
关于“比例尺”,与“网格背景”思路差不多,在绘制“刻度”和“数值”的时候相对麻烦一些,例如绘制“数值”的时候,需要动态判断应该使用多大的字体。
let fontSize = fontSizeMax
const text = new Konva.Text({
name: this.constructor.name,
y: this.option.size / scaleY / 2 - fontSize / scaleY,
text: (x * cellSize).toString(),
fontSize: fontSize / scaleY,
fill: '#999',
align: 'center',
verticalAlign: 'bottom',
lineHeight: 1.6
})
while (text.width() / scaleY > (cellSize / scaleY) * 4.6) {
fontSize -= 1
text.fontSize(fontSize / scaleY)
text.y(this.option.size / scaleY / 2 - fontSize / scaleY)
}
text.x(nx - text.width() / 2)
关于“拖拽”,这里设计的是通过鼠标右键拖拽画布,通过记录 mousedown 时 Konva.stage 起始位置、鼠标位置,mousemove 时将鼠标位置偏移与Konva.stage 起始位置计算最新的 Konva.stage 的位置即可。
mousedown: (e: Konva.KonvaEventObject<GlobalEventHandlersEventMap['mousedown']>) => {
if (e.evt.button === Types.MouseButton.右键) {
// 鼠标右键
this.mousedownRight = true
this.mousedownPosition = { x: this.render.stage.x(), y: this.render.stage.y() }
const pos = this.render.stage.getPointerPosition()
if (pos) {
this.mousedownPointerPosition = { x: pos.x, y: pos.y }
}
document.body.style.cursor = 'pointer'
}
},
mouseup: () => {
this.mousedownRight = false
document.body.style.cursor = 'default'
},
mousemove: () => {
if (this.mousedownRight) {
// 鼠标右键拖动
const pos = this.render.stage.getPointerPosition()
if (pos) {
const offsetX = pos.x - this.mousedownPointerPosition.x
const offsetY = pos.y - this.mousedownPointerPosition.y
this.render.stage.position({
x: this.mousedownPosition.x + offsetX,
y: this.mousedownPosition.y + offsetY
})
// 更新背景
this.render.draws[Draws.BgDraw.name].draw()
// 更新比例尺
this.render.draws[Draws.RulerDraw.name].draw()
}
}
}
关于“缩放”,可以参考 konva 官网的缩放示例,思路是差不多的,只是根据实际情况调整了逻辑。
接下来,计划增加下面功能:
- 坐标参考线
- 从左侧图片素材拖入节点
- 鼠标、键盘移动节点
- 鼠标、键盘单选、多选节点
- 键盘复制、粘贴
- 节点层次单个、批量调整
- 等等。。。
如果 github Star 能超过 20 个,将很快更新下一篇章。
源码在这,望多多支持
前端使用 Konva 实现可视化设计器(1)的更多相关文章
- 惊闻企业Web应用生成平台 活字格 V4.0 免费了,不单可视化设计器免费,服务器也免费!
官网消息: 针对活字格开发者,新版本完全免费!您可下载活字格 Web 应用生成平台 V4.0 Updated 1,方便的创建各类 Web 应用系统,任意部署,永不过期. 我之前学习过活字格,也曾经向用 ...
- (原创)【B4A】一步一步入门02:可视化界面设计器、控件的使用
一.前言 上篇 (原创)[B4A]一步一步入门01:简介.开发环境搭建.HelloWorld 中我们创建了默认的项目,现在我们来看一下B4A项目的构成,以及如何所见即所得的设计界面,并添加和使用自带的 ...
- Windows Phone 十二、设计器同步
在设计阶段为页面添加数据源 Blend或者VS的可视化设计器会跑我们的代码,然后来显示出来,当我们Build之后,设计器会进入页面的构造函数,调用InitializeComponent();方法来将U ...
- WinForms项目升级.Net Core 3.0之后,没有WinForm设计器?
目录 .NET Conf 2019 Window Forms 设计器 .NET Conf 2019 2019 9.23-9.25召开了 .NET Conf 2019 大会,大会宣布了 .Net Cor ...
- ActiveReports 9 新功能:可视化查询设计器(VQD)介绍
在最新发布的ActiveReports 9报表控件中添加了多项新功能,以帮助你在更短的时间里创建外观绚丽.功能强大的报表系统,本文将重点介绍可视化数据查询设计器,无需手动编写任何SQL语句,主要内容如 ...
- VS2015 android 设计器不能可视化问题解决。
近期安装了VS2015,体验了一下android 的开发,按模板创建执行了个,试下效果非常不错.也能够可视化设计.但昨天再次打开或创建一个android程序后,设计界面直接不能显示,显示错误:(可能是 ...
- 可视化流程设计——流程设计器演示(基于Silverlight)
上一篇文章<通用流程设计>对鄙人写的通用流程做了一定的介绍,并奉上了相关源码.但一个好的流程设计必少不了流程设计器的支持,本文将针对<通用流程设计>中的流程的设计器做一个简单的 ...
- Type Script 在流程设计器的落地实践
流程设计器项目介绍 从事过BPM行业的大佬必然对流程建模工具非常熟悉,做为WFMC三大体系结构模型中的核心模块,它是工作流的能力模型,其他模块都围绕工作流定义来构建. 成熟的建模工具通过可视化的操作界 ...
- .net erp(办公oa)开发平台架构概要说明之表单设计器
背景:搭建一个适合公司erp业务的开发平台. 架构概要图: 表单设计开发部署示例图 表单设计开发部署示例说明1)每个开发人员可以自己部署表单设计至本地一份(当然也可以共用一套开发环境,但是如 ...
- 解析大型.NET ERP系统核心组件 查询设计器 报表设计器 窗体设计器 工作流设计器 任务计划设计器
企业管理软件包含一些公共的组件,这些基础的组件在每个新项目立项阶段就必须考虑.核心的稳定不变功能,方便系统开发与维护,也为系统二次开发提供了诸多便利.比如通用权限管理系统,通用附件管理,通用查询等组件 ...
随机推荐
- git回退至指定版本,并更新远程仓库
1. git log 查到commit记录 2.复制 commit 后面的id 3. git reset --hard commit 后面的id // 回退 4. 强制更新远程仓库 git ...
- 阿里云 SMS 短信 Java SDK 封装
Github & Issues: https://github.com/cn-src/aliyun-sms 官方文档:https://help.aliyun.com/document_deta ...
- 用Taro写一个微信小程序——Taro3路由传参
参考https://docs.taro.zone/docs/router 1.传入参数 Taro.navigateTo({ url: '/pages/page/path/name?id=2&t ...
- python操作txt文件,去除文件中的隔行空行
conn = re.sub(result, '\r\n', content) res = "".join( [s for s in conn.strip().splitlines( ...
- Long和int比较用==还是用equals
应该用==,因为equels会先比较类型,这样值一样的不同类型的数字就直接返回false啦.看源码吧. public boolean equals(Object obj) { System.out.p ...
- 【Azure Redis 缓存】遇见Azure Redis不能创建成功的问题:至少一个资源部署操作失败,因为 Microsoft.Cache 资源提供程序未注册。
问题描述 在中国区微软云上创建Redis失败.收到的错误消息为: { "code": "DeploymentFailed", "message&quo ...
- 【Azure Developer】使用 Azure Python 查看 Azure 所有的 Alert rule
问题描述 在Azure Alert 门户中,可以列举出所有Azure资源的Alert rule信息,如下图: 如果像通过Python SDK来获取所有的Alert Rule,有什么可以参考的代码吗? ...
- 「实操」适配 NebulaGraph 新版本与压测实践
本文来自邦盛科技-知识图谱团队-繁凡,本文以 NebulaGraph v3.1.0 为例. 前言 NebulaGraph v3.1 版本已经发布有一段时间了,但是我们的项目之前是基于 v2.6.1 版 ...
- kafka 为什么能那么快?高效读写数据,原来是这样做到的
1. 利用 Partition 实现并行处理 我们都知道 Kafka 是一个 Pub-Sub 的消息系统,无论是发布还是订阅,都要指定 Topic. Topic 只是一个逻辑的概念.每个 Topic ...
- zookeeper源码(10)node增删改查及监听
本文将从leader处理器入手,详细分析node的增删改查流程及监听器原理. 回顾数据读写流程 leader ZookeeperServer.processPacket封装Request并提交给业务处 ...