I have an Image() object, which I need to resize. I am using it to fill a shape in canvas.
If I try to change it like image.width = 300, it doesn't resize. If I console.log it, it shows that only the html attribute has been changed.
Is there a way to edit the Image() size directly?
You can do this using the setting the fill.scale object with the properties fill.scale.x and fill.scale.y that you wish to apply to your image.
In the example, this could be done, for example like:
var patternPentagon = new Kinetic.RegularPolygon({
x: 220,
y: stage.getHeight() / 2,
sides: 5,
radius: 70,
fill: {
scale: { x:0.5, y:0.5 },
image: images.darthVader,
offset: [-220, -70]
},
stroke: 'black',
strokeWidth: 4,
draggable: true
});
You can see an example of this working here
Related
Is it possible to blur a closed path element that has a fill using paperjs? Would I have to create an SVG feGaussianBlur primitive for each path that I wanted to blur? How would that affect performance if there were a few hundred path elements on the canvas? I thought about making use of the shadowBlur with some color magic, where the shadow would match the selected path, but it's not quite the same effect. I do not want to use raster.
A trick could be to use the shadowBlur property of the item.
The only thing is that the shadow is only drawn if the item has a fill.
And we don't want the fill to be displayed but only the shadow.
So we could make clever usage of blend modes to hide the fill but not the shadow.
Here's a simple sketch demonstrating this.
new Path.Circle({
center: view.center,
radius: 50,
shadowColor: 'black',
shadowBlur: 20,
selected: true,
// set a fill color to make sure that the shadow is displayed
fillColor: 'white',
// use blendmode to hide the fill and only see the shadow
blendMode: 'multiply',
});
edit
This technique indeed seems to reach a limit when trying to stack items on top of each other.
We can prevent the multiply blend mode from "bleeding out" by wrapping the item into a group which has a blend mode of source-over. This has the effect to scope the children blend modes.
But there is still a trick to find to compose the items together.
Here's a sketch demonstrating where I stopped my investigation.
I'm quite sure that you can find a solution following this track.
function drawBlurryCircle(center, radius, blurAmount, color) {
const circle = new Path.Circle({
center,
radius,
shadowColor: color,
shadowBlur: blurAmount,
// set a fill color to make sure that the shadow is displayed
fillColor: 'white',
// use blendmode to hide the fill and only see the shadow
blendMode: 'multiply'
});
const blurPlaceholder = circle
.clone()
.set({ shadowColor: null, fillColor: null })
.scale((circle.bounds.width + (blurAmount * 2)) / circle.bounds.width);
return new Group({
children: [circle, blurPlaceholder],
blendMode: 'source-over'
});
}
drawBlurryCircle(view.center, 50, 20, 'red');
drawBlurryCircle(view.center + 30, 40, 30, 'lime');
drawBlurryCircle(view.center + 60, 30, 30, 'blue');
A little bit frustrated here. I am trying to get dynamic patterns work as it shown on demo here http://fabricjs.com/dynamic-patterns.
I wrote function but it won't change pattern size once t is created.
I tried to assign img object to window array and change sizes and even inserted rescale operation at the end of the function, but my pattern still won't change its size.
I know i'm doing something wrong, but i cannot figure what.
Maybe it is Fabric.js version or canvas.requestRenderAll();
Please, let me know if you have any idea on how to deal with this problem.
Here is the code.
'setBackgroundItem':function(){
fabric.Image.fromURL(arr.image, function(img) {
var patternSourceCanvas = new fabric.StaticCanvas();
var to_set_width = canvas.getActiveObject().width; // avtorkoda
img.set({opacity: 0.9});
img.scaleToWidth(to_set_width);
w.fills.push(img);
patternSourceCanvas.add(img);
patternSourceCanvas.setDimensions({
width: to_set_width,// на ноуте клиента работает с этим. у меня без может)
height: Math.floor(to_set_width)
});
var texture = patternSourceCanvas.getElement();
var pattern = new fabric.Pattern({
source: texture,
repeat: 'no-repeat',
offsetX: 0,
offsetY: 0
});
var activeObject = canvas.getActiveObject();
var activeGroup = canvas.getActiveGroup();
activeObject.setFill(pattern);
img.scaleToHeight(40);
canvas.renderAll();
});
},
Thanks in advance.
A bit late to the party:
The documentation doesn't specify this, but in order to change the pattern width after you've applied it, you must disable caching on the object that the pattern was applied upon.
In your case:
activeObject.set('objectCaching', false);
Another place where it can be observed (from FabricJS's own example here):
canvas.add(new fabric.Polygon([
{x: 185, y: 0},
{x: 250, y: 100},
{x: 385, y: 170},
{x: 0, y: 245} ], {
left: 0,
top: 200,
angle: -30,
fill: pattern,
objectCaching: false
}));
You either do it like this, or you can make objectCaching false as a default for all the objects (not recommeded for heavy projects)
i am trying to draw a simple circle using box2d with crafty.js but i can't seem to able to draw it
this is the jsfiddle : http://jsfiddle.net/B5UsC/2/
look at this part of the code :
var ball = Crafty.e("2D, Canvas,Color, Box2D,ball")
.attr({ x: 10, y: 15, z:5 })
.color("#fff")
.box2d({
bodyType: 'dynamic',
density: 1.0,
friction: 2,
restitution: 0.2,
shape: 'circle'
}).onContact("Floor",
function (data) {
alert("Hi");
});
the weird thing about it is that alert is executed but the ball is not showing . am i missing something please help
The external resources
Box2dWeb-2.1.a.3.js
box2d.js
crafty.js
this directs to an Unavailable Page that's why it doesn't work in the fiddle
Try downloading the source CraftyJS,Box2dweb and Box2d
Try and see if that works for you.
Ok I got your code working, it seems that the reference library crafty+box2d is a mod made by the user who made the pong game.
You forgot to put the width w and height h attribute in the .attr of the ball object.
var ball = Crafty.e("2D, Canvas,Color, Box2D,Ball")
.attr({ x: 10, y: 15, z:5 , w:25,h:25 })
.color("#dddddd")
.box2d({
bodyType: 'dynamic',
density: 1.0,
friction: 2,
restitution: 0.2,
shape: 'circle'
}).onContact("Floor",
function (data) {
alert("Hi");
});
On the other hand if you want the box outline eating the circle
remove the text ,color in the string argument of Crafty.e and erase the .color property
var ball = Crafty.e("2D, Canvas,ball, Box2D,")
.attr({ x: 10, y: 15, z:5 , w:25,h:25 })
.box2d({
bodyType: 'dynamic',
density: 1.0,
friction: 2,
restitution: 0.2,
shape: 'circle'
}).onContact("Floor",
function (data) {
alert("Hi");
});
Hope this helps :)
I'm working with kineticjs where I have a stage with one layer in it. This layer has multiple shapes on it who react on a mouseover event (they show a tooltip)
besides these shapes I also have some text nodes on a higher ZIndex (so they are above the shapes).
This all works fine with one exception, when a text is on top of a shape, the shape doesn't show a tooltip I assume it's because the textnode uses the event, rather than 'forward' it, eventhough I haven't bound anything to the text node.
How can I propagate events to nodes on a lower ZIndex?
Personally I'd create a separate layer to put anything you dont want to register mouse events on and when you create the layer set its listening property to false.
You could also set the this property for the individual elements.
Here's an example using layers...
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var normalLayer = new Kinetic.Layer();
var textLayer = new Kinetic.Layer({listening :false});
var rect = new Kinetic.Rect({
x: 20,
y: 20,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4
});
rect.on('click', function(evt) {
this.setFill('blue');
normalLayer.draw();
});
normalLayer.add(rect);
var simpleText = new Kinetic.Text({
x: 40,
y: 40,
text: 'Simple Text',
fontSize: 30,
fontFamily: 'Calibri',
textFill: 'yellow'
});
textLayer.add(simpleText);
stage.add(normalLayer);
stage.add(textLayer);
http://jsfiddle.net/MT435/
Remember the listening property can be set for individual elements aswell.
Some part of my code here:
var stage = new Kinetic.Stage({
container: "canvas",
width: 300,
height: 200
});
var layer = new Kinetic.Layer({
});
var line = new Kinetic.Polygon({
id: 'wall',
points: [50, 50, 100, 50, 100, 100, 50, 100],
stroke: "black",
strokeWidth: 4,
draggable: true
});
line.on('dragmove', function(mouseEvent) {
line.getPoints()[2] = {x:mouseEvent.x, y:mouseEvent.y};
layer.draw();
});
stage.add(layer);
layer.add(line);
layer.draw();
The task is to drag polygon by one of the corners (in example by right-bottom). But actually result is not that I expected. What is wrong in my code? or what is correct way of moving elemten by one of the points?
Check out this post iOS6 pull/drag border on circle
The effects are similar, I think, to what you're looking for. You could animate the drag on any of your corners by detecting the click/touch location.
Let me know if you need another example.