图片标注编辑平台搭建系列教程(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的几何定制化渲染。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

远程技术支持软件方案如何帮助一线客服提升效率?

远程控制在企业远程技术支持体系中,是非常主流的方案,而优秀的远程控制方案本身,就可以非常直观的帮助一线技术支持员工提升效率,降低时间与人力成本,其中向日葵技术支持解决方案就是很好的例子,这里我们来…

厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件开发之功能原理篇

接着上一篇《厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件开发之功能结构篇》继续总结一下厨余垃圾处理设备智能软硬件统的原理。所有的软硬件系统全是自己一人独自开发,看法和角度难免有局限性。希望抛砖引玉,将该智能软硬件系统分享给更多有类…

FPGA结构与片上资源

文章目录 0.总览1.可配置逻辑块CLB1.1 6输入查找表(LUT6)1.2 选择器(MUX)1.3 进位链(Carry Chain)1.4 触发器(Flip-Flop) 2.可编程I/O单元2.1 I/O物理级2.2 I/O逻辑级 3.布线资源4.其…

【STM32CubeMX(3)】GPIO上拉输入——读取按键状态

通过本节可以学习到: 如何在CubeMX配置上拉输入什么是上拉输入如何读取一个GPIO的输入状态 软件环境: STM32CubeMX version6.10.0 Keil_v5(MDK-ARM) version 5.32 硬件环境: STM32F103C8T6最小系统板(…

windwos权限维持

1.php 不死马权限维持 <?php ignore_user_abort(); //关掉浏览器&#xff0c;PHP脚本也可以继续执行. set_time_limit(0);//通过set_time_limit(0)可以让程序无限制的执行下去 $interval 5; // 每隔*秒运行 do { $filename test.php; if(file_exists($filename)) { echo…

深入探讨多线程编程:从0-1为您解释多线程(下)

文章目录 6. 死锁6.1 死锁原因 6.2 避免死锁的方法加锁顺序一致性。超时机制。死锁检测和解除机制。 6. 死锁 6.1 死锁 原因 系统资源的竞争&#xff1a;&#xff08;产生环路&#xff09;当系统中供多个进程共享的资源数量不足以满足进程的需要时&#xff0c;会引起进程对2…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 3月29日,星期五

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年3月29日 星期五 农历二月二十 1、 网络表演&#xff08;直播与短视频&#xff09;运营团体标准发布&#xff1a;应建立举报处置机制。 2、 商务部&#xff1a;中国决定终止对澳大利亚进口葡萄酒征收反倾销税和反补贴税。…

编程语言|C语言——数组与指针

一、数组 同一类型的变量——元素&#xff08;element&#xff09;集中在一起&#xff0c;在内存上排列成一条直线&#xff0c;这就是数组&#xff08;array&#xff09;。 1.1 一维数组 一维数组的声明 int arr1[10]; int arr2[2 8];#define N 10 int arr3[N];int count 10;…

深度学习 - PyTorch基本流程 (代码)

直接上代码 import torch import matplotlib.pyplot as plt from torch import nn# 创建data print("**** Create Data ****") weight 0.3 bias 0.9 X torch.arange(0,1,0.01).unsqueeze(dim 1) y weight * X bias print(f"Number of X samples: {len(…

蓝桥杯2016年第十三届省赛真题-生日蜡烛

一、题目 生日蜡烛. 某君从某年开始每年都举办一次生日party&#xff0c;并且每次都要吹熄与年龄相同根数的蜡烛。 现在算起来&#xff0c;他一共吹熄了236根蜡烛。 请问&#xff0c;他从多少岁开始过生日party的&#xff1f; 请填写他开始过生日party的年龄数。 注意&#xff…

python笔记(6)String(字符串)

目录 访问字符串中的值 Python字符串运算符 Python 字符串格式化 str.format() 数字格式化 多行注释 f-string Unicode 字符串 Python 的字符串内建函数 我们可以用单引号或者双引号"来创建字符串。 创建字符串很简单&#xff0c;给变量分配一个值即可例如 ahell…

基于资源的约束委派(下)

webclient http self relay Web 分布式创作和版本控制 (WebDAV) 是超文本传输协议 (HTTP) 的扩展&#xff0c;它定义了如何使用 HTTP ( docs.microsoft.com )执行复 制、移动、删除和创建等基本文件功能 需要启用 WebClient 服务才能使基于 WebDAV 的程序和功能正常工作。事实…

全国中学基础信息 API 数据接口

全国中学基础信息 API 数据接口 基础数据&#xff0c;高校高考&#xff0c;提供全国初级高级中学基础数据&#xff0c;定时更新&#xff0c;多维度筛选。 1. 产品功能 2024 年数据已更新&#xff1b;提供最新全国中学学校基本信息&#xff1b;包含全国初级中学与高等中学&…

Rust机器学习框架Candle

一、概述 Candle 是由知名开源组织 Hugging Face 开发的一个极简的机器学习框架。它专为 Rust 语言打造&#xff0c;致力于提供高性能和易用性的完美结合。Candle 的诞生为 Rust 生态在机器学习领域带来了新的选择&#xff0c;让 Rust 开发者能够更轻松地构建和部署机器学习应…

家庭琐事对工作效率的影响及应对策略

在快节奏的现代生活中&#xff0c;工作与家庭生活之间的界限日益模糊&#xff0c;人们往往难以将两者完全割裂开来。有时候&#xff0c;我们正在全身心投入工作时&#xff0c;却可能被突如其来的家庭琐事打扰&#xff0c;这不仅影响了心情&#xff0c;更会波及到工作效率和质量…

silk-v3-decoder将sil转为mp3

一、新建临时目录 新建临时目录&#xff0c;可自定义&#xff0c;本次新建目录为 /opt/packages mkdir /opt/packages二、下载、安装lame # cd /opt/packages# wget http://downloads.sourceforge.net/lame/lame-3.100.tar.gz# tar -zxvf lame-3.100.tar.gz# cd lame-3.100#…

git之目前的主流版本

官方文档 简介 我们都知道&#xff0c;在开发过程中&#xff0c;版本控制是至关重要的。Git作为目前最为流行的版本控制系统&#xff0c;已经成为了开发者们的标配。出于好奇&#xff0c;本人对git目前主流几大版本&#xff08;GitLab、GitHub、Gitee 和 GitCode&#xff09;…

虚拟现实(VR)项目的开发工具

虚拟现实&#xff08;VR&#xff09;项目的开发涉及到多种工具&#xff0c;这些工具可以帮助开发者从建模、编程到最终内容的发布。以下是一些被广泛认可的VR开发工具&#xff0c;它们覆盖了从3D建模到交互设计等多个方面。北京木奇移动技术有限公司&#xff0c;专业的软件外包…

取消svn关联脚本

写在前面&#xff0c;该脚本由朋友提供&#xff0c;来源与网络&#xff0c;侵删。 取消svn关联脚本 创建一个文件&#xff0c;后缀名为reg&#xff0c;将下面的脚本复制到文件里。 Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shel…

spring boot中使用spring cache

原因 项目原来越慢&#xff0c;为了提升效率加入spring cache 初步想法把数据库的压力减轻一点。 引入 pom 中加入&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId&g…