Fabric玩转动画、图像过滤器、颜色、渐变、文本、事件没有一个受欢迎的canvas库是没有动画功能的。Fabric也不
动画
没有一个受欢迎的canvas
库是没有动画功能的。Fabric也不例外。由于有如此强大的对象模型和图形功能,如果没有内置动画助手,那就太可惜了。
改变任何对象的属性有多容易吗?我们只是调用set
方法,传递相应的值:
rect.set('angle', 45);
动画对象也很简单。每个Fabric对象都有一个animate方法,使该对象动画化。
rect.animate({angle:45}, {
onChange: canvas.renderAll.bind(canvas)
});
第一个参数是动画的属性。第二个参数是动画的结束值。如果矩形的角度为-15°,我们传入45°,它将从-15°动画到45°。第三个参数是一个可选对象,指定动画的更精细的细节——持续时间、回调、缓动等。
animate的一个方便的特性是它还支持相对值。例如,如果你想让对象的left属性移动100px,你可以这样做:
rect.animate({left:'+=100'}, { onChange: canvas.renderAll.bind(canvas) });
同样,将物体逆时针旋转5度,可以实现如下:
rect.animate({angle:'-=5'}, { onChange: canvas.renderAll.bind(canvas) });
你可能想知道为什么我们总是在那里指定“onChange”回调。第三个参数不是可选的吗?是的,但是调用canvas。每个动画帧上的renderAll是让我们看到实际动画的东西!你看,当我们调用“animate”方法时,它只会根据特定的算法(即easing)随着时间的推移使属性值动画。所以的矩形。Animate ('angle', 45) '将更改对象的角度,但不会在每次更改角度后重新渲染画布屏幕。显然我们需要重新渲染才能看到真正的动画。
记住在画布表面下有整个对象模型。对象有自己的属性和关系,画布只负责将它们的存在投射到外部世界。
“animate”不会在每次更改后自动重新渲染画布的原因是由于性能。毕竟,我们可以在画布上拥有成百上千的动画对象,如果它们中的每一个都试图重新渲染屏幕,那就不太好了。在许多对象的情况下,你可以使用类似于“requestAnimationFrame”(或其他基于计时器)循环来连续渲染画布,而不必为每个对象调用“renderAll”。但大多数时候,您可能需要显式指定canvas.renderAll
作为“onChange”回调。
那么我们还可以将哪些选项传递给animate呢?
- from: 允许指定animatable属性的起始值(如果我们不想使用当前值)。
- duration: 默认为500 (ms)。可以用来改变动画的持续时间。
- onComplete: 在动画结束时调用的回调。
- easing: 缓动函数
所有这些选项都应该是不言自明的,或许只有easing一个选项除外。让我们仔细看看。
默认情况下,animate使用“easeInSine”函数进行动画。如果这不是你需要的,在fabric.util.ease下有大量的简化选项可用。例如,如果我们想要以有弹性的方式向右移动物体:
rect.animate({left:500}, {
onChange: canvas.renderAll.bind(canvas),
duration: 1000,
easing: fabric.util.ease.easeOutBounce
});
注意fabric.util.ease.easeOutBounce是一个缓和选项。其他值得注意的包括easeInCubic、easeOutCubic、easeInElastic、easeOutElastic、easeInBounce和easeOutExpo。
所以这几乎涵盖了Fabric的动画部分。只是给你们一些可能性的概念你可以动画物体的角度让它旋转;动画左/顶部属性,使其移动;动画宽度/高度,使其收缩/增长;动画不透明度,使其淡入/淡出;等等......。
fabric.runningAnimations
如果你需要访问fabric当前正在运行的动画,使用fabric. runningAnimations。它是一个对象数组,每个对象都是动画上下文对象。
方便的方法:
fabric.runningAnimations.findAnimation(signature)
- 返回与' signature '匹配的动画上下文,这是' fabric.util.animate '返回的中止函数。fabric.runningAnimations.findAnimationIndex(signature)
- 与' findAnimation '相同,返回索引fabric.runningAnimations.findAnimationsByTarget(target)
- 返回所有具有' target '属性等于target的动画fabric.runningAnimations.cancelAll()
- 取消所有运行的动画。fabric.runningAnimations.cancelByTarget(target)
- 取消带有target属性等于target的动画。object.dispose()
- 对象(object.animate(…))创建的所有动画将被取消。如果你想使用“fabric.util.animate”添加动画。 而不是 object.animate(…),你可以通过传递target属性将它们附加到对象上。这样,一旦对象被处理,动画就会取消。
let cancel = fabric.util.animate({...});
let i = fabric.runningAnimations.findAnimationIndex(cancel);
let context = fabric.runningAnimations.findAnimation(cancel);
let cancelled = fabric.runningAnimations.cancelAll();
// 下列陈述是正确的
cancelled[i] === context;
cancelled[i].cancel === cancel;
fabric.runningAnimations.length === 0;
图像过滤器
默认情况下,Fabric提供了很少的过滤器,无论是支持WEBGL的浏览器还是不支持WEBGL的浏览器。这也使您可以轻松地定义自己的。一些内置的你可能非常熟悉-过滤器去除白色背景,灰度过滤器,反转或亮度。其他可能不太受欢迎-颜色矩阵,棕褐色,或噪音。
那么我们如何在Fabric中对图像应用过滤器呢?嗯,fabric.Image
有"filters"属性,这是一个简单的过滤器数组。该数组中的每个过滤器都是一个Fabric过滤器的实例。或您自己的自定义过滤器的实例。
让我们来创建一个灰度图像。
var canvas = new fabric.Canvas("c");
var imgElement = document.getElementById('my-image');
var imgInstance = new fabric.Image(imgElement, {
left: 100,
top: 40,
angle: 30,
});
// 添加过滤器
imgInstance.filters.push(new fabric.filters.Grayscale());
// 应用过滤器并在完成后重新渲染画布
imgInstance.applyFilters();
canvas.add(imgInstance);
图像的色偏(Sepia)版本怎么样?
var canvas = new fabric.Canvas("c");
var imgElement = document.getElementById('my-image');
var imgInstance = new fabric.Image(imgElement, {
left: 100,
top: 40,
angle: 30,
});
// 添加过滤器
imgInstance.filters.push(new fabric.filters.Sepia());
// 应用过滤器并在完成后重新渲染画布
imgInstance.applyFilters();
canvas.add(imgInstance);
由于“filters”属性是一个数组,我们可以用数组方法执行任何所需的操作:移除滤镜(pop,splice,shift),添加滤镜(push,unshift,splice),甚至可以组合多个滤镜。当我们调用
applyFilters
时,“filters”数组中存在的任何滤镜将逐个应用,所以让我们尝试创建一个既色偏又明亮(Brightness)的图像。
var canvas = new fabric.Canvas("c");
var imgElement = document.getElementById("my-image");
var imgInstance = new fabric.Image(imgElement, {
left: 100,
top: 40,
angle: 30,
});
// 添加过滤器
imgInstance.filters.push(
new fabric.filters.Sepia(),
new fabric.filters.Brightness({ brightness: 0.1 })
);
// 应用过滤器并在完成后重新渲染画布
imgInstance.applyFilters();
canvas.add(imgInstance);
请注意,我们还将
{brightness:0.1}
对象传递给Brightness滤镜。这是因为有些滤镜不可配置,例如,灰度,反转,棕褐色(e.g. grayscale, invert, sepia),而其他过滤器可以配置。对于Brightness滤镜,能够配置亮度级别(-1 - 1 即: 全黑色 - 全白色)。对于噪声(noise)滤镜,能配置的是噪声值(0-1000)。对于“删除颜色”滤镜,能配置的是阈值和距离值。等等。
颜色(Colors)
无论您是否使用十六进制,RGB或RGBA颜色,Fabric都能提供一个完整的颜色基础,以帮助您最自然地表达自己。以下是在Fabric中定义颜色的一些方法:
new fabric.Color('#f55');
new fabric.Color('#123123');
new fabric.Color('356735');
new fabric.Color('rgb(100,0,100)');
new fabric.Color('rgba(10, 20, 30, 0.5)');
转换也很简单。 toHex()
将颜色实例转换为十六进制表示。 toRgb()
可以转换为RGB,toRgba()
转换为带Alpha通道的RGB。
new fabric.Color('#f55').toRgb(); // "rgb(255,85,85)"
new fabric.Color('rgb(100,100,100)').toHex(); // "646464"
new fabric.Color('fff').toHex(); // "FFFFFF"
转换不仅仅可以使单一的颜色。您也可以用另一种颜色叠加,或将其转换为灰度版本。
var redish = new fabric.Color('#f55');
var greenish = new fabric.Color('#5f5');
redish.overlayWith(greenish).toHex(); // "AAAA55"
redish.toGrayscale().toHex(); // "A1A1A1"
渐变(Gradients)
更加表现出色的方式是通过渐变。渐变让我们将一种颜色混合到另一种颜色中,创造出一些令人惊叹的图形效果。
Fabric支持在所有对象上设置渐变填充或描边属性。为了给一个对象设置渐变,首先创建渐变,然后给它指定填充或描边。
var canvas = new fabric.Canvas("c");
var circle = new fabric.Circle({
left: 100,
top: 100,
radius: 50,
});
var gradient = new fabric.Gradient({
type: "linear",
gradientUnits: "pixels", // or 'percentage'
coords: { x1: 0, y1: 0, x2: 0, y2: circle.height },
colorStops: [
{ offset: 0, color: "#000" },
{ offset: 1, color: "#fff" },
],
});
circle.set("fill", gradient);
canvas.add(circle);
在上面的例子中,我们在100,100的位置创建一个圆圈,半径为50px。然后,我们将其填充设置为跨越整个圆形高度的渐变,从黑色到白色。
渐变选项对象有2个主要属性,coords
和colorStops
。coords
期望至少有2个坐标对(x1, y1和x2, y2),它们将定义渐变在对象上的扩展方式,而colorStops
是一个定义渐变颜色的数组。数组中的每种颜色都由一个offset
定义,它代表了它在渐变上的位置,一个color
定义了颜色本身,最后是一个opacity
属性。你可以定义尽可能多的颜色停止,只要它们的偏移范围从' 0 '到' 1 '。' 0 '表示渐变的开始,' 1 '表示渐变的结束。坐标相对于对象的左上角,所以圆的最高点为0,最低点为circle.height
。
你可以指定类型线性或径向获得2种不同的梯度,梯度单位默认为像素,但可以指定为“百分比”。percentage
将允许以对象大小的百分比指定渐变大小,' 1 '表示对象大小的100%。
这个设置对fabric.Text
对象很有用。根据文本内容更改宽度或高度的文本对象。
下面是一个从左到右的红蓝渐变的例子:
var gradient = new fabric.Gradient({
type: 'linear',
gradientUnits: 'pixels', // or 'percentage'
coords: { x1: 0, y1: 0, x2: circle.width, y2: 0 },
colorStops:[
{ offset: 0, color: 'red' },
{ offset: 1, color: 'blue'}
]
})
// or in percentage
var gradient = new fabric.Gradient({
type: 'linear',
gradientUnits: 'percentage',
coords: { x1: 0, y1: 0, x2: 1, y2: 0 },
colorStops:[
{ offset: 0, color: 'red' },
{ offset: 1, color: 'blue'}
]
})
这是一个彩虹🌈渐变,颜色跨度20%:
var gradient = new fabric.Gradient({
type: 'linear',
gradientUnits: 'pixels', // or 'percentage'
coords: { x1: 0, y1: 0, x2: circle.width, y2: 0 },
colorStops:[
{ offset: 0, color: 'red' },
{ offset: 0.2, color: 'orange' },
{ offset: 0.4, color: 'yellow' },
{ offset: 0.6, color: 'green' },
{ offset: 0.8, color: 'blue' },
{ offset: 1, color: 'purple' }
]
});
文本(Text)
如果你想不仅在画布上显示图像和矢量形状,还要显示文本,该怎么办?Fabric也为您准备好了!认识fabric.Text
对象。
我们提供文本的原因有两个,首先是允许以面向对象的方式处理文本。原生canvas方法,只允许在非常低的级别上填充或描边文本。通过实例化fabric.Text
实例,我们可以使用文本,就像我们将使用任何其他Fabric对象:移动它,缩放它,更改其属性等。
第二个原因是提供比canvas给我们更丰富的功能,包括:
- 支持多行Multiline support 不幸的是,原生文本方法忽略了新建一行。
- 文本对齐Text alignment 左,中,右。使用多行文本时很有用。
- 文本背景Text background 背景也支持文本对齐。
- 文字装饰Text decoration 下划线,上划线,贯穿线。
- 行高Line Height 在使用多行文本时有用。
- 字符间距Char spacing 使文本更紧凑或更间隔。
- 子范围Subranges 将颜色和属性应用到文本对象的子对象中。
- 多字节Multibyte 支持表情符号。
- 交互式画布编辑On canvas editing 可以直接在画布上键入文本。
做一个hello world的例子:
var text = new fabric.Text('hello world', { left: 100, top: 100 });
canvas.add(text);
那就对了!在画布上显示文本就像在所需位置添加fabric.Text
实例一样简单。您可以看到,唯一必需的第一个参数是实际的文本字符串。第二个参数是通常的选项对象,它可以具有通常的left,top,填fill,opacity等属性。
当然,文本对象也有自己独有的与文本相关的属性。我们来看看其中的一些:
字体(fontFamily)
默认设置为“Times New Roman”,此属性允许我们更改用于呈现文本对象的字体系列。更改它将立即使文本以新字体呈现。
var comicSansText = new fabric.Text("I'm in Comic Sans", {
fontFamily: 'Comic Sans'
});
字体大小(fontSize)
字体大小控制渲染文本的大小。请注意,与Fabric中的其他对象不同,您不能直接更改文本的width / height属性。相反,您需要更改“fontSize”值才能使文本对象更大或更小。或者,您可以随时使用scaleX / scaleY属性。
var text40 = new fabric.Text("I'm at fontSize 40", {
fontSize: 40
});
var text20 = new fabric.Text("I'm at fontSize 20", {
fontSize: 20
});
粗体(fontWeight)
fontWeight
允许使文本更粗或更薄。就像CSS一样,您可以使用关键字(“normal”,“bold”)或数字(100,200,400,600,800)。请注意,您是否可以使用某些值取决于所选字体的粗体的可用性。如果您使用远程字体,则需要确保提供正常和粗体字体定义。
var normalText = new fabric.Text("I'm a normal text", {
fontWeight: 'normal'
});
var boldText = new fabric.Text("I'm at bold text", {
fontWeight: 'bold'
});
文本修饰(textDecoration)
文本修饰允许添加下划线,上划线或贯穿线到文本。这与CSS类似,但是Fabric进一步,并允许使用上述的任何组合。所以你可以有一个文本,既有下划线又有上划线,还有贯穿线。等等。
var underlineText = new fabric.Text("I'm an underlined text", {
underline; true
});
var strokeThroughText = new fabric.Text("I'm a stroke-through text", {
linethrough: true
});
var overlineText = new fabric.Text("I'm an overline text", {
overline: true
});
阴影
文本阴影由4个组件组成:颜色,水平偏移,垂直偏移和模糊大小。如果您在CSS中使用阴影,这可能看起来很熟悉。通过更改这些值可以实现许多组合。
var shadowText1 = new fabric.Text("I'm a text with shadow", {
shadow: 'rgba(0,0,0,0.3) 5px 5px 5px'
});
var shadowText2 = new fabric.Text("And another shadow", {
shadow: 'rgba(0,0,0,0.2) 0 0 5px'
});
var shadowText3 = new fabric.Text("Lorem ipsum dolor sit", {
shadow: 'green -5px -5px 3px'
});
字体风格(fontStyle)
字体样式可以是2个值之一:normal(正常)或italic(斜体)。这类似于同名的CSS属性。
var italicText = new fabric.Text("A very fancy italic text", {
fontStyle: 'italic',
fontFamily: 'Delicious'
});
var anotherItalicText = new fabric.Text("another italic text", {
fontStyle: 'italic',
fontFamily: 'Hoefler Text'
});
描边的颜色和宽度(stroke and strokeWidth)
通过结合stroke和strokeWidth,你可以在你的文字上获得一些有趣的效果。这里有几个例子:
var textWithStroke = new fabric.Text("Text with a stroke", {
stroke: '#ff1318',
strokeWidth: 1
});
var loremIpsumDolor = new fabric.Text("Lorem ipsum dolor", {
fontFamily: 'Impact',
stroke: '#c3bfbf',
strokeWidth: 3
});
文本对齐(textAlign)
使用多行文本时,文本对齐很有用。使用单行文本,边界框的宽度总是与该行的宽度完全匹配,因此没有任何对齐方式。
允许的值为“left”,“center”和“right”。
var text = 'this is\na multiline\ntext\naligned right!';
var alignedRightText = new fabric.Text(text, {
textAlign: 'right'
});
行高(lineHeight)
CSS中可能熟悉的另一个属性是lineHeight。它允许我们改变多行文本中文本行之间的垂直间距,只是值的规格和css中的不太一样,在以下示例中,第一个文本块的lineHeight为3,第二个为1。
var lineHeight3 = new fabric.Text('Lorem ipsum ...', {
lineHeight: 3
});
var lineHeight1 = new fabric.Text('Lorem ipsum ...', {
lineHeight: 1
});
文本背景颜色(textBackgroundColor)
最后,textBackgroundColor允许给文本一个背景。请注意,背景仅填充文本字符占用的空间,而不是整个边框。这意味着文本对齐改变了文本背景渲染的方式。一行的高度也是如此,因为背景是由lineHeight创建的线之间的垂直空间。
var text = 'this is\na multiline\ntext\nwith\ncustom lineheight\n&background';
var textWithBackground = new fabric.Text(text, {
textBackgroundColor: 'rgb(0,200,0)'
});
事件(Events)
事件驱动架构是框架内一些惊人的功能和灵活性的基础。Fabric也不例外,并提供广泛的事件系统,从低级“鼠标”事件开始到高级对象。
这些事件可以让我们在画布上发生的事件的同时,做一些事情。想知道什么时候鼠标被按下?只需要监听“mouse:down”事件,想知道什么时候对象被添加到canvas? 监听“object:add”事件,如果想知道画布什么时候渲染完成呢?只需监听“after:render”。
事件API非常简单,类似于jQuery,Underscore.js或其他流行的JS库。有一个on
方法来初始化事件监听器,off
用来删除它。
让我们来看个例子:
var canvas = new fabric.Canvas('...');
canvas.on('mouse:down', function(options) {
console.log(options.e.clientX, options.e.clientY);
});
我们将事件“mouse:down”事件侦听器添加到画布上,并给它一个事件处理程序,用于记录事件起始位置的坐标。换句话说,它会记录鼠标按下的位置。事件处理程序接收一个选项对象,它有两个属性e
:事件源,以及target
:在画布上点击的对象,它有时不存在。但是这个事件在任何时候都是存在的,但是只有当你在画布上点击某个对象时,target
才会存在。target
也只传递给有意义的事件处理程序。例如,会传递给“mouse:down”,而不会传递给“after:render”(表示整个画布被重新绘制)。
canvas.on('mouse:down', function(options) {
if (options.target) {
console.log('有对象被点击咯! ', options.target.type);
}
});
上面的例子将记录“有对象被点击咯!”如果您单击一个对象。它还将显示点击的对象的类型。
那么Fabric中有哪些其他的事件呢?那么,从鼠标级别可以看到“mouse:down”,“mouse:move”和“mouse:up”。从通用方面看,有“after:render”。然后有选择相关的事件:“before:selection:cleared”, “selection:created”, “selection:cleared”,最后,对象的事件:“object:modified”,“object:selected”,“object:moving”,“object:scaling”,“object:rotate”,“object:added”和“object:removed”。
请注意,每当一个对象被移动(或缩放)甚至一个像素时,诸如“object:moving”(或“object:scaling”)的事件被连续地触发。另一方面,诸如“object:modified”或“selection:created”之类的事件仅在操作结束时被触发(对象修改或选择创建)。
注意我们如何将事件附加到画布上(canvas.on('mouse:down',...)
)。可以想象,这意味着事件都被限定为canvas实例。如果您在页面上有多个canvas,您可以将不同的事件侦听器附加到每个canvas上。他们都是独立的,只处理分配给他们自己的事件。
为方便起见,Fabric将进一步提升事件系统,并允许您将侦听器直接附加到canvas画布中的对象上。让我们来看看:
var rect = new fabric.Rect({ width: 100, height: 50, fill: 'green' });
rect.on('selected', function() {
console.log('selected a rectangle');
});
var circle = new fabric.Circle({ radius: 75, fill: 'blue' });
circle.on('selected', function() {
console.log('selected a circle');
});
我们将事件侦听器直接附加到矩形和圆形实例。使用"selected"来代替"object:selected"。同样的,使用“modified”代替“object:modified”,使用“rotating”来代替“object:rotating”。等等。
查看此事件演示,以更广泛地探索Fabric的事件系统。
转载自:https://juejin.cn/post/7405774566566232127