Get to know Fabric.js. Part 2
This is the second part of a series of articles about the open Javascript canvas library Fabric.js.
In the first part of this series, we introduced the most basic aspects of the canvas fabric.js library . We learned how Fabric can be useful, examined its object model and hierarchy of objects; saw that there are both simple shapes (rectangle, triangle, circle), and complex (SVG). Learned how to perform simple operations on these objects.
Well, we’ve figured out the basics, let's get down to more interesting things!
Any self-respecting canvas library nowadays includes animation tools. Fabric is no exception. After all, we have a powerful object model and flexible graphical capabilities. It would be a sin not to be able to set this in motion.
You probably remember how to change the attribute of an object. We just call the method
You can animate an object by the same principle and with the same ease. Each object in Fabric has a method
The first argument is the attribute we want to change. The second argument is the final value of this attribute. For example, if the rectangle is at an angle of -15 °, and we indicate “45”, then the angle will gradually change from -15 ° to 45 °. Well, the last argument is an optional object for more detailed settings (duration, calls, easing, etc.), by the
According to the same principle, to rotate an object 5 degrees counterclockwise:
You probably noticed that we constantly indicate the call of "onChange". Isn't the 3rd argument optional? Yes exactly. The fact is that just this invocation
Well, why
Returning to the options for animation, what exactly can we change?
All these options are more or less obvious, except probably easing. Let's take a closer look.
By default, they
Notice what we use
That's basically all you need to know about animation. Now you can easily do interesting things - change the angle of an object to make it rotate; animate left / top to move it; animate width / height to increase / decrease; animate opacity to appear / disappear; etc.
In the first part of this series, we learned how to work with images in Fabric. As you probably remember, a
Working with images is fun, and with image filters - even more fun!
Fabric already has several filters, and also allows you to easily define your own. Some filters from Fabric are probably familiar to you - removal of a white background, conversion to black and white, negative or brightness. And some are less popular - gradient transparency, sepia, noise.
So how do you apply a filter to an image? Each
Well, for example, let's make the picture black and white:
And here you can make sepia:
With the attribute «filters» can do everything the same as with the usual array - remove the filter (using the
Notice that we passed the
Well, sorted out the filters; it's time to create your own!
A sample for creating filters will be quite simple. We need to create a "class", and write a method
Without delving deeply into the details of the code, it is worth noting that the most important thing happens in the loop, where we change the green (data [i + 1]) and blue (data [i + 2]) components of each pixel to 0, essentially deleting them. The red component remains untouched, which makes the entire image red. As you can see, the
No matter what you prefer working with — hex, RGB, or RGBA color formats — Fabric simplifies the tedious operations and transfers from one format to another. Let's look at a few ways to define color in Fabric:
Format translation is very simple.
By the way, you can do more than just translation. You can "overlay" the colors one on top of the other, or make them a black and white version.
An even more expressive way to work with colors is to use gradients. Gradients allows you to smoothly mix one color with another, opening up the possibility of quite amazing effects.
Fabric supports them using a method
In this example, we create a circle at 100,100, with a radius of 50px. Then we set the gradient to it, running along the entire height of the object, from black to white.
As you can see, the method receives a configuration object, which may contain 2 pairs of coordinates (x1, y1 and x2, y2), and a colorStops object. Coordinates indicate where the gradient begins and where it ends. colorStops indicate what colors it consists of. You can define as many colors as you like; the main thing is that their positions are in the range from 0 to 1 (for example, 0, 0.1, 0.3, 0.5, 0.75, 1). 0 represents the beginning of the gradient, 1 represents its end.
Here is an example of a red-blue gradient going from left to right:
And here is a 5-step gradient rainbow, with flowers occupying 20% of the entire length:
Can you come up with something interesting?
What if you need to display not only pictures and vector shapes on canvas, but also text? Fabric can do it too! Meet me
Before talking about the text, it is worth noting why we generally provide support for working with text. After all, canvas has built-in methods fillText and strokeText.
Firstly, in order to be able to work with text as objects. Built-in canvas methods - as usual - allow you to display text at a very low level. But
The second reason is to have richer functionality than what canvas gives us. Some things that are in Fabric but not in native methods:
Well then, let's look at the ubiquitous "hello world"?
That's all! To display text, you just need to add a type object
In addition to the usual attributes, text objects certainly have their own, related to the text. In short, about these attributes:
The default is Times New Roman. Allows you to change the font family for text.
Controls the size of the text. Note that unlike other objects in Fabric, we cannot resize text using width / height. Instead, fontSize is used, and of course scaleX / scaleY.
Allows you to make the text fatter or thinner. Just like in CSS, you can use either words (“normal”, “bold”) or numerical values (100, 200, 400, 600, 800). It is important to understand that for a certain thickness you need to have an appropriate font. If the font does not have a “bold” (bold) option, for example, then bold text may not be displayed.
Allows you to add strikethrough, underlining, or underlining to text. Again, this declaration works just like in CSS. However, Fabric can do a bit more, allowing you to use these decorations together (such as underlining and strikethrough) by simply listing them with a space.
Shadow for the text. It consists of 4 components: color, horizontal indentation, vertical indentation, and blur size. This should all be familiar if you've worked with shadows in CSS before. By changing these 4 options, you can achieve many interesting effects.
Text style. There can be only one of two: “normal” or “italic”. Again, it works the same as in CSS.
By combining stroke (the color of the outer stroke) and strokeWidth (the width of the outer stroke), pretty interesting effects can be achieved. Here are a couple of examples:
Alignment is useful when working with multi-line text. In a single-line text, alignment is not visible, because the width of the text object itself is the same as the length of the line.
Possible values are “left”, “center”, “right”, and “justify”
Another attribute most likely familiar from CSS is lineHeight (line height). Allows you to change the distance between lines in multi-line text. Here is an example of text with lineHeight 3, and the second with lineHeight 1.
Finally, you can give the text a background using textBackgroundColor. Note that the background is filled only under the text itself, and not on the entire "box". To paint over the entire text object, you can use the attribute "backgroundColor". You can also see that the background depends on the alignment of the text and lineHeight. If lineHeight is very large, the background will only be visible under the text.
Events are an indispensable tool for creating complex applications. For ease of use, and more detailed configuration, Fabric has an extensive event system; starting from low-level mouse events, and up to high-level events of objects.
Events allow us to “catch” various moments when something happens on the canvas. Want to know when the mouse was clicked? We follow the mouse: down event. How about when an object was added to the canvas? There is an “object: added” for this. Well, what about redrawing the canvas? We use "after: render".
The event API is very simple, and similar to what you are most likely used to in jQuery, Underscore.js, or other popular JS libraries. There is a method
Let's look at an example:
We added a “mouse: down” event listener to the canvas object, and specified a handler that would record the coordinates of where this event occurred. Thus, we can see exactly where the click on the canvas occurred. The event handler receives an options object, with two parameters:
This example will output “an object was clicked!” If we click on an object. The type of this object will also be shown.
What other events are available in Fabric? At the mouse level, we have " mouse: down ", " mouse: move ", and " mouse: up ". Of the general ones, there is " after: render ". There are events regarding the selection of objects: " before: selection: cleared ", " selection: created ", " selection: cleared ". And of course, the events of the objects: " object: modified ", " object: selected ", " object: moving ", " object: scaling ", "".
It is worth noting that events of the type" object: moving "(or" object: scaling ") occur continuously, while moving or scaling an object, even if it is one pixel. At the same time, events of the type" object: modified "or "Selection: created" occurs only at the end of the action (changing the object, creating a group of objects, etc.).
In the previous examples, we attached the listener to the canvas object (
For convenience, Fabric allows you to add listeners directly to Fabric objects!
In this example, the listeners “join” directly to the rectangle and the circle. Instead of “object: selected”, we use the “selected” event. By the same principle, you can use the event "modified" ("object: modified" when "hang" on the canvas), "rotating" (analogue of "object: rotating"), etc.
You can get acquainted with the events closer and directly in real time in this demo .
On this, the second part came to an end. So many new things, but that's not all! In the 3rd part, we will consider groups of objects, serialization / deserialization of the canvas and the JSON format, SVG parser, as well as the creation of subclasses.
In the first part of this series, we introduced the most basic aspects of the canvas fabric.js library . We learned how Fabric can be useful, examined its object model and hierarchy of objects; saw that there are both simple shapes (rectangle, triangle, circle), and complex (SVG). Learned how to perform simple operations on these objects.
Well, we’ve figured out the basics, let's get down to more interesting things!
Animation
Any self-respecting canvas library nowadays includes animation tools. Fabric is no exception. After all, we have a powerful object model and flexible graphical capabilities. It would be a sin not to be able to set this in motion.
You probably remember how to change the attribute of an object. We just call the method
set
, passing the appropriate value:rect.set('angle', 45);
You can animate an object by the same principle and with the same ease. Each object in Fabric has a method
animate
(inheriting from fabric.Object
) that ... animates this object.rect.animate('angle', 45, {
onChange: canvas.renderAll.bind(canvas)
});
The first argument is the attribute we want to change. The second argument is the final value of this attribute. For example, if the rectangle is at an angle of -15 °, and we indicate “45”, then the angle will gradually change from -15 ° to 45 °. Well, the last argument is an optional object for more detailed settings (duration, calls, easing, etc.), by the
animate
way, it has very useful functionality - support for relative values. For example, if you want to move the object 100px to the right, then this is very simple:rect.animate('left', '+=100', { onChange: canvas.renderAll.bind(canvas) });
According to the same principle, to rotate an object 5 degrees counterclockwise:
rect.animate('angle', '-=5', { onChange: canvas.renderAll.bind(canvas) });
You probably noticed that we constantly indicate the call of "onChange". Isn't the 3rd argument optional? Yes exactly. The fact is that just this invocation
canvas.renderAll
for each frame of the animation allows you to see the animation itself! The method animate
only changes the value of the attribute within the specified time, and according to a certain algorithm (easing). rect.animate('angle', 45)
changes the value of the angle, without redrawing the screen after each change. And redrawing the screen is needed in order to see the animation. Well, why
animate
not redraw the screen automatically? Due to performance. After all, hundreds or even thousands of objects can be on the canvas. It would be pretty awful if each of the objects redraws the screen when changing. In this case, it is better to use for examplerequestAnimationFrame
to constantly draw the canvas without calling renderAll
for each object. However, in most cases, you will most likely use it canvas.renderAll
as an “onChange” call. Returning to the options for animation, what exactly can we change?
- from : Allows you to change the initial attribute value for the animation (if you do not want to use the current one).
- duration : The duration of the animation. The default is 500 (ms).
- onComplete : Function to call at the end of the animation.
- easing : The easing function.
All these options are more or less obvious, except probably easing. Let's take a closer look.
By default, they
animate
use a linear function to soften the animation. If this option is not suitable, Fabric has a large set of popular easing functions (accessible through the object fabric.util.ease
). For example, like this, you can move the object to the right, while springing at the end:rect.animate('left', 500, {
onChange: canvas.renderAll.bind(canvas),
duration: 1000,
easing: fabric.util.ease.easeOutBounce
});
Notice what we use
fabric.util.ease.easeOutBounce
as a mitigation option. There are other popular features - easeInCubic
, easeOutCubic
, easeInElastic
, easeOutElastic
, easeInBounce
, easeOutExpo
,, etc. That's basically all you need to know about animation. Now you can easily do interesting things - change the angle of an object to make it rotate; animate left / top to move it; animate width / height to increase / decrease; animate opacity to appear / disappear; etc.
Image filters
In the first part of this series, we learned how to work with images in Fabric. As you probably remember, a
fabric.Image
constructor is used for this , passing an element to it . There is also a method fabric.Image.fromURL
by which you can create an object directly from a URL string. And of course, these fabric.Image
objects can be thrown onto the canvas where they will be displayed like everything else. Working with images is fun, and with image filters - even more fun!
Fabric already has several filters, and also allows you to easily define your own. Some filters from Fabric are probably familiar to you - removal of a white background, conversion to black and white, negative or brightness. And some are less popular - gradient transparency, sepia, noise.
So how do you apply a filter to an image? Each
fabric.Image
the object has a “filters” attribute, which is simply an array of filters. Each element in this array is either one of the existing ones in Fabric or its own filter. Well, for example, let's make the picture black and white:
fabric.Image.fromURL('pug.jpg', function(img) {
// добавляем фильтр
img.filters.push(new fabric.Image.filters.Grayscale());
// применяем фильтры и перерисовываем канвас после применения
img.applyFilters(canvas.renderAll.bind(canvas));
// добавляем изображения на холст
canvas.add(img);
});
And here you can make sepia:
fabric.Image.fromURL('pug.jpg', function(img) {
img.filters.push(new fabric.Image.filters.Sepia());
img.applyFilters(canvas.renderAll.bind(canvas));
canvas.add(img);
});
With the attribute «filters» can do everything the same as with the usual array - remove the filter (using the
pop
, splice
, or shift
), add a filter (using push
, splice
, unshift
), or even to combine multiple filters. When called applyFilters
, all filters in the array are applied to the picture in turn. Here, for example, let's create a picture with increased brightness and with a sepia effect:fabric.Image.fromURL('pug.jpg', function(img) {
img.filters.push(
new fabric.Image.filters.Sepia(),
new fabric.Image.filters.Brightness({ brightness: 100 }));
img.applyFilters(canvas.renderAll.bind(canvas));
canvas.add(img);
});
Notice that we passed the
{ brightness: 100 }
object to the Brightness filter. This is because some filters do not need anything extra, and some (for example grayscale, invert, sepia) need to specify certain parameters. For a brightness filter, this is the brightness value itself (0-255). For a noise filter, this is the noise value (0-1000). And the filter remove the white background ("remove white"), has a threshold (threshold) and distance (distance). Well, sorted out the filters; it's time to create your own!
A sample for creating filters will be quite simple. We need to create a "class", and write a method
applyTo
. Optionally, we can give the filter a toJSON
method (support for JSON serialization), and / or initialize
(if the filter has additional parameters).fabric.Image.filters.Redify = fabric.util.createClass({
type: 'Redify',
applyTo: function(canvasEl) {
var context = canvasEl.getContext('2d'),
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
data = imageData.data;
for (var i = 0, len = data.length; i < len; i += 4) {
data[i + 1] = 0;
data[i + 2] = 0;
}
context.putImageData(imageData, 0, 0);
}
});
fabric.Image.filters.Redify.fromObject = function(object) {
return new fabric.Image.filters.Redify(object);
};
Without delving deeply into the details of the code, it is worth noting that the most important thing happens in the loop, where we change the green (data [i + 1]) and blue (data [i + 2]) components of each pixel to 0, essentially deleting them. The red component remains untouched, which makes the entire image red. As you can see, the
applyTo
method receives a canvas element, which is an image. Having such a canvas, we can go through all the pixels of the image ( getImageData().data
) changing them as we please.Colors
No matter what you prefer working with — hex, RGB, or RGBA color formats — Fabric simplifies the tedious operations and transfers from one format to another. Let's look at a few ways to define color in 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)');
Format translation is very simple.
toHex()
translates color to hex. toRgb()
- in RGB, and toRgba()
- in RGB with alpha channel (transparency).new fabric.Color('#f55').toRgb(); // "rgb(255,85,85)"
new fabric.Color('rgb(100,100,100)').toHex(); // "646464"
new fabric.Color('fff').toHex(); // "FFFFFF"
By the way, you can do more than just translation. You can "overlay" the colors one on top of the other, or make them a black and white version.
var redish = new fabric.Color('#f55');
var greenish = new fabric.Color('#5f5');
redish.overlayWith(greenish).toHex(); // "AAAA55"
redish.toGrayscale().toHex(); // "A1A1A1"
Gradients
An even more expressive way to work with colors is to use gradients. Gradients allows you to smoothly mix one color with another, opening up the possibility of quite amazing effects.
Fabric supports them using a method
setGradient
that is present on all objects. Invoking setGradient('fill', ...)
it is almost like setting the fill value of an object, only a gradient is used instead of color.var circle = new fabric.Circle({
left: 100,
top: 100,
radius: 50
});
circle.setGradient('fill', {
x1: 0,
y1: 0,
x2: 0,
y2: circle.height,
colorStops: {
0: '#000',
1: '#fff'
}
});
In this example, we create a circle at 100,100, with a radius of 50px. Then we set the gradient to it, running along the entire height of the object, from black to white.
As you can see, the method receives a configuration object, which may contain 2 pairs of coordinates (x1, y1 and x2, y2), and a colorStops object. Coordinates indicate where the gradient begins and where it ends. colorStops indicate what colors it consists of. You can define as many colors as you like; the main thing is that their positions are in the range from 0 to 1 (for example, 0, 0.1, 0.3, 0.5, 0.75, 1). 0 represents the beginning of the gradient, 1 represents its end.
Here is an example of a red-blue gradient going from left to right:
circle.setGradient('fill', {
x1: 0,
y1: circle.height / 2,
x2: circle.width,
y2: circle.height / 2,
colorStops: {
0: "red",
1: "blue"
}
});
And here is a 5-step gradient rainbow, with flowers occupying 20% of the entire length:
circle.setGradient('fill', {
x1: 0,
y1: circle.height / 2,
x2: circle.width,
y2: circle.height / 2,
colorStops: {
0: "red",
0.2: "orange",
0.4: "yellow",
0.6: "green",
0.8: "blue",
1: "purple"
}
});
Can you come up with something interesting?
Text
What if you need to display not only pictures and vector shapes on canvas, but also text? Fabric can do it too! Meet me
fabric.Text
. Before talking about the text, it is worth noting why we generally provide support for working with text. After all, canvas has built-in methods fillText and strokeText.
Firstly, in order to be able to work with text as objects. Built-in canvas methods - as usual - allow you to display text at a very low level. But
fabric.Text
after creating an object of type , we can work with it like with any other object on the canvas - move it, scale it, change attributes, etc. The second reason is to have richer functionality than what canvas gives us. Some things that are in Fabric but not in native methods:
- Multi-line . Native methods allow you to write only one line, ignoring line breaks.
- Text alignment . Left, center, right. Useful when working with multi-line text.
- Text background . The background is displayed only under the text itself, depending on the alignment.
- The scenery of the text . Underscore, overline, strikeout.
- The row height . Useful when working with multi-line text.
Well then, let's look at the ubiquitous "hello world"?
var text = new fabric.Text('hello world', { left: 100, top: 100 });
canvas.add(text);
That's all! To display text, you just need to add a type object
fabric.Text
to the canvas, indicating the desired position. The first parameter is needed - this is actually the line of text itself. The second argument is an optional configuration, as usual; You can specify left, top, fill, opacity, etc. In addition to the usual attributes, text objects certainly have their own, related to the text. In short, about these attributes:
fontFamily
The default is Times New Roman. Allows you to change the font family for text.
var comicSansText = new fabric.Text("I'm in Comic Sans", {
fontFamily: 'Comic Sans'
});
fontSize
Controls the size of the text. Note that unlike other objects in Fabric, we cannot resize text using width / height. Instead, fontSize is used, and of course 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
Allows you to make the text fatter or thinner. Just like in CSS, you can use either words (“normal”, “bold”) or numerical values (100, 200, 400, 600, 800). It is important to understand that for a certain thickness you need to have an appropriate font. If the font does not have a “bold” (bold) option, for example, then bold text may not be displayed.
var normalText = new fabric.Text("I'm a normal text", {
fontWeight: 'normal'
});
var boldText = new fabric.Text("I'm a bold text", {
fontWeight: 'bold'
});
textDecoration
Allows you to add strikethrough, underlining, or underlining to text. Again, this declaration works just like in CSS. However, Fabric can do a bit more, allowing you to use these decorations together (such as underlining and strikethrough) by simply listing them with a space.
var underlineText = new fabric.Text("I'm an underlined text", {
textDecoration: 'underline'
});
var strokeThroughText = new fabric.Text("I'm a stroke-through text", {
textDecoration: 'line-through'
});
var overlineText = new fabric.Text("I'm an overline text", {
textDecoration: 'overline'
});
shadow
Shadow for the text. It consists of 4 components: color, horizontal indentation, vertical indentation, and blur size. This should all be familiar if you've worked with shadows in CSS before. By changing these 4 options, you can achieve many interesting effects.
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
Text style. There can be only one of two: “normal” or “italic”. Again, it works the same as in 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
By combining stroke (the color of the outer stroke) and strokeWidth (the width of the outer stroke), pretty interesting effects can be achieved. Here are a couple of examples:
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
Alignment is useful when working with multi-line text. In a single-line text, alignment is not visible, because the width of the text object itself is the same as the length of the line.
Possible values are “left”, “center”, “right”, and “justify”
var text = 'this is\na multiline\ntext\naligned right!';
var alignedRightText = new fabric.Text(text, {
textAlign: 'right'
});
lineHeight
Another attribute most likely familiar from CSS is lineHeight (line height). Allows you to change the distance between lines in multi-line text. Here is an example of text with lineHeight 3, and the second with lineHeight 1.
var lineHeight3 = new fabric.Text('Lorem ipsum ...', {
lineHeight: 3
});
var lineHeight1 = new fabric.Text('Lorem ipsum ...', {
lineHeight: 1
});
textBackgroundColor
Finally, you can give the text a background using textBackgroundColor. Note that the background is filled only under the text itself, and not on the entire "box". To paint over the entire text object, you can use the attribute "backgroundColor". You can also see that the background depends on the alignment of the text and lineHeight. If lineHeight is very large, the background will only be visible under the text.
var text = 'this is\na multiline\ntext\nwith\ncustom lineheight\n&background';
var textWithBackground = new fabric.Text(text, {
textBackgroundColor: 'rgb(0,200,0)'
});
Events
Events are an indispensable tool for creating complex applications. For ease of use, and more detailed configuration, Fabric has an extensive event system; starting from low-level mouse events, and up to high-level events of objects.
Events allow us to “catch” various moments when something happens on the canvas. Want to know when the mouse was clicked? We follow the mouse: down event. How about when an object was added to the canvas? There is an “object: added” for this. Well, what about redrawing the canvas? We use "after: render".
The event API is very simple, and similar to what you are most likely used to in jQuery, Underscore.js, or other popular JS libraries. There is a method
on
for initializing an event listener, and there is a method off
for deleting it.Let's look at an example:
var canvas = new fabric.Canvas('...');
canvas.on('mouse:down', function(options) {
console.log(options.e.clientX, options.e.clientY);
});
We added a “mouse: down” event listener to the canvas object, and specified a handler that would record the coordinates of where this event occurred. Thus, we can see exactly where the click on the canvas occurred. The event handler receives an options object, with two parameters:
e
- the original event, and target
- the Fabric object on the canvas, if it is found. The first parameter is always present, but target
only if a click has occurred on the object. And of course, it is target
transmitted only to the developers of those events where it makes sense. For example, for “mouse: down” but not for “after: render” (since this event does not “have” any objects, it simply means that the canvas was redrawn).canvas.on('mouse:down', function(options) {
if (options.target) {
console.log('an object was clicked! ', options.target.type);
}
});
This example will output “an object was clicked!” If we click on an object. The type of this object will also be shown.
What other events are available in Fabric? At the mouse level, we have " mouse: down ", " mouse: move ", and " mouse: up ". Of the general ones, there is " after: render ". There are events regarding the selection of objects: " before: selection: cleared ", " selection: created ", " selection: cleared ". And of course, the events of the objects: " object: modified ", " object: selected ", " object: moving ", " object: scaling ", "".
It is worth noting that events of the type" object: moving "(or" object: scaling ") occur continuously, while moving or scaling an object, even if it is one pixel. At the same time, events of the type" object: modified "or "Selection: created" occurs only at the end of the action (changing the object, creating a group of objects, etc.).
In the previous examples, we attached the listener to the canvas object (
canvas.on('mouse:down', ...)
). As you might guess, this means that events only apply to that the canvas to which we attached them.If you have several canvases on the page, you can give them knowledgeable listeners. Events on one canvas do not apply to other canvases. For convenience, Fabric allows you to add listeners directly to Fabric objects!
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');
});
In this example, the listeners “join” directly to the rectangle and the circle. Instead of “object: selected”, we use the “selected” event. By the same principle, you can use the event "modified" ("object: modified" when "hang" on the canvas), "rotating" (analogue of "object: rotating"), etc.
You can get acquainted with the events closer and directly in real time in this demo .
On this, the second part came to an end. So many new things, but that's not all! In the 3rd part, we will consider groups of objects, serialization / deserialization of the canvas and the JSON format, SVG parser, as well as the creation of subclasses.