使用 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)的更多相关文章

  1. 惊闻企业Web应用生成平台 活字格 V4.0 免费了,不单可视化设计器免费,服务器也免费!

    官网消息: 针对活字格开发者,新版本完全免费!您可下载活字格 Web 应用生成平台 V4.0 Updated 1,方便的创建各类 Web 应用系统,任意部署,永不过期. 我之前学习过活字格,也曾经向用 ...

  2. (原创)【B4A】一步一步入门02:可视化界面设计器、控件的使用

    一.前言 上篇 (原创)[B4A]一步一步入门01:简介.开发环境搭建.HelloWorld 中我们创建了默认的项目,现在我们来看一下B4A项目的构成,以及如何所见即所得的设计界面,并添加和使用自带的 ...

  3. Windows Phone 十二、设计器同步

    在设计阶段为页面添加数据源 Blend或者VS的可视化设计器会跑我们的代码,然后来显示出来,当我们Build之后,设计器会进入页面的构造函数,调用InitializeComponent();方法来将U ...

  4. WinForms项目升级.Net Core 3.0之后,没有WinForm设计器?

    目录 .NET Conf 2019 Window Forms 设计器 .NET Conf 2019 2019 9.23-9.25召开了 .NET Conf 2019 大会,大会宣布了 .Net Cor ...

  5. ActiveReports 9 新功能:可视化查询设计器(VQD)介绍

    在最新发布的ActiveReports 9报表控件中添加了多项新功能,以帮助你在更短的时间里创建外观绚丽.功能强大的报表系统,本文将重点介绍可视化数据查询设计器,无需手动编写任何SQL语句,主要内容如 ...

  6. VS2015 android 设计器不能可视化问题解决。

    近期安装了VS2015,体验了一下android 的开发,按模板创建执行了个,试下效果非常不错.也能够可视化设计.但昨天再次打开或创建一个android程序后,设计界面直接不能显示,显示错误:(可能是 ...

  7. 可视化流程设计——流程设计器演示(基于Silverlight)

    上一篇文章<通用流程设计>对鄙人写的通用流程做了一定的介绍,并奉上了相关源码.但一个好的流程设计必少不了流程设计器的支持,本文将针对<通用流程设计>中的流程的设计器做一个简单的 ...

  8. Type Script 在流程设计器的落地实践

    流程设计器项目介绍 从事过BPM行业的大佬必然对流程建模工具非常熟悉,做为WFMC三大体系结构模型中的核心模块,它是工作流的能力模型,其他模块都围绕工作流定义来构建. 成熟的建模工具通过可视化的操作界 ...

  9. .net erp(办公oa)开发平台架构概要说明之表单设计器

    背景:搭建一个适合公司erp业务的开发平台.   架构概要图: 表单设计开发部署示例图    表单设计开发部署示例说明1)每个开发人员可以自己部署表单设计至本地一份(当然也可以共用一套开发环境,但是如 ...

  10. 解析大型.NET ERP系统核心组件 查询设计器 报表设计器 窗体设计器 工作流设计器 任务计划设计器

    企业管理软件包含一些公共的组件,这些基础的组件在每个新项目立项阶段就必须考虑.核心的稳定不变功能,方便系统开发与维护,也为系统二次开发提供了诸多便利.比如通用权限管理系统,通用附件管理,通用查询等组件 ...

随机推荐

  1. error C2039: "function": 不是 "std" 的成员的解决方法

    这个错误通过某度没找到合适的解决方案,故记录下来 其实如果使用 google 搜索错误的英文关键词,大概第一条就是解决问题的链接 Large number of "'function' is ...

  2. centos7 安装vmware tool 遇到遇到 kernel-headers 问题修复

    安装 vmware tool 步骤 1. cp VMwareTools-10.3.25-20206839.tar.gz 到 用户目录下 2. tar zxf VMwareTools-10.3.25-2 ...

  3. 【Android逆向】apk 反编译

    1. Kali搭建apktool环境 1. 访问apktool 官网https://ibotpeaches.github.io/Apktool/install/ 参考红圈里的步骤处理即可 2. 执行命 ...

  4. 万字Java进阶笔记总结

    JavaApi 字符串 String 注意:Java中"=="操作符的作用: 基本数据类型:比较的是内容. 引用数据类型比较的是对象的内存地址. StringBuffer/Stri ...

  5. java+文件实现的超市管理系统

    一.需求 1.使用java语言实现系统 2.数据存储使用io读写文件 3.超市的商品管理+销售功能 二.效果 商品列表 商品增删改查 购买 三.说明 1.开发工具/技术 java  eclipse 2 ...

  6. BIGO 的数据管理与应用实践

    本文首发于 Nebula Graph Community 公众号 本文整理自 BIGO 在 nMeetp 上的主题分享,主要介绍 BIGO 过去一年在数据管理建设方面的理解和探索.而 BIGO 数据管 ...

  7. 记一次dockerfile无法构建问题追溯

    我有一个dockerfile如下: ENTRYPOINT ["/sbin/tini","-g", "--"] CMD /home/scrap ...

  8. .NET周刊【3月第1期 2024-03-03】

    国内文章 推荐10款C#开源好用的Windows软件 https://www.cnblogs.com/Can-daydayup/p/18035760 DevToys.Microsoft PowerTo ...

  9. Java 封装性的四种权限测试 + 总结

    *    总结封装性:Java提供了4中权限修饰符来修饰类及类的内部结构,体现类及类的内部结构再被调用时的可见性的大小 1 package com.bytezero.circle; 2 3 publi ...

  10. WAF和IPS的区别

    简介 Web应用防火墙WAF(Web Application Firewall)和入侵防御系统IPS(Intrusion Prevention System)是网络安全领域中常见的两种安全解决方案,它 ...