I am using a Kinetic.image object like this:
this.icon = new Kinetic.Image({
x: self.x,
y: self.y,
offset: [32,32],
image: self.imageItem.image,
width: self.size,
height: self.size,
scale: self.scale,
rotationDeg: self.angle,
draggable: true
});
The image is a PNG with transparent pixels. I also create a image hit region:
self.icon.createImageHitRegion(function() {
self.icon.getLayer().drawHit();
});
However, the hit region is wrong when I use the mouseover event. I suspect the hitregion is not scaled. Note that I also use offset so that the image rotates around it's center.
Am I doing something wrong of am I dealing with a bug here?
I had the same problem when the image is created passing width and height.
The library uses the width and height of the image to create the canvas to draw the hit region but the width and height is not used to scale the image that is drawn on the canvas.
If you search the kineticjs source you will see that inside createImageHitRegion there is a line that looks something like:
_context.drawImage(image, 0, 0);
Add the width and height for the image and it should work as expected:
_context.drawImage(image, 0, 0, this.getWidth(), this.getHeight());
In my case I didn't have to pass the scale attribute while creating the image, please verify if this is working when you provide the scale attribute otherwise you will have to tweak createImageHitRegion to account for that.
Related
I have the map on which I need to draw some amount of hexagons (approximately it will be from 50*50 to 150*150 elements).
When I draw them on the canvas using PIXI, I get really strange behavior: while it's not a lot of elements, the map has been drawn correctly, all the elements on their places. But when the canvas size changed to about 5000px width and height, all the elements are moved top above the screen. Moreover, the click on the element has been handled on the place where it should be.
I've created a pen to demonstrate this: https://codepen.io/cuddlemeister/pen/OdzMBw
Try to change canvasWidth and canvasHeight in the evnironment from
canvasWidth: 1500, canvasHeight: 1500 to canvasWidth: 4500, canvasHeight: 7500 and you will see the result.
Here's the evnironment object:
const environment = {
size: 60,
map: {
rows: 30,
cols: 30,
},
canvasWidth: 1500,
canvasHeight: 1500
}
You will the that all the visible content has been moved in top direction and it depends on the height of the canvas.
There's a logger enabled on click, try to click the elements or the area where they are supposed to be - the click is handled correctly on the place where the element should be
It's because the max size that WebGL context can handle. You can check it by logging app.gl property.
When using not accelereated canvas via "forceCanvas" everything is ok.
I don't think there is any way to bypass this limitation.
Why do you need so big canvas?
Let's say I'm working on a 1000x1000 px fabric canvas. I add an 200x200px image right in the middle (top: 400, left: 400), then save my canvas as json. (the bag on these pictures is a background image, don't mind it)
I create another canvas, which is smaller. If I load my json, image will still be 200x200px, and 400px from top and left, therefore getting out of my canvas.
How can I make sure that, once loaded in a smaller/bigger canvas, my objects will scale accordingly ?
Work out the new canvas dimensions as a percentage of the original canvas then set the scale on each of the items in the callback of loadJSON.
As in your example if original canvas was 400x400, new one is 200x200 then scale is 0.5. Apply that to each object in the callback of loadJSON and to its coordinates (top, left etc etc).
I am using fabric version '2.2.0'.
while creating an image object pass top, left, width, height.
const imageobj = new fabric.Image(image, {'top': 50, 'left': 50, 'width': 300, 'height': 300});
width / height values passed to initialize the image object are used in the image.
But the image does not fit to the full width/height when the image's width/height is less than the width/height values passed to initialize the object
If the actual image's width/height is more than the width/height passed to initialize the object, the image is cropped
I want the image to fit in given width/height; but the scaleX/scaleY should not be changed. It should always be 1.
I understand there is a breaking change with fabric.image from Fabric.js V 2.0
http://fabricjs.com/v2-breaking-changes
I have changed the fabric.Image.fromObject() as suggested in the above link. But that does not affect setting width/height during image creation.
In fabricjs version 1.7.19, the full image is fit in the given width/height.
I want the similar behaviour with fabric.js2.2.0
I have an image (the blue box) and ad red rectangle. The image's offset is set to the center of the image to make rotation around the center of the image. The code is similar to the following:
var image = new Kinetic.Image({
x: 200,
y: 100
});
image.offsetX(100);
image.offsetY(50);
var rect = new Kinetic.Rect();
var group = new Kinetic.Group();
group.add(image);
group.add(rect);
layer.add(group);
stage.add(layer);
The stage than looks something like this:
After I rescale the image with
image.scaleX(0.5);
image.scaleY(0.5);
I get the following:
The red rectangle is not attached to the image anymore.
I could do
rect.scaleX(0.5);
rect.scaleY(0.5);
but this would change the size of the rect.
How do I rescale the image and keep the rectangle attached to the same position as before?
Edit:
The following image shows what it should look like after the image scaling. Event after the scaling the red rectangle should be attached to the image.
If you want the red rect to be centered in the top-left of the blue image after scaling the image, you will need to listen for changes in the images scaleX and scaleY properties.
You can listen for scaleX / scaleY property changes like this:
image.on("scaleXChange scaleYChange",function(){
// either scaleX or scaleY has changed on this image
});
Then you can reposition the rect to be centered on the images top-left corner like this:
image.on("scaleXChange scaleYChange",function(){
var imgX=this.x()-this.offsetX()*this.scaleX();
var imgY=this.y()-this.offsetY()*this.scaleY();
rect.position({x:imgX-rect.width()/2,y:imgY-rect.height()/2});
})
Here's a Demo: http://jsfiddle.net/m1erickson/6H9aK/
Do this instead to apply the scaling to both x and y axes at the same time, rather than scaling one first, then the other:
rect.scale({x:0.5,y:0.5});
I'm using context-blender to apply a multiply effect on the first 192 pixels of the html background-image with a fixed color to achieve a transparency effect on the header of the page.
On the html I have 2 canvas. One for the part of the image to apply the multiply effect and one for the color.
On the javascript, after setting the color of the color-canvas and the width of both canvas to the window.innerWidth I'm getting the background image with:
imageObj.src = $('html').css('background-image').replace(/^url|[\(\)]/g, '');
Now comes the problem. I want to draw a cropped image to the image to the image-canvas so I can apply the multiply effect. I'm trying to do the following:
imageObj.onload = function(){
// getting the background-image height
var imageHeight = window.innerWidth * imageObj.height / imageObj.width;
// get the corresponding pixels of the source image that correspond to the first 192 pixels of the background-image
var croppedHeight = 192 * imageObj.height / imageHeight;
// draw the image to the canvas
imageCanvas.drawImage(imageObj, 0, 0, imageObj.width, croppedHeight, 0, 0, window.innerWidth, 192);
// apply the multiply effect
colorCanvas.blendOnto( imageCanvas, 'multiply');
}
But I'm doing something wrong getting the cropped height.
Ex: For an 1536x1152 image and a 1293x679 browser container, the value I'm getting for the source cropped height is 230 but to get the correct crop I need to use something around 296.
Edit:
I'm using background-size: cover on the css to create the background-image
Edit2:
I created a fiddle to illustrate the problem. If you uncomment the line //cHeight *= magicConstant; the cropped image looks a lot better but things stop making sense. I removed the multiply effect on the fiddler but that's not required to reproduce the problem. I also noticed that the behavior changed if I remove the second canvas from the URL.
Btw, this behavior happened with google chrome, but I think the same thing happens on safari and firefox.
OK, I've fixed it. Man was that hard! Mainly because you forgot to set the imageCanvas' canvas height. It also didn't help that the image has a white border. I spent a hell of a lot of time trying to figure out where the padding was coming from.
So to start, for the case of the fiddle, in function doBlending(), set imageCanvas.canvas.height = height;
Then the calculations in crop() need to cover 2 possibilities. Is the image being scaled for height and truncated on the left or scaled for width and truncated on the bottom? I'm not going to write both for you, but here's the one for the case where it is scaled for height:
function crop(imageObj, imageCanvas, colorCanvas) {
// Assumes bg image is scaled for hight
var scale = imageObj.height / window.innerHeight;
var targetHeight = imageCanvas.canvas.height;
var targetWidth = window.innerWidth;
imageCanvas.drawImage(imageObj,
0, 0, targetWidth * scale, targetHeight * scale,
0, 0, targetWidth, targetHeight);
}
I really have no idea where you came up with the scaling factors in your example. The image is going to be scaled by multiplying both the x and y dimensions by some scale factor. That's how you preserve the aspect ratio. The scale factor will be the larger of the one to make the height of the image match the height of the window and the one to make the width of the image match the width of the window.
I think it may not be valid for you to be using window inner dimensions here. Since cover will maintain the aspect ratio of the background image it means that both of its dimensions may not be fully displayed. So if you are trying to transform between aspect ratios to determine where to clip, you would have to account for the fact that the image may flow out of the window borders.