I need to build some canvas app, but the shapes are irregular and elements are overlapping each other. I am using fabric.js for canvas and importing SVG files to draw elements, but I can't detect right hovered objects.
Here are examples:
I want to detect on mouse over when it will be above shape.
How it is actualy on my canvas (the red line corners are invisible in canvas ofc)
Example code from Fabric.js
You have to use the "perPixelTargetFind" property of fabricjs.
This will check the mouse over the object with accuracy.
If there is graphic it will trigger the target, otherwise not.
var canvas = new fabric.Canvas('canvas');
canvas.perPixelTargetFind = true;
canvas.add(new fabric.Circle({ radius: 30, fill: 'green', top: 50, left: 100 }));
canvas.add(new fabric.Circle({ radius: 30, fill: 'green', top: 100, left: 200 }));
canvas.on('mouse:over', function(e) {
e.target.setFill('red');
canvas.renderAll();
});
canvas.on('mouse:out', function(e) {
e.target.setFill('green');
canvas.renderAll();
});
<script src="http://fabricjs.com/lib/fabric.js"></script>
<canvas id='canvas' width="550" height="550" style="border:#000 1px solid;"></canvas>
Related
I'm new to Konva.js lib, I implemented drag and drop of the img inside the canvas element, I would like to point user that the img is draggable so I would like to do something like this ->
Any Ideas how to do this inside Konva.js ? Thanks!
You can use stroke with the combination of dash property to make a dotted stroke
Konva.Image.fromURL('https://i.imgur.com/ktWThtZ.png', img => {
img.setAttrs({
x: 50,
y: 50,
scaleX: 0.5,
scaleY: 0.5,
stroke: 'red',
strokeWidth: 10,
dash: [10, 10],
draggable: true
});
layer.add(img);
layer.draw();
});
Demo: https://jsbin.com/xoporixura/1/edit?html,js,output
If you need padding for the stroke you can add a rectangle on top of the image with the bigger size.
When I draw a circle on fabricjs canvas it always appears on bottom right corner even though I set the coordinates to center. How can I make the circle draw center of the canvas?
var circle = new fabric.Circle({
top: 300,
left: 300,
radius: 100
});
You can set drawing origin of the circle object to center, using originX and originY property.
var canvas = new fabric.Canvas('c');
var circle = new fabric.Circle({
top: 100,
left: 100,
radius: 50,
originX: 'center',
originY: 'center'
});
canvas.add(circle);
canvas{border:1px solid #ccc}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.14/fabric.min.js"></script>
<canvas id="c" width="200" height="200"></canvas>
You have centerObject().
canvas.add(oImg)
canvas.centerObject(circle);
canvas.renderAll();
That sets your circle in the center of the canvas.
I currently have some javascript that receives an image from a variable and loads it into the canvas. The canvas is inside a div in order to use kineticjs. I'm loading a regular hexagon with the following code:
function MakeShape()
{
var stage = new Kinetic.Stage({
container: 'container',
width: 490,
height: 225
});
var polyLayer = new Kinetic.Layer();
var hexagon = new Kinetic.RegularPolygon({
x: stage.width()/2,
y: stage.height()/2,
sides: 6,
radius: 70,
fill: 'red',
offset: {
x: 100,
y: 0
},
draggable: true
});
polyLayer.add(hexagon);
stage.add(polyLayer);
}
However, when loading, the layer receives the background of the canvas, when I want the shape to be above the image. Do I have to draw the image onto the layer as well as the shape? How am I supposed to do this when the image is loaded before the shape? Thanks.
I'm not sure what you mean by "javascript receives an image from a variable and loads it into the Canvas". I'm guessing that your Canvas element's is assigned a background-image==that image.
Anyway, new Kinetic.Stage plus new Kinetic.Layer will create a new canvas that covers the container element. So any image you put in your Div and Canvas will be overlaid by the new Canvas that KineticJS creates.
Bottom line...Yes, draw the image onto the layer (using new Kinetic.Image) and eliminate your Canvas element with the image.
Good luck with your project!
[ Added Example code ]
var stage = new Kinetic.Stage({
container: 'container',
width: 490,
height: 225
});
var polyLayer = new Kinetic.Layer();
stage.add(polyLayer);
var hexagon,image1;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/nightscape.jpg";
function start(){
// add the image first
// It's z-index will be lower then the hexagon's z-index
// so the hexagon will be drawn over the image
image1=new Kinetic.Image({
x:0,
y:0,
image:img,
});
polyLayer.add(image1);
hexagon = new Kinetic.RegularPolygon({
x: stage.width()/2,
y: stage.height()/2,
sides: 6,
radius: 70,
fill: 'red',
offset: {
x: 100,
y: 0
},
draggable: true
});
polyLayer.add(hexagon);
polyLayer.draw();
}
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:490px;
height:225px;
}
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.1.0.min.js"></script>
<h4>Background image with draggable hex on top.</h4>
<div id="container"></div>
I'm using fabric.js to create objects on a canvas. I have a couple of objects together in a Group. When the group is selected, an event is triggered, which creates and adds a circle, centered at the end of a line. When a selection is cleared, another event is triggered, which removes the circle.
What I don't understand is why the circle doesn't change position to the line's new end point, when I move the group, deselect it, and then re-select it.
<html>
<head>
<script type="text/javascript" src="path/to/fabric.1.4.5.js"></script>
</head>
<body>
<canvas id="c" width="800" height="600"></canvas>
<script type="text/javascript">
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
var canvas = new fabric.Canvas('c');
var circle;
var text = new fabric.Text('hello world', {
fontSize: 30,
originX: 'left',
originY: 'top',
left: 25,
top: 30
});
var line = new fabric.Line([10,10, 100,100], {
stroke: 'green',
strokeWidth: 2
});
var group = new fabric.Group([line, text], {
});
group.on('selected', function() {
circle = new fabric.Circle({
strokeWidth: 5,
radius: 28,
fill: 'rgba(200,200,200,0.4)',
stroke: '#666',
left: line.get('x2'),
top: line.get('y2')
})
canvas.add(circle);
});
canvas.add(group);
canvas.renderAll();
canvas.on('selection:cleared', function () {
group._objects.length = 2;
canvas.remove(circle);
});
</script>
</body>
</html>
Here's the same code on jsFiddle: http://jsfiddle.net/Tqmdw/
The position of your line actually doesn't change. Have a look at the groups tutorial. http://fabricjs.com/fabric-intro-part-3/#groups. In a group items are positioned relative to the groups center and the group is handled as a single entity. That means moving the group will only update the groups top and left position. You can use these new top/left values and calculate the endpoint of the line.
group.on('selected', function() {
circle = new fabric.Circle({
strokeWidth: 5,
radius: 28,
fill: 'rgba(200,200,200,0.4)',
stroke: '#666',
left: group.left + line.get('x2'),,
top: group.top + line.get('y2'),
})
canvas.add(circle);
});
I created an updated fiddle: http://jsfiddle.net/2e9B9/5/
I have a canvas drawn in Fabric.js that i am adding a group of rectangles to, i want to limit the edges of those rectangles as a group to not go outside a certain area.
Imagine making a stripy t-shirt, the stripes are make by using a series of rectangles and i need to keep them to the shape of the t-shirt.
I think its better to clip the entire canvas to the shape of the t shirt, so anything i add to it remains within the t-shirt but i am stuck. So far i am only clip to basic circles and rectangles.
Thanks
You can just render a shape inside canvas.clipTo :)
I just loaded a random SVG shape in kitchensink and did this:
var shape = canvas.item(0);
canvas.remove(shape);
canvas.clipTo = function(ctx) {
shape.render(ctx);
};
As you can see, entire canvas is now clipped by that SVG shape.
You may also try this one: http://jsfiddle.net/ZxYCP/198/
var clipPoly = new fabric.Polygon([
{ x: 180, y: 10 },
{ x: 300, y: 50 },
{ x: 300, y: 180 },
{ x: 180, y: 220 }
], {
originX: 'left',
originY: 'top',
left: 180,
top: 10,
width: 200,
height: 200,
fill: '#DDD', /* use transparent for no fill */
strokeWidth: 0,
selectable: false
});
You can simply use Polygon to clip. Answer is based on #natchiketa idea in this question Multiple clipping areas on Fabric.js canvas