I don't know how to use Raphael JS events.
I need some example. I see the documentation and a function must be passed, but is not working.
Someone can provide some example of how to get the mouse position of a click in the canvas?
EDIT: I see in documentation events for Element. This will work for Paper? How I create a mousedown() event for Paper?
clickEvent = function(){
alert("Hello World!");
}
paper = Raphael(...);
paper.raphael.click(clickEvent);
p.mouseover(function () {
p.stop().animate({transform: "s1.1 1.1 " + cx + " " + cy}, ms, "elastic");
txt.stop().animate({opacity: 1}, ms, "elastic");
}).mouseout(function () {
p.stop().animate({transform: ""}, ms, "elastic");
txt.stop().animate({opacity: 0}, ms);
});
check out the source code in the Raphael examples.
Here's another example with a click event:
movers[2].click(function () {
this.cx = this.cx || 300;
this.animate({cx: this.cx, "stroke-width": this.cx / 100, fill: this.cx - 100 ? "hsb(.2, .75, .75)" : "#000", "fill-opacity": +!!(this.cx - 100)}, 1000, "<");
this.cx = this.cx == 300 ? 100 : 300;
});
which is taken from the easing example.
I don't know if the code will work on version 2, though
Related
I have a problem. Whenever I try to create an object of the Candy function, all the attributes seem to be created fine. But, whenever I attempt to run the draw function, all of the properties of the newest created object are used, instead of the one I am using. It will always draw the second object that I created twice, but never the first one. I have no idea why. I have tried everything to try to fix this, so if something seems highly inefficient in this code, it was probably one of the many attempts of me trying to fix this. Do you guys know the problem?
Here is the code for the Candy function:
Candy = function(img, location, canvas) {
self = {}
self.image = new Image()
self.image.src = img
self.location = {x: location.x, y: location.y}
self.canvas = canvas
self.draw = function() {
self.canvas.drawImage(self.image, self.location.x, self.location.y, 132.4, 132.4)
}
self.move = function(FPS, seconds, location) {
frames = FPS * seconds
deltaX = (location.x - self.location.x) / frames
deltaY = (location.y - self.location.y) / frames
counter = 0
setInterval(function() {
self.location.x += deltaX
self.location.y += deltaY
counter++
self.draw()
if(counter >= frames)
clearInterval()
}, 1000 / FPS)
}
self.image.onload = function() {
Candy.list.push(self)
Candy.queue.splice(0, 1)
if(Candy.queue.length == 0)
draw()
else
Candy(Candy.queue[0].img, Candy.queue[0].location, Candy.queue[0].canvas)
}
}
Candy.list = []
Candy.queue = []
Here is where I call the Candy function:
gameStarted = true
Candy.queue.push({img: "client/img/candy.png", location: {x: width / 3 - 87.5, y: height / 10}, canvas: canvasContext})
Candy.queue.push({img: "client/img/candy2.png", location: {x: width / 3 - 87.5, y: 3 * (height / 10)}, canvas: canvasContext})
Candy(Candy.queue[0].img, Candy.queue[0].location, Candy.queue[0].canvas)
Finally, here is the draw function:
function draw() {
colorRect(0, 0, canvas.width, canvas.height, 'white');
colorText("Player 1", 0.02, 0.05, "black", "40px Comic Sans");
colorText("Player 2", 0.88, 0.05, "black", "40px Comic Sans");
if(!gameStarted) {
if(player1.ready)
colorText("Ready", 0.02, 0.09, "green", "20px Comic Sans");
else
colorText("Not Ready", 0.02, 0.09, "red", "20px Comic Sans");
if(player2.ready)
colorText("Ready", 0.88, 0.09, "green", "20px Comic Sans");
else
colorText("Not Ready", 0.88, 0.09, "red", "20px Comic Sans");
if(player1.ready && player2.ready)
colorText("Press a button to start the game!", 0.32, 0.5, "black", "40px Comic Sans")
}else{
alert(Candy.list[0].image.src)
alert(Candy.list[0].getImg())
for(var i = 0; i < Candy.list.length; i++) {
Candy.list[i].draw()
}
//TODO
}
}
Alright, I figured it out. In the function, I replaced self with this and it fixed the issue. No need for any replies.
I was just going though THIS SVG animation demo , its pritty straightforward , i was jus tgoing through the JS code and came actoss the below lines of code;
var g = Snap();
g.attr({
viewBox: [0, 0, 800, 600]
});
Snap.load("map.svg", function (f) {
function getShift(dot) {
return "t" + (400 - dot.x) + "," + (300 - dot.y);
}
var gr = f.select("g"),
wrd = f.select("#world").attr({fill: "#fff"}),
syd = f.select("#sydney").attr({fill: "red"}),
msk = f.select("#san_francisco").attr({fill: "red"}),
pth = f.select("#flight"),
pln = f.select("#plane"),
top = g.g()
// DIFF above line of code , what is g.g();
top.attr({
mask: g.rect(100, 0, 600, 600).attr({
fill: "r(.5,.5,.25)#fff-#000"
})
});
top.add(gr);
var click = top.text(410, 310, "click!").attr({
font: "20px Source Sans Pro, sans-serif",
fill: "#fff"
});
pth.attr({
display: "none"
});
// DIFF , i am not quite understanding below line of code.
pln = gr.g(pln, pln.clone());
pln.attr({
display: "none"
});
pln[0].attr({
stroke: "#fff",
strokeWidth: 2
});
gr.attr({
transform: getShift({
x: syd.attr("cx"),
y: syd.attr("cy")
})
});
Now my question is about the below lines of code:
gr.attr({
transform: getShift({
x: syd.attr("cx"),
y: syd.attr("cy")
})
});
I beleive the layer gr is being transform , but i don't entirely understand this line of code , What exactly is getShift and ofcourse i do understand that the 'cx' and 'cy' attributes of the syd layer above are being used to transform the elements, but how does this line of code work as a whole and also what is getShift ?
getShift itself has nothing to do specifically with the Snap library. It is defined in the top of the code you included, and simply returns a string based on an object you provide:
function getShift(dot) {
return "t" + (400 - dot.x) + "," + (300 - dot.y);
}
So if you call getShift with a parameter of an object with the following properties, {x: 10, y: 20}, then getShift will return the string "t380,290".
That string, however, can then be used by Snap to transform an element. Specifically, it is being used as follows:
gr.attr({transform: "t380,290"});
(based on my fictitious initial values).
It seems like what it's trying to do is the following: Translate the entire group ("gr") (i.e. the whole world map?) such that the position of Sydney, Australia ("syd") ends up at the coordinates (400, 300), i.e. in a pleasantly-viewable somewhat-central part of the screen/window/div. Without going through the entire code, it seems like this is probably setting up the characteristics for the end of the animation.
I have a circle added to a layer. In the top of the layer I added a text. I would like to run an animation when the mouse is over the circle, but when the mouse reaches the text the mouseout callback function is called. How can I prevent that?
var circle = new Kinetic.Circle({
x: j * xcenterstep + xshift,
y: i * ycenterstep + yshift,
radius: t_radius,
fill: t_fill,
stroke: t_stroke,
strokeWidth: t_stroke_w,
strokeOpacity: 0.1,
opacity: 0.3 + t_number * 0.05,
});
if (t_number) {
circle.tw;
circle.on("mouseover", function () {
this.tw = new Kinetic.Tween({
node: this,
duration: 0.3,
strokeWidth: 6
});
this.tw.play();
});
circle.on("mouseout", function () {
this.tw.reverse();
});
}
// Adding the text
var radiusText = new Kinetic.Text({
x : circle.getX(),
y : circle.getY(),
text : t_number,
fontSize : radius,
fill : '#fff',
fontStyle: 'bold',
align : 'center'
});
radiusText.setOffset({
x : radiusText.getWidth()/2,
y : radiusText.getHeight()/2
});
bgLayer.add(circle);
bgLayer.add(radiusText);
I think it is better to use mouseenter event. You can disable text's events to prevent mouseout from circle.
radiusText.listening(false)
Reviewing your code, you were missing a } to close the if (t_number) {. I am not sure if it was supposed to encompass the mouseover and mouseout events, but it might have caused your code to respond differently than you are expecting.
I'm having a lot of trouble getting a smooth animation using Kinetic.js in Firefox. It looks great in Chrome and Safari, and even looks more-or-less okay in IE9, but Firefox is jerky. I tried using both the built-in Kinetic.Animate, and requestAnimationFrame, and both ended up looking the same. Any ideas?
<div id="container"></div>
<script>
$(function() {
var stage = new Kinetic.Stage({
container: 'container',
width: 1000,
height: 1000
});
var layer = new Kinetic.Layer();
var blackRect = new Kinetic.Rect({
x: 700,
y: 650,
width: 300,
height: 620,
fill: "black",
offset: [150, 620]
});
var colorRect = new Kinetic.Rect({
x: 300,
y: 650,
width: 300,
height: 620,
fill: "blue",
offset: [150, 620]
});
layer.add(blackRect);
layer.add(colorRect);
stage.add(layer);
function oscillate(node, time) {
var period = 5400;
var phase = 1200;
var amplitude = 1.2;
var shift = amplitude * Math.cos(phase + time * 2 * Math.PI / period);
node.setPosition(node.getX() + shift, node.getY());
}
function rotate(node, time) {
var period = 5400;
var amplitude = 0.08;
node.setRotation((amplitude * Math.sin(time * 2 * Math.PI / period) ));
}
function render(time) {
layer.draw();
}
var anim = new Kinetic.Animation(function (frame) {
oscillate(blackRect, frame.time);
oscillate(colorRect, frame.time);
rotate(blackRect, frame.time);
rotate(colorRect, frame.time);
}, layer);
anim.start();
});
</script>
Edit:
Here is the above example: http://jsfiddle.net/cantino/yr8Zr/
Yes, FF currently produces less-smooth animations.
You can get smoother-but-slower animation results by:
Using frame.timeDiff to throttle the frames-per-second,
And reducing your amplitude.
If smoother-but-slower breaks your design you can use the custom Kinetic.Shape to get "closer to the metal".
With Kinetic.Shape, you get a canvas context to draw on instead of relying on the easier (but less performant) Kinetic.Rect.
I know that this question was answered long time ago, but i encountered this issue recently too, and the answers provided here gave only a marginal performance boost.
So i looked into the core of KineticJS and found a fix that got my FPS from 10 to almost 60. Some times the FPS dropped as low as 2.
The fix is for those who may encounter this issue in the future and search for an answer.
stage._mousemove = Kinetic.Util._throttle( stage._mousemove, 60);
someKineticLayer._getIntersection = function() {return {};};
//keep in mind that tampering with _getIntersection will disable mouse interaction for that layer and may have other effects.
I would like to make a "prototype" of animations for a future game. But I'm totally a noob in kineticJS.
I have an object where I make all my functions:
var app = {}
I have a function init to build a layer, a stage and declare that I will use requestAnimationFrame:
init: function(){
layer = new Kinetic.Layer();
DrawingTab = [];
stage = new Kinetic.Stage({
container: 'canvasDemo',
width: 800,
height: 600
});
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
}
Secondly, I've got one function to build my rects:
createObject: function(){
rect = new Kinetic.Rect({
x: 50,
y: 50,
width: 150,
height: 150,
fill: 'black',
name: 'batteur',
id: 'batteur'
});
rect1 = new Kinetic.Rect({
x: 300,
y: 50,
width: 150,
height: 150,
fill: 'black',
name: 'batteur1',
id: 'batteur1'
});
rect2 = new Kinetic.Rect({
x: 550,
y: 50,
width: 150,
height: 150,
fill: 'black',
name: 'batteur2',
id: 'batteur2'
});
layer.add(rect);
layer.add(rect1);
layer.add(rect2);
stage.add(layer);
DrawingTab.push(rect,rect1,rect2,rect3,rect4,rect5);
}
That's all I did. And then, I want to know how to animate like that:
every 20 secondes, one of the rect (select randomly) change of color,
and the user have to click on it.
the user have 5sec to click on it, and if he doesn't click, the rect change to the beginning color.
I hope explanations are clear and something will can help me, because I'm totally lost.
You should use Kinetic.Animation for animations because it optimizes redraws. Here's an example
If your game is using sprites, you should be using the Sprite shape. Here's an example of that
You don't need requestAnimationFrame or Kinetic.Animation to handle this, considering the kind of animation you want. Only use animations if you need to change the animation status every frame.
See this working DEMO.
Using setInterval and setTimeout the application became more performant.
I reduce the time of change of color to 5 seconds and the time to click to 2 seconds, just to quickly visualization of the features.
Here is the code added:
// times (make changes according)
var timeToChange = 5000; // 5 seconds
var timeToClick = 2000; // 2 seconds
// render all rects
layer.drawScene();
// add a logical rect for each rect in DrawingTab
var LogicalTab = [];
for (var i = 0; i < DrawingTab.length; ++i) {
LogicalTab.push({
isPressed: false,
frame: 0
});
}
// return a random integer between (min, max)
function random(min, max) {
return Math.round(Math.random() * (max - min) + min);
};
// define colors
var colors = ["red", "green", "blue"];
// reset state of current rect
function reset(n) {
var drect = DrawingTab[n];
var lrect = LogicalTab[n];
// check if current rect was clicked
setTimeout(function () {
if (!lrect.isPressed) {
drect.setFill("black");
// redraw scene
layer.drawScene();
lrect.frame = 0;
}
// turn off click event
drect.off("click");
}, timeToClick);
}
// start the animation
var start = setInterval(function () {
// select a rect randomly
var rand = random(0, 2);
var drect = DrawingTab[rand];
var lrect = LogicalTab[rand];
// change color
drect.setFill(colors[lrect.frame]);
// redraw scene
layer.drawScene();
// flag that current rect is not clicked
lrect.isPressed = false;
// check for click events
drect.on("click", function () {
// flag that current rect is clicked
lrect.isPressed = true;
// hold current color
lrect.frame++;
lrect.frame = lrect.frame % colors.length;
});
// reset current rect (only if it is not clicked)
reset(rand);
}, timeToChange);
I'm a newbye here, but I hope I'm able to help. KineticJS don't need requestAnimationFrame, because it has already something that handles animations. so first of all I think you should have a look to this page
if you want to make the rect's color change every 20 s, you may do something like this:
var anim = new Kinetic.Animation(function(frame) {
if(frame.time > 20000)
{
frame.time = 0;
colors = ['red', 'blue', 'violet'];
ora = colors[Math.floor(Math.random()*3)];
DrawingTab[Math.floor(Math.random*6)].setAttrs({fill: ora});
}
},layer);
then, for the 5sec stuff, I tried to write something
var currentRect = { value:0, hasClicked : true };
var anim2 = new Kinetic.Animation(function(frame) {
if(frame.time > 20000)
{
frame.time = 0;
colors = ['red', 'lightblue', 'violet'];
ora = colors[Math.floor(Math.random()*3)];
currentRect.hasClicked = false;
currentRect.value=Math.floor(Math.random()*6);
DrawingTab[currentRect.value].setAttrs({fill: ora});
}
if (!currentRect.hasClicked && frame.time>5000)
{
DrawingTab[currentRect.value].setAttrs({fill: 'black'});
currentRect.hasClicked = true;
}
DrawingTab[currentRect.value].on('click',function(){ if (frame.time<=5000) currentRect.hasClicked = true;});
},layer);
anim2.start();
I've just tried something similiar and it looks like it's working :)
p.s. sorry about my english, I'm only a poor italian student
p.p.s. I'm sure the code can be optimized, but for now I think it can be alright