HTML5 Mobile Web Canvas animation using Phonegap + Kinetic.JS


Kinetic.JS: http://www.kineticjs.com/

JQuery-mobile: http://jquerymobile.com/

Phonegap: http://phonegap.com/

Download:
Github: https://github.com/w2davids/phonegap-kineticjs.git

Android Java File:

package demo.kinetic;

import com.phonegap.*;
import android.os.Bundle;

public class DemoPhonegapKineticJSActivity extends DroidGap {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.loadUrl("file:///android_asset/www/index.html");
	}
}

var demo1= function() {
	var stage = new Kinetic.Stage({
		container : "container",
		width : $(document).width() - 20,
		height : $(document).height() - 100,
		draggable : true
	});

	var flowerLayer = new Kinetic.Layer();
	var lineLayer = new Kinetic.Layer();
	var flower = new Kinetic.Group({
		x : stage.getWidth() / 2,
		y : stage.getHeight() / 2
	});

	// build stem
	var stem = new Kinetic.Line({
		strokeWidth : 10,
		stroke : "green",
		points : [{
			x : flower.getX(),
			y : flower.getY()
		}, {
			x : stage.getWidth() / 2,
			y : stage.getHeight() + 10
		}]
	});

	// build center
	var center = new Kinetic.Circle({
		x : 0,
		y : 0,
		radius : 20,
		fill : "yellow",
		stroke : "black",
		strokeWidth : 4
	});

	center.on("mousedown", function() {
		document.body.style.cursor = "pointer";
	});

	center.on("mouseover", function() {
		flower.setDraggable(true);
		this.setFill("orange");
		flowerLayer.draw();
	});

	center.on("mouseout", function() {
		flower.setDraggable(false);
		this.setFill("yellow");
		flowerLayer.draw();
	});
	// build petals
	var numPetals = 10;
	for (var n = 0; n < numPetals; n++) {
		// induce scope
		( function() {
				/*
				 * draw custom shape because KineticJS
				 * currently does not support tear drop
				 * geometries
				 */
				var petal = new Kinetic.Shape({
					drawFunc : function() {
						var context = this.getContext();
						context.globalAlpha = 0.8;
						context.beginPath();
						context.moveTo(-5, -20);
						context.bezierCurveTo(-40, -90, 40, -90, 5, -20);
						context.closePath();
						this.fill();
						this.stroke();
					},
					fill : "#00dddd",
					strokeWidth : 4,
					draggable : true,
					rotation : 2 * Math.PI * n / numPetals
				});

				petal.on("dragstart", function() {
					this.moveToTop();
					center.moveToTop();
				});

				petal.on("mouseover", function() {
					this.setFill("blue");
					flowerLayer.draw();
				});

				petal.on("mouseout", function() {
					this.setFill("#00dddd");
					flowerLayer.draw();
				});

				flower.add(petal);
			}());
	}

	stage.on("mouseup", function() {
		document.body.style.cursor = "default";
	});

	flower.on("dragmove", function() {
		stem.attrs.points[0] = this.getPosition();
		lineLayer.draw();
	});

	lineLayer.add(stem);
	flower.add(center);
	flowerLayer.add(flower);
	stage.add(lineLayer);
	stage.add(flowerLayer);

}

var demo2 = function() {
	function writeMessage(messageLayer, message) {
		var context = messageLayer.getContext();
		messageLayer.clear();
		context.font = "18pt Calibri";
		context.fillStyle = "black";
		context.fillText(message, 10, 25);
	}

	//
	var stage = new Kinetic.Stage({
		container : "container2",
		width : $(document).width() - 20,
		height : $(document).height() - 100,
		draggable : true
	});

	//
	var boxLayer = new Kinetic.Layer();
	var messageLayer = new Kinetic.Layer();
	var rectX = stage.getWidth() / 2 - 50;
	var rectY = stage.getHeight() / 2 - 25;

	var box = new Kinetic.Rect({
		x : rectX,
		y : rectY,
		width : 100,
		height : 50,
		fill : "#00D2FF",
		stroke : "black",
		strokeWidth : 4,
		draggable : true
	});

	// write out drag and drop events
	box.on("dragstart", function() {
		writeMessage(messageLayer, "dragstart");
	});
	box.on("dragend", function() {
		writeMessage(messageLayer, "dragend");
	});

	boxLayer.add(box);

	stage.add(messageLayer);
	stage.add(boxLayer);

	var amplitude = 150;
	var period = 2000;
	// in ms
	var centerX = stage.getWidth() / 2 - 80;

	stage.onFrame(function(frame) {
		box.setY(amplitude * Math.sin(frame.time * 2 * Math.PI / period) + centerX);
		boxLayer.draw();
	});

	//Start Animation
	document.getElementById('start').addEventListener('click', function() {
		stage.start();
	}, false);

	// resume transition
	document.getElementById('stop').addEventListener('click', function() {
		stage.stop();
	}, false);
}

Complete code:

