Fabric js displaced resize rotate controls - javascript

I have a simple fabric.canvas element which has a background and I have set its width and height equal to that of the above image.
and then added the cap image. the problem is that the resize controls are displaced. I have made this clear in the image too.
This is how I am adding the canvas to the page
$('#canvas_container').empty();
canvas_el = document.createElement('canvas');
canvas_el.id = "canvas";
$('#canvas_container').append(canvas_el);
canvas = new fabric.Canvas('canvas');
var img = new Image();
img.onload = function() {
canvas.setWidth(this.width);
canvas.setHeight(this.height);
canvas.renderAll()
}
img.src =$(this).attr('picUrl');
canvas.setBackgroundImage($(this).attr('picUrl'),function(){
canvas.renderAll();
});
And this is how I am adding the image
fabric.Image.fromURL('img/hat.png', function(img) {
oImg = img.set({ left: 50, top: 50, angle: 0 })
canvas.add(oImg);
canvas.renderAll();
});

I have got the answer on twitter.
I added a canvas.calcOffset() right after changing the width and height of the canvas and also adding the image.
It worked.

Try with oImg.setCoords() after canvas.add(oImg);

Related

Fabric JS clipPath: how to fit the image to the canvas after cropping?

I implemented image cropping using FabricJS and clipPath property.
The question is how do I make the image fit the canvas after cropping? I want the cropped image to fill the canvas area but can't figure out whether it's possible to do using fabric js.
So I want the selected part of the image to fit the canvas size after the user clicks the Crop button:
About the code: I draw a rectangle on the canvas and the user can resize and move it. After that, the user can click the Crop button and get a cropped image. But the cropped part stays the same size it was on the original image whereas I want it to scale and fit the canvas.
Note: I tried to use methods like scaleToWidth. Additionally, I used absolutePositioned set to true for the selection rectangle. I tried to scale to image with this property set to false, but it didn't help.
Please do not suggest using cropX and cropY properties for cropping instead of clipPath as they don't work properly for rotated images.
HTML:
<button>Crop</button>
<canvas id="canvas" width="500" height="500"></canvas>
JS:
// crop button
var button = $("button");
// handle click
button.on("click", function(){
let rect = new fabric.Rect({
left: selectionRect.left,
top: selectionRect.top,
width: selectionRect.getScaledWidth(),
height: selectionRect.getScaledHeight(),
absolutePositioned: true
});
currentImage.clipPath = rect;
canvas.remove(selectionRect);
canvas.renderAll();
});
var canvas = new fabric.Canvas('canvas');
canvas.preserveObjectStacking = true;
var selectionRect;
var currentImage;
fabric.Image.fromURL('https://www.sheffield.ac.uk/polopoly_fs/1.512509!/image/DiamondBasement.jpg', img => {
img.scaleToHeight(500);
img.selectable = true;
canvas.add(img);
canvas.centerObject(img);
currentImage = img;
canvas.backgroundColor = "#333";
addSelectionRect();
canvas.setActiveObject(selectionRect);
canvas.renderAll();
});
function addSelectionRect() {
selectionRect = new fabric.Rect({
fill: 'rgba(0,0,0,0.3)',
originX: 'left',
originY: 'top',
stroke: 'black',
opacity: 1,
width: currentImage.width,
height: currentImage.height,
hasRotatingPoint: false,
transparentCorners: false,
cornerColor: 'white',
cornerStrokeColor: 'black',
borderColor: 'black',
});
selectionRect.scaleToWidth(300);
canvas.centerObject(selectionRect);
selectionRect.visible = true;
canvas.add(selectionRect);
}
Here is my jsfiddle: https://jsfiddle.net/04nvdeb1/23/
I also faced this same issue for a few days. But i could not found any solution even i also found your SO question and github issue. I think clipPath is the best choice for clipping the image using a nice adjustable musk.
Demo Link
Github Repo Link
In the button callback function, you have to implement like this way
step 1: 1st you have to create an Image instance to hold the cropped image
let cropped = new Image();
Step 2: You have to use Canvas.toDataURL() to exports the canvas element to a dataurl image. Here wan want to export only the selection rectangle or mask rectangle, so we pass the mast rect left, top, width, and height
cropped.src = canvas.toDataURL({
left: rect.left,
top: rect.top,
width: rect.width,
height: rect.height,
});
Step 3: I the last step after the image loaded we clear the canvas. create new object with our cropped image, and set some option and rerender the canvas
cropped.onload = function () {
canvas.clear();
image = new fabric.Image(cropped);
image.left = rect.left;
image.top = rect.top;
image.setCoords();
canvas.add(image);
canvas.renderAll();
};
i actually marged Crop Functionality using FabricJs #soution2 with your problem.
Actually you don't have to use clipPath method. What you want is actually move the area you need to the corner, and change the size of canvas.
so the sodo code is as below:
fabricCanvas.setDimensions({
width: cropRectObject.getScaledWidth(),
height: cropRectObject.getScaledHeight()
})
imageObject.set({
left: -cropRectObject.left,
top: -cropRectObject.top
})
fabricCanvas.remove(cropRectObject);
tweaked your fiddle a bit to show this idea:
https://jsfiddle.net/tgy320w4/4/
hope this could help.
const { width, height, left = 0, top = 0 } = rect;
if (width == null || height == null) return;
const zoom = canvas.getZoom();
// toExact is a prototype for precision
const nw = (width * zoom).toExact(1);
const nh = (height * zoom).toExact(1);
const nl = (left * zoom).toExact(1);
const nt = (top * zoom).toExact(1);
// Apply
canvas.clipPath = o;
// Size
canvas.setWidth(nw);
canvas.setHeight(nh);
canvas.absolutePan(new fabric.Point(nl, nt));
canvas.remove(rect);

