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

背景

标注的几何,有时需要一些定制化的渲染样式,例如,线中间展示箭头,表示方向。本期教程教大家如何实现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.hqwc.cn/news/578865.html

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

相关文章

EditStarters使用

1、需要的插件&#xff0c;引入maven依赖快速 在maven页面右击 点击editstarters 点击ok 找我们需要的依赖

(一)kafka实战——kafka源码编译启动

前言 本节内容是关于kafka消息中间键的源码编译&#xff0c;并通过idea工具实现kafka服务器的启动&#xff0c;使用的kafka源码版本是3.6.1&#xff0c;由于kafka源码是通过gradle编译的&#xff0c;以及服务器是通过scala语言实现&#xff0c;我们要预先安装好gradle编译工具…

FreeRTOS day1

1.总结keil5下载代码和编译代码需要注意的事项 需要与板子连通 配置完成后才点击下载 2.总结STM32Cubemx的使用方法和需要注意的事项 下载支持包 打开芯片配置界面 3.总结STM32Cubemx配置GPIO的方法

蓝桥OJ 6003递归函数 (快速幂)

递归函数 通过这道题学习了快速幂思想 以下是我简单的总结,帮助我复习回顾: 如果指数为奇数,收集current底数后,指数除以2,底数翻倍,继续循环 如果指数为偶数,直接指数除以2,底数翻倍,继续循环 #include<bits/stdc.h> using namespace std; using ll long long; const …

什么是超声波清洗机?六大超声波清洗机必读干货分享指南

传统的清洁方式往往难以满足高效、高质量的需求&#xff0c;这时&#xff0c;超声波清洗机就显得格外重要。但什么是超声波清洗机&#xff1f;为什么它能在众多清洁设备中脱颖而出&#xff1f;接下来&#xff0c;我们将通过六大必读干货&#xff0c;一探究竟&#xff0c;开启清…

JavaScript练手小技巧:仿米哈游官网人物跟随鼠标位移效果

最近&#xff0c;有同学找到我&#xff0c;说&#xff1a;老师&#xff0c;我想模仿米哈游官网。 我说&#xff1a;可以&#xff0c;很不错的。 她说&#xff1a;有些效果有点难&#xff0c;能不能帮我看下。 于是&#xff0c;我就简单大概粗糙的讲解了下大致的原理&#xf…

网络安全入门 5 天速成教程_ WEB 安全渗透攻防技术

前言 随着 Web 技术发展越来越成熟&#xff0c;而非 Web 服务越来越少的暴露在互联网上&#xff0c;现在互联网安全主要指的是 Web 安全。 为了自身不“裸奔”在大数据里&#xff0c;渐渐开始学习 Web 安全&#xff0c;在学习 Web 安全的过程中&#xff0c;发现很大一部分知识…

【Git项目部署到本地仓库】

1. 下载安装Git 根据您的操作系统&#xff0c;访问Git的官方网站&#xff1a;https://git-scm.com/download/win 具体安装教程请访问其他博客&#xff0c;例如&#xff1a;http://t.csdnimg.cn/I28VO 安装完成后&#xff0c;您可以通过在winR键输入cmd打开命令行输入 git -…

高架学习笔记之UML图概要

目录 零、什么是UML图 一、类图 二、对象图 三、构件图 四、部署图 五、制品图 六、包图 七、组合结构图 八、用例图 九、序列图 十、通信图 十一、状态图 十二、活动图 十三、定时图 十四、交互概览图 零、什么是UML图 统一建模语言&#xff08;Unified Modeli…

SinoDB数据库导入导出工具onunload/onload

onunload以二进制形式将数据库或表写到磁带上或磁盘上。当写到磁盘时&#xff0c;以磁盘页为单位卸下数据&#xff0c;这种方式卸下的数据其效率高于dbexport。 1.onunload语法 onunload [-l] [-t <tape_device>] [-b <block size>] [-s <tape size>] <…

微服务demo(四)nacosfeigngateway

一、gateway使用&#xff1a; 1、集成方法 1.1、pom依赖&#xff1a; 建议&#xff1a;gateway模块的pom不要去继承父工程的pom&#xff0c;父工程的pom依赖太多&#xff0c;极大可能会导致运行报错&#xff0c;新建gateway子工程后&#xff0c;pom父类就采用默认的spring-b…

Redis中处理处理没有ACK确认的Stream

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 Stream是一个只能追加内容的数据类型。也就是说Stream这种数据类型,我们…