Stop a function from running after being passed a value - javascript

I'm trying to stop the displayDistance function from running until I click the button. It keeps running the function, I assume because values are being passed to it so it automatically calls it I guess? I need it to display the current lat/long on window load, and then after a button click display the distance to each locations. Right now it displays all it on window load
window.addEventListener("load", setupEventHandlers, false);
window.addEventListener("load", displayLocation, false);
function setupEventHandlers() {
console.log("Inside setupEventHandlers function that is fired on the window load event");
var displayButtonReference = document.getElementById("butCalculate");
displayButtonReference.addEventListener("click", displayDistance, false);
}
//-------------------------------------------------------------------------------
// Name: displayLocation()
// Description:
//-------------------------------------------------------------------------------
function displayLocation() {
console.log("displayLocation function called!");
//Call getCurrentPosition() method to retrieve current position data
//This is an asynchronous call.
//When completed it calls the cb_GetCurrentPosition_Success callback function
//navigator.geolocation.getCurrentPosition(cb_GetCurrentPosition_Success);
navigator.geolocation.getCurrentPosition(cb_GetCurrentPosition_Success,
cb_GetCurrentPosition_Error,
{
enableHighAccuracy: true,
maximumAge: 5000
}
);
}
//-------------------------------------------------------------------------------
// Name: cb_GetCurrentPosition_Success
// Description: Callback function if GeoLocation info retrieved successfully
//-------------------------------------------------------------------------------
function cb_GetCurrentPosition_Success(positionObject) {
console.log("cb_GetCurrentPosition_Success callback function called!");
//Show returned positionObject in Inspect Element Console
console.dir(positionObject);
//1. Declare variables
var accuracy,
distanceInKilometers,
distanceInFeet,
distanceInMiles,
displayString,
currentLat,
currentLong;
//Extract geolocation data from returned object
currentLat = positionObject.coords.latitude;
currentLong = positionObject.coords.longitude;
console.log("distanceInFeet = " + distanceInFeet);
distanceInFeet = calculateDistanceInFeet(currentLat, currentLong)
//Display retrieved Geolocation data
document.getElementById("divLat").innerHTML = currentLat;
document.getElementById("divLon").innerHTML = currentLong;
}
//---------------------------------------------------------------------------------------
// Name: cb_GetCurrentPosition_Error
// Description: Callback function if there is a problem retrieving GeoLocation info
//---------------------------------------------------------------------------------------
function cb_GetCurrentPosition_Error(err) {
var errorMessage;
if (err.code == 1) {
errorMessage = "You chose not to share your location info.";
}
else if (err.code == 2) {
errorMessage = "Location information currently unavailable!";
}
else if (err.code == 3) {
errorMessage = "Timed out waiting to receive location information!";
}
else {
errorMessage = "Unknown error occured";
}
}
// ---------------------------------------------------------------------------------------
// name: calculateDistanceInFeet
// source: http://www.codecodex.com/wiki/Calculate_distance_between_two_points_on_a_globe
// ---------------------------------------------------------------------------------------
function calculateDistanceInFeet(parcurrentLat, parcurrentLon) {
console.log("calculateDistanceInFeet function called!");
console.log("parcurrentLat = " + parcurrentLat);
console.log("parcurrentLon = " + parcurrentLon);
var distanceInKilometersToRamsey,
distanceInKilometersToPicnic,
distanceInFeetToRamsey,
distanceInFeetToPicnic,
Lat1 = 35.303209, //Ramsey Coordinates
Lon1 = -83.182745,
Lat2 = 35.314455, //Picnic Shelter Coordinates
Lon2 = -83.188011;
//Distance to Ramsey
//Code retrieved from source shown above - don't modify
//-------------------------------------------------------
var R1 = 6371; // km
var dLat1 = (Lat1 - parcurrentLat) * Math.PI / 180;
var dLon1 = (Lon1 - parcurrentLon) * Math.PI / 180;
var a1 = Math.sin(dLat1 / 2) * Math.sin(dLat1 / 2) +
Math.cos(parcurrentLat * Math.PI / 180) * Math.cos(Lat1 * Math.PI / 180) *
Math.sin(dLon1 / 2) * Math.sin(dLon1 / 2);
var c1 = 2 * Math.asin(Math.sqrt(a1));
distanceInKilometersToRamsey = R1 * c1;
//---------------------------------------------------------
//end of code to not modify
//Distance to Picnic
//Code retrieved from source shown above - don't modify
//-------------------------------------------------------
var R2 = 6371; // km
var dLat2 = (Lat2 - parcurrentLat) * Math.PI / 180;
var dLon2 = (Lon2 - parcurrentLon) * Math.PI / 180;
var a2 = Math.sin(dLat2 / 2) * Math.sin(dLat2 / 2) +
Math.cos(parcurrentLat * Math.PI / 180) * Math.cos(Lat2 * Math.PI / 180) *
Math.sin(dLon2 / 2) * Math.sin(dLon2 / 2);
var c2 = 2 * Math.asin(Math.sqrt(a2));
distanceInKilometersToPicnic = R2 * c2;
//---------------------------------------------------------
//end of code to not modify
//3. Do calculations
distanceInFeetToRamsey = distanceInKilometersToRamsey * 1000 * 3.2808;
distanceInFeetToPicnic = distanceInKilometersToPicnic * 1000 * 3.2808;
var passedDistance = displayDistance(distanceInFeetToRamsey, distanceInFeetToPicnic);
console.log("distanceInFeetToRamsey = " + distanceInFeetToRamsey);
console.log("distanceInFeetToPicnic = " + distanceInFeetToPicnic);
}
function displayDistance(parRamsey, parPicnic) {
if (parRamsey >= 5280) {
var distanceInMilesToRamsey = parRamsey / 5280;
document.getElementById("divDistance1").innerHTML = distanceInMilesToRamsey.toFixed(2) + "miles";
}
else {
document.getElementById("divDistance1").innerHTML = parPicnic.toFixed(2) + "feet";
}
if (parPicnic >= 5280) {
var distanceInMilesToPicnic = distanceInFeetToPicnic / 5280;
document.getElementById("divDistance2").innerHTML = distanceInMilesToPicnic.toFixed(2) + "miles";
}
else {
document.getElementById("divDistance2").innerHTML = parPicnic.toFixed(2) + "feet";
}
}

displayDistance is getting indirectly called by your load event:
Loading calls displayLocation:
window.addEventListener("load", displayLocation, false);
displayLocation calls cb_GetCurrentPosition_Success (via a callback):
navigator.geolocation.getCurrentPosition(cb_GetCurrentPosition_Success,
cb_GetCurrentPosition_Error,
{
enableHighAccuracy: true,
maximumAge: 5000
}
);
cb_GetCurrentPosition_Success calls calculateDistanceInFeet:
distanceInFeet = calculateDistanceInFeet(currentLat, currentLong)
And calculateDistanceInFeet calls displayDistance:
var passedDistance = displayDistance(distanceInFeetToRamsey, distanceInFeetToPicnic);

Related

Creating a class of Crafty JS entity (class of a class?)