Why is this appearing behind the canvas instead of drawing over it?

I am working on a dynamic web map with HTML5 and canvas.
I loaded the map in PNG format, but whenever I try to draw on it, it draws behind the map like this:
I need it to draw over the white squares.
This is my code:
window.onload = function() {
var canvas = document.getElementById('canvas1');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
}
img.src = "img/plano.png"; //transparent png
ctx.fillRect(1039, 150, 50, 50);
}
Thanks in advance!
The fillRect needs to happen after the image has loaded. The image loads asynchronously so the only safe place for this to happen is after the drawImage...
img.onload = function() {
ctx.drawImage(img, 0, 0);
ctx.fillRect(200,200,50,50); // Draw rect after image
}

canvas drawimage draw zoomed image

I need to set canvas size using code and than drawImage on this canvas. The problem is drawn image is zoomed.
code follows -
currentImageDIV = $("#cnv").css({ "position" : "relative" ,"height": 400, "width": 800,"top" :"100px" , "border": "1px solid red" });
var c = document.getElementById("cnv");
var ctx = c.getContext("2d");
ctx.imageSmoothingEnabled = false;
var img = new Image();
img.src = "/images/sample2.jpg";
img.onload = function () {
ctx.drawImage(img, 0, 0);
}
If I do not set the canvas size than image drawn as expected, not zoomed.
How can I control the canvas size without drawImage zoomed image ?
I found out that if I hard code the width and height of the canvas tag than no zooming is taking place.
Another solution for this is to set the width and height using prop rather than css (e.g. $("#cnv").prop({"width": 800, "height": 600});)

Why can't I change CSS attributes of my image in javascript?

