Smooth animations in kinetic.js (html5 canvas) - javascript

I need a better understanding of kinetic.js animation. I was using the tutorial found http://www.html5canvastutorials.com/kineticjs/html5-canvas-stop-animation-with-kineticjs/ . I played with the code and made my animation set my rectangle at x position 100. My question is how do I the movement of the rectangle to have a smooth transition. I was unable to get my head wrapped around the explanation of kinetic.js animations off the html5canvastutorials.com. here is my code.
var stage = new Kinetic.Stage({
container: 'container',
width: 960,
height: 480
});
var layer = new Kinetic.Layer();
var block = new Kinetic.Rect({
x: 100,
y: 465,
width: 14,
height: 14,
stroke: 'black',
strokeWidth: 1
});
layer.add(block);
stage.add(layer);
var moveLeft = new Kinetic.Animation(function(frame) {
block.setX(1);
}, layer);
var moveRight = new Kinetic.Animation(function(frame) {
block.setX(100);
}, layer);
document.addEventListener('keydown', function(e){
switch(e.keyCode) {
case 37:
moveLeft.start();
break;
case 39:
moveRight.start();
break;
default:
moveLeft.stop();
moveRight.stop();
break;
}
});
Can someone please give me an example of how to create smooth animations and a great explanation of how to repeat the process. Not sure how frame timing works either.

I think you should look at this change:
API Changes
new Tween class. The old Transition class has been retired. For advanced tweens, such as tweening things along curves, or constructing timelines, KineticJS recommends the GreenSock Animation Platform which integrates seamlessly.

For simple tweens, you can use the built in Tween class. Here's an example:
http://www.html5canvastutorials.com/kineticjs/html5-canvas-linear-transition-tutorial-with-kineticjs/

Related

Scale down a Konvajs stage without losing quality

Consider having a large (2000x1000) stage with some text in it. The stage gets downscaled to 1000x500 making the text unreadable. Then we try to enlarge the text by zooming it in.
Expected: the text should become readable again at some point.
Actual: the text remains unreadable (blurred) no matter how much we zoom in.
Try zooming the page in (with native browser zoom on desktop) after running the snippet:
const stage = new Konva.Stage({
container: 'container',
width: 2000,
height: 1000,
});
const layer = new Konva.Layer();
stage.add(layer);
const rect = new Konva.Text({
x : 50, y : 50, width: 100, height: 100,
fontSize: 12,
text: "This text should be readable when the viewport gets downscaled"
});
layer.add(rect).draw();
stage.scale({x: 0.5, y: 0.5});
stage.setAttrs({width: 1000, height: 500});
stage.draw();
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.6.0/konva.js"></script>
<div id="container"></div>
The quality loss can be avoided by downscaling with CSS only, like this:
const stage = new Konva.Stage({
container: 'container',
width: 2000,
height: 1000,
});
const layer = new Konva.Layer();
stage.add(layer);
const rect = new Konva.Text({
x : 50, y : 50, width: 100, height: 100,
fontSize: 12,
text: "This text should be readable when the viewport gets downscaled"
});
layer.add(rect).draw();
stage.getChildren().forEach(function(layer) {
layer.canvas._canvas.style.width = "1000px";
layer.canvas._canvas.style.height = "500px";
layer.hitCanvas.setSize(1000, 500);
layer.hitCanvas.context.scale(0.5, 0.5);
});
stage.draw();
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.6.0/konva.js"></script>
<div id="container"></div>
Note how text becomes readable at a certain level of zooming.
The workaround breaks Konvajs abstraction. What problems it can potentially cause? Is there a better way, which uses only public methods exposed by Konvajs?
In fabric.js it can be done like this (complete example here):
canvas.setDimensions({width: '1000px', height: '500px'}, {cssOnly: true});
Konva is a canvas framework. Canvas is a bitmap image unlike vector elements like SVG. So that "blur" should be expected. Technically to fix the issue you can redraw stage with higher pixelRatio on zoom event:
Konva.pixelRatio = 4
stage.draw();
That code will generate more pixels for canvas element. But the page may be very heavy in RAM in this case because Konva will have to produce very large canvas. In most of the mobile apps, you don't need native zooming and you can use responsive design. For zooming the stage, you can use Konva methods.

How to dynamically move Vector Features in OpenLayers 3

Based from an example given here: http://openlayers.org/en/vector-api/examples/dynamic-data.html?q=dynamic
Instead of using circle:
var imageStyle = new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({color: 'yellow'}),
stroke: new ol.style.Stroke({color: 'red', width: 1})
});
I want to use Vector Feature (Marker) as the object which is moving instead of using that yellow circle.
An example of using a feature vector is found here:
how to add markers with OpenLayers 3
Sorry, just a beginner in OpenLayers 3. Hope someone can help me. Thanks!
I've made you a basic example.
The idea is: You move an Overlay through a path using an interval to change its position like:
//fire the animation
map.once('postcompose', function(event) {
interval = setInterval(animation, 500);
});
var i = 0, interval;
var animation = function(){
if(i == path.length){
i = 0;
}
marker.setPosition(path[i]);
i++;
};

