I have a canvas that has some elements and i would like to add an event handler when the user selects an element(clicks on an element) on the canvas.
I tried using selection: created and object: selected events to handle the same but It only works when a user selects an element and then clicks on somewhere else in the canvas and then tries to select another element it works perfectly, But When the user clicks on one element(event handler triggered) and then clicks on another element the event handler is not triggering. How do I handle this?
i see that there is an option to use as mentioned here in the issue with selection:created and
selection:updated https://github.com/fabricjs/fabric.js/issues/4886
But is there a way i could use them together ?
const canvas = new fabric.Canvas('paper', {
preserveObjectStacking: true,
enableRetinaScaling: false,
imageSmoothingEnabled: false
});
canvas.setHeight(500);
canvas.setWidth(700);
const red = new fabric.Rect({
id: 'red',
left: 10,
top: 10,
width: 100,
height: 100,
fill: 'red'
});
const green = new fabric.Rect({
id: 'green',
left: 150,
top: 150,
width: 100,
height: 100,
fill: 'green'
});
canvas.add(red);
canvas.add(green);
canvas.renderAll();
canvas.on("selection:created", function(obj){
alert(obj.target.id)
});
canvas.on("selection:updated", function(obj){
alert(obj.target.id)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.2.3/fabric.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="paper" width="400" height="400" style="border:1px solid #ccc"></canvas>
Here is a pretty simple solution for having both the event handlers combined and linking both of them to the same method will be a simple solution for this, Any better solutions will be appreciated.
canvas.on({
'selection:updated': HandleElement,
'selection:created': HandleElement
});
function HandleElement(obj){
//Handle the object here
}
This is driving me crazy. If I run the simple HTML below it works on my IPad2 (A1396) but not on my IPad 3 (A1416). Whenever I rotate the IPad 3 from Portrait to Landscape Safari will crash. I looks like there is a relation between the number of layers added and the width/height (of each layer).
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.2.min.js"></script>
<script defer="defer">
var stage = new Kinetic.Stage({
container: 'container',
width: 580,
height: 400
});
var NrOfAttribute = 50;
for (var AttributeNo = 0, NrOfAttribute; AttributeNo < NrOfAttribute; AttributeNo++) {
var layer = new Kinetic.Layer();
var rect = new Kinetic.Rect({
x: 20*AttributeNo,
y: 20*AttributeNo,
width: 50,
height: 10,
fill: 'green',
stroke: 'black',
strokeWidth: 4
});
// add the shape to the layer
layer.add(rect);
// add the layer to the stage
stage.add(layer);
}
</script>
</body>
</html>
Is this a bug or some memory problem on the IPad? Any help would be appreciated because I really need this to work.
Thanks!
Edit: I just tested to do the same with "regular" Canvas and if I increase the number of layers it will also crash (so it doesn't seem to be Kinetic specific). It will also crash on Ipad2 if you increase the number of layers enough.
This might not be an option for you, but do you need a separate layer for each Rect, or could you put them all in the same layer? I suspect that would help reduce memory usage, as you'd wouldn't end up with 50 canvas elements. You could give each Rect a unique name and then still be able to manipulate them individually with something like rect = layer.find('.{name}'); # do something with rect
SO I have a lot of Kinetic polygons, and I collect them and store in a variable like this:
var midr = layer.find('.midr');
I want to change their colors, so I want to delete them and draw them with different colour:
midr.on('mouseover',function(){
midr.destroy();
Boxes.MidR(color.R,color.G,color.B,1,'midr');
midr = layer.find('.midr');
});
midr.on('mouseout',function(){
midr.destroy();
Boxes.MidR(color.R,color.G,color.B,0,'midr');
midr = layer.find('.midr');
});
where:
var Boxes={
.....
MidR:function(R,G,B,A,group){
var C = shade(R,G,B,25,"+");
Mid_right.left(C.r,C.g,C.b,A,group);
var C = shade(R,G,B,20,"-");
Mid_right.back(C.r,C.g,C.b,A,group);
Mid_right.right(R,G,B,A,group);
Mid_right.bottom(R,G,B,A,group);
Mid_right.shelf(R,G,B,A,group);
}, ....
}
and
var Mid_right={
left:function(R,G,B,A,group){
frame([89,192,120,192,120,309,89,315],150,150,150,A,group);
frame([75,311,89,315,89,192,75,192],R,G,B,A,group)
},
right:function(R,G,B,A,group){
frame([99,193.5,99,306,118.5,309,118.5,193.5],R,G,B,A,group)
},
back:function(R,G,B,A,group){
frame([90.5,308,99,306,99,193.5,90.5,193.5],R,G,B,A,group);
},
shelf:function(R,G,B,A,group){
frame([90.5,270,118.5,266,99,264,90.5,265],R,G,B,A,group)
},
bottom:function(R,G,B,A,group){
frame([120,309,99,306,90.5,308,90.5,315],R,G,B,A,group)
}
};
and
function frame(array,R,G,B,A,group){
poly = new Kinetic.Polygon({
points: array,
stroke: 'white',
strokeWidth: 1,
name: group
});
if(R!=null||G!=null||B!=null){
poly.setFill('rgba('+R+','+G+','+B+','+A+')');
} else {
poly.setFill('rgba(0,0,0,0)');
};
layer.add(poly);
};
maybe it is kind of stupid and I could do it much easier, but there are other things I have to think about, which are not included here and I thought this should be a good way.
so what I want is to delete a set of polygons then redraw them with different colour, when the mouse hovers them and when it leaves, it should change back to original. but using destroy, redraw, and then collecting them again does not seem to work, dont know why. any ideas?
Instead of removing/recreating the poly, just use myPoly.setFill inside the mouseover and mouseleave events:
Add 2 additional properties to your poly: hoverColor and blurColor,
On mouseover: this.setFill(this.hoverColor);
On mouseleave: this.setFill(this.blurColor);
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/GTe9j/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.7.2.min.js"></script>
<style>
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
newPoly("red","green",[50,50, 100,50, 50,100]);
newPoly("blue","green",[100,50, 150,50, 150,100]);
newPoly("orange","green",[150,100, 150,150, 100,150]);
newPoly("purple","green",[100,150, 50,150, 50,100]);
function newPoly(hovercolor,blurcolor,array){
var poly = new Kinetic.Polygon({
points: array,
stroke: 'gray',
strokeWidth: 1,
fill:blurcolor
});
poly.hoverColor=hovercolor;
poly.blurColor=blurcolor;
poly.on("mouseover",function(){
this.setFill(this.hoverColor);
this.draw();
});
poly.on("mouseleave",function(){
this.setFill(this.blurColor);
this.draw();
});
layer.add(poly);
layer.draw();
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Hover over a triangle to change its hover-color</h4>
<div id="container"></div>
</body>
</html>
I'm trying to make a kinetic canvas where I can add pictures from another source dynamically and I wanted a grid in the background so I used the kinetic.rect from kinetic v3.8.2.
The images needs to be draggable, from kinetic v.3.6.0, but if I set draggable when having v3.8.2 active it breaks.
"config is undefined" according to FireBug.
"img.kinetic.draggable is not a method" says FireBug.
Is there a fix for this?
Can you post a small example? There have been changes to the Kinetic API. Here is a draggable image with 3.8.2:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='js/kinetic/kinetic-v3.8.2.js'></script>
<script type='text/javascript'>
window.onload = function () {
var stage = new Kinetic.Stage('container', 400, 300);
var layer = new Kinetic.Layer({
name: 'someLayer'
});
var logo = new Image();
logo.onload = function() {
var myImage = new Kinetic.Image({
x: stage.width / 2 - (logo.width / 2)
, y: stage.height - logo.height - 5
, image: logo
, width: logo.width
, height: logo.height
});
myImage.draggable(true)
layer.add(myImage);
layer.draw();
}
logo.src = "\./resources/images/ccs_logo.png";
stage.add(layer)
}
</script>
</head>
<body onmousedown="return false;" bgcolor=#000000>
<div id="container">
</div>
</body>
</html>
Most notably, configs were recently introduced for class instantiation. A Kinetic rectangle used to be defined like so:
var rect = new Kinetic.Rectangle(function () {
//do drawing stuff here
});
But now it is defined with a config (an object literal):
var rect = new Kinetic.Rectangle({
x: 0,
y: 0,
height: 20,
width: 20
});
You can see examples in the docs; also check out the updated KineticJS Tutorials.
I'm creating some circles using Raphael. When a user clicks a button, I want to animate these circles (by growing their radius). How do I do this?
For example, here's my example code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="raphael.js"></script>
<script type="text/javascript">
$(function() {
var paper = new Raphael("canvas_container", 300, 150);
paper.circle(50, 75, 30);
paper.circle(150, 75, 30);
$("button").click(function() {
$("circle").each(function(i) {
this.animate({ r: 100 }, 500); // Doesn't work.
});
});
});
</script>
</head>
<body>
<div id="canvas_container"></div>
<button>Click me to animate the circles</button>
</body>
</html>
[In general, I'm not clear what is the difference between the following two variables:
var c = paper.circle(50, 75, 30); // Raphael circle
$("circle").first(); // using jQuery to grab that Raphael circle
Is the jQuery object a wrapper around the Raphael circle?]
Reading through the Raphaël Reference, it seems that you can do this using Raphaël's own Event methods
circle.click(function (event) {
this.animate({ r: 100 }, 500);
});
The same part of the documentation also notes that you can use libraries like jQuery, but you have to pass in the node, like this:
$(circle.node)
Where circle is the object returned from the paper.circle call.
In your case, however, I think the following code will work:
var paper = new Raphael("canvas_container", 300, 150),
circles = [];
circles.push(paper.circle(50, 75, 30));
circles.push(paper.circle(150, 75, 30));
$("button").click(function() {
$.each(circles, function(i, c){
c.animate({ r: 100 }, 500);
});
});
Your selector "circle" isn't targeting anything - there's no circle element for you to target. However, you could do this:
circle1 = paper.circle(50, 75, 30);
circle2 = paper.circle(150, 75, 30);
$("button").click(function() {
circle1.animate({ r: 100 }, 500);
circle2.animate({ r: 100 }, 500);
});
I couldn't tell you if you can animate() the circles based on the radius, but at the very least this gives you a jQuery object to work with.