图片标注编辑平台搭建系列教程(4)——fabric几何定制渲染

news2024/10/10 2:17:19

背景

标注的几何,有时需要一些定制化的渲染样式,例如,线中间展示箭头,表示方向。本期教程教大家如何实现fabric几何定制化渲染。

带箭头的线

fabric提供了一些原生的几何,例如Point、Polyline、Polygon。同时提供了一些抽象的实体,如Object、Path。

如果使用原生的几何,可配置的样式是有限的。

比如Point的配置是:

{
    radius: 5,
    stroke: 'rgba(0,0,0,1)',
    strokeWidth: 2,
    fill: 'rgba(255,0,0,1)'
}

Polyline的配置是:

{
    stroke: 'rgba(0,0,0,1)',
    strokeWidth: 5
}

Polygon的配置是:

{
    fill: 'rgba(255,0,0,0,3)',
    strokeWidth: 1
}

可见这些线宽、线颜色、填充色等并不能实现箭头样式,需要对这些类进行扩展。

fabric提供了方法,可以扩展原生几何,代码如下:

export const NewPolyline = fabric.util.createClass(fabric.Polyline, {
  type: 'NewPolyline',

  initialize: function (points: any = [], options: any = {}) {
    this.callSuper('initialize', points, { ...options }); // 调用Polyline的初始化方法
  },
  
  _render: function (ctx: any) {
    // 自定义渲染,每次canvas.renderAll()都会触发该方法。
    this.callSuper('_render', ctx);
  }
}

此时我们得到了一个新的fabric几何类型:NewPolyline。其初始化参数和Polyline一致,points是点序,options里设置其样式。

而箭头样式,需要在_render方法里实现。_render方法可以拿到ctx,即canvas的实例,我们可以利用ctx进行各种绘制操作。

注意:在_render这个步骤,每个几何都有自己的坐标系,其坐标系原点是几何的外接矩形的中心点。

因此,我们每个坐标都需要减去当前几何的width/2和height/2,进行原点平移。

举个例子,比如我们有一条线,其参数如下:

{
    left: 10,
    top: 10,
    points: [{x: 0, y: 0}, {x: 5, y: 0}, {x: 5, y: 5}],
}

在坐标系中,如图,

left和top将要素的坐标系从O移动到了O',在此基础上,绘制折线[[0,0],[5,0],[5,5]]。

在渲染时,fabric又将坐标原点O'平移到外接矩形的中心点O''。

知道坐标系后,我们先来求线段的中点:

const points = this.get('points');
const width = this.get('width');
const height = this.get('height');

for (let i = 0; i < points.length; i++) {
  const midX = (points[i].x + points[i + 1].x) / 2 - width / 2;
  const midY = (points[i].y + points[i + 1].y) / 2 - height / 2;
  console.log(midX, midY);
}

// 结果:
// -2.5, -2.5
// 2.5, -2.5
// 2.5, 2.5

看懂上面的代码,你就可以以线段中心点为中心,画沿着线段的三角形了,代码如下:

for (let i = 0; i < points.length - 1; i++) {
      const midX = (points[i].x + points[i + 1].x) / 2 - width / 2;
      const midY = (points[i].y + points[i + 1].y) / 2 - height / 2;
      const rotate = Math.atan2(points[i + 1].y - points[i].y, points[i + 1].x - points[i].x);
      ctx.moveTo(midX, midY);
      const firstX = midX - (arrowWidth / 2) * Math.sin(rotate);
      const firstY = midY + (arrowWidth / 2) * Math.cos(rotate);
      ctx.lineTo(firstX, firstY);
      const secondX = midX + (arrowWidth / 2) * Math.sqrt(3) * Math.cos(rotate);
      const secondY = midY + (arrowWidth / 2) * Math.sqrt(3) * Math.sin(rotate);
      ctx.lineTo(secondX, secondY);
      const thirdX = midX + (arrowWidth / 2) * Math.sin(rotate);
      const thirdY = midY - (arrowWidth / 2) * Math.cos(rotate);
      ctx.lineTo(thirdX, thirdY);
      ctx.closePath();
      ctx.fill();
 }

效果图如下:

了解这个原理,你就可以利用canvas的绘制操作实现任何的自定义样式。

缩放控制线宽等宽

上一章我们讲到了,画布是可以拖拽和缩放的,本质上是修改canvas的transform。

在每次缩放后,canvas会调用renderAll方法,从而调用每个几何的_render方法。在_render内,我们需要重新计算strokeWidth:

const strokeWidth = 5;
const zoom = canvas.getZoom();
this.set({
    strokeWidth: strokeWidth / zoom
});

这样可以保证每次缩放后,线宽依然维持一个固定值。如果我们不修改线宽,则会被同样得缩放。

预告

下一章,我们详细聊一个极其隐蔽的问题:线居中渲染。

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

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

相关文章

【快速上手ESP32(基于ESP-IDFVSCode)】01-环境配置GPIO口延时函数(先点个灯)

前言 立创开发板之前出了个ESP32S3R8N8的开发板&#xff0c;当时嫖了个优惠券&#xff0c;九块九拿下了。 现在不仅是35.9一个&#xff0c;而且还没货。 如果真的想要的小伙伴可以自己去打板焊一个&#xff0c;人家开源了&#xff08;目测难度较大&#xff0c;反正我是焊不上…

vue-devtools 不显示的问题

vue 项目中浏览器右上角可以显示出插件&#xff0c;但是控制台却没有显示。 项目中在main.js中添加设置devtools为trueVue.config.devtools true插件显示可以使使用&#xff0c;控制台没有显示VUE选项 项目使用了 externals 打包优化&#xff0c;使用了vue的压缩版本&#x…

Etcd 基本入门

1&#xff1a;什么是 Etcd ? Etcd 是 CoreOS 团队于2013年6月发起的开源项目&#xff0c;它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法&#xff0c;Etcd基于 Go 语言实现。 名字由来&#xff0c;它源于两个方面&#xff0c;…

Intel Arc显卡安装Stable Diffusion

StableDiffusion是一种基于深度学习的文本到图像生成模型&#xff0c;于2022年发布。它主要用于根据文本描述生成详细图像&#xff0c;也可应用于其他任务&#xff0c;如内补绘制、外补绘制和在提示词指导下生成图像翻译。通过给定文本提示词&#xff0c;该模型会输出一张匹配提…

Nagios工具

一 nagios 相关概念 Nagios 是一款开源的免费网络监视工具&#xff0c;能有效监控 Windows、Linux 和 Unix 的主机状态&#xff0c;交换机路由器等网络设置&#xff0c;打印机等。在系统或服务状态异常时发出邮件或短信报警第 一时间通知网站运维人员&#xff0c;在状态恢复后…

不愧是字节出来的,真厉害...

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 前段时间公司缺人&#xff0c;也面了许多测试&#xff0c;一开始…

互联网轻量级框架整合之JavaEE基础

不得不解释得几个概念 JavaEE SUN公司提出来的企业版Java开发中间件&#xff0c;主要用于企业级互联网系统的框架搭建&#xff0c;同时因为Java语言优质的平台无关性、可移植性、健壮性、支持多线程和安全性等优势&#xff0c;其迅速成为构建企业互联网平台的主流技术&#x…

4T第十四届省赛模拟2

一、Seg 温度读取&#xff1a; ①温度 温度读他读出来就是有精度的所以自带小数 我们读取的时候直接强制类型转换读它的各个位也不会丢失精度 ②电压 电压是你人为的/51.0了&#xff0c;从char->float->char所以会有精度丢失 所以要用原始数据来换算 在原始数据上多…

web布局——说清楚fixed布局

极限省流 想要fixed做导航页面&#xff1a;指定清楚top、left、right、bottom&#xff0c;没指定清楚布局位置就会采用默认的方式&#xff1a; 0&#xff09;父元素的padding&#xff1a;fixed元素相对位移 1&#xff09;同级元素是fixed元素&#xff1a;覆盖 2&#xff09…

.NET CORE 分布式事务(三) DTM实现Saga及高并发下的解决方案

目录(结尾附加项目代码资源地址) 引言&#xff1a; 1. SAGA事务模式 2. 拆分为子事务 3. 失败回滚 4. 如何做补偿 4.1 失败的分支是否需要补偿 5. 异常 6. 异常与子事务屏障 6.1 NPC的挑战 6.2 现有方案的问题 6.3 子事务屏障 6.4 原理 7. 更多高级场景 7.1 部分…

Golang-Gorm-快速上手

Gorm文档 GORM文档地址 安装依赖 go get -u "gorm.io/driver/mysql"go get -u "gorm.io/gorm"连接数据库 默认连接方式 func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情dsn : "user:passtcp(127.0.0…

Django自动化测试平台项目前端框架设计

引言 在之前根据项目具体情况&#xff0c;开发了一套自动预报数据的平台&#xff0c;但是前端页面不耐看&#xff0c;久了就生厌。于是就想更换前端框架&#xff0c;顺便记录一下。 前端设计 原来的界面&#xff1a; 一键预报模块&#xff1a; 为了有更好的感官体验&#xf…

设计模式——结构型——外观模式Facade

处理器类 public class Cpu {public void start() {System.out.println("处理器启动了...");} } 内存类 public class Memory {public void start() {System.out.println("内存启动了...");} } 硬盘类 public class Disk {public void start() {Syste…

单目图像加单点测距,求解目标位姿

单目图像加单点测距&#xff0c;求解目标位 附赠自动驾驶学习资料和量产经验&#xff1a;链接 单目相机通过对极约束来求解相机运动的位姿。参考了ORBSLAM中单目实现的代码&#xff0c;这里用opencv来实现最简单的位姿估计。 对极约束的概念可以参考我的这篇 Visual SLAM –…

总结TCP各类知识点

前言 本篇博客博主将详细地介绍TCP有关知识点&#xff0c;坐好板凳发车啦~ 一.TCP特点 1.有连接 TCP传输的过程中类似于打电话的各个过程 2.可靠传输 通过TCP自身的多种机制来保证可靠传输 3.面向字节流 内容是以字节的方式来进行发送与接收 4.缓冲区 TCP有接收缓冲区…

谈一谈BEV和Transformer在自动驾驶中的应用

谈一谈BEV和Transformer在自动驾驶中的应用 BEV和Transformer都这么火&#xff0c;这次就聊一聊。 结尾有资料连接 一 BEV有什么用 首先&#xff0c;鸟瞰图并不能带来新的功能&#xff0c;对规控也没有什么额外的好处。 从鸟瞰图这个名词就可以看出来&#xff0c;本来摄像头…

使用启智OpenI平台体验Open-Sora笔记

OpenI准备部分 镜像代码仓 创建云脑任务 新建调试任务 镜像选择 如果不想体验整个安装配置过程的话&#xff0c;我准备了一个Open-Sora的环境镜像应该可以直接开箱即用 地址&#xff1a; 192.168.204.22:5000/default-workspace/99280a9940ae44ca8f5892134386fddb/image:Open…

【C++的奇迹之旅】C++关键字命名空间使用的三种方式C++输入输出命名空间std的使用惯例

文章目录 &#x1f4dd;前言&#x1f320; C关键字(C98)&#x1f309; 命名空间&#x1f320;命名空间定义&#x1f309;命名空间使用 &#x1f320;命名空间的使用有三种方式&#xff1a;&#x1f309;加命名空间名称及作用域限定符&#x1f320;使用using将命名空间中某个成员…

NSGA算法

先给自己叠甲&#xff0c;记录自己的学习过程&#xff0c;如有内容错误欢迎指正!!!。 1. NSGA算法简介&#xff08;Nondominated Sorting Genetic Algorithm&#xff09; 根据标题&#xff0c;NSGA算法分为两个要点&#xff0c;Nondominated Sorting&#xff08;非支配排序&a…

基本数据类型

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 数据类型是一种用于描述数据存储格式的结构。 PL/SQL 和其他编程语言一样也有多种数据类型&#xff0c;PL/SQL 语言中的常用数据类型和 Oracle 数据库中内置的数据类型基本…