Animation text in a snake way with canvas

I find this website -> http://bit.ly/1FCtQSQ and he has this animation scroll, which I am not interested, however in the middle of the scroll animation, a text snake animation appears. I want very badly to know how I can do this, just to learn.
I researched all plugins that curve texts, such as:
Arctext.js
CircleType
This one
Also, i tried 'still' the code from http://bit.ly/1FCtQSQ, but is minified, i know this guys are using the timelinemax, which uses the canvas, i tried to copy the code, but didn't work, as you can see here in the bottom of this question.
So i came here as the last resource.
Could someone give me an explanation with a working example, or maybe a plugin which i can study the code?
I know this is not the best way to find a answer to my question, but i don't have money to pay for codementor, hackhands, airpair or something like this.
Thanks!
Pen: http://codepen.io/anon/pen/GJjjxG
Code that i copy:
<h1 class="snake">Animate this like a snake!</h1>
var animation = new TimelineMax({
paused: !0,
ease: Linear.easeNone
});
var T = 0;
var f = 30;
animation.add(
TweenMax.to(e(".snake").parent(), f, {
left: -5e3
}), T);
Thanks.
The KonvaJS (formerly KineticJS) canvas library has some nice text-along-path code with a liberal MIT license:
https://github.com/konvajs/konva/blob/f6e2cf19a30dec2f94f50152f20c35988b1bf99e/src/plugins/TextPath.js
The KonvaJS TextPath code works like this:
Start with a path made up of curves and lines defined using the same syntax that SVG uses to define path.
Calculate waypoints along that path.
Fit characters one-by-one along the path using the calculated waypoints.
Use transformations to position the characters properly. (using context.translate & context.rotate to match the letter to the angle of the path / curve.)
You can cause the text to animate along the curve by beginning the text further & further beyond the first waypoint on the curve.
Example code using the KonvaJS libarary:
var stage = new Konva.Stage({
container: 'container',
width: 1000,
height: 1000
});
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
var textpath = new Konva.TextPath({
x: 0,
y: 50,
fill: '#333',
fontSize: 16,
fontFamily: 'Arial',
text: 'Now is the time for all good men to come to the aid of their party -- An phrase from an old touch-typing test.',
data: 'M 100 200 C 200 100 300 0 400 100 C 500 200 600 300 700 200 C 800 100 900 100 900 100'
});
layer.add(textpath);
layer.draw();
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
<script src="https://cdn.rawgit.com/konvajs/konva/0.9.0/konva.min.js"></script>
<div id="container"></div>

kinetic.js change fill type of object after instantiation, after added to layer and scene, and in animation loop

I am attempting to change the fill style of a KineticJS Rect object after it has been instantiated, after being added to the layer and scene, and in the animation loop.
I am trying to toggle the fill type between a single color type to a linear gradient type based on a user button control in my main app file that renders the canvas.
I instantiate the object in a different file which is a class I wrote that instantiates a KineticJS Rect with a linear gradient fill initially in it's constructor like so:
function MyBackground(width,height,c1,c2,mode) {
this.width = width;
this.height = height;
this.color1 = c1;
this.color2 = c2;
this.mode = mode;
this.background = new Kinetic.Rect({
x: 0,
y: 0,
width: this.width,
height: this.height,
fillLinearGradientStartPoint: [0, 0],
fillLinearGradientEndPoint: [this.width, this.height],
fillLinearGradientColorStops: [0, this.color1, 1, this.color2]
});
this.getMode = function() { return this.mode; }; }
I then create an instance of this in the main file:
var myBack= new MyBackground(stageWidth,stageHeight,getRandomHexColor(),getRandomHexColor(),'dualColorLinearGradientStatic');
var background = myBack.getBackground();
myBack.setMode('singleColor');
I then add the background Rect to the layer, and the layer to the stage:
layer.add(background);
stage.add(layer);
I then start the animation loop code and after that the event handler that catches the button press to change the fill trying this inside:
myBack.setMode(bgmodeselected);
background = myBack.getBackground();
The app page loads fine showing the initial linear gradient fill. If I select that same mode of linear gradient and press the button control, it changes the colors as I desire maintaining the fill type of linear gradient. If I then switch the mode to single color fill and click the control button, that works too, changing the rect to a single color.
Here is what I have inside my class function to change the mode that makes that specifically work:
this.background.setFill(this.color1);
Inside that same function based on a conditional it should change the fill to linear gradient (and does this as long as its not changed to single color fill as above first)
this.background.setAttrs({
fillLinearGradientStartPoint: [0, 0],
fillLinearGradientEndPoint: [960, 600],
fillLinearGradientColorStops: [0, this.color1, 1, this.color2]
});
I've also tried within that same block:
this.background.setFillLinearGradientStartPoint(0, 0);
this.background.setFillLinearGradientEndPoint(960, 600);
this.background.setFillLinearGradientColorStops([0, this.color1, 1, this.color2]);
I know that the proper variables and values are being passed to the function and that the conditionals are working because it will change the fill mode type from its (as initially instantiated) linear gradient fill to a single color fill (which will continue working even as a different single color).
The problem is when I try to switch BACK to linear gradient fill it will not do so, or repaint/refresh at least despite it's calling this same function with the proper values. So, I suppose that my specific question is how can I change the fill style of a KineticJS Rect multiple times, from a single color fill back to a linear gradient fill after it has been already been added to the layer and stage and has an animation loop implemented?
This is my first question post so I hope that I am doing so properly; please inform me if I should be doing anything differently. Thanks.
Welcome to stackoverflow!
When you’re re-applying your gradient, be sure to clear out the solid color fill:
// clear the solid fill
this.setFill('');
// then apply the gradient fill
this.setFillLinearGradientStartPoint(-50);
this.setFillLinearGradientEndPoint(50);
this.setFillLinearGradientColorStops([0, 'green', 1, 'yellow']);
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/dmMF2/
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.3.0-beta2.js"></script>
<script>
function draw(images) {
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var linearGradPentagon = new Kinetic.Rect({
x: 100,
y: 30,
width: 75,
height: 50,
fill:"red",
stroke: 'black',
strokeWidth: 4,
draggable: true
});
linearGradPentagon.on('mouseover touchstart', function() {
this.setFill('');
this.setFillLinearGradientStartPoint(-50);
this.setFillLinearGradientEndPoint(50);
this.setFillLinearGradientColorStops([0, 'green', 1, 'yellow']);
layer.draw();
});
linearGradPentagon.on('mouseout touchend', function() {
this.setFill('red');
layer.draw();
});
layer.add(linearGradPentagon);
stage.add(layer);
}
draw();
</script>
</body>
</html>