I created a new image but I'm trying to resize it and add some transformations to it. How ever, they are not taking effect.
Example: https://jsfiddle.net/chung9ey/3/
img.onload = function(){
img.style.width = "500";
img.style.height = "300";
img.style.transform = "perspective(500px) rotateZ(30deg)";
context.drawImage(img, 0 ,0);
}
Styles change properties, not attributes. In order to change the actual attributes you would need to use
img.height = 300;
//or by native API
img.setAttribute("height",300);
and so on for each attribute you wanted to change. Note that attributes are part of the html element and not necessarily part of the css definition (more on that here: https://www.w3.org/TR/CSS21/cascade.html#preshint).
Try using this.
document.getElementById("imageID").style.height="300px";
document.getElementById("imageID").style.width="500px";
That should change the element's style width and height to what you want.
In the HTML script, it'd be
<img src="source.jog" id="imageID"/>
Based on this Stack Overflow answer, change your JS to:
var img = new Image();
var canvas = document.getElementById("hello");
var context = canvas.getContext("2d");
img.onload = function(){
context.save(); // Saves current canvas state (includes transformations)
context.rotate(30); // This rotates canvas context around its top left corner...
context.translate(-275, 125); // ...so you need to make a correction.
context.drawImage(img, 0, 0, 500, 300);
context.restore(); // Restore canvas state
};
img.src = "https://www.enterprise.com/content/dam/global-vehicle-images/cars/CHRY_200_2015.png";
This essentially rotates the canvas's contents after the image is drawn on it.
Part of the image is off-canvas as a result of this rotation, so you may also want to scale the canvas to fit the rotated image.
https://jsfiddle.net/Lcyksjoz/
i would change the image size in the canvas and then manipulating the canvas through id
var img = new Image(100, 100);
var canvas = document.getElementById("hello");
var context = canvas.getContext("2d");
var width = 500;
var height = 300;
img.onload = function(){
img.style.transform = "perspective(200px) rotateZ(30deg)";
context.drawImage(img, 0 ,0, width,height);
}
img.src = "https://www.enterprise.com/content/dam/global-vehicle-images/cars/CHRY_200_2015.png";
document.getElementById("hello").style.width="300px";
https://jsfiddle.net/chung9ey/27/

How the canvas manage the ratio of the image

All:
I wonder if I draw a image on canvas, if the image ratio is not fit the canvas, how does canvas scale it( suppose only width and height set on canvas)?
For example:
<canvas id="myCanvas" style="width:200px; height:200px;"></canvas>
<script>
var canvas = d3.select("#myCanvas").node();
var context = canvas.getContext("2d");
var img = new Image();
img.onload = function(){
console.log(img.naturalWidth, img.naturalHeight);
context.drawImage(img, 0, 0);
}
img.src = "https://www.google.com/images/srpr/logo11w.png";
</script>
The result seems that the image has been stretch a little bit vertically and squeeze horizontally, I want to know why canvas deal it in that way and how to draw it as it is or scale in its ratio like ?
I also tried giving width and height when draw the image, but it still seems not quite right, for example:
// in this way, the image still get stretched and squeeze
<script>
var canvas = d3.select("#myCanvas").node();
var context = canvas.getContext("2d");
var img = new Image();
img.onload = function(){
console.log(img.naturalWidth, img.naturalHeight);
context.drawImage(img, 0, 0, img.naturalWidth/5, img.naturalHeight/5);
}
img.src = "https://www.google.com/images/srpr/logo11w.png";
</script>
OR
// Even I give it a 100 by 100 size, it can not do it that way
<script>
var canvas = d3.select("#myCanvas").node();
var context = canvas.getContext("2d");
var img = new Image();
img.onload = function(){
console.log(img.naturalWidth, img.naturalHeight);
context.drawImage(img, 0, 0, 100, 100);
}
img.src = "https://www.google.com/images/srpr/logo11w.png";
</script>
Thanks
The bitmap of the canvas is by default 300x150 independent of the CSS size.
<canvas id="myCanvas" style="width:200px; height:200px;"></canvas>
This will stretch anything drawn to the 300x150 bitmap to fit 200x200 CSS size.
Use canvas' attributes (or properties from JavaScript) to set the size properly:
<canvas id="myCanvas" width=200 height=200></canvas>

Categories

Resources