How can resume animation Kineticjs canvas? - animation

I have problem with resume animation after stop it. Any suggestion ? I using kineticjs to make element run along the path, after i reach the end, the animation stop for 2 second then start again.
here my code :
var stage = new Kinetic.Stage({
container: 'canvas',
height: 484,
width: 478
});
var layer = new Kinetic.Layer();
stage.add(layer);
var img = new Image();
img.src = 'images/ani/bullet_blue.png';
var circle = new Image();
circle.src = 'images/ani/1.png';
var shapeCircle = new Kinetic.Image({
x: 10,
y: 10,
image: circle,
width: circle.width,
height: circle.height,
offset: {
x: 0,
y: 0
}
});
layer.add(shapeCircle);
layer.draw();
function animation(points, shape, duration, loop, callback) {
layer.add(shape);
window.anim = new Kinetic.Animation(function (frame) {
var time = frame.time, timeDiff = frame.timeDiff, frameRate = frame.frameRate;
var percent = time / duration, scale = 0.5, opacity = 0;
if (percent < 0.05 || percent > 0.95) opacity = 0;
else opacity = 1;
// scale calculate
if (percent < 0.5) {
scale += percent
}
else if (percent > 0.5) {
scale = 1 - (percent - 0.5)
}
if (percent > 1) {
anim.stop();
percent = 0;
setTimeout(function () { anim.start(); }, 500);
} else {
var pos = Math.ceil(percent * points.length);
pos = pos > (points.length - 1) ? (points.length - 1) : pos;
if (pos == points.length - 1) anim.stop();
shape.setScale(scale, scale);
shape.setOpacity(opacity);
shape.setPosition(points[pos].x, points[pos].y);
}
}, layer);
anim.start();
}
animation(points1, new Kinetic.Image({
x: points1[0].x,
y: points1[0].y,
image: img,
width: img.width,
height: img.height,
opacity: 0,
scaleX: 0.5,
scaleY: 0.5,
offset: {
x: 15,
y: 30
}
}), 2000);

If you want a repeating animation, you might consider a tween instead.
When a tween finishes, it fires a finished event. In that finished handler, you can:
Reset the tween to the starting position using tween.reset,
Start a timer to wait 2 seconds using setTimer,
When the timer fires, restart the tween using tween.start.

Related

Swap image sprite in HTML5 Canvas game