I am trying to create a class which creates a Crafty entity with specific properties. So far, the functions within the class do not run because 'this' refers to the window object
$(document).ready(function () {
Crafty.init(window.innerWidth, window.innerHeight);
var player = new controller(37,38,39,40);
player.d.color("red").attr({
w: 50,
h: 50,
x: 0,
y: 0
});
// Jump Height = velocity ^ 2 / gravity * 2
// Terminal Velocity = push * (1 / viscosity)
var gravity = 1;
var viscosity = 0.5;
var frame = (1 / 20);
var distanceMultiplier = 10; //pixels per meter
var timeMultiplier = 20; //relative to actual time
var keystart = [];
var keyboard = [];
function controller (controls) {
this.d = Crafty.e();
this.d.addComponent("2D, Canvas, Color, Collision");
this.d.collision();
this.d.mass = 1;
this.d.a = {
extradistance : 0,
velocity : 0,
acceleration : 0,
force : 0,
resistance : 0
};
this.d.a.push = 0;
this.d.v = {
extradistance : 0,
velocity : 0,
acceleration : 0,
force : 0
};
this.d.jumping = true;
this.d.onHit("Collision", function () {
var a = this.d.hit("Collision");
if (a) {
for (var b in a) {
this.d.x = this.d.x - a[b].normal.x * a[b].overlap;
this.d.y = this.d.y - a[b].normal.y * a[b].overlap;
if (a[b].normal.y < -0.5) {
this.d.jumping = false;
}
if (Math.abs(a[b].normal.x) < 0.2) {
this.d.v.velocity = this.d.v.velocity * a[b].normal.y * 0.2;
}
if (Math.abs(a[b].normal.y) < 0.2) {
this.d.a.velocity = this.d.a.velocity * a[b].normal.x * 0.2;
}
}
return;
}
});
this.d.physics = function () {
if (keyboard[arguments[1]] && !this.jumping) {
this.v.velocity = 5;
this.jumping = true;
}
if (keyboard[arguments[1]] && this.jumping) {
var now = new Date();
if (now.getTime() - keystart[arguments[1]].getTime() < 500) {
this.v.velocity = 5;
}
}
if (keyboard[arguments[0]] && keyboard[arguments[2]]) {
this.a.velocity = 0;
} else {
if (keyboard[arguments[0]]) {
this.a.velocity = -3;
}
if (keyboard[arguments[2]]) {
this.a.velocity = 3;
}
}
if (keyboard[arguments[3]]) {
this.v.velocity = -5;
}
this.a.force = this.a.push - this.a.resistance;
this.a.acceleration = this.a.force / this.mass;
this.a.velocity = this.a.velocity + (this.a.acceleration * frame);
this.a.extradistance = (this.a.velocity * frame);
this.a.resistance = this.a.velocity * viscosity;
this.attr({
x: (this.x + (this.a.extradistance * distanceMultiplier))
});
this.v.force = gravity * this.mass;
this.v.acceleration = this.v.force / this.mass;
this.v.velocity = this.v.velocity - (this.v.acceleration * frame);
this.v.extradistance = (this.v.velocity * frame);
this.attr({
y: (this.y - (this.v.extradistance * distanceMultiplier))
});
setTimeout(this.physics, (frame * 1000) / timeMultiplier);
};
this.d.listen = function(){ document.body.addEventListener("keydown", function (code) {
var then = new Date();
if (!keyboard[code.keyCode] && !this.jumping && code.keyCode == arguments[1]) { //only if not yet pressed it will ignore everything until keyup
keyboard[code.keyCode] = true; //start movement
keystart[code.keyCode] = then; //set time
}
if (!keyboard[code.keyCode] && code.keyCode != arguments[1]) { //only if not yet pressed it will ignore everything until keyup
keyboard[code.keyCode] = true; //start movement
keystart[code.keyCode] = then; //set time
}
});
};
}
player.d.physics();
player.d.listen();
document.body.addEventListener("keyup", function (code) {
keyboard[code.keyCode] = false;
});
});
In trying to put the functions as prototypes of the class, I run into a problem.
Crafty.init(500,500);
function block () {
block.d = Crafty.e("2D, Color, Canvas");
block.d.color("red");
block.d.attr({x:0,y:0,h:50,w:50});
}
block.d.prototype.green = function() {
this.color("green");
}
var block1 = new block();
block1.d.color();
If an object is defined in the constructor, I cannot use it to add a prototype to.
Generally in Crafty, we favor composition. That is, you extend an entity by adding more components to it. You can have kind of a hierarchy by having one component automatically add others during init.
I haven't looked through all of your example code, because there's a lot! But consider the second block:
function block () {
block.d = Crafty.e("2D, Color, Canvas");
block.d.color("red");
block.d.attr({x:0,y:0,h:50,w:50});
}
block.d.prototype.green = function() {
this.color("green");
}
var block1 = new block();
block1.d.color();
You're trying to combine Crafty's way of doing things (an entity component system) with classes in a way that's not very idiomatic. Better to do this:
// Define a new component with Crafty.c(), rather than creating a class
Crafty.c("Block", {
// On init, add the correct components and setup the color and dimensions
init: function() {
this.requires("2D, Color, Canvas")
.color("red")
.attr({x:0,y:0,h:50,w:50});
},
// method for changing color
green: function() {
this.color("green");
}
});
// Create an entity with Crafty.e()
block1 = Crafty.e("Block");
// It's not easy being green!
block1.green();

Subract a random number from a variable, store this new value, and repeat the process until it reaches 0?

