点赞 + 关注 + 收藏 = 学会了
本文介绍 Fabric.js 的橡皮擦功能。

Fabric.js 的基础包并没有包含橡皮擦模块,如果你的项目需要使用橡皮擦,要使用定制版的 Fabric.js 。
本文需要有 Fabric.js 基础知识。
如果你还不清楚什么是 Fabric.js ,我墙裂建议你点赞 《Fabric.js 从入门到目中无人》。
同时最好了解基础画笔的用法 《Fabric.js 基础画笔的用法 BaseBrush》。
本文使用的是 Fabric 5.2 版本。
本文使用原生三件套的方式进行开发。同时也会提供包含橡皮擦的 npm 下载方式。
基础版的 Fabric.js 不包含橡皮擦功能,如果你的项目需要使用橡皮擦功能,需要到 FabricJS builder 里进行定制。

选中 Erasing ,然后滑动到页面底部,根据你项目所需下载开发版或者压缩版

以上是 CDN 的做法,在 <script> 标签里,使用 src 引用即可。
npm 上也有人打包了一份带橡皮擦功能的 Fabric.js 包。
可以使用命令下载到你项目中
npm i fabric-with-erasing
需要注意的是,fabric-with-erasing 是在基础版的 fabric 中添加了橡皮擦功能,使用 fabric-with-erasing 时无需再下载 Fabric 。
在写本文时,fabric-with-erasing 中所使用的 Fabric 版本是 5.2 。
console.log(fabric.version)

