I drew a rectangle with kinetic.js and animating it in a circular path. In each animation frame i reduce it's radius, and i draw animating path of this object by kineticJS Line. But This Kinetics animation loop develops an undesirable pausing "stagger". This stagger is small in Chrome, noticeable in IE and horrible in FireFox. This seems to be due to the Kinetic.Line being unable to smoothly add + draw thousands of changing points of data. How can make this animation flawless, smooth. It would be great help if you give me the link of a jsfiddle. Bunches of thanks in advance.
CODES:
var R= 80;
$(document).ready(function(){
var stage= new Kinetic.Stage({
container: 'container',
width:500,
height:500
});
var layer = new Kinetic.Layer();
var line = new Kinetic.Line({
points:[0,0,0,0],
stroke:'blue',
strokeWidth:2
});
var rect = new Kinetic.Rect({
x:10,
y:10,
width:10,
height: 10,
fill:'black',
stroke:'red'
});
layer.add(rect);
layer.add(line);
stage.add(layer);
var centerX = stage.width()/2;
var points=[];
var anim = new Kinetic.Animation(
function(f){
var cX= stage.width()/2;
var cY= stage.height()/2;
R=R-1/100;
var X = cX + R*Math.cos(f.time/1000);
var Y = cY+ R*Math.sin(f.time/1000);
points.push(X,Y);
line.setPoints(points);
rect.setX(X);
rect.setY(Y);
}
,layer);
anim.start();
});
JSFIDDLE: http://jsfiddle.net/tanvirgeek/n8z8N/7/
Thanks In advance.
As you’ve discovered, updating and drawing a Kinetic.Line containing thousands of line segments causes a noticable lag.
One Kinetic trick that I rarely seen used is useful to create a lag-free animation of thousands of line segments.
First, draw your line segments on an off-screen html5 canvas. When a new line segment is needed, just add that segment to all the pre-existing segments. This is very efficient because only the last line segment needs to be drawn.
You can use a Kinetic.Image to display the offscreen html5 canvas on the screen.
The trick is to set the Kinetic.Image image-source to the html canvas: myKineticImage.setImage(myOffscreenCanvas). This works because “behind the scenes” the Kinetic.Image is using context.drawImage to display its image. Since context.drawImage can also accept another canvas as its image-source, you can efficiently display the current offscreen canvas drawings.
A Demo: http://jsfiddle.net/m1erickson/rYC96/
And example 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-v5.0.1.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);
// variables used to set the stage and animate
var rectSize=15;
var cx=stage.getWidth()/2;
var cy=stage.getHeight()/2;
var R=100;
var A=0;
var deltaA=Math.PI/180;
var lastX=cx+R*Math.cos(A);
var lastY=cy+R*Math.sin(A);
// the html canvas incrementally draws the line segments
// which are in turn displayed as a Kinetic.Image (called line)
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
canvas.width=stage.getWidth();
canvas.height=stage.getHeight();
ctx.strokeStyle="blue";
ctx.lineWidth=2;
// this Kinetic.Image exactly displays the current html canvas drawings
// (this trick cures the lags)
var line=new Kinetic.Image({
x:0,
y:0,
width:canvas.width,
height:canvas.height,
image:canvas
});
layer.add(line);
// the rotating Kinetic.Rectangle
var rect = new Kinetic.Rect({
x:lastX,
y:lastY,
width:rectSize,
height:rectSize,
fill:'black',
stroke:'red'
});
layer.add(rect);
// use requestAnimationFrame (RAF) to drive the animation
// RAF efficiently schedules animation frames with display
function animate(){
// stop animating when rect reaches center
if(R<=rectSize/2){return;}
// schedule another animation frame even before this one is done
requestAnimationFrame(animate);
// calc the new XY position
R=R-.01;
A+=deltaA;
var X=cx+R*Math.cos(A);
var Y=cy+R*Math.sin(A);
// animate the rect and line to their next position
// draw just the latest line segment to the canvas
// (all the previous line segments are still there--no need to redraw them)
ctx.beginPath();
ctx.moveTo(lastX,lastY);
ctx.lineTo(X,Y);
ctx.stroke();
// set lastXY for next frame
lastX=X;
lastY=Y;
// update the rect position
rect.setX(X);
rect.setY(Y);
// draw the changed line-image and rect to the kinetic layer
layer.draw();
}
// start animating!
animate();
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
Related
I have a sprite sheet consisting of 12 frames.
I want to extract each individual frame from it and want to show it in different canvas like below.
what i have tried so far is posted below
//HTML code for define the canvas area .
<body onload="image_render();">
<div id="image_area"> <canvas id="image"></canvas></div>
<script src="sprite_demo.js"></script>
</body>
// javascript to slice the image and assign to the canvas
var canvasImage = new Image();
canvasImage.src = "image/sprite_xxdpi.jpg";
var can= document.getElementById("image");
can.width = 500;
can.height = 300;
function image_render()
{
coin.render();
}
var coin = sprite({
context: can.getContext("2d"),
width: 500,
height: 300,
image: coinImage
});
function sprite (options) {
var that = {};
that.context = options.context;
that.width = options.width;
that.height = options.height;
that.image = options.image;
that.render = function () {
// Draw the animation
that.context.drawImage(
that.image,
0, //X-axis starting position from where slicing begins
0, //y-axis starting position from where slicing begins
that.width, //width of slicing image
that.height,//height of slicing image
0, //X-axis starting position where image will be drawn
0, //y-axis starting position where image will be drawn
150, // width of the resulting image
150); //height of the resulting image
};
return that;
}
I am only able to get a single image ,But I want to get all the images to show in a grid.And also i want to get the image to show any where I want.
I also want to scale down big size images to show in a grid and while taping on it I want to show the original image.
Note: I don't want to animate my frames, I just want to show in grid. There are mostly examples of sprite animation available on internet.
You have the correct version of drawImage to clip individual sprites from the spritesheet, but you must alter the values in drawImage for each sprite.
The "faces" example spritesheet you show appear to have equal sized individual sprites (75px by 75px).
Assuming all your sprites are the same size, you would alter the 2nd & 3rd drawImage parameters which tell canvas the top-left x/y coordinate to begin clipping on the spritesheet.
Here's example code and a Demo: http://jsfiddle.net/m1erickson/tVD2K/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var spriteWidth=75;
var spriteHeight=75;
var spriteCols=4;
var spriteRows=3;
var y=20-sprightHeight;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/spritesheet1.jpg";
function start(){
var canvasY=0;
for(var col=0;col<spriteCols;col++){
for(var row=0;row<spriteRows;row++){
var sourceX=col*spriteWidth;
var sourceY=row*spriteHeight;
// testing: calc a random position to draw this sprite
// on the canvas
var canvasX=Math.random()*150+20;
canvasY+=spriteHeight+5;
// drawImage with changing source and canvas x/y positions
ctx.drawImage(img,
sourceX,sourceY,spriteWidth,spriteHeight,
canvasX,canvasY,spriteWidth,spriteHeight
);
}}
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Draw individual sprites from a spritesheet</h4>
<canvas id="canvas" width=300 height=1000></canvas>
</body>
</html>
i have created a grass field which is a combination of several small 60x36 images.a grass object is introduced and then drawn on the canvas.now i want to give it motion .the continuous scrolling effect .i made a code for it and it isn't working( the images (the grass field)are not scrolling along the width of the canvas which is the goal of this script).i haven't work much with oop in js. a little discussion on the mistakes i have done will be great
(the image i have used is added to the post)
<html>
<body>
<canvas id="mycanvas"></canvas>
<script>
function makeit(){
var canvas=document.getElementById("mycanvas");
var ctx=canvas.getContext('2d');
var height=500-36;
var xpos=[];
var img=new Image();
img.src="grass.jpg";
drawcanvas();
function drawcanvas(){
canvas.width=600;
canvas.height=500;
canvas.style.border="1px solid black";
}
for(i=0;i<10;i++){
xpos.push(i*60);
}
var grass=function(x,y){
this.x=x;
this.y=y;
this.img=img;
ctx.drawImage(this.img,this.x,this.y);
}
grass.prototype.motion=function(){
for(i=0;i<xpos.length;i++){
xpos[i]--;
if(xpos[i]<=-60){
xpos[i]=canvas.width;
}
ctx.drawImage(this.img,this.x,this.y);
}
}
for(i=0;i<xpos.length;i++){
var grass1=new grass(xpos[i],height);
}
var m=setTimeout(function(){
for(i=0;i<xpos.length;i++){
grass1.motion();
}
},1000);
}
window.onload=makeit;
</script>
</body>
</html>
actual canvas after drawing all the images
In essence, all you need is to create an image pattern then translate and draw it to screen.
An example assuming image has been loaded:
var ph = img.height; // pattern height
var w = canvas.width; // width of canvas/scoll area
var h = canvas.height; // used to calculate y pos.
var x = 0; // scroll position
ctx.fillStyle = ctx.createPattern(img, 'repeat-x'); // pattern
Then in the loop scrolling the grass:
function scroll() {
ctx.translate(x, h - ph); // translate to next position
ctx.fillRect(-x, 0, w, ph); // fill rectangle (fillstyle = pattern)
ctx.translate(-x, -(h -ph)); // translate back for other operations
x--; // scroll speed (here 1 pixel / frame)
requestAnimationFrame(scroll); // loop
}
FIDDLE
Pattern fills are anchored to the coordinate system which is why the translate is necessary. As we translate we also compensate for it using draw position in the opposite direction. This will make the pattern be filled into the same position but at a variable offset which creates the animation effect.
Just note that if you change fillStyle you need to store the pattern in a variable and reinitialize the fill style. If the loop is long-running also limit x so it doesn't overflow. This can be done using w as a condition (or modulo) to reset x to 0.
I'm making a game that uses pixi and it renders on a canvas that's 640x480 pixels. As you can imagine, this is very small when viewed on a PC. I'd like to accomplish this:
I want to increase the size of the canvas so it fills up the whole screen
I want to zoom in on the content so that it fills up as much as possible without changing its aspect ratio
I'd like to center the canvas if there's left over space from the previous step
When I google for how to do this in pixi, I can find each of these individually. But I'd like to have the information on how to do this all in one place and on stackoverflow, because you usually want to do all of these things together.
I modified the source code in this example made by the creator: http://www.goodboydigital.com/pixi-js-tutorial-getting-started/ (source download)
Here's what I came up with:
<!DOCTYPE HTML>
<html>
<head>
<title>pixi.js example 1</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #000000;
}
</style>
<script src="pixi.js"></script>
</head>
<body>
<script>
// create an new instance of a pixi stage
var stage = new PIXI.Stage(0x66FF99);
// create a renderer instance
var renderer = PIXI.autoDetectRenderer(400, 300);
renderer.resize(800, 600);
// add the renderer view element to the DOM
document.body.appendChild(renderer.view);
requestAnimFrame( animate );
// create a texture from an image path
var texture = PIXI.Texture.fromImage("bunny.png");
// create a new Sprite using the texture
var bunny = new PIXI.Sprite(texture);
// center the sprites anchor point
bunny.anchor.x = 0.5;
bunny.anchor.y = 0.5;
// move the sprite t the center of the screen
bunny.position.x = 200;
bunny.position.y = 150;
var container = new PIXI.DisplayObjectContainer();
container.scale.x = 2;
container.scale.y = 2;
container.addChild(bunny);
stage.addChild(container);
function animate() {
requestAnimFrame( animate );
// just for fun, lets rotate mr rabbit a little
bunny.rotation += 0.1;
// render the stage
renderer.render(stage);
}
</script>
</body>
</html>
Now the one thing I didn't do is center it. I see two potential ways to do this. I could use CSS to center the canvas (what I'll probably use), or I could do this in code by adding another outer display object to the stage that centers container.
There is a tut on line drag and drop here :
http://www.html5canvastutorials.com/kineticjs/html5-canvas-drag-and-drop-a-line-with-kineticjs/
But more interestingly how to do drag and drop a line segment (fragment only) in kinetic JS ?
There's no example for doing this.
In my use case the segment stays attached to polyline, it just changes angle. so I don't want to create another polyline with one segment only which would also be a waste of resource.
How to drag one segment of a polyline with the other segments remaining connected
You can create a series of 2-point kinetic.lines (just a start and end point).
Each new start point is the end point of the previous line
This screenshot shows the green segment being dragged and the other segments changing accordingly.
Result: A polyline made up of draggable segments.
Note: after any segment is dragged, the getX()/getY() contain the distance dragged from its original XY.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/GrEEL/
<!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.5.5.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:300px;
height:300px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width:300,
height: 300
});
var layer = new Kinetic.Layer();
stage.add(layer);
var colors=['red','green','blue','orange'];
var lines=[];
var points=[];
points.push({x:125,y:50});
points.push({x:75,y:75});
points.push({x:200,y:200});
points.push({x:275,y:100});
for(var i=0;i<points.length-1;i++){
var p1=points[i];
var p2=points[i+1];
addSegment(i,p1.x,p1.y,p2.x,p2.y,colors[i]);
}
layer.draw();
function addSegment(i,x1,y1,x2,y2,color){
var line = new Kinetic.Line({
points: [x1,y1,x2,y2],
stroke:color,
strokeWidth: 25,
lineCap:"round",
lineJoin:"round",
draggable:true
});
line.index=i;
line.on("dragend",function(){
// get the amount of xy drag
var i=this.index;
var dx=this.getX();
var dy=this.getY();
// update the points array
var p0=points[i];
var p1=points[i+1];
p0.x+=dx;
p0.y+=dy;
p1.x+=dx;
p1.y+=dy;
// reset the dragged line
this.setPosition(0,0);
this.setPoints([p0.x,p0.y,p1.x,p1.y]);
layer.draw();
});
line.on("dragmove",function(){
// get the amount of xy drag
var i=this.index;
var dx=this.getX();
var dy=this.getY();
// adjust the ending position of the previous line
if(i>0){
var line=lines[i-1];
var pts=line.getPoints();
pts[1].x=points[i].x+dx;
pts[1].y=points[i].y+dy;
line.setPoints(pts);
}
// adjust the starting position of the next line
if(i<lines.length-1){
var line=lines[i+1];
var pts=line.getPoints();
pts[0].x=points[i+1].x+dx;
pts[0].y=points[i+1].y+dy;
line.setPoints(pts);
}
layer.draw();
});
layer.add(line);
lines.push(line);
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
I am making a loading spinner with html5 canvas. I have my graphic on the canvas but when i rotate it the image rotates off the canvas. How do I tell it to spin the graphic on its center point?
<!DOCTYPE html>
<html>
<head>
<title>Canvas test</title>
<script type="text/javascript">
window.onload = function() {
var drawingCanvas = document.getElementById('myDrawing');
// Check the element is in the DOM and the browser supports canvas
if(drawingCanvas && drawingCanvas.getContext) {
// Initaliase a 2-dimensional drawing context
var context = drawingCanvas.getContext('2d');
//Load the image object in JS, then apply to canvas onload
var myImage = new Image();
myImage.onload = function() {
context.drawImage(myImage, 0, 0, 27, 27);
}
myImage.src = "img/loading.png";
context.rotate(45);
}
}
</script>
</head>
<body>
<canvas id="myDrawing" width="27" height="27">
</canvas>
</body>
</html>
Here is the complete working example:)
<!DOCTYPE html>
<html>
<head>
<title>Canvas Cog</title>
<script type="text/javascript">
var cog = new Image();
function init() {
cog.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABK1JREFUeNqMVt1ZGzkUvVfS4IW1l8GO82w6IBXE7mCpAFMB+Pt4Z6iApALcAe4AU0HoAJfg7BPYHinnXmmciX+y0YdmJHnQ0bk/R5cvh5cUyFPwRD4EChgEvGWMB36R3+JaiTkmD5gOs8yNb25uLlerFf1pM2yIGA82TEY7xow1oj4GBU6S6yywPNG4JwDH+XGv0Whs7ndN8n97mmPsLCSYgy7ImPQE/pFDyAF+7L0fgTNFUDBcLal90taD1doQ/T6NT9DnW8zkT+jJuQVYukG3hifCVk/L3JOxMBa8VVlSp9MhHKLaB+zpNo1fdgEpmByuMqUAV5viOQLwXNax9KBAFNEEpN1pUwnQmvl6aTza6zNjrCKaymeyOdYAMgfg18iG4T/qw+AC94zvpzDjcwqOXo3VGH26H0xMZ7jPxgT0R2zUi4BYt6bAfEbJvJFZKA4ODgZ5nhcJLE9mk35X21vWC/TXKmiwr2xszoQd/PQv3t/QCzY2twpqBpb5FKOp+hCgzWaTWq0W1Xx0ij5An9WC5VtiLMwvNBrVaSGMvQk5jHQVPN7sb0HzAtE+QJrNgrcUNEARieWCut0ugR0tl8sKcJ5Ahc3jRviPK8ZGTaaBwGKyT+gTiwM4a3Jrba6MbeVXo5F4kp9shn29ndUYC9vLirGDXzRhrYhD8DME5Hkg22df5rDYS/RXmVIsaP/Q/SXs600YnifTjbeSWliEdTYb3QyTqYfdDKTL4B1KS6tVqf6SgGq3P9BvZGpvNIrPCgVKZlGlCDQDxJiCjVppCab05DJHzb+b1Gm36X80cVjLuzozexs0f6IgRkA5XRhzIixRL1+IzhwdHVHrn1Y9oXe1i10aKT6bGGhg1CKK+cT0zCGCs0oXTIogybJMw/779//o48duMvnO9rzLn+Kz8wgS5Shqo4njpCoOQA5Ajb8adHh4SMvVghaLhYb/HsBip88krNVISSEigOlhjmi0LziNhr6wOsgO9C1339vbGznnNAU2AM9Svk235cqKieKGkldAf7DGvTrjnjJnzyQoMu0ZTuZgUqvmlYR+f39XIE4uqCX1E/rDZpCYmKwOOmivAfYK9KF1AM7EdG4uAMLAOjmQideQXOJQkyUisqYiFRhtSFbxCxj8do0T30dmTvLhC+an0MZZVBHX09tBTG4qFigZEJEChjTIEwtRik81Qa7uOQU0IrYAe7FRjqYw6SlYjgAyN1GmHsFIGPfVnxzFuFITKEkfYK+oWZ5qKlIkcZ7UE92oXBmeIgIxtAO5UtSHqo9uiLW+sme5ejSIRASeAFR4LYy8MMzL1aq3EYWzJF28BgMEzGYpBkrMKelgl+P6uTcVY8NjLYyYPwMTCcufSaouH6al9xNJcjC82vDb9uVZKbrWIumNO+waVsu1TCC+Wxcg6xaSpsZSYM2wLO9/U8qZWH+wztQnsfAxV/E3MIKZVf1FsmJVV8mamhEmxZ0X7sSsABsGv1tZJGejmptU7FBUDYzPAXQBwFEEl+9+stFEroJEci2ELwIMmZuWoSTE9DYYcWVCjlJrZWMpeBhlAEqBiulPE84S3ixU5gSTwGGOdyEVNJXxA8nPevshwABHktBS1YoQ+QAAAABJRU5ErkJggg=='; // Set source path
setInterval(draw,10);
}
var rotation = 0;
function draw(){
var ctx = document.getElementById('myCanvas').getContext('2d');
ctx.globalCompositeOperation = 'destination-over';
ctx.save();
ctx.clearRect(0,0,27,27);
ctx.translate(13.5,13.5); // to get it in the origin
rotation +=1;
ctx.rotate(rotation*Math.PI/64); //rotate in origin
ctx.translate(-13.5,-13.5); //put it back
ctx.drawImage(cog,0,0);
ctx.restore();
}
init();
</script>
</head>
<body>
<canvas width="27" height="27" id="myCanvas"></canvas>
</body>
</html>
rotate turns the canvas(?) around your current position, which is 0, 0 to start. you need to "move" to your desired center point, which you can accomplish with
context.translate(x,y);
after you move your reference point, you want to center your image over that point. you can do this by calling
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
this tells the browser to start drawing the image from above and to the left of your current reference point, by have the size of the image, whereas before you were starting at your reference point and drawing entirely below and to the right (all directions relative to the rotation of the canvas).
since your canvas is the size of your image, your call to translate will use the same measurement, (27/2), for x and y coordinates.
so, to put it all together
// initialization:
context.translate(27/2, 27/2);
// onload:
context.rotate(Math.PI * 45 / 180);
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
edit: also, rotation units are radians, so you'll need to translate degrees to radians in your code.
edits for rearranging stuff.
For anyone else looking into something like this, you might want to look at this script which does exactly what was originally being requested:
http://projects.nickstakenburg.com/spinners/
You can find the github source here:
https://github.com/staaky/spinners
He uses rotate, while keeping a cache of rectangles which slowly fade out, the older they are.
I find another way to do html loading spinner. You can use sprite sheet animation. This approach can work both by html5 canvas or normal html/javascript/css. Here is a simple way implemented by html/javascript/css.
It uses sprite sheet image as background. It create a Javascript timer to change the background image position to control the sprite sheet animation. The example code is below. You can also check the result here: http://jmsliu.com/1769/html-ajax-loading-spinner.html
<html>
<head><title></title></head>
<body>
<div class="spinner-bg">
<div id="spinner"></div>
</div>
<style>
.spinner-bg
{
width:44px;
height:41px;
background: #000000;
}
#spinner
{
width: 44px;
height: 41px;
background:url(./preloadericon.png) no-repeat;
}
</style>
<script>
var currentbgx = 0;
var circle = document.getElementById("spinner");
var circleTimer = setInterval(playAnimation, 100);
function playAnimation() {
if (circle != null) {
circle.style.backgroundPosition = currentbgx + "px 0";
}
currentbgx -= 44; //one frame width, there are 5 frame
//start from 0, end at 176, it depends on the png frame length
if (currentbgx < -176) {
currentbgx = 0;
}
}
</script>
</body>