Trying to make a hp bar go down from 200 to 0 by constantly subracting the randomized number, but I can only manage to store the new value once. Then if I click on the button which calls the function, it subtracts from 200 again and not the previous stored value. How do I fix this? Going mad over here.
Here's my javascript:
window.onload = function() {
document.getElementById("hpLeft1").innerHTML= "200/200";
document.getElementById("hpLeft2").innerHTML = "200/200";
};
var myHit = Math.floor(Math.random() * 40 + 1);
var dragonHit = Math.floor(Math.random() * 40 + 1);
var playerHitpoints, dragonHitpoints = 200;
function play() {
var myHit = Math.floor(Math.random() * 40 + 1);
var dragonHit = Math.floor(Math.random() * 40 + 1);
dragonHitpoints -= dragonHit;
playerHitpoints -= myHit;
document.getElementById("DragonHit").innerHTML = dragonHit;
document.getElementById("MyHit").innerHTML = myHit;
document.getElementById("hpLeft1").innerHTML = dragonHitpoints + "/200";
document.getElementById("hpLeft2").innerHTML = playerHitpoints + "/200";
}
You want to update the values of dragonHitpoints and playerHitpoints.
function play() {
var myHit = Math.floor(Math.random() * 40 + 1);
var dragonHit = Math.floor(Math.random() * 40 + 1);
// Update the dragon's HP
dragonHitpoints -= dragonHit;
// Update the player's HP
playerHitpoints -= myHit;
document.getElementById("DragonHit").innerHTML = dragonHit;
document.getElementById("MyHit").innerHTML = myHit;
document.getElementById("hpLeft1").innerHTML = dragonHitpoints + "/200";
document.getElementById("hpLeft2").innerHTML = playerHitpoints + "/200";
}
There is a issue in your code. You are declaring local variables, which are overwriting the outer ones:
function play() {
var myHit = Math.floor(Math.random() * 40 + 1);
var dragonHit = Math.floor(Math.random() * 40 + 1);
This should be
function play() {
myHit = Math.floor(Math.random() * 40 + 1);
dragonHit = Math.floor(Math.random() * 40 + 1);
To reuse the variables from outside.

0x800a01bd - JavaScript runtime error: Object doesn't support this action

I am reading and trying to do this tutorial:
http://www.sitepoint.com/creating-a-simple-windows-8-game-with-javascript-input-and-sound/
Yesterday, I wrote in this forum with one error, and solved it, but today, I'm in the final one and getting another error.
My default.html file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CatapultGame</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-light.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!-- CatapultGame references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<script src="js/CreateJS/easeljs-0.6.0.min.js"></script>
<script src="js/CreateJS/preloadjs-0.2.0.min.js"></script>
</head>
<body>
<canvas id="gameCanvas"></canvas>
</body>
</html>
and default.js file :
// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
WinJS.strictProcessing();
var canvas, context, stage;
var bgImage, p1Image, p2Image, ammoImage, p1Lives, p2Lives, title, endGameImage;
var bgBitmap, p1Bitmap, p2Bitmap, ammoBitmap;
var preload;
// calculate display scale factor - original game assets assume 800x480
var SCALE_X = window.innerWidth / 800;
var SCALE_Y = window.innerHeight / 480;
var MARGIN = 25;
var GROUND_Y = 390 * SCALE_Y;
var LIVES_PER_PLAYER = 3;
var player1Lives = LIVES_PER_PLAYER;
var player2Lives = LIVES_PER_PLAYER;
var isShotFlying = false;
var playerTurn = 1;
var playerFire = false;
var shotVelocity;
var MAX_SHOT_POWER = 10;
var GRAVITY = 0.07;
var isAiming = false;
var aimPower = 1;
var aimStart, aimVector;
var FIRE_SOUND_FILE = "/sounds/CatapultFire.wav";
var HIT_SOUND_FILE = "/sounds/BoulderHit.wav";
var EXPLODE_SOUND_FILE = "/sounds/CatapultExplosion.wav";
var LOSE_SOUND_FILE = "/sounds/Lose.wav";
var AIM_SOUND_FILE = "/sounds/RopeStretch.wav";
var WIN_SOUND_FILE = "/sounds/Win.wav";
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll());
}
};
function initialize() {
canvas = document.getElementById("gameCanvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
context = canvas.getContext("2d");
canvas.addEventListener("MSPointerUp", endAim, false);
canvas.addEventListener("MSPointerMove", adjustAim, false);
canvas.addEventListener("MSPointerDown", beginAim, false)
**var stage = new createjs.Stage(canvas);** <<========== HERE IS THE ERROR LINE !!!!
// use preloadJS to get sounds and images loaded before starting
preload = new createjs.PreloadJS();
preload.onComplete = prepareGame;
var manifest = [
{ id: "screenImage", src: "images/Backgrounds/gameplay_screen.png" },
{ id: "redImage", src: "images/Catapults/Red/redIdle/redIdle.png" },
{ id: "blueImage", src: "images/Catapults/Blue/blueIdle/blueIdle.png" },
{ id: "ammoImage", src: "images/Ammo/rock_ammo.png" },
{ id: "winImage", src: "images/Backgrounds/victory.png" },
{ id: "loseImage", src: "images/Backgrounds/defeat.png" },
{ id: "blueFire", src: "images/Catapults/Blue/blueFire/blueCatapultFire.png" },
{ id: "redFire", src: "images/Catapults/Red/redFire/redCatapultFire.png" },
{ id: "hitSound", src: HIT_SOUND_FILE },
{ id: "explodeSound", src: EXPLODE_SOUND_FILE },
{ id: "fireSound", src: FIRE_SOUND_FILE },
{ id: "loseSound", src: LOSE_SOUND_FILE },
{ id: "aimSound", src: AIM_SOUND_FILE },
{ id: "winSound", src: WIN_SOUND_FILE }
];
preload.loadManifest(manifest);
}
function prepareGame()
{
// draw Bg first, others appear on top
bgImage = preload.getResult("screenImage").result;
bgBitmap = new createjs.Bitmap(bgImage);
bgBitmap.scaleX = SCALE_X;
bgBitmap.scaleY = SCALE_Y;
stage.addChild(bgBitmap);
// draw p1 catapult
p1Image = preload.getResult("redImage").result;
p1Bitmap = new createjs.Bitmap(p1Image);
p1Bitmap.scaleX = SCALE_X;
p1Bitmap.scaleY = SCALE_Y;
p1Bitmap.x = MARGIN;
p1Bitmap.y = GROUND_Y - p1Image.height * SCALE_Y;
stage.addChild(p1Bitmap);
// draw p2 catapult and flip
p2Image = preload.getResult("blueImage").result;
p2Bitmap = new createjs.Bitmap(p2Image);
p2Bitmap.regX = p2Image.width;
p2Bitmap.scaleX = -SCALE_X; // flip from right edge
p2Bitmap.scaleY = SCALE_Y;
p2Bitmap.x = canvas.width - MARGIN - (p2Image.width * SCALE_X);
p2Bitmap.y = GROUND_Y - (p2Image.height * SCALE_Y);
stage.addChild(p2Bitmap);
// draw the boulder, and hide for the moment
ammoImage = preload.getResult("ammoImage").result;
ammoBitmap = new createjs.Bitmap(ammoImage);
ammoBitmap.scaleX = SCALE_X;
ammoBitmap.scaleY = SCALE_Y;
ammoBitmap.visible = false; // hide until fired
stage.addChild(ammoBitmap);
// player 1 lives
p1Lives = new createjs.Text("Lives Left : " + player1Lives, "20px sans-serif", "red");
p1Lives.scaleX = SCALE_X;
p1Lives.scaleY = SCALE_Y;
p1Lives.x = MARGIN;
p1Lives.y = MARGIN * SCALE_Y;
stage.addChild(p1Lives);
//player 2 lives
p2Lives = new createjs.Text("Lives Left : " + player2Lives, "20px sans-serif", "red");
p2Lives.scaleX = SCALE_X;
p2Lives.scaleY = SCALE_Y;
p2Lives.x = canvas.width - p2Lives.getMeasuredWidth() * SCALE_X - MARGIN;
p2Lives.y = MARGIN * SCALE_Y;
stage.addChild(p2Lives);
// game title
title = new createjs.Text("Catapult Wars", "30px sans-serif", "black");
title.scaleX = SCALE_X;
title.scaleY = SCALE_Y;
title.x = canvas.width / 2 - (title.getMeasuredWidth() * SCALE_X) / 2
title.y = 30 * SCALE_Y;
stage.addChild(title);
stage.update();
startGame();
}
function startGame()
{
Ticker.setInterval(window.requestAnimationFrame);
Ticker.addListener(gameLoop);
}
function gameLoop()
{
update();
draw();
}
function update() {
if (isShotFlying)
{
// shot in the air
ammoBitmap.x += shotVelocity.x;
ammoBitmap.y += shotVelocity.y;
shotVelocity.y += GRAVITY; //apply gravity to the y(height) values only, obviously
if (ammoBitmap.y + ammoBitmap.image.height >= GROUND_Y ||
ammoBitmap.x <= 0 ||
ammoBitmap.x + ammoBitmap.image.width >= canvas.width)
{
// missed
isShotFlying = false; //stop shot
ammoBitmap.visible = false;
playerTurn = playerTurn % 2 + 1; // invert player ( switch between 1 and 2)
}
else if (playerTurn == 1)
{
if (checkHit(p2Bitmap)) {
// Hit
p2Lives.text = "Lives Left : " + --player2Lives;
processHit();
}
}
else if (playerTurn == 2)
{
if (checkHit(p1Bitmap))
{
// Hit
p1Lives.text = "Lives Left : " + --player1Lives;
processHit();
}
}
}
// No current shot, should either player fire ?
else if (playerTurn == 1)
{
// does the player want to fire ?
if (playerFire)
{
playerFire = false;
ammoBitmap.x = p1Bitmap.x + (p1Bitmap.image.width * SCALE_X / 2);
ammoBitmap.y = p1Bitmap.y;
shotVelocity = aimVector;
fireShot();
}
}
else if (playerTurn == 2)
{
// AI automatically fires (randomly on it's turn)
ammoBitmap.x = p2Bitmap.x + (p2Bitmap.image.width * SCALE_X / 2);
ammoBitmap.y = p2Bitmap.y;
shotVelocity = new createjs.Point(
Math.random() * (-4 * SCALE_X) - 3,
Math.random() * (-3 * SCALE_Y) - 1);
fireShot();
}
}
// triggered by MSPointerDown event
function beginAim(event)
{
if (playerTurn == 1)
{
if (!isAiming)
{
aimStart = new createjs.Point(event.x, event.y);
isAiming = true;
}
}
}
// triggered by MSPointerMove event
function adjustAim(event)
{
if (isAiming)
{
var aimCurrent = new createjs.Point(event.x, event.y);
aimVector = calculateAim(aimStart, aimCurrent);
// TODO write text and/or show aiming arrow on screen
Debug.writeln("Aiming..." + aimVector.x + "/" + aimVector.y);
}
}
// triggered by MSPointerUp event
function endAim(event)
{
if (isAiming) {
isAiming = false;
var aimCurrent = new createjs.Point(event.x, event.y);
aimVector = calculateAim(aimStart, aimCurrent);
playerFire = true;
}
}
function calculateAim(start, end)
{
// this only works for player 1
var aim = new createjs.Point(
(end.x - start.x) / 80,
(end.y - start.y) / 80);
aim.x = Math.min(MAX_SHOT_POWER, aim.x); // cap velocity
aim.x = Math.max(0, aim.x); // fire forward only
aim.y = Math.max(-MAX_SHOT_POWER, aim.y);/// cap velocity
aim.y = Math.min(0, aim.y); // fire up only
return aim;
}
function checkHit(target)
{
// EaselJS hit test doesn't factor in scaling
// so use simple bounding box vs center of rock
// get centre of rock
var shotX = ammoBitmap.x + ammoBitmap.image.width / 2;
var shotY = ammoBitmap.y + ammoBitmap.image.height / 2;
// return wether center of rock is in rectangle bounding target player
return (((shotX > target.x) &&
(shotX <= target.x + (target.image.width * SCALE_X)))
&&
((shotY >= target.y) &&
(shotY <= target.y + (target.image.height * SCALE_Y))));
}
function fireShot()
{
playSound(FIRE_SOUND_FILE);
ammoBitmap.visible = true;
isShotFlying = true;
}
function processHit()
{
playSound(EXPLODE_SOUND_FILE);
isShotFlying = false; // stop shot
ammoBitmap.visible = false; // hide shot
playerTurn = playerTurn % 2 + 1; // change player
if ((player1Lives <= 0) || (player2Lives <= 0)) {
endGame();
}
}
function endGame()
{
Ticker.setPaused(true); // stop game loop
// show win/lose graphic
var endGameImage;
if (player1Lives <= 0)
{
playSound(LOSE_SOUND_FILE);
endGameImage = preload.getResult("loseImage").result;
}
else if (player2Lives <= 0)
{
endGameImage = preload.getResult("winImage").result;
playSound(WIN_SOUND_FILE);
}
var endGameBitmap = new createjs.Bitmap(endGameImage);
stage.addChild(endGameBitmap);
endGameBitmap.x = (canvas.width / 2) - (endGameImage.width * SCALE_X / 2);
endGameBitmap.y = (canvas.height / 2) - (endGameImage.height * SCALE_Y / 2);
endGameBitmap.scaleX = SCALE_X;
endGameBitmap.scaleY = SCALE_Y;
stage.update();
}
function draw() {
// EaselJS allows for easy updates
stage.update();
}
function playSound(path)
{
var sound = document.createElement("audio");
sound.src = path;
sound.autoplay = true;
}
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
document.addEventListener("DOMContentLoaded", initialize, false);
app.start();
})();
And there is the problem: when I'm trying to build this game, I'm getting error like this:
0x800a01bd - JavaScript runtime error: Object doesn't support this action
in the marked place in my code
Thanks for any help :)
Three problems, I report them from previous comments:
easeljs not present in the correct folder
mages/Catapults/Red/redFire/redC‌​atapultFire.png missing
change var stage = new createjs.Stage(canvas); to stage = new createjs.Stage(canvas); you don't have to instantiate that variable as reported in the tutorial (http://www.sitepoint.com/creating-a-simple-windows-8-game-with-javascript-game-basics-createjseaseljs/)
And close this other related question (https://stackoverflow.com/a/16101960/975520), I think is solved by posting your solution as answer.

EaselJS BitmapAnimation.gotoAndPlay lag

I've written a requirejs module to take a BitmapAnimation and add methods to allow it to move around on the stage at a certain speed and once its destination has been reached, to move to another looped animation.
The problem I'm having is that there is quite a lot of lag between gotoAndPlay being called and anything happening on stage. I've console.logged the methods that call gotoAndPlay but the logs happen immediately where the animation doesn't change as quickly.
here is my abstract object:
'use strict';
/**
* AbstractCharacter
* Provides common functionality for all characters
*/
define(['easeljs'], function () {
var AbstractCharacter = function (model) {
this.model = model;
// changed from original code
// allows better encapsulation
this._s = new createjs.SpriteSheet(model.ssInit);
// add reversed frames
createjs.SpriteSheetUtils.addFlippedFrames(this._s, true, false, false),
this.initialize();
};
AbstractCharacter.prototype = Object.create(createjs.BitmapAnimation.prototype);
AbstractCharacter.prototype.constructor = AbstractCharacter;
// speed constant
AbstractCharacter.prototype.SPEED = 10;
// from Flash CS6
AbstractCharacter.prototype.BitmapAnimation_initialize = AbstractCharacter.prototype.initialize;
/**
* moves a character to a destination and sets their state at the end of the move
* #param {object} destination destination coordinates {x:XX}
* #param {string} nextAction the next action to perform
* #return {null}
*/
AbstractCharacter.prototype.moveTo = function(destination, nextAction) {
nextAction = nextAction || 'idle';
if (destination) {
if (destination.x < this.x) {
this.walkLeft();
} else {
this.walkRight();
}
this.destination = destination;
this.nextAction = nextAction;
}
};
/**
* public method to perform action
* #param {string} room name of the current room the character is in
* #param {string} action action name
* #param {object} params any parameters required by the action
* #return {null}
*/
AbstractCharacter.prototype.action = function(room, action, params) {
switch (action) {
case 'walk' :
this.moveTo(params, 'idle');
break;
case 'talk' :
this.moveTo(params, 'talk');
break;
case 'sleep' :
this.moveTo(this.model.actions.room[room].sleep, 'sleep');
break;
}
};
/**
* onTick callback to call next animation frame for use with easeljs
* #return {null}
*/
AbstractCharacter.prototype.onTick = function() {
if (this.destination) {
var destination = this.destination,
speed;
if (destination.x < this.x) {
speed = -this.SPEED;
if (this.x + speed < destination.x) {
this.endMove(destination);
} else {
this.x += speed;
}
} else {
speed = this.SPEED;
if (this.x + speed > destination.x) {
this.endMove(destination);
} else {
this.x += speed;
}
}
}
};
/**
* finishes move by calling nextAction() and clearing away desination and nextAction vars
* #param {object} destination format {x:XX}
* #return {null}
*/
AbstractCharacter.prototype.endMove = function(destination) {
this.x = destination.x;
this[this.nextAction]();
this.destination = null;
this.nextAction = null;
};
/**
* these methods come from Flash CS6
* the only difference is that I've removed
* the reference to the Object prototype
*/
AbstractCharacter.prototype.initialize = function() {
this.BitmapAnimation_initialize(this._s);
this.idle();
};
AbstractCharacter.prototype.idle = function(){
console.log('idle'); // fires almost a second before animation plays
this.gotoAndPlay("idle");
};
AbstractCharacter.prototype.idleLeft = function(){
this.gotoAndPlay("idleside");
};
AbstractCharacter.prototype.idleRight = function(){
this.gotoAndPlay("idleside_h");
};
AbstractCharacter.prototype.walkLeft = function(){
this.gotoAndPlay("walk");
};
AbstractCharacter.prototype.walkRight = function(){
this.gotoAndPlay("walk_h");
};
AbstractCharacter.prototype.talk = function(){
console.log('talk');
this.gotoAndPlay("talk");
};
AbstractCharacter.prototype.sleep = function(){
console.log('sleep'); // fires almost a second before animation plays
this.gotoAndPlay("sleep");
};
// public interface
return AbstractCharacter;
});
EDIT: this only seems to affect chrome - ie9 and firefox17 are fine
EDIT: if I use the following code instead of extending my abstractcharacter, this plays out without issue or lag
var test = new createjs.BitmapAnimation(new createjs.SpriteSheet({
images: [model.assets['mycharacters']],
frames: [[0,0,129,344,0,74,327],[129,0,129,345,0,74,327],[258,0,162,331,0,93,313],[420,0,162,331,0,93,313],[582,0,141,338,0,91,320],[723,0,141,338,0,91,320],[864,0,129,345,0,74,327],[993,0,129,345,0,74,327],[1122,0,162,331,0,93,313],[1284,0,162,331,0,93,313],[1446,0,141,338,0,91,320],[1446,0,141,338,0,91,320],[1587,0,129,344,0,74,327],[1716,0,129,344,0,74,327],[1845,0,162,330,0,93,313],[0,345,162,330,0,93,313],[162,345,141,337,0,91,320],[303,345,141,337,0,91,320],[444,345,129,344,0,74,327],[573,345,129,344,0,74,327],[702,345,162,330,0,93,313],[864,345,162,330,0,93,313],[1026,345,141,337,0,91,320],[1167,345,141,337,0,91,320],[1308,345,129,344,0,74,327],[1437,345,129,344,0,74,327],[1566,345,162,330,0,93,313],[1728,345,162,331,0,93,313],[1890,345,141,338,0,91,320],[0,689,141,338,0,91,320],[141,689,129,345,0,74,327],[270,689,129,345,0,74,327],[399,689,162,331,0,93,313],[399,689,162,331,0,93,313],[561,689,141,338,0,91,320],[702,689,141,338,0,91,320],[0,0,129,344,0,74,327],[843,689,129,343,0,74,327],[972,689,162,330,0,93,313],[1134,689,162,330,0,93,313],[1296,689,141,337,0,91,320],[1437,689,141,337,0,91,320],[1578,689,129,344,0,74,327],[1707,689,129,344,0,74,327],[1836,689,162,330,0,93,313],[0,1034,162,329,0,93,313],[162,1034,141,336,0,91,320],[303,1034,141,336,0,91,320],[444,1034,129,343,0,74,327],[573,1034,129,343,0,74,327],[702,1034,162,329,0,93,313],[864,1034,162,329,0,93,313],[1026,1034,141,335,0,91,320],[1167,1034,141,336,0,91,320],[1308,1034,129,343,0,74,327],[1308,1034,129,343,0,74,327],[1437,1034,162,329,0,93,313],[1599,1034,162,329,0,93,313],[1761,1034,141,336,0,91,320],[1902,1034,141,336,0,91,320],[0,1377,129,343,0,74,327],[129,1377,129,343,0,74,327],[258,1377,162,329,0,93,313],[420,1377,162,329,0,93,313],[582,1377,141,336,0,91,320],[723,1377,141,336,0,91,320],[864,1377,129,343,0,74,327],[993,1377,129,343,0,74,327],[1122,1377,162,330,0,93,313],[1284,1377,162,330,0,93,313],[1446,1377,141,337,0,91,320],[1587,1377,141,337,0,91,320],[1728,1377,129,344,0,74,327],[1857,1377,129,344,0,74,327],[0,1721,162,330,0,93,313],[162,1721,162,330,0,93,313],[324,1721,141,325,0,91,320],[465,1721,158,337,0,91,320],[623,1721,141,345,0,74,327],[764,1721,141,345,0,74,327],[905,1721,162,331,0,93,313],[1067,1721,162,331,0,93,313],[1229,1721,158,338,0,91,320],[1387,1721,158,338,0,91,320],[1545,1721,141,345,0,74,327],[1686,1721,141,344,0,74,327],[1827,1721,162,330,0,93,313],[0,2066,162,330,0,93,313],[162,2066,158,337,0,91,320],[320,2066,158,337,0,91,320],[478,2066,141,344,0,74,327],[619,2066,141,344,0,74,327],[760,2066,162,330,0,93,313],[922,2066,162,330,0,93,313],[1084,2066,158,337,0,91,320],[1242,2066,158,337,0,91,320],[1400,2066,141,344,0,74,327],[1541,2066,141,345,0,74,327],[1682,2066,162,331,0,93,313],[1844,2066,162,331,0,93,313],[0,2411,158,338,0,91,320],[158,2411,158,338,0,91,320],[316,2411,141,345,0,74,327],[457,2411,141,345,0,74,327],[598,2411,162,331,0,93,313],[760,2411,162,319,0,93,313],[922,2411,141,337,0,91,320],[1063,2411,141,338,0,91,320],[1204,2411,129,345,0,74,327],[1333,2411,129,345,0,74,327],[1462,2411,162,331,0,93,313],[1624,2411,162,331,0,93,313],[1786,2411,141,338,0,91,320],[0,2756,141,338,0,91,320],[141,2756,129,345,0,74,327],[270,2756,129,345,0,74,327],[399,2756,162,331,0,93,313],[561,2756,162,330,0,93,313],[723,2756,141,337,0,91,320],[864,2756,141,337,0,91,320],[1005,2756,129,344,0,74,327],[1134,2756,129,344,0,74,327],[1263,2756,162,330,0,93,313],[1425,2756,162,330,0,93,313],[1587,2756,141,337,0,91,320],[1728,2756,141,337,0,91,320],[1869,2756,129,344,0,74,327],[0,3101,129,344,0,74,327],[129,3101,162,330,0,93,313],[291,3101,162,330,0,93,313],[453,3101,141,337,0,91,320],[594,3101,141,337,0,91,320],[735,3101,129,344,0,74,327],[864,3101,129,345,0,74,327],[993,3101,162,331,0,93,313],[1155,3101,162,331,0,93,313],[1317,3101,141,338,0,91,320],[1458,3101,141,338,0,91,320],[1599,3101,129,345,0,74,327],[1728,3101,129,345,0,74,327],[1857,3101,162,331,0,93,313],[0,3446,162,331,0,93,313],[162,3446,141,326,0,91,320],[303,3446,148,280,0,82,281]],
animations: {idle:[0,36, true], idleside:[37,76, true], walk:[77,105, true], talk:[106,142, true], sleep:[143,143, true]}
}));
this.addChild(test);
test.gotoAndPlay('idle');
setTimeout(function () {
console.log('idleside');
test.gotoAndPlay('idleside');
}, 3000);
setTimeout(function () {
console.log('walk');
test.gotoAndPlay('walk');
},6000)
setTimeout(function () {
console.log('talk');
test.gotoAndPlay('talk');
},9000)
setTimeout(function () {
console.log('sleep');
test.gotoAndPlay('sleep');
},12000)
I've discovered what the issue is:
// add reversed frames
createjs.SpriteSheetUtils.addFlippedFrames(this._s, true, false, false),
The issue is that the addReversedFrames has issues in chrome - this may be caused by the size of my spritesheet - I'm going to test what happens when i break the spritesheet down into multiple parts
This may be because of the issue documented with multiple images here: Stuttering animation when spanning multiple sprite sheets in easeljs
I've updated my abstract class to use scaleX = -1 instead of flipped frames which works much better. Note: there will be a slight cpu overhead to do this but testing will bear this out. Worse case scenario, I'll have to add the extra frames to the assets.
enjoy
'use strict';
/**
* AbstractCharacter
* Provides common functionality for all characters
* #author Allandt Bik-Elliott
* #version 0.1
*/
define(['easeljs'], function () {
var AbstractCharacter = function (model) {
this.model = model;
// changed from original code
// allows better encapsulation
this._s = new createjs.SpriteSheet(model.ssInit);
// add reversed frames
// NOTE: removed because there is lag switching between spritesheets
//createjs.SpriteSheetUtils.addFlippedFrames(this._s, true, false, false),
this.initialize();
};
AbstractCharacter.prototype = Object.create(createjs.BitmapAnimation.prototype);
AbstractCharacter.prototype.constructor = AbstractCharacter;
// speed constant
AbstractCharacter.prototype.SPEED = 10;
// from Flash CS6
AbstractCharacter.prototype.BitmapAnimation_initialize = AbstractCharacter.prototype.initialize;
/**
* moves a character to a destination and sets their state at the end of the move
* #param {object} destination destination coordinates {x:XX}
* #param {string} nextAction the next action to perform
* #return {null}
*/
AbstractCharacter.prototype.moveTo = function(destination, nextAction) {
nextAction = nextAction || 'idle';
if (destination) {
if (destination.x < this.x) {
this.walkLeft();
} else {
this.walkRight();
}
this.model.destination = destination;
this.model.nextAction = nextAction;
}
};
/**
* public method to perform action
* #param {string} room name of the current room the character is in
* #param {string} action action name
* #param {object} params any parameters required by the action
* #return {null}
*/
AbstractCharacter.prototype.act = function(room, action, actionparams) {
//console.log(action);
switch (action) {
case 'walk' :
this.moveTo(actionparams, 'idle');
break;
case 'talk' :
this.moveTo(actionparams, 'talk');
break;
case 'sleep' :
this.moveTo(this.model.actions.room[room].sleep, 'sleep');
break;
}
};
/**
* onTick callback for use with easeljs
* #return {null}
*/
AbstractCharacter.prototype.onTick = function() {
if (this.model.destination) {
var destination = this.model.destination,
speed;
if (destination.x < this.x) {
speed = -this.SPEED;
if (this.x + speed < destination.x) {
this.endMove(destination);
} else {
this.x += speed;
}
} else {
speed = this.SPEED;
if (this.x + speed > destination.x) {
this.endMove(destination);
} else {
this.x += speed;
}
}
}
};
/**
* finishes move by calling nextAction() and clearing away desination and nextAction vars
* #param {object} destination format {x:XX}
* #return {null}
*/
AbstractCharacter.prototype.endMove = function(destination) {
//console.log('ending move');
this.x = destination.x;
this[this.model.nextAction]();
this.model.destination = null;
this.model.nextAction = null;
};
/**
* these methods come from Flash CS6
* the only difference is that I've removed
* the reference to the Object prototype
*
* scaleX used instead of flipped frames
*/
AbstractCharacter.prototype.initialize = function() {
this.BitmapAnimation_initialize(this._s);
this.idle();
};
AbstractCharacter.prototype.idle = function(){
//console.log('idle');
this.gotoAndPlay("idle");
this.scaleX = 1;
};
AbstractCharacter.prototype.idleLeft = function(){
//console.log('idle left');
this.gotoAndPlay("idleside");
this.scaleX = 1;
};
AbstractCharacter.prototype.idleRight = function(){
//console.log('idle right');
// this.gotoAndPlay("idleside_h");
this.gotoAndPlay("idleside");
this.scaleX = -1;
};
AbstractCharacter.prototype.walkLeft = function(){
//console.log('walk left');
this.gotoAndPlay("walk");
this.scaleX = 1;
};
AbstractCharacter.prototype.walkRight = function(){
//console.log('walk right');
// this.gotoAndPlay("walk_h");
this.gotoAndPlay("walk");
this.scaleX = -1;
};
AbstractCharacter.prototype.talk = function(){
//console.log('talk');
this.gotoAndPlay("talk");
this.scaleX = 1;
};
AbstractCharacter.prototype.sleep = function(){
//console.log('sleep');
this.gotoAndPlay("sleep");
this.scaleX = 1;
};
// public interface
return AbstractCharacter;
});

How to animate zoom on jquery iviewer plugin?

I have this jquery plugin that zooms in on photos, but I would like to animate the zoom so it just doesn't zoom in, but so that there is like an animated effect on the zoom. Is this possible?
Here is the page I have the plugin set up on right now. http://www.buildinfocus.com/clients/gallery_detail.php?title=1&mapid=239
Maybe something like this http://api.jquery.com/animate/
Below is the code I have for plugin
(function($){
$.fn.iviewer = function(o)
{
return this.each(function()
{
$(this).data('viewer', new $iv(this,o));
});
}
var defaults = {
/**
* start zoom value for image, not used now
* may be equal to "fit" to fit image into container or scale in %
**/
zoom: "fit",
/**
* base value to scale image
**/
zoom_base: 100,
/**
* maximum zoom
**/
zoom_max: 800,
/**
* minimum zoom
**/
zoom_min: 25,
/**
* base of rate multiplier.
* zoom is calculated by formula: zoom_base * zoom_delta^rate
**/
zoom_delta: 1.4,
/**
* if true plugin doesn't add its own controls
**/
ui_disabled: false,
/**
* if false, plugin doesn't bind resize event on window and this must
* be handled manually
**/
update_on_resize: true,
/**
* event is triggered when zoom value is changed
* #param int new zoom value
* #return boolean if false zoom action is aborted
**/
onZoom: null,
/**
* callback is fired after plugin setup
**/
initCallback: null,
/**
* event is fired on drag begin
* #param object coords mouse coordinates on the image
* #return boolean if false is returned, drag action is aborted
**/
onStartDrag: null,
/**
* event is fired on drag action
* #param object coords mouse coordinates on the image
**/
onDrag: null,
/**
* event is fired when mouse moves over image
* #param object coords mouse coordinates on the image
**/
onMouseMove: null,
/**
* mouse click event
* #param object coords mouse coordinates on the image
**/
onClick: null,
/**
* event is fired when image starts to load
*/
onStartLoad: null,
/**
* event is fired, when image is loaded and initially positioned
*/
onFinishLoad: null
};
$.iviewer = function(e,o)
{
var me = this;
/* object containing actual information about image
* #img_object.object - jquery img object
* #img_object.orig_{width|height} - original dimensions
* #img_object.display_{width|height} - actual dimensions
*/
this.img_object = {};
this.zoom_object = {}; //object to show zoom status
this.image_loaded = false;
//drag variables
this.dx = 0;
this.dy = 0;
this.dragged = false;
this.settings = $.extend({}, defaults, o || {});
this.current_zoom = this.settings.zoom;
if(this.settings.src === null){
return;
}
this.container = $(e);
this.update_container_info();
//init container
this.container.css("overflow","hidden");
if(this.settings.update_on_resize == true)
{
$(window).resize(function()
{
me.update_container_info();
});
}
this.img_object.x = 0;
this.img_object.y = 0;
//init object
this.img_object.object = $("<img>").
css({ position: "absolute", top :"0px", left: "0px"}). //this is needed, because chromium sets them auto otherwise
//bind mouse events
mousedown(function(e){ return me.drag_start(e); }).
mousemove(function(e){return me.drag(e)}).
mouseup(function(e){return me.drag_end(e)}).
click(function(e){return me.click(e)}).
mouseleave(function(e){return me.drag_end(e)}).
mousewheel(function(ev, delta)
{
//this event is there instead of containing div, because
//at opera it triggers many times on div
var zoom = (delta > 0)?1:-1;
me.zoom_by(zoom);
return false;
});
this.img_object.object.prependTo(me.container);
this.loadImage(this.settings.src);
if(!this.settings.ui_disabled)
{
this.createui();
}
if(this.settings.initCallback)
{
this.settings.initCallback.call(this);
}
}
var $iv = $.iviewer;
$iv.fn = $iv.prototype = {
iviewer : "0.4.2"
}
$iv.fn.extend = $iv.extend = $.extend;
$iv.fn.extend({
loadImage: function(src)
{
this.current_zoom = this.settings.zoom;
this.image_loaded = false;
var me = this;
if(this.settings.onStartLoad)
{
this.settings.onStartLoad.call(this);
}
this.img_object.object.unbind('load').
removeAttr("src").
removeAttr("width").
removeAttr("height").
css({ top: 0, left: 0 }).
load(function(){
me.image_loaded = true;
me.img_object.display_width = me.img_object.orig_width = this.width;
me.img_object.display_height = me.img_object.orig_height = this.height;
if(!me.container.hasClass("iviewer_cursor")){
me.container.addClass("iviewer_cursor");
}
if(me.settings.zoom == "fit"){
me.fit();
}
else {
me.set_zoom(me.settings.zoom);
}
if(me.settings.onFinishLoad)
{
me.settings.onFinishLoad.call(me);
}
//src attribute is after setting load event, or it won't work
}).attr("src",src);
},
/**
* fits image in the container
**/
fit: function()
{
var aspect_ratio = this.img_object.orig_width / this.img_object.orig_height;
var window_ratio = this.settings.width / this.settings.height;
var choose_left = (aspect_ratio > window_ratio);
var new_zoom = 0;
if(choose_left){
new_zoom = this.settings.width / this.img_object.orig_width * 100;
}
else {
new_zoom = this.settings.height / this.img_object.orig_height * 100;
}
this.set_zoom(new_zoom);
},
/**
* center image in container
**/
center: function()
{
this.setCoords(-Math.round((this.img_object.display_height - this.settings.height)/2),
-Math.round((this.img_object.display_width - this.settings.width)/2));
},
/**
* move a point in container to the center of display area
* #param x a point in container
* #param y a point in container
**/
moveTo: function(x, y)
{
var dx = x-Math.round(this.settings.width/2);
var dy = y-Math.round(this.settings.height/2);
var new_x = this.img_object.x - this.dx;
var new_y = this.img_object.y - this.dy;
this.setCoords(new_x, new_y);
},
/**
* set coordinates of upper left corner of image object
**/
setCoords: function(x,y)
{
//do nothing while image is being loaded
if(!this.image_loaded)
{
return;
}
//check new coordinates to be correct (to be in rect)
if(y > 0){
y = 0;
}
if(x > 0){
x = 0;
}
if(y + this.img_object.display_height < this.settings.height){
y = this.settings.height - this.img_object.display_height;
}
if(x + this.img_object.display_width < this.settings.width){
x = this.settings.width - this.img_object.display_width;
}
if(this.img_object.display_width <= this.settings.width){
x = -(this.img_object.display_width - this.settings.width)/2;
}
if(this.img_object.display_height <= this.settings.height){
y = -(this.img_object.display_height - this.settings.height)/2;
}
this.img_object.x = x;
this.img_object.y = y;
this.img_object.object.css("top",y + "px")
.css("left",x + "px");
},
/**
* convert coordinates on the container to the coordinates on the image (in original size)
*
* #return object with fields x,y according to coordinates or false
* if initial coords are not inside image
**/
containerToImage : function (x,y)
{
if(x < this.img_object.x || y < this.img_object.y ||
x > this.img_object.x + this.img_object.display_width ||
y > this.img_object.y + this.img_object.display_height)
{
return false;
}
return { x : $iv.descaleValue(x - this.img_object.x, this.current_zoom),
y : $iv.descaleValue(y - this.img_object.y, this.current_zoom)
};
},
/**
* convert coordinates on the image (in original size) to the coordinates on the container
*
* #return object with fields x,y according to coordinates or false
* if initial coords are not inside image
**/
imageToContainer : function (x,y)
{
if(x > this.img_object.orig_width || y > this.img_object.orig_height)
{
return false;
}
return { x : this.img_object.x + $iv.scaleValue(x, this.current_zoom),
y : this.img_object.y + $iv.scaleValue(y, this.current_zoom)
};
},
/**
* get mouse coordinates on the image
* #param e - object containing pageX and pageY fields, e.g. mouse event object
*
* #return object with fields x,y according to coordinates or false
* if initial coords are not inside image
**/
getMouseCoords : function(e)
{
var img_offset = this.img_object.object.offset();
return { x : $iv.descaleValue(e.pageX - img_offset.left, this.current_zoom),
y : $iv.descaleValue(e.pageY - img_offset.top, this.current_zoom)
};
},
/**
* set image scale to the new_zoom
* #param new_zoom image scale in %
**/
set_zoom: function(new_zoom)
{
if(this.settings.onZoom && this.settings.onZoom.call(this, new_zoom) == false)
{
return;
}
//do nothing while image is being loaded
if(!this.image_loaded)
{
return;
}
if(new_zoom < this.settings.zoom_min)
{
new_zoom = this.settings.zoom_min;
}
else if(new_zoom > this.settings.zoom_max)
{
new_zoom = this.settings.zoom_max;
}
/* we fake these values to make fit zoom properly work */
if(this.current_zoom == "fit")
{
var old_x = Math.round(this.settings.width/2 + this.img_object.orig_width/2);
var old_y = Math.round(this.settings.height/2 + this.img_object.orig_height/2);
this.current_zoom = 100;
}
else {
var old_x = -parseInt(this.img_object.object.css("left"),10) +
Math.round(this.settings.width/2);
var old_y = -parseInt(this.img_object.object.css("top"),10) +
Math.round(this.settings.height/2);
}
var new_width = $iv.scaleValue(this.img_object.orig_width, new_zoom);
var new_height = $iv.scaleValue(this.img_object.orig_height, new_zoom);
var new_x = $iv.scaleValue( $iv.descaleValue(old_x, this.current_zoom), new_zoom);
var new_y = $iv.scaleValue( $iv.descaleValue(old_y, this.current_zoom), new_zoom);
new_x = this.settings.width/2 - new_x;
new_y = this.settings.height/2 - new_y;
this.img_object.object.attr("width",new_width)
.attr("height",new_height);
this.img_object.display_width = new_width;
this.img_object.display_height = new_height;
this.setCoords(new_x, new_y);
this.current_zoom = new_zoom;
$.isFunction( this.settings.onAfterZoom ) && this.settings.onAfterZoom.call( this, new_zoom );
this.update_status();
},
/**
* changes zoom scale by delta
* zoom is calculated by formula: zoom_base * zoom_delta^rate
* #param Integer delta number to add to the current multiplier rate number
**/
zoom_by: function(delta)
{
var closest_rate = this.find_closest_zoom_rate(this.current_zoom);
var next_rate = closest_rate + delta;
var next_zoom = this.settings.zoom_base * Math.pow(this.settings.zoom_delta, next_rate)
if(delta > 0 && next_zoom < this.current_zoom)
{
next_zoom *= this.settings.zoom_delta;
}
if(delta < 0 && next_zoom > this.current_zoom)
{
next_zoom /= this.settings.zoom_delta;
}
this.set_zoom(next_zoom);
},
/**
* finds closest multiplier rate for value
* basing on zoom_base and zoom_delta values from settings
* #param Number value zoom value to examine
**/
find_closest_zoom_rate: function(value)
{
if(value == this.settings.zoom_base)
{
return 0;
}
function div(val1,val2) { return val1 / val2 };
function mul(val1,val2) { return val1 * val2 };
var func = (value > this.settings.zoom_base)?mul:div;
var sgn = (value > this.settings.zoom_base)?1:-1;
var mltplr = this.settings.zoom_delta;
var rate = 1;
while(Math.abs(func(this.settings.zoom_base, Math.pow(mltplr,rate)) - value) >
Math.abs(func(this.settings.zoom_base, Math.pow(mltplr,rate+1)) - value))
{
rate++;
}
return sgn * rate;
},
/* update scale info in the container */
update_status: function()
{
if(!this.settings.ui_disabled)
{
var percent = Math.round(100*this.img_object.display_height/this.img_object.orig_height);
if(percent)
{
this.zoom_object.html(percent + "%");
}
}
},
update_container_info: function()
{
this.settings.height = this.container.height();
this.settings.width = this.container.width();
},
/**
* callback for handling mousdown event to start dragging image
**/
drag_start: function(e)
{
if(this.settings.onStartDrag &&
this.settings.onStartDrag.call(this,this.getMouseCoords(e)) == false)
{
return false;
}
/* start drag event*/
this.dragged = true;
this.container.addClass("iviewer_drag_cursor");
this.dx = e.pageX - this.img_object.x;
this.dy = e.pageY - this.img_object.y;
return false;
},
/**
* callback for handling mousmove event to drag image
**/
drag: function(e)
{
this.settings.onMouseMove &&
this.settings.onMouseMove.call(this,this.getMouseCoords(e));
if(this.dragged){
this.settings.onDrag &&
this.settings.onDrag.call(this,this.getMouseCoords(e));
var ltop = e.pageY -this.dy;
var lleft = e.pageX -this.dx;
this.setCoords(lleft, ltop);
return false;
}
},
/**
* callback for handling stop drag
**/
drag_end: function(e)
{
this.container.removeClass("iviewer_drag_cursor");
this.dragged=false;
},
click: function(e)
{
this.settings.onClick &&
this.settings.onClick.call(this,this.getMouseCoords(e));
},
/**
* create zoom buttons info box
**/
createui: function()
{
var me=this;
$("<div>").addClass("iviewer_zoom_in").addClass("iviewer_common").
addClass("iviewer_button").
mousedown(function(){me.zoom_by(1); return false;}).appendTo(this.container);
$("<div>").addClass("iviewer_zoom_out").addClass("iviewer_common").
addClass("iviewer_button").
mousedown(function(){me.zoom_by(- 1); return false;}).appendTo(this.container);
$("<div>").addClass("iviewer_zoom_zero").addClass("iviewer_common").
addClass("iviewer_button").
mousedown(function(){me.set_zoom(100); return false;}).appendTo(this.container);
$("<div>").addClass("iviewer_zoom_fit").addClass("iviewer_common").
addClass("iviewer_button").
mousedown(function(){me.fit(this); return false;}).appendTo(this.container);
this.zoom_object = $("<div>").addClass("iviewer_zoom_status").addClass("iviewer_common").
appendTo(this.container);
this.update_status(); //initial status update
}
});
$iv.extend({
scaleValue: function(value, toZoom)
{
return value * toZoom / 100;
},
descaleValue: function(value, fromZoom)
{
return value * 100 / fromZoom;
}
});
})(jQuery);
Try updating to the latest version, it looks to support smooth zoom transition (so you won't have to implement this yourself):
https://github.com/can3p/iviewer/blob/master/jquery.iviewer.js#L415
On line 415, the set_zoom function animates the trnasition, as opposed to the older code you pasted, which just changes the css values.
The last version of the plugin(0.5) supports smooth zoom, try it.

Categories