图片标注编辑平台搭建系列教程(3)——画布拖拽、缩放实现

简介

标注平台很关键的一点,对于整个图片为底图的画布,需要支持缩放、拖拽,并且无论画布位置在哪里,大小如何,所有绘制的点、线、面的坐标都是相对于图片左上角的,并且,拖拽、缩放,点、线、面的坐标不改变。

要实现这一点,其实就是理解这个画布的坐标系,以及变换矩阵。

画布

fabric.js的底层是canvas绘图。canvas作为画布,要支持拖拽、缩放,就需要有个容器监听鼠标事件。如果我们直接对canvas dom进行拖拽、缩放,有两个缺陷:1是后续只能在最新的canvas范围内进行缩放、拖拽,不易点击;2是dom大小和位置变更,会不断触发浏览器的重绘,性能开销较大,容易卡顿。

为了解决上述问题,我提供以下解决方案:

以一个固定位置的canvas作为画布,拖拽、缩放,只改变canvas的变形矩阵即可transform(a, b, c, d, e, f)。

a:水平方向的缩放;b:竖直方向的倾斜偏移;c:水平方向的倾斜偏移;d:竖直方向的缩放;e:水平方向的移动;f:竖直方向的移动

因此,我们的平移可以通过设置e和f,缩放可以通过设置a和d。

在fabric.js中,可以通过viewportTransform属性,获取这六个参数。然后再通过setViewportTransform方法,设置这六个参数。

居中

画布居中是标注平台必须的功能,因为你拖拽缩放后图像可能偏离视图范围很多,需要快速复原。居中的功能,说起来简单,但是实现还是有一些困难。其原理如下图所示。

首先,获取要标注的图片,宽100,高80,设置canvas的背景图片。

const canvas = new fabric.Canvas(domId, {
    width: 100,
    height: 80
}); 
canvas.setBackgroundImage('图片链接');

其次,初始化canvas的为父容器的宽高(100x60),初始化变换矩阵[1,0,0,1,0,0],即平移0,缩放1(不缩放)。

canvas.setDimensions({ width: 100, height: 60 });
canvas.setViewportTransform([1,0,0,1,0,0]);

再次,根据canvas父容器的宽高(100x60),按图像能全展示的比例对canvas视图范围进行等比缩放(0.75),得到新的宽高75x60。即a=0.75,d=0.75。

canvas.setCanvasZoom(0.75);

最后,将canvas视图范围往右平移15,即e=15,f=0。

canvas.setViewportTransform[0.75,0,0,0.75,15,0]

这样,我们的canvas始终是父容器的范围,而viewport范围已经居中。

注意,变换矩阵设置后,还需要执行渲染重置方法,这个是fabric的底层逻辑漏洞,如果不重置,画布上的点线面的位置会偏移。

canvas.renderAndReset();

平移

首先,我们需要监听canvas的mousedown、mousemove、mouseup。

mousedown的回调函数,我们设置全局变量active为true(用于mousemove判断是否需要执行平移),并记录lastX = e.pageX和lastY = e.pageY。

mousemove的回调函数,如果active为true,我们根据e.pageX - lastX和e.pageY - lastY确定横向和纵向的平移量,再通过对transform的e和f进行叠加这个平移量,实现平移功能。

mouseup的回调函数,设置acitve为false。

缩放

监听canvas的wheel,鼠标滚轮事件。

wheel的回调函数,如果e.deltaY > 0,则表示缩小,否则表示放大。缩小,我们对当前的缩放比例统一进行 -0.1,放大统一 +0.1。如果你想更人性化,可以对缩放比例做非线性的变化。

注意点

canvas的缩放,是基于canvas左上角的原点,并非基于平移后的点为原点。因此,需要先将canvas的平移参数置为0后,再设置缩放比例。

另外,我们的缩放,是基于鼠标当前位置为原点进行缩放。如图,红色点处(x, y)进行缩放,视图从v1变到v2,我们已知两个视图对应的缩放比例z1和z2,要求deltaX和deltaY,根据相似定理得:

