I'm currently developping an application on mobile device (android and iPhone) with ionic and cordova. I would like to edit a picture. I use fabric.js library to do that. Fabric.js converts an image and other items into canvas. Then I add some image on the canvas (stickers) and export it as an image(dataURL). So the size of the canvas is really important because it is a quality factor (export an image based on small canvas will result in poor quality). The canvas size is about 607*1080 pixel (depending on the device that took the photo). I would like to fit it in the screen without losing quality (like explained below I can't resize the canvas without losing quality).
I tried 3 ideas but no one has worked.
I don't know if there are other ways to do that but I'm stucked with this issue for 3 days and I've spend a lot of time on forums, fabricjs doc and google and I don't find any working solution or something else that can help me.
EDIT: There are 2 working solution below. Check my answer to see how to do that with css.
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = 800;
canvas.height = 600;
css:
/* media query 1 */
#canvas{
width: 400px;
height: 250px;
}
/* media query 2 */
#canvas{
width: 200px;
height: 120px;
}
pros:
All the resolution is given by canvas width and height (800/600)
cons:
Fit well for square canvases aspect ration (1:1), problems with output for weird aspect ratios where you need to compute your css height based,
original height / original width * new width = new height;
this is out of my league in css...
Read some time ago on fabric.js git issues section where, technique (css resize) isn't recommended due to slowness and incorrect objects transactions, this may be changed I know I tested and objects were incorrect re-sized (random colored pixels, transactions shadows remain in canvas , in other words a mess)
Just re-size your canvas at window re-size (responsive canvas) and when you need to export to exact dimension you need to re size your canvas to exact pixel resolution, or create another canvas hidden.
this example is for 1:1 ration canvas (you need to apply aspect ratio to canvas and objects inside):
$(window).resize(function (){
if (canvas.width != $(".container").width()) {
var scaleMultiplier = $(".container").width() / canvas.width;
var objects = canvas.getObjects();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX * scaleMultiplier;
objects[i].scaleY = objects[i].scaleY * scaleMultiplier;
objects[i].left = objects[i].left * scaleMultiplier;
objects[i].top = objects[i].top * scaleMultiplier;
objects[i].setCoords();
}
canvas.setWidth(canvas.getWidth() * scaleMultiplier);
canvas.setHeight(canvas.getHeight() * scaleMultiplier);
canvas.renderAll();
canvas.calcOffset();
}
});
At submit export canvas data re-size canvas to desired resolution, voila:
function GetCanvasAtResoution(newWidth)
{
if (canvas.width != newWidth) {
var scaleMultiplier = newWidth / canvas.width;
var objects = canvas.getObjects();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX * scaleMultiplier;
objects[i].scaleY = objects[i].scaleY * scaleMultiplier;
objects[i].left = objects[i].left * scaleMultiplier;
objects[i].top = objects[i].top * scaleMultiplier;
objects[i].setCoords();
}
canvas.setWidth(canvas.getWidth() * scaleMultiplier);
canvas.setHeight(canvas.getHeight() * scaleMultiplier);
canvas.renderAll();
canvas.calcOffset();
}
return canvas.toDataURL();
}
);
It's not a big deal with the rations different then 1:1 you need to compute scale multiplayer for height as well, easy to understand ratio: http://andrew.hedges.name/experiments/aspect_ratio/