Is there any solution for maintaining object size even if the user zoom in or out? I want to achieve like on the google maps behavior. So if I have an object (group of object) with a height and width of 20 even if I zoom into it, it should still be 20 pixels by default. Right now the behavior I have is that when the user zoom in or out the image gets bigger / smaller. I also did looping all the objects that I have on the canvas then set the scaleX and scaleY for it but the result was so laggy for me.
var canvas = new fabric.Canvas('c') ;
var circle = new fabric.Circle({
radius: 20, fill: 'red', left: 100, top: 100
});
var triangle = new fabric.Triangle({
fill: 'red', left: 200, top: 200
});
canvas.add(circle, triangle) ;
//canvas.zoomToPoint(new fabric.Point(canvas.getCenter().left, canvas.getCenter().top,1)) ;
$(function(){
$('#zoomIn').click(function(){
canvas.setZoom(canvas.getZoom() * 1.1 ) ;
}) ;
$('#zoomOut').click(function(){
canvas.setZoom(canvas.getZoom() / 1.1 ) ;
}) ;
}) ;
#canvasContainer {border: dotted gray thin ;}
<script src=".1.1/jquery.min.js"></script>
<script src=".js/1.7.22/fabric.min.js"></script>
<button id="zoomIn">+</button>
<button id="zoomOut">-</button>
<div id="canvasContainer">
<canvas id="c" width="400" height="400"></canvas>
</div>
Is there any solution for maintaining object size even if the user zoom in or out? I want to achieve like on the google maps behavior. So if I have an object (group of object) with a height and width of 20 even if I zoom into it, it should still be 20 pixels by default. Right now the behavior I have is that when the user zoom in or out the image gets bigger / smaller. I also did looping all the objects that I have on the canvas then set the scaleX and scaleY for it but the result was so laggy for me.
var canvas = new fabric.Canvas('c') ;
var circle = new fabric.Circle({
radius: 20, fill: 'red', left: 100, top: 100
});
var triangle = new fabric.Triangle({
fill: 'red', left: 200, top: 200
});
canvas.add(circle, triangle) ;
//canvas.zoomToPoint(new fabric.Point(canvas.getCenter().left, canvas.getCenter().top,1)) ;
$(function(){
$('#zoomIn').click(function(){
canvas.setZoom(canvas.getZoom() * 1.1 ) ;
}) ;
$('#zoomOut').click(function(){
canvas.setZoom(canvas.getZoom() / 1.1 ) ;
}) ;
}) ;
#canvasContainer {border: dotted gray thin ;}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/fabric.js/1.7.22/fabric.min.js"></script>
<button id="zoomIn">+</button>
<button id="zoomOut">-</button>
<div id="canvasContainer">
<canvas id="c" width="400" height="400"></canvas>
</div>
Share
Improve this question
edited Feb 2, 2018 at 9:18
AndreaBogazzi
14.8k3 gold badges41 silver badges67 bronze badges
asked Feb 2, 2018 at 8:52
Mark SantosMark Santos
3771 gold badge3 silver badges15 bronze badges
10
- If you want to maintain the scale of the objects then what is the use of canvas zoom? – Durga Commented Feb 2, 2018 at 9:20
- I did some work around on it using the zoom level divided by 1 but the output for me was so laggy. – Mark Santos Commented Feb 2, 2018 at 9:24
- I already updated the fiddle example. Right now I'm experiencing so much lag when zoom in or out since the group are posed of 6 different type of objects. – Mark Santos Commented Feb 2, 2018 at 9:28
- 1 The right example for my problem is the google maps. I want the object not to get bigger or smaller even if I zoom in or out into it. – Mark Santos Commented Feb 2, 2018 at 9:32
- Mark the lag can e from the fabric 1.5 version. Depending how much code you wrote and on what project you are, try to switch to 2.0 or at least 1.7.22 How many groups of 6 objects do you have on your map? – AndreaBogazzi Commented Feb 2, 2018 at 9:33
2 Answers
Reset to default 4This is not a built in feature of fabricjs and you have to solve it with subclassing or modification of the standard code of the fabric.Object class.
I will make an example then you can use it to find the solution that better suits your project.
So for the whole canvas there is a zoom stage, and then every object has its own transformation. This happen in fabric.Object.prototype.transform
. At that point the zoom is done and you can't really avoid it. What you can do is zoom in the opposite direction before drawing.
So flag the objects you need to do not zoom with a new property ignoreZoom
default to false.
Modify the fabric.Object.prototype.transform in this way:
transform: function(ctx, fromLeft) {
if (this.group && !this.group._transformDone && this.group === this.canvas._activeGroup) {
this.group.transform(ctx);
}
// ADDED CODE FOR THE ANSWER
if (this.ignoreZoom && !this.group && this.canvas) {
var zoom = 1 / this.canvas.getZoom();
ctx.scale(zoom, zoom);
}
// END OF ADDED CODE FOR THE ANSWER
var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();
ctx.translate(center.x, center.y);
this.angle && ctx.rotate(degreesToRadians(this.angle));
ctx.scale(
this.scaleX * (this.flipX ? -1 : 1),
this.scaleY * (this.flipY ? -1 : 1)
);
this.skewX && ctx.transform(1, 0, Math.tan(degreesToRadians(this.skewX)), 1, 0, 0);
this.skewY && ctx.transform(1, Math.tan(degreesToRadians(this.skewY)), 0, 1, 0, 0);
},
This solves rendering, but does not solve controls and caching. Caching is harder to understand, so i suggest you just disable caching for the objects that do not need to zoom.
For controls i ll be back later, is not super simple.
fabric.Object.prototype.ignoreZoom = false;
fabric.Object.prototype.transform = function(ctx, fromLeft) {
if (this.group && !this.group._transformDone && this.group === this.canvas._activeGroup) {
this.group.transform(ctx);
}
// ADDED CODE FOR THE ANSWER
if (this.ignoreZoom && !this.group && this.canvas) {
var zoom = 1 / this.canvas.getZoom();
ctx.scale(zoom, zoom);
}
// END OF ADDED CODE FOR THE ANSWER
var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();
ctx.translate(center.x, center.y);
this.angle && ctx.rotate(degreesToRadians(this.angle));
ctx.scale(
this.scaleX * (this.flipX ? -1 : 1),
this.scaleY * (this.flipY ? -1 : 1)
);
this.skewX && ctx.transform(1, 0, Math.tan(degreesToRadians(this.skewX)), 1, 0, 0);
this.skewY && ctx.transform(1, Math.tan(degreesToRadians(this.skewY)), 0, 1, 0, 0);
};
var canvas = new fabric.Canvas('c') ;
var circle = new fabric.Circle({
radius: 20, fill: 'red', left: 100, top: 100, ignoreZoom: true
});
var triangle = new fabric.Triangle({
fill: 'red', left: 200, top: 200
});
canvas.add(circle, triangle) ;
//canvas.zoomToPoint(new fabric.Point(canvas.getCenter().left, canvas.getCenter().top,1)) ;
$(function(){
$('#zoomIn').click(function(){
canvas.setZoom(canvas.getZoom() * 1.1 ) ;
}) ;
$('#zoomOut').click(function(){
canvas.setZoom(canvas.getZoom() / 1.1 ) ;
}) ;
}) ;
#canvasContainer {border: dotted gray thin ;}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/fabric.js/1.7.22/fabric.min.js"></script>
<button id="zoomIn">+</button>
<button id="zoomOut">-</button>
<div id="canvasContainer">
<canvas id="c" width="400" height="400"></canvas>
</div>
Here are the following steps on how we solved this problem:
1.GET the scale - (1 / zoomLevel). I set it to "1" by default.
Loop all the group objects and set the "scaleX" and "scaleY" into this kind of calculation.
objects.forEach(object => {
object.scaleX = (scale || 1) * 2.5;
object.scaleY = (scale || 1) * 2.5;
});