<!DOCTYPE HTML>
<html>
	<head>

		<style>
			body {
				margin: 2px;
				padding: 2px;
			}
			canvas {
				border: 1px solid #9C9898;
			}

			#container {
				background-image: url('http://www.html5canvastutorials.com/demos/assets/lines.jpg');
			}
		</style>

		<meta name="viewport" content="width=device-width, initial-scale=1">
		<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
		<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
		<script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
		<script src="http://www.html5canvastutorials.com/libraries/kinetic-v3.9.7.js"></script>
		<script src="demo1.js"></script>
		<script src="demo2.js"></script>

		<script type="text/javascript">
			$(document).bind("pageinit", function() {
				console.log( "Init...");
			});
		</script>
        </head>
		<body onmousedown="return false;">

			<!-- HomePage-->
			<div data-role="page" id="homePage">
				<div data-role="header">
					<h1>PhoneGap- Kinetic.js Demo</h1>
				</div>

				<div data-role="content">
					<a href="#demoPage1" data-role="button">Kinetic.js Demo - 1</a>
					<a href="#demoPage2" data-role="button">Kinetic.js Demo - 2</a>

				</div>

				<div data-role="footer" data-position="fixed">
					<h3>Footer</h3>
				</div>
			</div>

			<!-- DemoPage1-->
			<div data-role="page" id="demoPage1" data-theme="a">
				<div data-role="header">
					<a href="#homePage" data-icon="back" class="ui-btn-left">Back</a>
					<h1>Kinetic.js Demo - 1 </h1>
				</div>

				<div data-role="content">
					<div id="container"></div>
				</div>

				<div  data-role="footer"  class="ui-bar ui-bar-b" >
					<h2>Kinetic.js Demo - 1</h2>
				</div>
				<script type="text/javascript">
					demo1();
				</script>
				
			</div>

			<!-- DemoPage2-->
			<div data-role="page" id="demoPage2" data-theme="a">
				<div data-role="header">
					<a href="#homePage" data-icon="back" class="ui-btn-left">Back</a>
					<h1>Kinetic.js Demo - 2 </h1>
				</div>

				<div data-role="content">
					<div id="container2"></div>
				</div>

				<div  data-role="footer"  class="ui-bar ui-bar-b" >
					<a href="" id="start" data-role="button" class="ui-btn-left">Start</a>
					<h2>Kinetic.js Demo - 2</h2>
					<a href="" id="stop" data-role="button" class="ui-btn-right">Stop</a>
				</div>
				
				<script type="text/javascript">
					demo2();
				</script>
			</div>
		</body>
</html>

6 thoughts on “HTML5 Mobile Web Canvas animation using Phonegap + Kinetic.JS

  1. Thanks so much for the tutorial! I have been having a lot of trouble with KineticJS and PhoneGap. Does your app have full functionality on an android emulator? … I noticed that you don’t reference the Cordova script in your html doc. I added the necessary code and tried it out on an android emulator in Eclipse and the buttons won’t respond. How did you get past this problem?

    • Hi,

      I tested it on a Samsung Galaxy. It worked, but somewhat sluggish on the animations. The problem I encountered was referencing KineticJS in the correct load order during script loading. Its better to debug this on desktop Google-chrome , Firefox and IE to get a rough idea and then on the emulator.

      Regards,
      -w

  2. Thanks for the in depth post, it is quite nice. I’ve played around with it on my Samsung Galaxy S3 ( Cyanogenmod 4.1) and this looks a bit buggy. I notice the flower / rectangle both duplicating on using the drag / drop (http://imgur.com/4VXhcmg / http://imgur.com/ga2YSh1 ) Trying to figure out if this is just an issue with my phone, or the code itself. any insight would be great. When opened in a browser, it works as expected.

    I’ve also tried playing around with kinectJS by itself on my phone and the results seem choppy at best, not nearly as nice as chrome itself.. Have you had this experience? What i’ve worked with: http://jsfiddle.net/whomba/NZfC3/
    (if you use it, note the use of the following libs: jquery, underscore, kinetic)

    Thanks for any of your thoughts
    -Andrew

  3. Hi,
    Thanks a lot for the post.. It worked pretty good on the browser.. However on my nexus 7 tablet , in demo 2, I see 2 rectangle going up and down.. I faced similar problem for my kineticjs + jquery + phonegap program too.. whenever I do the color transition and layer.draw()… whole underneath diagram is redraw.. have you ever faced this situation.. Appreciate any help..

    Kind Regards
    Johnson Thomas
    PS : I am using android version 4.2.2.

    • Hi JT & Andrew,

      The frame rates are a bit disasterous for mobile web-based apps..LOL. Its about 15-20 frames/sec. Its good for games in which motion is not the main show point.

      In comparison, when I was using android-flixel, I was clocking about 60 frames/sec! absolute no chopiness.

      Initially, I had a javascript load order problem – the load order is important and this you can see when u have a debug console in the browser. There are various script loaders where u can specifiy the load order, and dependencies when loading.

      Dont quote me on this ..lol…but i am wondering about double buffering, since the layer.draw() would need to update.

      -w

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s