I am using Raphael to make a simple clock for my website. I am trying to plot the seconds hand to make it tick like a normal clock.
Here is the code I am running:
window.onload = function() {
var paper = new Raphael(0, 0, 400, 400);
var backGround = paper.rect(0, 0, 400, 400);
backGround.attr({
fill: "orange"
});
var face = paper.circle(100, 100, 95);
face.attr({
"fill": "#f5f5f5",
"stroke": "#ff0000",
"stroke-width": "3"
})
var hand = paper.path("M100 110L100 25");
hand.attr({
stroke: "#ffff00",
"stroke-width": 1
});
function startTime() {
var hands = now.getSeconds();
hands = checkTime(hands);
hand.animate({
transform: ['r', ((hands * 6) - 180), 200, 200]
});
setTimeout(function() {
startTime()
}, 1000);
function checkTime(i) {
if (i < 10) {
i = "0" + i
};
return i;
}
startTime();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.4/raphael-min.js"></script>
You need to start the time function outside the function itself
You missed a new Date statement
I also moved the hands to 100x100
Removed the useless second formatter.
Changed the hand to black to see it better
window.onload = function() {
var paper = new Raphael(0, 0, 400, 400);
var backGround = paper.rect(0, 0, 400, 400);
backGround.attr({
fill: "orange"
});
var face = paper.circle(100, 100, 95);
face.attr({
"fill": "#f5f5f5",
"stroke": "#ff0000",
"stroke-width": "3"
})
var hand = paper.path("M100 110L100 25");
hand.attr({
stroke: "#000000",
"stroke-width": 1
});
function startTime() {
var now = new Date(),
hands = now.getSeconds();
hand.animate({
transform: ['r', ((hands * 6) - 180), 100, 100]
});
setTimeout(function() {
startTime()
}, 1000);
}
startTime();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.4/raphael-min.js"></script>
Related
How do we always connect two objects with a line in Snap.svg?
Plunkr: https://plnkr.co/edit/IgY0jyHbWTLuH4FfZt6o?p=preview
var circleOne = s.circle(150, 150, 100);
var circleTwo = s.circle(450, 450, 100);
var boxOne = circleOne.getBBox();
var boxTwo = circleTwo.getBBox();
var line = s.line(boxOne.cx, boxOne.cy, boxTwo.cx, boxTwo.cy);
line.attr({
stroke: 'red'
});
var t = new Snap.Matrix();
t.translate(200, 0, boxTwo.cx, boxTwo.cy);
setTimeout(function() {
circleTwo.animate({ transform: t}, 500, mina.easein);
}, 1000);
Nevermind, figured it out!
setTimeout(function() {
circleTwo.animate({ transform: t}, 500, mina.easein);
line.animate({
x2: boxTwo.cx + 200
}, 500, mina.easein);
}, 1000);
https://plnkr.co/edit/IgY0jyHbWTLuH4FfZt6o?p=preview
I am creating a little app with KineticJS which creates multiple nodes (RegularPolygons). After the stage is loaded (triggered with play(); ) I fill each node sequentially with an (pattern)image (triggered with loadImages(urls);.
This works fine, but now I want to add a nice fade-in effect with a Tween, like:
set all nodes > load single image > set node patternImage > tween to opacity 0.8 > on tween complete, load next image (repeat).
For some reason the tweens won't play, they just appear in complete state (opacity 1) ;(
var stage = new Kinetic.Stage({
container: 'canvas',
width: $(window).width(),
height: $(window).height()
});
var layer = new Kinetic.Layer()
var layer2 = new Kinetic.Layer()
var urls =
[
'http://lorempixel.com/300/300/sports/1',
'http://lorempixel.com/300/300/sports/2',
'http://lorempixel.com/300/300/sports/3',
'http://lorempixel.com/300/300/sports/4',
'http://lorempixel.com/300/300/sports/5',
'http://lorempixel.com/300/300/sports/6',
'http://lorempixel.com/300/300/sports/7',
'http://lorempixel.com/300/300/sports/8',
'http://lorempixel.com/300/300/sports/9',
'http://lorempixel.com/300/300/sports/10',
'http://lorempixel.com/300/300/business/1',
'http://lorempixel.com/300/300/business/2',
'http://lorempixel.com/300/300/business/3',
'http://lorempixel.com/300/300/business/4',
'http://lorempixel.com/300/300/business/5',
'http://lorempixel.com/300/300/business/6',
'http://lorempixel.com/300/300/business/7',
'http://lorempixel.com/300/300/business/8',
'http://lorempixel.com/300/300/business/9',
'http://lorempixel.com/300/300/business/10'/*,
'http://lorempixel.com/300/300/cats/1',
'http://lorempixel.com/300/300/cats/2',
'http://lorempixel.com/300/300/cats/3',
'http://lorempixel.com/300/300/cats/4',
'http://lorempixel.com/300/300/cats/5',
'http://lorempixel.com/300/300/cats/6',
'http://lorempixel.com/300/300/cats/7',
'http://lorempixel.com/300/300/cats/8',
'http://lorempixel.com/300/300/cats/9',
'http://lorempixel.com/300/300/cats/10',
'http://lorempixel.com/300/300/nature/1',
'http://lorempixel.com/300/300/nature/2',
'http://lorempixel.com/300/300/nature/3',
'http://lorempixel.com/300/300/nature/4',
'http://lorempixel.com/300/300/nature/5',
'http://lorempixel.com/300/300/nature/6',
'http://lorempixel.com/300/300/nature/7',
'http://lorempixel.com/300/300/nature/8',
'http://lorempixel.com/300/300/nature/9',
'http://lorempixel.com/300/300/nature/10',
'http://lorempixel.com/300/300/people/1',
'http://lorempixel.com/300/300/people/2',
'http://lorempixel.com/300/300/people/3',
'http://lorempixel.com/300/300/people/4',
'http://lorempixel.com/300/300/people/5'*/
];
// LOAD IMAGES
function loadImages(arrayOfImages, index) {
index = index || 0;
if (arrayOfImages && arrayOfImages.length && arrayOfImages.length > index) {
var img = new Image();
img.onload = function() {
var pane = layer2.get('#pane_' + index );
pane.fill('').fillPatternImage(img);
stage.draw(); // <<< THIS WORKS
var tween = new Kinetic.Tween({
node: pane,
duration: 1,
opacity: 0.8,
easing: Kinetic.Easings.BackEaseOut,
onFinish: function() {
loadImages(arrayOfImages, index + 1
}
}).play; // <<< NOT WORKING
//setTimeout(function(){ loadImages(arrayOfImages, index + 1); }, 200);
};
img.src = arrayOfImages[index];
}
}
function start() {
console.log("numOfPanes: " +urls.length);
for (i = 0; i <= urls.length; i++) {
var shape0 = new Kinetic.RegularPolygon({
x: i * 15,
y: i * 15,
sides: 5,
rotation: i * 10,
radius: 70,
fill: 'Red'
});
var shape1 = new Kinetic.RegularPolygon({
x: i * 15,
y: i * 15,
sides: 5,
rotation: i * 10,
radius: 70,
opacity: 0,
fillPatternOffset: {x:-220, y:70},
id: 'pane_' + i,
name: 'pane',
fill: 'Green'
});
layer.add(shape0);
layer2.add(shape1);
}
stage.add(layer,layer2);
}
// INIT
start();
// trigger loadimages() with console
loadImages(urls);
play is a function. So you should call it.
var tween = new Kinetic.Tween({
node: pane,
duration: 1,
opacity: 0.8,
easing: Kinetic.Easings.BackEaseOut,
onFinish: function() {
loadImages(arrayOfImages, index + 1
}
}).play();
Also: when you are finding node with get function it returns Collection. So if you need just node use:
var pane = layer2.get('#pane_' + index )[0];
I am trying to recreate the game http://www.sinuousgame.com/ and studying html5 canvas and kineticJS.
This is my fiddle:
http://jsfiddle.net/2WRwY/7/
My problem:
The tail part of the player in the fiddle doesn't seem to retract back.
The red ball objects should appear over the player objects.
(Try running the fiddle with layer.removeChildren(); and without it.)
Right now,I have commented "layer.removeChildren();" on the fiddle.. (basically which causes the problem for me)
Here's my html:
<!DOCTYPE html>
<html>
<head>
<title>Collision Detection-player</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="../css/style.css"/>
</head>
<body>
<div id="container" style="width: auto; height: auto; background:#000; margin:auto; float:left;"></div>
<script src="../js/jquery.min.js"></script>
<script src="../js/kinetic-v5.0.0.min.js"></script>
<script src="../js/main_kinetic_combined.js"></script>
</body>
</html>
Here's my javascript:
//The working player code
var LimitedArray = function(upperLimit) {
var storage = [];
// default limit on length if none/invalid supplied;
upperLimit = +upperLimit > 0 ? upperLimit : 100;
this.push = function(item) {
storage.push(item);
if (storage.length > upperLimit) {
storage.shift();
}
return storage.length;
};
this.get = function(flag) {
return storage[flag];
};
this.iterateItems = function(iterator) {
var flag, l = storage.length;
if (typeof iterator !== 'function') {
return;
}
for (flag = 0; flag < l; flag++) {
iterator(storage[flag]);
}
};
};
var tail = new LimitedArray(50);
var flag = 0, jincr = 0;
var stage = new Kinetic.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
listening: true
});
var layer = new Kinetic.Layer({
listening: true
});
stage.add(layer);
var player = new Kinetic.Circle({
x: 20,
y: 20,
radius: 6,
fill: 'cyan',
stroke: 'black',
draggable: true
});
layer.add(player);
// move the circle with the mouse
stage.getContent().addEventListener('mousemove', function() {
<!--layer.removeChildren(); -->
layer.add(player);
player.setPosition(stage.getPointerPosition());
var obj = {
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y
};
tail.push(obj);
var arr = [];
tail.iterateItems(function(p) {
arr.push(p.x, p.y);
});
var line = new Kinetic.Line({
points: arr,
stroke: 'white',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
// layer.draw();
});
var x = 0;
var y = 0;
var noOfEnemies = 150;
var enemyArmada = new Array();
createEnemy();
function createEnemy() {
for (var i = 0; i < noOfEnemies; i++) {
var enemy = new Kinetic.Circle({
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
radius: 4.5 + 1.5 * Math.random(),
fill: 'red',
stroke: 'black',
});
enemy.speedX = enemy.speedY = (0.3 + Math.random() * 50);
enemyArmada.push(enemy);
layer.add(enemy);
}
}
var anim = new Kinetic.Animation(function(frame) {
for (var i = 0; i < noOfEnemies; i++) {
var e = enemyArmada[i];
e.position({
x: e.position().x - e.speedX * frame.timeDiff / 500,
y: e.position().y + e.speedY * frame.timeDiff / 500
});
if (e.position().y < 0 || e.position().x < 0) {
e.position({
x: (Math.random() * (window.innerWidth + 600)),
y: -(Math.random() * window.innerHeight)
});
}
}
}, layer);
anim.start();
Any suggestions?
The problem is that after you've added the enemies, you're adding the player and the line to the layer again, so they'll be on top. Also, on each mouse move, you're creating the line over and over again.
So, instead, you should just update the line points (and you don't need the layer.removeChildren(); line at all), like this:
var line = new Kinetic.Line({
points: [],
stroke: 'white',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.add(player);
// move the circle with the mouse
stage.getContent().addEventListener('mousemove', function() {
player.position(stage.getPointerPosition());
var obj = {
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y
};
tail.push(obj);
var arr = [];
tail.iterateItems(function(p) {
arr.push(p.x, p.y);
});
line.points(arr);
});
See fiddle: http://jsfiddle.net/Kunstmord/p9fnq/2/
This way, you're only creating the line once. This also seems to fix the non-disappearing trail.
Also, please note:
1) use position instead of setPosition and getPosition (see KineticJS 5.0 docs)
2) adding <!-- --> does not comment out a line in Javascript (layer.removeChildren(); line).
Ok, so I have an animated diagram that animates multiple lines and shapes at the same time. Once the user plays the animation, I want he/she to be able to hit pause and the whole thing stop, then start again when the user hits the play button once more. I shouldn't need a loop to do this as it should do it with each mouse click. Here's a sample of the code.
var tween = new Kinetic.Tween({
node: lineTween,
points: [563.965, 258.163, 604.272, 258.163],
duration: 2
});
var tween3 = new Kinetic.Tween({
node: path3,
points: [582.81, 257.901, 582.81, 214.216],
duration: 2,
onFinish: function(){
tween3a.play();
}
});
document.getElementById('play').addEventListener('click', function(){
tween.play(
setTimeout(function(){
tween3.play();
}, 1000)
);
}, false);
document.getElementById('pause').addEventListener('click', function(){
tween.pause();
}, false);
Anyone have any suggestions?
You will have to store all tweens and turn them off/on:
Demo: http://jsfiddle.net/m1erickson/rF3Mm/
Code:
<!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);
$(stage.getContent()).on('click', function (event) {
var pos = stage.getMousePosition();
var mouseX = parseInt(pos.x);
var mouseY = parseInt(pos.y);
});
var tweens = [];
var circle1 = new Kinetic.Circle({
x: 30,
y: 100,
radius: 20,
fill: 'blue',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
layer.add(circle1);
var circle2 = new Kinetic.Circle({
x: 30,
y: 30,
radius: 15,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
layer.add(circle2);
layer.draw();
var tween1 = new Kinetic.Tween({
node: circle1,
duration: 15,
x: 250,
y: 250,
});
tweens.push(tween1);
var tween2 = new Kinetic.Tween({
node: circle2,
duration: 15,
x: 250,
y: 250,
});
tweens.push(tween2);
tween1.play();
tween2.play();
isPaused = false;
$("#toggle").click(function () {
if (isPaused) {
for (var i = 0; i < tweens.length; i++) {
tweens[i].play();
}
} else {
for (var i = 0; i < tweens.length; i++) {
tweens[i].pause();
}
}
isPaused = !isPaused
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="toggle">Toggle:Pause/Resume</button>
<div id="container"></div>
</body>
</html>
Here's the fiddle: http://jsfiddle.net/G2VKx/3/
When I hover over the circle, the text shows up nicely, but if I remove the mouse, the THIRD time I mouseover, the height and width of the box that matches the dimensions of the text starts growing continuously and there's this weird stroboscopic effect.
var rsr = Raphael("holder", '1160', '1400');
xpos = 200;
ypos = 200;
rad = 50;
var rectext, el, txt;
cir = rsr.circle(xpos, ypos, rad);
cir.attr({
fill: '#444',
'fill-opacity': 1,
stroke: 'none'
});
cir.hover(function () {
this.animate({
r: rad * 1.2
}, 200);
recttext = rsr.set();
el = rsr.rect(0, 0, 0, 0, 3);
el.attr({
fill: '#fff'
});
txt = rsr.text(4, 10, "Title text").attr({
"text-anchor": "start",
fill: '#000000',
"font-size": 12
});
recttext.push(el);
recttext.push(txt);
var att = {
width: recttext.getBBox().width,
height: recttext.getBBox().height
};
el.attr(att);
recttext.translate(xpos - recttext.getBBox().width / 2, ypos - rad - 20);
}, function () {
this.animate({
r: rad
}, 100);
recttext.remove();
el.remove();
txt.remove();
});
Anto Jurković got it, using Raphael 2.1.2 instead of Fiddle's built-in 2.1.0 solved the problem.