I have a Fabric.js canvas inside in a responsive design with boostrap. To resize the canvas, i use canvas.setDimensions({width:w, height:h}); From the width and the height of the current window clientWidth and clientHeight. Here is my canvas and his container :
<div style="width: 100%;" class="canvas-container">
<canvas id="canvas" class='img-fluid'></canvas>
</div>
When the canvas is resized, for each object in the canvas i change proportionally their size and location. I calculate a factor to apply to each object's top/left/width/height using the original and new canvas sizes. This code runs every time the canvas is resized:
function resizeCanvas() {
const outerCanvasContainer = $('.canvas-container')[0];
const ratio = canvas.getWidth() / canvas.getHeight();
const containerWidth = outerCanvasContainer.clientWidth;
const containerHeight = outerCanvasContainer.clientHeight;
const scale = containerWidth / canvas.getWidth();
const zoom = canvas.getZoom() * scale;
canvas.setDimensions({width: containerWidth, height: containerWidth / ratio});
canvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);
canvas.calcOffset();
canvas.forEachObject(function(o) {
o.setCoords();
});
if (canvas.width != containerWidth) {
var scaleMultiplier = newWidth / canvas.width;
var objects = canvas.getObjects();
var factorX = newWidth / canvas.getWidth();
var factorY = newWidth / canvas.getHeight();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX *factorX;
objects[i].scaleY = objects[i].scaleY *factorX;
objects[i].left = factorX * objects[i].left;
objects[i].top = factorX * objects[i].top ;
objects[i].setCoords();
};
canvas.setWidth(canvas.getWidth() * factorX);
canvas.setHeight(canvas.getHeight() * factorY);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
Resizing works fine, all the objects change their dimensions correctly. The problem is that most objects cannot be selected after the canvas is resized. Also, clicking on empty areas of the canvas sometimes selects objects...
// Create a new instance of Canvas
var canvas = new fabric.Canvas("canvas");
canvas.setDimensions({width: 1000, height: 1000});
resizeCanvas();
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 100,
borderColor: '#000',
cornerColor: '#000'
});
// Render the Text on Canvas
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
// function to resize canvas and its objects
function resizeCanvas() {
const outerCanvasContainer = $('.canvas-container')[0];
const ratio = canvas.getWidth() / canvas.getHeight();
const containerWidth = outerCanvasContainer.clientWidth;
const containerHeight = outerCanvasContainer.clientHeight;
const scale = containerWidth / canvas.getWidth();
const zoom = canvas.getZoom() * scale;
canvas.setDimensions({width: containerWidth, height: containerWidth / ratio});
canvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);
canvas.calcOffset();
canvas.forEachObject(function(o) {
o.setCoords();
});
if (canvas.width != containerWidth) {
var containerWidth_ = $(outerCanvasContainer).width();
var scaleMultiplier = containerWidth_ / canvas.width;
var objects = canvas.getObjects();
var factorX = containerWidth_ / canvas.getWidth();
var factorY = containerWidth_ / canvas.getHeight();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX *factorX;
objects[i].scaleY = objects[i].scaleY *factorX;
objects[i].left = factorX * objects[i].left + 15;
objects[i].top = factorX * objects[i].top + 10;
objects[i].setCoords();
};
canvas.setWidth(canvas.getWidth() * factorX);
canvas.setHeight(canvas.getHeight() * factorY);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
body { background-color:#000 }
#canvas{border: 1px solid #666}
.upper-canvas {max-width: 1000px;max-height: 1000px;}
.container{margin:0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<div style="width: 100%;" class="canvas-container">
<canvas id="canvas" class='img-fluid'>
<p>This is fallback content for users of assistive technologies or of browsers that don't have full support for the Canvas API.</p>
</canvas>
</div>
</div>
</div>
</div>As you can see in the snippet, when page is loaded, you can modify the text like you want but if you click to "Full page", you cannot do it anymore or it become difficult to do it.
Here a video explaining the problem : https://a.uguu.se/pgOYGfJy.webm
I have done a lot of research on the internet and tried a lot of things and i would like to know if anyone knows the best way to make a responsive design while keeping the correct values of the canvas objects in order to avoid this problem happening.
Thank you
from The best way to resize canvas with its objects
No comments:
Post a Comment