deltaX = (x - left) * (1 - z2 / z1)

deltaY = (y - top) * (1 - z2 / z1)

newLeft = deltaX + left

newTop = deltaY + top

因此,我们在上一步设置好缩放比例后,执行平移操作(e=newLeft,f=newTop),从而将视图从黑色框缩放至蓝色框。

预告

下一章, 聊聊fabric的几何定制化渲染。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/496806.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从零开始学习在VUE3中使用canvas(六):线条样式(线条宽度lineWidth,线条端点样式lineCap)

一、线条宽度lineWidth 1.1简介 值为一个数字 const ctx canvas.getContext("2d"); ctx.lineWidth 6; 1.2效果展示 1.3全部代码 <template><div class"canvasPage"><!-- 写一个canvas标签 --><canvas class"main" r…

图像处理与视觉感知---期末复习重点(5)

文章目录 一、膨胀与腐蚀1.1 膨胀1.2 腐蚀 二、开操作与闭操作 一、膨胀与腐蚀 1.1 膨胀 1. 集合 A A A 被集合 B B B 膨胀&#xff0c;定义式如下。其中集合 B B B 也称为结构元素&#xff1b; ( B ^ ) z (\hat{B})z (B^)z 表示 B B B 的反射平移 z z z 后得到的新集合。…

冥想打坐睡觉功法

睡觉把手机放远一点&#xff0c;有电磁辐射&#xff0c;我把睡觉功法交给你&#xff0c;这样就可以睡好了。

55、Qt/事件机制相关学习20240326

一、代码实现设置闹钟&#xff0c;到时间后语音提醒用户。示意图如下&#xff1a; 代码&#xff1a; #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), speecher(new QTextToSpeech(t…

C++超市商品管理系统

一、简要介绍 1.本项目为面向对象程序设计的大作业&#xff0c;基于Qt creator进行开发&#xff0c;Qt框架版本6.4.1&#xff0c;编译环境MINGW 11.2.0。 2.项目结构简介&#xff1a;关于系统逻辑部分的代码的头文件在head文件夹中&#xff0c;源文件在s文件夹中。与图形界面…

权限提升-Win系统权限提升篇AD内网域控NetLogonADCSPACKDCCVE漏洞

知识点 1、WIN-域内用户到AD域控-CVE-2014-6324 2、WIN-域内用户到AD域控-CVE-2020-1472 3、WIN-域内用户到AD域控-CVE-2021-42287 4、WIN-域内用户到AD域控-CVE-2022-26923 章节点&#xff1a; 1、Web权限提升及转移 2、系统权限提升及转移 3、宿主权限提升及转移 4、域控权…

Git命令上传本地项目至github

记录如何创建个人仓库并上传已有代码至github in MacOS环境 0. 首先下载git 方法很多 这里就不介绍了 1. Github Create a new repository 先在github上创建一个空仓库&#xff0c;用于一会儿链接项目文件&#xff0c;按照自己的需求设置name和是否private 2.push an exis…

指针数组的有趣程序【C语言】

文章目录 指针数组的有趣程序指针数组是什么&#xff1f;指针数组的魅力指针数组的应用示例&#xff1a;命令行计算器有趣的颜色打印 结语 指针数组的有趣程序 在C语言的世界里&#xff0c;指针是一种强大的工具&#xff0c;它不仅能够指向变量&#xff0c;还能指向数组&#…

如何利用OpenCV4.9离散傅里叶变换

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:如何利用OpenCV4.9 更改图像的对比度和亮度 下一篇:OpenCV 如何使用 XML 和 YAML 文件的文件输入和输出 目标 我们将寻求以下问题的答案&#xff1a; 什么是傅里叶变换&#xff0c;为什…

《数据结构学习笔记---第五篇》---链表OJ练习下

