使用 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. win32 - service的创建

    参考这篇教程:Simple Windows Service in C++ 安装service需要在管理员权限下运行cmd,并输入下面的命令行 C:\>sc create "My Sam ...

  2. golang常用库包:redis操作库go-redis使用(03)-高级数据结构和其它特性

    Redis 高级数据结构操作和其它特性 第一篇:go-redis使用,介绍Redis基本数据结构和其他特性,以及 go-redis 连接到Redis https://www.cnblogs.com/j ...

  3. 2021-07-20 JavaScript中关于eval()方法

    eval()常见用途 1.使用ajax获取到后台返回的json数据时,使用 eval 这个方法将json字符串转换成对象数组 let jsonString = JSON.stringify({fang ...

  4. 麒麟系统开发笔记(四):从Qt源码编译安装之编译安装QtCreator4.8.1,并配置编译测试Demo

    前言   本篇紧接上一篇,上一篇已经从Qt源码编译了Qt,那么Qt开发的IDE为QtCreator,本篇从源码编译安装QtCreator,并配置好构建套件,运行Demo并测试.   QtCreator ...

  5. GPS坐标系转换 go golang 版本

    GPS坐标系转换 坐标系 解释 WGS84坐标系 地球坐标系,国际通用坐标系 GCJ02坐标系 火星坐标系,WGS84坐标系加密后的坐标系:Google国内地图.高德.腾讯地图 使用 BD09坐标系 ...

  6. 第一百一十八篇: JavaScript 原型链式继承

    好家伙,好家伙,本篇为<JS高级程序设计>第八章"对象.类与面向对象编程"学习笔记 1.原型链 原型链是JS实现"继承"的方案之一 ECMA-262 ...

  7. 【Azure 应用服务】App Services 恶意软件防护相关

    问题描述 App Services 恶意软件防护相关资料,App Service是否默认开启病毒防护呢? 问题解答 App Services 默认启用了Antimalware 软件功能,Microso ...

  8. SPFA最短路

    目录 从Bellman-Ford开始 核心思想 模拟算法执行过程 时间复杂度 模板 spfa spfa优化的思想 模板 从Bellman-Ford开始 对于所有边权都大于等于0的图,任意两个顶点之间的 ...

  9. 告别os.path,拥抱pathlib

    pathlib 模块是在Python3.4版本中首次被引入到标准库中的,作为一个可选模块.从Python3.6开始,内置的 open 函数以及 os . shutil 和 os.path 模块中的各种 ...

  10. .vscode/extensions.json 是项目用到的 插件 推荐列表,项目应该将此配置 写入用到的插件

    .vscode/extensions.json 是项目用到的 插件 推荐列表,项目应该将此配置 写入用到的插件 .vscode/extensions.json { "recommendati ...