Trying to add basically different looking zombie. Is there a way to just swap the sprite or would I have to keep adding the code for class, scrolling etc.
class Zombie1 {
constructor({
position,
velocity,
distance = {
limit: 50,
traveled: 0
}
}) {
this.position = {
x: position.x,
y: position.y
}
this.velocity = {
x: velocity.x,
y: velocity.y
}
this.width = 97.49
this.height = 150
this.image = createImage(spriteZombie1)
this.frames = 0
this.distance = distance
}
draw() {
// c.fillStyle = 'red'
// c.fillRect(this.position.x, this.position.y, this.width, this.height)
c.drawImage(
this.image,
130 * this.frames,
0,
130,
150,
this.position.x,
this.position.y,
this.width,
this.height
)
}
update() {
this.frames++
if (this.frames >= 58) this.frames = 0
this.draw()
this.position.x += this.velocity.x
this.position.y += this.velocity.y
this.enemies = [];
if (this.position.y + this.height + this.velocity.y <= canvas.height)
this.velocity.y += gravity
// walk the zombie back and forth
this.distance.traveled += Math.abs(this.velocity.x)
if (this.distance.traveled > this.distance.limit) {
this.distance.traveled = 0
this.velocity.x = -this.velocity.x
}
}
}
zombies1 = [
new Zombie1({
position: {
x: 4000,
y: -950
},
velocity: {
x: -1,
y: 0
},
distance: {
limit: 7,
traveled: 0
}
}),
I have no problem adding more classes, it gets tedious and clutters the code. It won't let me post anymore code but that seems to be the important ones, other than importing the sprites.

Loading image in Canvas with mouse follow

I am struggling to make an image appear in a Canvas animated card. I can get text and drawn images to show up, but I can't seem to load the image and still have the ball follow the mouse. Why is that? I'm sure it's something super easy but I keep trying different things and am getting no where!
<script>
var canvas = document.querySelector("#myCanvas");
var context = canvas.getContext("2d");
var canvasPos = getPosition(canvas);
var mouseX = 525;
var mouseY = 325;
canvas.addEventListener("mousemove", setMousePosition, false);
function setMousePosition(e) {
mouseX = e.clientX - canvasPos.x;
mouseY = e.clientY - canvasPos.y;
}
function getPosition(el) {
var xPosition = 0;
var yPosition = 0;
while (el) {
xPosition += (el.offsetLeft - el.scrollLeft + el.clientLeft);
yPosition += (el.offsetTop - el.scrollTop + el.clientTop);
el = el.offsetParent;
}
return {
x: xPosition,
y: yPosition
};
}
function loadTeacher() {
var myImage = new Image();
myImage.src = 'images/teacher.jpg';
myImage.addEventListener("load", loadImage, false);
function loadImage(e) {
context.drawImage(myImage, 0, 75, 500, 350);
}
} loadTeacher();
function update() {
context.clearRect(0, 0, canvas.width, canvas.height);
//write text
context.font = "bold 12pt Helvetica, Ariel, sans-serif";
context.textAlign = "center";
context.fillStyle = "black";
context.fillText("This teacher needs an apple now! Drag the apple to her mouth.", 250, 50);
//draw circle
context.beginPath();
context.arc(mouseX, mouseY, 15, 0, 2 * Math.PI, true);
context.fillStyle = "red";
context.fill();
requestAnimationFrame(update);
}
update();
</script>

Coin spin effect animation on grouped shapes

I have been asked, using Konvajs, to work out an animation that will rotate a circle as if spinning on its central x-axis. So imagine a coin spinning on a table. The intention is to reveal some text on the circle. At the start the circle is fully visible as if from behind so no text visible, then it flips to reveal the text.
I have this code that does a rotation like a spinning wheel.
Can anyone give me a tween / animation approach that would achieve the spinning coin effect?
// the tween has to be created after the node has been added to the layer
var tween = new Konva.Tween({
node: group,
duration: 4,
rotation: 360,
easing: Konva.Easings.BackEaseOut
}
});
tween.play();
After some research it looks like a 3D spin requires heavier lifting which may not be available or work well on mobile.
A good second-best appears to be using scaleX and animating from 0 > 1.
group.scaleX(0);
var tween = new Konva.Tween({
node: group,
duration: .25,
scaleX: 1,
easing: Konva.Easings.EaseOut
});
Here is an example of the second-best version using scaleX() effect. Because of the need to calculate scaleX() and control visibility of the text so as to make it appear that the disc is solid, I moved away from a tween and over to an animation().
// Set up the canvas / stage
var s1 = new Konva.Stage({container: 'container1', width: 300, height: 200});
// Add a layer for line
var layer = new Konva.Layer({draggable: false});
s1.add(layer);
// just a plain JS object to keep common variables in hand.
var cfg = { w: 300, h: 200, r: 80, txtSize: 520};
var group = new Konva.Group();
var circle = new Konva.Circle({x: cfg.w/2, y: cfg.h/2, radius: cfg.r, fill: 'DodgerBlue', stroke: 'DeepPink', strokeWidth: 5})
group.add(circle)
var textValue = new Konva.Text({
id: "t1",
x: cfg.w/2,
y: cfg.h/2,
text: '',
fill: 'DeepPink ',
fontSize: cfg.txtSize
});
group.add(textValue);
textValue.offset({x: textValue.getWidth()/2, y: textValue.getHeight()/2});
layer.add(group)
// to spin a group about a point, set the offset to that point, then set the x & y to that point to !
var pos = group.getClientRect();
RotatePoint(group, {x: pos.x + pos.width/2, y: pos.y + pos.height/2});
// Everything is ready so draw the canvas objects set up so far.
s1.draw()
$('#st').on('click', function(){
group.scaleX(1);
var txt = $('#theText').val();
setValue(txt);
})
// set the offset for rotation to the given location and re-position the shape
function RotatePoint(shape, pos){ // where pos = {x: xpos, y: yPos}
var initialPos = shape.getAbsolutePosition();
var moveBy = {x: pos.x - initialPos.x, y: pos.y - initialPos.y};
// offset is relative to initial x,y of shape, so deduct x,y.
shape.offsetX(moveBy.x);
shape.offsetY(moveBy.y);
shape.x(initialPos.x + moveBy.x);
shape.y(initialPos.y + moveBy.y);
}
var setValue = function(newText){
// work out scaling to make text fit into the circle
var txt = this.layer.find('#t1')[0];
txt.text(newText).scale({x:1, y: 1})
var txtSize = txt.getClientRect();
var maxW = (cfg.r); // max allowed width of text
var txtScaleW = (txtSize.width > maxW ? ( maxW / txtSize.width) : 1);
var maxH = cfg.r; // max allowed height of text
var txtScaleH = (txtSize.height > maxH ? ( maxH / txtSize.height) : 1);
// finally decide which is the worst case and use that scaling
var txtScale = ( txtScaleW > txtScaleH ? txtScaleH : txtScaleW);
txt.scale({x: txtScale, y: txtScale});
txt.offset({x: txt.getWidth()/2, y: txt.getHeight()/2});
layer.draw()
}
// set initial text & spin !
setValue('BBB');
var anim, pos = 0, frameCnt = 0
if (anim) {anim.stop(); }
anim = new Konva.Animation(function(frame) {
frameCnt = frameCnt + 1;
if (frameCnt % 2 === 0){
pos = pos + .2
var scaleX = Math.sin(pos)
textValue.visible(scaleX < 0 ? false : true);
group.scaleX(scaleX);
if (pos % 360 === 0){ console.log('spin') }
}
}, layer);
anim.start();
div
{
float: left;
margin: 0 5px;
}
p
{
margin: 0 5px 5px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.5.1/konva.min.js"></script>
<div id='container1' style="width: 300px, height: 200px;"></div>
<div>
<p> <input type='text' id='theText' value='BBB' /> <button id='st'>Change text</button> </p>
</div>

Can't Detect Mouseover on This KineticJS Shape?

I have a KineticJS shape that draws a bezier curve that is wider on one end. It draws correctly, but I can't yet detect a 'mouseover' event on it. I have created a small JSFiddle demo of the anomaly, at:
http://jsfiddle.net/VikR0001/nZYxL/6/
How can I detect 'mouseover' events on this shape?
Thanks very much in advance to all for any info!
var mainLayer;
//bezier curve code:
//http://stackoverflow.com/questions/8325680/how-to-draw-a-bezier-curve-with-variable-thickness-on-an-html-canvas
//draw a bezier curve that gets larger as it flows
//adapted for use with KineticJS
function drawBezierCurve() {
var centerLeft = new Object();
centerLeft.x = 100;
centerLeft.y = 400;
var centerRight = new Object();
centerRight.x = 400;
centerRight.y = 100;
var thicknessLeft = 1;
var thicknessRight = 50;
var color = "#000";
var context = mainLayer.getContext();
var leftUpper = {
x: centerLeft.x,
y: centerLeft.y - thicknessLeft / 2
};
var leftLower = {
x: centerLeft.x,
y: leftUpper.y + thicknessLeft
};
var rightUpper = {
x: centerRight.x,
y: centerRight.y - thicknessRight / 2
};
var rightLower = {
x: centerRight.x,
y: rightUpper.y + thicknessRight
};
var center = (centerRight.x + centerLeft.x) / 2;
var cp1Upper = {
x: center,
y: leftUpper.y
};
var cp2Upper = {
x: center,
y: rightUpper.y
};
var cp1Lower = {
x: center,
y: rightLower.y
};
var cp2Lower = {
x: center,
y: leftLower.y
};
var bezierCurve = new Kinetic.Shape({
drawFunc: function (canvas) {
var context = mainLayer.getContext();
context.fillStyle = color;
context.beginPath();
context.moveTo(leftUpper.x, leftUpper.y);
context.bezierCurveTo(cp1Upper.x, cp1Upper.y, cp2Upper.x, cp2Upper.y, rightUpper.x, rightUpper.y);
context.lineTo(rightLower.x, rightLower.y);
context.bezierCurveTo(cp1Lower.x, cp1Lower.y, cp2Lower.x, cp2Lower.y, leftLower.x, leftLower.y);
context.lineTo(leftUpper.x, leftUpper.y);
context.fill();
canvas.stroke(this);
},
fill: color,
stroke: color,
strokeWidth: 1
});
bezierCurve.on('mouseover', function (evt) {
document.body.style.cursor = "pointer";
$("#debug").html("MOUSEOVER DETECTED."); //<==NEVER CALLED
});
bezierCurve.on('mouseout', function (evt) {
document.body.style.cursor = "default";
$("#debug").html("MOUSEOUT DETECTED."); //NEVER CALLED
});
bezierCurve.setAttrs({
'leftUpper': leftUpper,
'leftLower': leftLower,
'rightUpper': rightUpper,
'rightLower': rightLower,
'cp1Upper': cp1Upper,
'cp2Upper': cp2Upper,
'cp1Lower': cp1Lower,
'cp2Lower': cp2Lower
});
mainLayer.add(bezierCurve);
mainLayer.draw();
$("#debug").html("bezier curve has been drawn onscreen.");
}
$(document).ready(function () {
var stage = new Kinetic.Stage({
container: 'canvasContainer',
width: 500,
height: 500
});
mainLayer = new Kinetic.Layer('main');
stage.add(mainLayer);
mainLayer.draw();
drawBezierCurve();
});
Can you define it as an SVG element, and just give that an onmouseover?
Fixed it! Changes are shown at the jsFiddle link in the original post.
//FIXED!
//OLD VERSION: DOES NOT WORK
// var bezierCurve = new Kinetic.Shape({
// drawFunc: function (canvas) {
// var context = mainLayer.getContext();
// context.fillStyle = color;
// context.beginPath();
// context.moveTo(leftUpper.x, leftUpper.y);
// context.bezierCurveTo(cp1Upper.x, cp1Upper.y, cp2Upper.x, cp2Upper.y, rightUpper.x, rightUpper.y);
// context.lineTo(rightLower.x, rightLower.y);
// context.bezierCurveTo(cp1Lower.x, cp1Lower.y, cp2Lower.x, cp2Lower.y, leftLower.x, leftLower.y);
// context.lineTo(leftUpper.x, leftUpper.y);
// context.closePath();
// context.fill();
// canvas.stroke(this);
// },
// fill: color,
// stroke: color,
// strokeWidth: 1
// });
//NEW VERSION: WORKS!
var bezierCurve = new Kinetic.Shape({
drawFunc: function (canvas) {
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(leftUpper.x, leftUpper.y);
context.bezierCurveTo(cp1Upper.x,cp1Upper.y, cp2Upper.x,cp2Upper.y, rightUpper.x,rightUpper.y);
context.lineTo(rightLower.x, rightLower.y);
context.bezierCurveTo(cp1Lower.x,cp1Lower.y, cp2Lower.x,cp2Lower.y, leftLower.x,leftLower.y);
context.lineTo(leftUpper.x, leftUpper.y);
context.fill();
canvas.stroke(this);
},
fill: color,
stroke: color,
strokeWidth: 3
});

Mouseup event is intermittant from Scaled KineticJS layer

See here for example:
http://jsfiddle.net/tigz_uk/B8UDq/45/embedded/result/
Fiddle code:
http://jsfiddle.net/tigz_uk/B8UDq/45/
Most Relevant snippet:
function whenAreaSelected(stage, layer, image) {
var rect, down = false;
var eventObj = layer;
eventObj.off("mousedown");
eventObj.off("mousemove");
eventObj.off("mouseup");
eventObj.on("mousedown", function (e) {
console.log("Mousedown...");
if (rect) {
rect.remove();
}
var relativePos = getRelativePos ( stage, layer);
down = true;
var r = Math.round(Math.random() * 255),
g = Math.round(Math.random() * 255),
b = Math.round(Math.random() * 255);
rect = new Kinetic.Rect({
x: relativePos.x,
y: relativePos.y,
width: 11,
height: 1,
fill: 'rgb(' + r + ',' + g + ',' + b + ')',
stroke: 'black',
strokeWidth: 4,
opacity: 0.3
});
layer.add(rect);
});
eventObj.on("mousemove", function (e) {
if (!down) return;
var relativePos = getRelativePos ( stage, layer );
var p = rect.attrs;
rect.setWidth(relativePos.x - p.x);
rect.setHeight(relativePos.y - p.y);
layer.draw();
});
eventObj.on("mouseup", function (e) {
console.log("Mouse Up...");
down = false;
var p = rect.attrs;
var s = layer.getScale();
console.log("Rect x: " + p.x + " y: " + p.y + " width: " + p.width + " height: " + p.height + " sx: " + s.x + " sy: " + s.y);
});
}
var stageWidth = 1024;
var stageHeight = 700;
var imageWidth = 1299;
var imageHeight = 1064;
var initialScale = calcScale(imageWidth, imageHeight, stageWidth, stageHeight);
var stage = new Kinetic.Stage({
container: "canvas",
width: stageWidth,
height: stageHeight
});
var layer = new Kinetic.Layer();
var imageObj = new Image();
imageObj.onload = function () {
var diagram = new Kinetic.Image({
x: -500,
y: -500,
image: imageObj,
width: imageWidth,
height: imageHeight
});
layer.add(diagram);
layer.setScale(initialScale);
whenAreaSelected(stage, layer, diagram);
layer.draw();
}
var zoom = function (e) {
var zoomAmount = e.wheelDeltaY * 0.001;
layer.setScale(layer.getScale().x + zoomAmount)
layer.draw();
}
document.addEventListener("mousewheel", zoom, false);
stage.add(layer);
imageObj.src = 'https://dl.dropbox.com/u/746967/Serenity/MARAYA%20GA.png';
It seems to me as though the mouseup event is intermittent at best.
Any idea what's going on here? It also seems to be worse when the Image is offset rather than displayed at 0,0. And I think it relates to the scaling of the layer as it all works okay at scale 1.
Is this a kinetic bug?
Try using layer.drawScene() instead of layer.draw() in your mousemove handler
eventObj.on("mousemove", function (e) {
if (!down) return;
var relativePos = getRelativePos ( stage, layer );
var p = rect.attrs;
rect.setWidth(relativePos.x - p.x);
rect.setHeight(relativePos.y - p.y);
// try drawScene() instead of draw()
layer.drawScene();
});
[Edited based on info forwarded by from user814628 here: Binding MouseMove event causes inconsistency with mouse release event being fired

Resources