step1:思路分析 1.实现复制&#xff0c;且是两个独立的复制&#xff0c;我们必须要理清指针之间的逻辑&#xff0c;注意random的新指针要链接到复制体的后面。 2.我们先完成对于结点的复制&#xff0c;并将复制后的结点放在原节点的后面&#xff0c;并链接。 3.完成random结点…

黑马鸿蒙笔记1

这里与前端类似。

斜率优化dp 笔记

任务安排1 有 N 个任务排成一个序列在一台机器上等待执行&#xff0c;它们的顺序不得改变。 机器会把这 N 个任务分成若干批&#xff0c;每一批包含连续的若干个任务。 从时刻 00 开始&#xff0c;任务被分批加工&#xff0c;执行第 i 个任务所需的时间是 Ti。 另外&#x…

PHP开发全新29网课交单平台源码修复全开源版本,支持聚合登陆易支付

这是一套最新版本的PHP开发的网课交单平台源代码&#xff0c;已进行全开源修复&#xff0c;支持聚合登录和易支付功能。 项目 地 址 &#xff1a; runruncode.com/php/19721.html 以下是对该套代码的主要更新和修复&#xff1a; 1. 移除了论文编辑功能。 2. 移除了强国接码…

linux之进程

一、背景 冯.诺依曼体系结构 输入设备键盘、鼠标、摄像头、话筒、磁盘、网卡...输出设备显示器、声卡、磁盘、网卡...CPU运算器、控制器存储器一般就是内存 数据在计算机的体系结构进行流动&#xff0c;流动过程中&#xff0c;进行数据的加工处理&#xff0c;从一个设备到另一…

网上兼职赚钱攻略:六种方式让你轻松上手

在互联网时代&#xff0c;网上兼职已经成为一种非常流行的赚钱方式。对于许多想要在家里挣钱的人来说&#xff0c;网上兼职不仅可以提供灵活的工作时间&#xff0c;还可以让他们在自己的兴趣领域中寻求机会&#xff0c;实现自己的财务自由。 在这里&#xff0c;我将为您介绍六…

OpenGL 实现“人像背景虚化“效果

手机上的人像模式,也被人们称作“背景虚化”或 ”双摄虚化“ 模式,也称为 Bokeh 模式,能够在保持画面中指定的人或物体清晰的同时,将其他的背景模糊掉。突出画面的主体部分,主观上美感更强烈。 人像模式的一般实现原理是,利用双摄系统获取景深信息,并通过深度传感器和图…

带流量主功能的外卖菜谱小程序源码:助你轻松领取优惠券,个人使用也可通过审查

外卖菜谱小程序源码-带流量主功能-外卖领劵个人也可过审 这套小程序优点就带很多菜谱&#xff0c;各种你爱吃菜的做法与各类食材介绍营养搭配&#xff0c;相信很多小姐姐会感兴趣。 宝妈宝爸这个小程序肯定能留的住这个群体的人脉流量&#xff0c;这是小程序最大的亮点&#…

深圳区块链交易所app系统开发,撮合交易系统开发

随着区块链技术的迅速发展和数字资产市场的蓬勃发展&#xff0c;区块链交易所成为了数字资产交易的核心场所之一。在这个快速发展的领域中&#xff0c;区块链交易所App系统的开发和撮合交易系统的建设至关重要。本文将探讨区块链交易所App系统开发及撮合交易系统的重要性&#…

【QGIS从shp文件中筛选目标区域导出为shp】

文章目录 1、写在前面2、QGIS将shp文件中目标区域输出为shp2.1、手动点选2.2、高级过滤 3、上述shp完成后&#xff0c;配合python的shp文件&#xff0c;即可凸显研究区域了 1、写在前面 利用shp文件制作研究区域mask&#xff0c;Matlab版本&#xff0c;请点击 Matlab利用shp文…

【Leetcode】单链表常见题

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;Leetcode刷题 本节内容我们来讲解常见的几道单链表的题型&#xff0c;文末会赋上单链表增删查&#xff0c;初始化等代码 目录 1.移除链表元素2.链表的中间节点3.返回倒数第K个节点&#xff1a;4.环…