本例要实现的功能:
<!-- 修改画布模式的按钮 -->
<div style="margin-bottom: 10px;">
<button id="select" type="button" onclick="changeAction('select')">select</button>
<button id="erase" type="button" onclick="changeAction('erase')">erase</button>
<button id="erase" type="button" onclick="changeAction('undoErasing')">undo erasing</button>
</div>
<!-- 画布 -->
<canvas id="c" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
<!-- 引入定制好的 fabric -->
<script src="./fabric.js"></script>
<script>
// 初始化画布
const canvas = this.__canvas = new fabric.Canvas('c')
// 在画布中添加图形(本例添加2个正方形)
canvas.add(
// 第一个正方形(宝蓝色)
new fabric.Rect({
top: 50,
left: 50,
width: 50,
height: 50,
fill: "#4b5cc4",
opacity: 0.8,
erasable: false // 不允许擦拭
}),
// 第二个正方形(桃红色)
new fabric.Rect({
top: 50,
left: 150,
width: 50,
height: 50,
fill: "#f47983",
opacity: 0.8
})
)
// 修改画板行为模式
function changeAction(mode) {
switch (mode) {
case "select":
canvas.isDrawingMode = false // 不允许绘画(返回普通框选模式)
break
case "erase":
canvas.isDrawingMode = true // 进入绘画模式
canvas.freeDrawingBrush = new fabric.EraserBrush(canvas) // 使用橡皮擦画笔
canvas.freeDrawingBrush.width = 10 // 设置画笔粗细为 10
break
case 'undoErasing':
canvas.isDrawingMode = true
canvas.freeDrawingBrush = new fabric.EraserBrush(canvas)
canvas.freeDrawingBrush.width = 10
canvas.freeDrawingBrush.inverted = true // 恢复被擦拭的地方
default:
break
}
}
</script>
isDrawingMode 设为 true 。new fabric.EraserBrush 里需要传入画布本身,在初始化画布时的那个对象 const canvas = this.__canvas = new fabric.Canvas('c') 。canvas.freeDrawingBrush.inverted 设为 true 就能恢复被擦拭的地方。| 文章 | 简介 |
|---|---|
| 《Fabric.js 基础画笔的用法 BaseBrush》 | 在阅读本文前我强烈建议你先了解一下基础画笔的用法,因为橡皮擦其实也是个画笔 |
| 《Fabric.js 自由绘制圆形》 | 将“框选”动作改造成自由绘制圆形 |
| 《Fabric.js 3个api设置画布宽高》 | 宽高设置并不是在初始化是才能进行的,本文介绍3种方法设置画布宽高,让你的画布更容易适配不同的使用场景 |
| 《Fabric.js 更换图片的3种方法(包括更换分组内的图片,以及存在缓存的情况)》 | 如果你的项目需要动态更换画布上的图片,那我也给你总结了3中方法 |
| 《Fabric.js 摆正元素的4种方法(带过渡动画)》 | 一键摆正被你旋转过的元素 |
| 《Fabric.js 将本地图像上传到画布背景》 | 除了在初始化时设置画布背景外,我还做了本地上传背景的功能,让画布在运行时也能修改背景图 |
| 《在 Vue3中使用Fabric.js实现渐变(Gradient)效果,包括径向渐变radial》 | 官方入门教程也只有线性渐变,以至于某些文章说 Fabric.js 只支持线性渐变。但其实径向渐变也完全支持 |
| 《Fabric.js 从入门到目中无人》 |
Fabric.js 入门指南,学完能应付简单业务 |
| 《Fabric.js 右键菜单》 |
Fabric.js 暂时还没右键事件,如果你想实现右键菜单的功能,可直接复制该文章的代码~ |
点赞 + 关注 + 收藏 = 学会了
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
我的Gallery模型中有以下查询:media_items.includes(:photo,:video).rank(:position_in_gallery)我的图库模型有_许多媒体项,每个都有一个照片或视频关联。到目前为止,一切正常。它返回所有media_items包括它们的photo或video关联,由media_item的position_in_gallery属性排序。但是我现在需要将此查询返回的照片限制为仅具有is_processing属性的照片,即nil。是否可以进行相同的查询,但条件是返回的照片等同于:.where(photo:'photo.is_processingIS
-if!request.path_info.include?'A'%{:id=>'A'}"Text"-else"Text"“文本”写了两次。我怎样才能只写一次并同时检查path_info是否包含“A”? 最佳答案 有两种方法可以做到这一点。使用部分,或使用content_forblock:如果“文本”较长,或者是一个重要的子树,您可以将其提取到一个部分。这会使您的代码变干一点。在给出的示例中,这似乎有点矫枉过正。在这种情况下更好的方法是使用content_forblock,如下所示:-if!request.path_info.inc
Ocra无法处理需要“tk”的应用程序require'tk'puts'nope'用奥克拉http://github.com/larsch/ocra不起作用(如链接中的一个问题所述)问题:https://github.com/larsch/ocra/issues/29(Ocra是1.9的"new"rubyscript2exe,本质上它用于将rb脚本部署为可执行文件)唯一的问题似乎是缺少tcl的DLL文件我不认为这是一个问题据我所知,问题是缺少tk的DLL文件如果它们是已知的,则可以在执行ocra时将它们包括在内有没有办法知道tk工作所需的DLL依赖项? 最佳答
我正在使用DMOZ的listofurltopics,其中包含一些具有包含下划线的主机名的url。例如:608609TheOuterHeaven610InformationandimagegalleryofMcFarlane'sactionfiguresforTrigun,Akira,TenchiMuyoandotherJapaneseSci-Fianimations.611Top/Arts/Animation/Anime/Collectibles/Models_and_Figures/Action_Figures612虽然此url可以在网络浏览器中使用(或者至少在我的浏览器中可以使用:
在Rails自动生成的功能测试(test/functional/products_controller_test.rb)中,我看到以下代码:classProductsControllerTest我的问题是:方法调用products()在哪里/如何定义?products(:one)到底是什么意思?看代码,大概意思是“创建一个产品”,但是它是如何工作的呢?注意我是Ruby/Rails的新手,如果这些是微不足道的问题,我深表歉意。 最佳答案 如果您查看test/fixtures文件夹,您会看到一个products.yml文件。这是在您创建
我有一个数组:array=['Footballs','Baseball','football','Soccer']而且我需要计算看到Football或Baseball的次数,无论大小写和复数形式如何。这是我尝试做的,但没有成功:array.count{|x|x.downcase.include?'football'||x.downcase.include?'baseball'}编写这段代码的正确或更好的方法是什么?我正在寻找3作为答案。 最佳答案 我会将count与一个block结合使用,该block根据与您正在寻找的约束相匹配的正
我正在学习Ruby,遇到了inject。我正处于理解它的风口浪尖,但当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用inject来添加一个(1..10)范围的总和,我不太关心这个。这是一个任意的例子。在实际程序中我会用它做什么?我正在学习,所以我可以继续使用Rails,但我不必有一个以Web为中心的示例。我只需要一些我可以全神贯注的目标。谢谢大家。 最佳答案 inject有时可以通过它的“其他”名称reduce更好地理解。它是一个对Enumerable进行操作(迭代一次)并返回单个值的函数。它有许多有