How to prevent loss hover in Raphael?

I'm developing some page when I use Raphael liblary to draw some items.
my App
So my problem is in that when I'm moving to some rect it growing up but when my mouse is on text which is positioning on my rect, it loss his hover. You can see it on my app example.
var paper = new Raphael(document.getElementById('holder'), 500, object.length * 100);
drawLine(paper, aType.length, bType.length, cType.length, cellSize, padding);
process = function(i,label)
{
txt = paper.text(390,((i+1)* cellSize) - 10,label.devRepo)
.attr({ stroke: "none", opacity: 0, "font-size": 20});
var a = paper.rect(200, ((i+1)* cellSize) - 25, rectWidth, rectHeight)
.hover(function()
{
this.animate({ transform : "s2"}, 1000, "elastic");
this.prev.animate({opacity: 1}, 500, "elastic");
this.next.attr({"font-size" : 30});
},
function()
{
this.animate({ transform : "s1" }, 1000, "elastic");
this.prev.animate({opacity: 0}, 500);
this.next.attr({"font-size" : 15});
});
}
I have tried e.preventDefault(); on hover of this.next and some other solutions but it's doesn't work.
Any help would be appreciated.
Most people will suggest you place a transparent rectangle over the box and the labels and attach the hover functions to that instead. (If memory serves, you have to make the opacity 0.01 instead of 0 to prevent the object from losing its attached events.) This works fine, but I don't love this solution; it feels hacky and clutters the page with unnecessary objects.
Instead, I recommend this: Remove the second function from the hover, making it functionally a mouseover function only. Before you draw any of the rectangles and labels, make a rectangular "mat" the size of the paper. Then, attach the function that minimizes the label as a mouseover on the mat. In other words, you're changing the trigger from mousing out of the box to mousing over the area outside of it.
I left a tiny bit of opacity and color on the mat to be sure it's working. You can just change the color to your background color.
var mat = paper.rect(0, 0, paper.width, paper.height).attr({fill: "#F00", opacity: 0.1});
Now, you want to make a container for all the rectangles so you can loop through them to see which need to be minimized. I made an object called "rectangles" that contains the objects we're concerned with. Then:
mat.mouseover(function () {
for (var c = 0; c < rectangles.length; c += 1) {
//some measure to tell if rectangle is presently expanded
if (rectangles[c].next.attr("font-size")) {
rectangles[c].animate({
transform : "s1"
}, 1000, "elastic");
rectangles[c].prev.animate({opacity: 0}, 500);
rectangles[c].next.attr({"font-size" : 15});
}
}
});
Then I just removed the mouseout function from the individual rectangles.
jsBin
To be clear, this will have some downsides: If people run the mouse around really fast, they can expand several rectangles at the same time. This is remedied as soon as the mouse touches the mat. I think the functionality looks pretty nice. But the invisible mats is always an option.
I wrote a small extension to Raphael - called hoverInBounds - that resolves this limitation.
Demo: http://jsfiddle.net/amustill/Bh276/1
Raphael.el.hoverInBounds = function(inFunc, outFunc) {
var inBounds = false;
// Mouseover function. Only execute if `inBounds` is false.
this.mouseover(function() {
if (!inBounds) {
inBounds = true;
inFunc.call(this);
}
});
// Mouseout function
this.mouseout(function(e) {
var x = e.offsetX || e.clientX,
y = e.offsetY || e.clientY;
// Return `false` if we're still inside the element's bounds
if (this.isPointInside(x, y)) return false;
inBounds = false;
outFunc.call(this);
});
return this;
}

Categories