var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var Circle = new Kinetic.Circle ({
x: 100,
y: 100,
radius: 10,
fill: 'green',
stroke: 'black',
strokeWidth: 5
});
layer.add(Circle);
stage.add(layer);
var a = 1;
var anim = new Kinetic.Animation(function(frame) {
Circle.setX(frame.time * 350 / 1000 + 100);
}, layer);
anim.start();
How do i stop the animation at a specific point or coordinate? like animate to x=700 and then stop. i want to have a circle that is able to animate with a button to coordinate x=700, stop and then stop, and after that with another button back or down.
thank you.
There are 2 ways,
1.
var anim = new Kinetic.Animation(function(frame) {
if(Circle.getX() < 700)
Circle.setX(frame.time * 350 / 1000 + 100);
else
this.stop();
}, layer);
OR2. Use Kinetic.Transition check here
Related
I have a simple setup where use clicks location and creates a label with text.
What i would like to be able to do is resize on zoom, so that label is relative size always. Currently label is huge when i zoom in covering key areas.
code:
createTag() {
return new Konva.Tag({
// omitted for brevity
})
}
createLabel(x: number, y: number) {
return new Konva.Label({
x: x,
y: y,
opacity: 0.75
});
}
createText() {
return new Konva.Text({
// omitted for brevity
});
}
createMarker(point: any) {
var label = createLabel(point.x, point.y);
var tag = createTag();
var text = createText();
label.add(tag);
label.add(text);
this.layer.add(label);
this.stage.add(this.layer);
}
Mouse click event listener
this.stage.on('click', function (e) {
// omitted for brevity
var pointer = this.getRelativePointerPosition();
createMarker(pointer);
// omitted for brevity
}
this.stage.on('wheel', function (e) {
// zoom code
});
How can i resize the labels to be relative size of the canvas?
There are many possible solutions. If you are changing scale of the whole stage, then you can just apply reversed scale to the label, so its absolute scale will be always 1.
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
var layer = new Konva.Layer();
stage.add(layer);
var circle = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 50,
fill: 'green',
});
layer.add(circle);
// tooltip
var tooltip = new Konva.Label({
x: circle.x(),
y: circle.y(),
opacity: 0.75,
});
layer.add(tooltip);
tooltip.add(
new Konva.Tag({
fill: 'black',
pointerDirection: 'down',
pointerWidth: 10,
pointerHeight: 10,
lineJoin: 'round',
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.5,
})
);
tooltip.add(
new Konva.Text({
text: 'Try to zoom with wheel',
fontFamily: 'Calibri',
fontSize: 18,
padding: 5,
fill: 'white',
})
);
var scaleBy = 1.01;
stage.on('wheel', (e) => {
e.evt.preventDefault();
var oldScale = stage.scaleX();
var pointer = stage.getPointerPosition();
var mousePointTo = {
x: (pointer.x - stage.x()) / oldScale,
y: (pointer.y - stage.y()) / oldScale,
};
var newScale =
e.evt.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy;
stage.scale({ x: newScale, y: newScale });
// apply reversed scale to label
// so its absolte scale is still 1
tooltip.scale({ x: 1 / newScale, y: 1 / newScale })
var newPos = {
x: pointer.x - mousePointTo.x * newScale,
y: pointer.y - mousePointTo.y * newScale,
};
stage.position(newPos);
});
<script src="https://unpkg.com/konva#8.3.0/konva.min.js"></script>
<div id="container"></div>
I am utilizing FabricJs it is a javascript canvas library to make a small application where you can create shapes and animation between different objects.
To Run it You can follow the following steps.
Click new animation
Click Rectangle
Click Add Child button (This allows you to link objects)
Click Circle or Rectangle
If you follow the steps above you will see that you can create 2 shapes and animation between the two displayed by a small circle going back and forth.
I was wondering if it is possible to create similar animation that goes either left to right or right to left only once. I would really appreciate if someone can guide me.
Here is my FIDDLE
Here is the code for the animation
var animateBallBetweenObjects = function (obj1, obj2) {
// Add the "ball"
var circle = new fabric.Circle({
radius: 10,
fill: 'blue',
left: obj1.getCenterPoint().x,
top: obj1.getCenterPoint().y,
originX: 'center',
originY: 'middle',
selectable: false
});
canvas.add(circle);
var period = 1000;
var amplitude = 0;
var angle = 0;
var prevTime = Date.now();
var loop = function () {
// Calculate the new amplitude
var now = Date.now();
var elapsed = now - prevTime;
prevTime = now;
angle += Math.PI * (elapsed / (period * 0.5));
amplitude = 0.5 * (Math.sin(angle - (0.5 * Math.PI)) + 1);
// Set the new position
var obj1Center = obj1.getCenterPoint();
var obj2Center = obj2.getCenterPoint();
circle.setLeft(obj1Center.x + (amplitude * (obj2Center.x - obj1Center.x)));
circle.setTop(obj1Center.y + (amplitude * (obj2Center.y - obj1Center.y)));
canvas.renderAll();
requestAnimationFrame(loop);
}
// Animate as fast as possible
requestAnimationFrame(loop);
};
You can try yo use fabric built in animation:
http://jsfiddle.net/asturur/s6ju2858/2/
I did not replicate your loop function, that requires extra work, but fabricJS gives you the ability to define an animation for a property ( in our case left and top ) with a start and end value.
var animateBallBetweenObjects = function (obj1, obj2) {
var completedLeft, completedTop;
// obj1, obj2 are predefined.
var c1 = obj1.getCenterPoint();
var c2 = obj2.getCenterPoint();
var circle = new fabric.Circle({
radius: 10,
fill: 'blue',
left: c1.x,
top: c1.y,
originX: 'center',
originY: 'center',
selectable: false
});
canvas.add(circle);
circle.animate('left', c2.x, {
onChange: canvas.renderAll.bind(canvas),
startValue: c1.x,
endValue: c2.x,
onComplete: function() {
completedLeft = true;
completedTop && canvas.remove(circle);
},
easing: fabric.util.ease['easeInQuad']
}).animate('top', c2.y, {
startValue: c1.y,
endValue: c2.y,
onChange: canvas.renderAll.bind(canvas),
onComplete: function() {
completedTop = true;
completedLeft && canvas.remove(circle);
},
easing: fabric.util.ease['easeInQuad']
});
};
Updated fiddle with ball removal at the end of animation.
I'm struggling to implement a little things on canvas with KineticJS.
I want to create a circle + a line which form a group (plane).
The next step is to allow the group to rotate around itself with a button that appears when you click on the group.
My issue is that when I click on the rotate button, it does not rotate near the button but elsewhere. Have a look :
My rotation atm : http://hpics.li/b46b73a
I want the rotate button to be near the end of the line. Not far away..
I tried to implement it on jsfiddle but I'm kinda new and I didn't manage to put it correctly , if you could help me on that, I would be thankful !
http://jsfiddle.net/49nn0ydh/1/
function radians (degrees) {return degrees * (Math.PI/180)}
function degrees (radians) {return radians * (180/Math.PI)}
function angle (cx, cy, px, py) {var x = cx - px; var y = cy - py; return Math.atan2 (-y, -x)}
function distance (p1x, p1y, p2x, p2y) {return Math.sqrt (Math.pow ((p2x - p1x), 2) + Math.pow ((p2y - p1y), 2))}
jQuery (function(){
var stage = new Kinetic.Stage ({container: 'kineticDiv', width: 1200, height:600})
var layer = new Kinetic.Layer(); stage.add (layer)
// group avion1
var groupPlane1 = new Kinetic.Group ({
x: 150, y: 150,
draggable:true
}); layer.add (groupPlane1)
// avion 1
var plane1 = new Kinetic.Circle({
radius: 10,
stroke: "darkgreen",
strokeWidth: 3,
}); groupPlane1.add(plane1);
var trackPlane1 = new Kinetic.Line({
points: [10, 0, 110, 0],
stroke: "darkgreen",
strokeWidth: 2
}); groupPlane1.add(trackPlane1);
groupPlane1.on('click', function() {
controlGroup.show();
});
groupPlane1.setOffset (plane1.getWidth() * plane1.getScale().x / 2, plane1.getHeight() * plane1.getScale().y / 2)
var controlGroup = new Kinetic.Group ({
x: groupPlane1.getPosition().x + 120,
y: groupPlane1.getPosition().y ,
opacity: 1, draggable: true,
}); layer.add (controlGroup)
var signRect2 = new Kinetic.Rect({
x:-8,y: -6,
width: 20,
height: 20,
fill: 'white',
opacity:0
});
controlGroup.add(signRect2);
var sign = new Kinetic.Path({
x: -10, y: -10,
data: 'M12.582,9.551C3.251,16.237,0.921,29.021,7.08,38.564l-2.36,1.689l4.893,2.262l4.893,2.262l-0.568-5.36l-0.567-5.359l-2.365,1.694c-4.657-7.375-2.83-17.185,4.352-22.33c7.451-5.338,17.817-3.625,23.156,3.824c5.337,7.449,3.625,17.813-3.821,23.152l2.857,3.988c9.617-6.893,11.827-20.277,4.935-29.896C35.591,4.87,22.204,2.658,12.582,9.551z',
scale: {x:0.5, y:0.5}, fill: 'black'
}); controlGroup.add (sign)
controlGroup.setDragBoundFunc (function (pos) {
var groupPos = groupPlane1.getPosition();
var rotation = degrees (angle (groupPos.x, groupPos.y, pos.x, pos.y));
var dis = distance (groupPos.x, groupPos.y, pos.x, pos.y);
groupPlane1.setRotationDeg (rotation);
layer.draw()
return pos
})
controlGroup.on ('dragend', function() {
controlGroup.hide();
layer.draw()
})
controlGroup.hide();
layer.draw()
})
You can adjust the rotation point by setting the offsetX and offsetY of the group.
I've been staring at this for the past hour and cannot figure it out.
I'm trying to use KineticJS to rotate a shape 45 degrees when it is clicked. I found http://jsfiddle.net/JUu2Q/6/ from a previous question on Stack Overflow which does basically what I want. When I apply this to my code (and change 'layer' to 'stage'), I get the following error: Cannot read property 'rotation' of undefined:
layer.on('click tap', function(evt) {
evt.targetNode.tween = new Kinetic.Tween({
node: evt.targetNode,
duration: 0.3,
rotationDeg: evt.targetNode.rotation()+45,
easing: Kinetic.Easings.EaseOut
});
evt.targetNode.tween.play();
});
I'm sure I'm doing something wrong but I just can't figure it out.
My code can be found at http://jsfiddle.net/0h55fdzL/
I've only be using KineticJS for a few hours so I apologize if this is stupid question
Thanks for your help!
1 Create closure for x variable.
2 Use target instead of targetNode
var x = -50;
var y = -50;
var stage = new Kinetic.Stage({
container: 'container',
width: 1200,
height: 1200,
});
for (i=0; i<3; i++){
x = x + 50;
y = y + 50;
var layer = [];
layer[i] = new Kinetic.Layer();
var hex = [];
(function(x){
hex[i] = new Kinetic.Shape({
sceneFunc: function(context) {
context.beginPath();
context.moveTo(x+25, 0);
context.lineTo(x+40, 10);
context.lineTo(x+40, 25);
context.lineTo(x+25, 35);
context.lineTo(x+10, 25);
context.lineTo(x+10, 10);
context.closePath();
// KineticJS specific context method
context.fillStrokeShape(this);
},
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 4,
draggable: true,
rotation:0
});
})(x);
// add the triangle shape to the layer
layer[i].add(hex[i]);
// add the layer to the stage
stage.add(layer[i]);
}
stage.on('click tap', function(evt) {
evt.target.tween = new Kinetic.Tween({
node: evt.target,
duration: 0.3,
rotationDeg: evt.target.rotation()+45,
easing: Kinetic.Easings.EaseOut
});
evt.target.tween.play();
});
http://jsfiddle.net/0h55fdzL/1/
Here is the code: http://jsfiddle.net/MTDpC/
function drawArrow(firstShape, lastShape){
var group = new Kinetic.Group();
group.previousShape = firstShape;
group.nextShape = lastShape;
var beginX = group.previousShape.getX() + group.previousShape.getChildren()[0].getWidth() / 2;
var beginY = group.previousShape.getY() + group.previousShape.getChildren()[0].getHeight();
var endX = group.nextShape.getX() + group.nextShape.getChildren()[0].getWidth() / 2;
var endY = group.nextShape.getY() - 8;
var linha = new Kinetic.Line({
points: [ beginX, beginY, endX, endY],
name: 'linha',
stroke: '#555',
strokeWidth: 4,
lineCap: 'butt'
});
var seta = new Kinetic.RegularPolygon({
x: endX,
y: endY,
sides: 3,
radius: 4,
fill: '#555',
stroke: '#555',
strokeWidth: 4,
name: 'seta'
});
seta.rotateDeg(180);
group.add(seta);
group.add(linha);
firstShape.arrow = group;
lastShape.arrow = group;
group.reposition = function(){
var beginX = this.previousShape.getX() + this.previousShape.getChildren()[0].getWidth() / 2;
var beginY = this.previousShape.getY() + this.previousShape.getChildren()[0].getHeight();
var endX = this.nextShape.getX() + this.nextShape.getChildren()[0].getWidth() / 2;
var endY = this.nextShape.getY() - 8;
this.get('.linha')[0].transitionTo({
points:[ beginX, beginY, endX, endY],
duration: 0.0000001,
});
this.get('.seta')[0].transitionTo({
x: endX,
y: endY,
duration: 0.0000001,
});
};
return group;
}
function getProcess (processText, x, y, width) {
var group = new Kinetic.Group();
var complexText = new Kinetic.Text({
text: processText + '\nX: ' + x + '\nY: ' + y,
fontSize: 12,
fontFamily: 'Calibri',
fill: '#555',
padding: 20,
align: 'center',
name: 'Texto-Processo'
});
var rect = new Kinetic.Rect({
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: complexText.getWidth(),
height: complexText.getHeight(),
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: [10, 10],
shadowOpacity: 0.2,
cornerRadius: 10,
name: 'Quadro-Processo'
});
group.add(rect);
group.add(complexText);
group.setDraggable(true);
group.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
group.on('mouseout', function() {
document.body.style.cursor = 'default';
});
group.on('dragmove', function(){
group.getChildren()[1].setText(this.customText + "\nX: " + this.getX() + "\nY: " + this.getY());
group.arrow.reposition();
group.arrow.draw();
});
group.setX(x);
group.setY(y);
group.customText = processText;
return group;
}
var stage = new Kinetic.Stage({
container: 'container',
width: 800,
height: 600,
id: 'myCanvas'
});
var layer = new Kinetic.Layer();
var processo = getProcess('Processo de Teste de canvas 1', (stage.getWidth() / 2) - 100, 10 , 100);
processo.setId('canvas1');
layer.add(processo);
var processo2 = getProcess('Processo de Teste de canvas 2', (stage.getWidth() / 2) -100, processo.getY() + 300, processo.getX());
layer.add(processo2);
layer.add(drawArrow(processo, processo2));
// add the layer to the stage
stage.add(layer);
When one of the boxes are dragged, the arrow connecting them moves too.
As the arrow was made using 2 shapes, I want to know if is there some way to use .transtionTo at the same time, because you can see some delay between the line and the triangle that forms the arrrow when you move the bottom box.
The problem is that the transitionTo function does not support transitioning points. Also, each time you move the object, you are creating a new transition object... which is extremely slow. You do not need transitions for this, transitions are only useful for animating things automatically when the user is not meant to control them.
Try this instead:
this.get('.linha')[0].setPoints([beginX, beginY, endX, endY]);
this.get('.seta')[0].setPosition(endX,endY);
this.getLayer().draw();
/* this.get('.linha')[0].transitionTo({ //cant transition points
points: [beginX, beginY, endX, endY],
duration: 0.0000001,
});
this.get('.seta')[0].transitionTo({ // lags because everytime you move, a new transition is created, no this would be extremely slow
x: endX,
y: endY,
duration: 0.0000001,
});
*/
http://jsfiddle.net/MTDpC/1/
works fast eh?