I'm having trouble performing a simple rotation animation using jquery's animate method. I am trying to start a square at 45 degrees rotation and then, when clicking a button, rotate the square another 45 degrees (to complete at 90).
However, when I attempt the animation, the square first jerks back to a rotation of 0 before starting to progress towards its final completion point (90 degrees).
This appears to be because the "now" argument of animate()'s "step" option is starting at 0, rather than the actual starting point of the element, 45 degrees.
Any thoughts on what I'm doing wrong here?
http://jsfiddle.net/agentfitz/btz89/2/
// css
.square {
transform: rotate(45deg); // starting point
}
// js
$(".square").animate(
{
rotation: 90,
},
{
step: function(now, tween) {
var $el = $(this);
if (tween.prop === "rotation") {
console.log(now);
$el.css('transform','rotate('+now+'deg)');
}
},
duration: 2000
}
);
Please follow this example: http://jqversion.com/#!/1GLob7P
Javascript code:
$("a").click(function(e){
e.preventDefault();
var initRotation = 0;
$(".square").animate(
{
rotation: 45, // how many degrees do you want to rotate
},
{
start: function(promise){
initRotation = getRotationDegrees($(this));
},
step: function(now, tween) {
var $el = $(this);
if (tween.prop === "rotation") {
var newRotation = initRotation + now;
$el.css('-webkit-transform','rotate('+newRotation+'deg)');
$el.css('-moz-transform','rotate('+newRotation+'deg)');
$el.css('transform','rotate('+newRotation+'deg)');
}
},
duration: 2000
}
);
});
function getRotationDegrees(obj) {
var matrix = obj.css("-webkit-transform") ||
obj.css("-moz-transform") ||
obj.css("-ms-transform") ||
obj.css("-o-transform") ||
obj.css("transform");
if(matrix !== 'none') {
var values = matrix.split('(')[1].split(')')[0].split(',');
var a = values[0];
var b = values[1];
var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
} else { var angle = 0; }
return (angle < 0) ? angle +=360 : angle;
}
You can use start option to customize property start value:
// css
.square {
transform: rotate(45deg); // starting point
}
// js
var startRotation = 45;
$(".square").animate(
{
rotation: 90,
},
{
start: function(promise) {
for (var i = 0; i < promise.tweens.length; i++) {
var tween = promise.tweens[i];
if (tween.prop === "rotation") {
tween.start = startRotation;
}
}
},
step: function(now, tween) {
var $el = $(this);
if (tween.prop === "rotation") {
console.log(now);
$el.css('transform','rotate('+now+'deg)');
}
},
duration: 2000
}
);
Related
I am trying to create a carousel type effect in Phaser for selecting a character, there are many tutorials on creating a standard Carousel (Website Slideshows etc) but I am trying to create a Carousel that can display up 3 options at once, (if there are 3 to display), which I am not sure if there's a name for this specific type of carousel as my google searches so far haven't turned up anything I can learn from.
I cannot work out the logic needed to shift each image into the next slot along when the next and previous functions are called.
this.scrollingOptionsMenu.ShowSelectedOption();
ShowSelectedOption(); is called in the update function of the theme select state, other than this and the Prev(), Next() functions are called on keyboard press left or right respectively other than this all code is in the below file.
I have included the code I have so far below ScrollingOptionsMenu() is called in my create function of the theme select state, the options parameter is an array of files (for now just the thumbnail of each theme) pulled from a json file.
With my own current attempt, the images don't see to move into their new slots and I get an "property of x undefined' which I understand and could limit it going over but I am not really sure if I'm going the 'right' way with this.
Any help appreciated,
Thanks!
function ScrollingOptionsMenu(game, x, y, options)
{
this.x = x;
this.y = y;
this.options = options;
this.optionsCount = options.length;
this.game = game;
this.currentIndex = 0;
this.leftImage = game.add.sprite(x , y, 'theme1_thumbail');
this.centerImage = game.add.sprite(x, y, 'theme2_thumbail');
this.rightImage = game.add.sprite(x , y, 'theme3_thumbail');
this.ImageGroup = [this.leftImage, this.centerImage, this.rightImage];
this.leftImage.anchor.setTo(0.5);
this.centerImage.anchor.setTo(0.5);
this.rightImage.anchor.setTo(0.5);
this.leftImage.x = x - this.leftImage.width;
this.rightImage.x = x + this.rightImage.width;
this.leftImage.scale.setTo(0.5);
this.rightImage.scale.setTo(0.5);
//console.log(width);
console.log(this.leftImage);
console.log(this.centerImage);
console.log(this.rightImage);
}
//Display currently centerImage Option
ScrollingOptionsMenu.prototype.ShowSelectedOption = function()
{
if(this.currentIndex == 0)
{
//if we are at 0 then the left slot should be empty
this.leftImage.loadTexture('transParent', 0);
this.centerImage.loadTexture(this.options[this.currentIndex].thumbnail.name, 0);
this.rightImage.loadTexture(this.options[this.currentIndex+1].thumbnail.name, 0);
}
else{
//if currentIndex is above 0 then place
this.leftImage.loadTexture(this.options[this.currentIndex-1].thumbnail.name, 0);
this.centerImage.loadTexture(this.options[this.currentIndex].thumbnail.name, 0);
this.rightImage.loadTexture(this.options[this.currentIndex+1].thumbnail.name, 0);
}
}
ScrollingOptionsMenu.prototype.NextOption = function()
{
this.ChangeIndex(1);
}
ScrollingOptionsMenu.prototype.PreviousOption = function()
{
this.ChangeIndex(-1);
}
//returns the index of the currently centerImage option
ScrollingOptionsMenu.prototype.GetCurrentIndex = function()
{
return this.currentIndex;
}
ScrollingOptionsMenu.prototype.ChangeIndex = function(index)
{
var optionsLength = this.options.length-1;
if(this.currentIndex + index < 0)
{
this.currentIndex = 0;
}
else if(this.currentIndex + index > optionsLength)
{
this.currentIndex = optionsLength;
}else{
this.currentIndex += index;
}
}
I setup for you this example showing one way to approach this problem:
https://codepen.io/ChrisGhenea/pen/WZGjLg/
First all available themes are added to an array so you can keep track of them. Each element needs to be initialized
//array of all available themes
var themes = [];
themes.push(game.add.sprite(0, 0, 'theme1'));
themes.push(game.add.sprite(0, 0, 'theme2'));
themes.push(game.add.sprite(0, 0, 'theme3'));
themes.push(game.add.sprite(0, 0, 'theme4'));
themes.push(game.add.sprite(0, 0, 'theme5'));
themes.push(game.add.sprite(0, 0, 'theme6'));
themes.forEach(function (item) {
item.anchor.setTo(0.5, 0.5);
item.x = game.width + 150;
item.y = game.height / 2;
item.inputEnabled = true;
item.events.onInputDown.add(clickListener, this);
})
The you set the highlighted position (the one in the middle) and place the elements on the stage:
function setToPosition(prime) {
themes[prime].x = game.width / 2;
//check if there is another theme available to display on the right side; if yes then position it
if (prime<(totalThemes-1)) {
themes[prime + 1].x = game.width / 2 + 140;
themes[prime + 1].scale.setTo(0.5,0.5);
}
//check if there is another theme available to display on the left side; if yes then position it
if (prime > 0) {
themes[prime - 1].x = game.width / 2 - 140;
themes[prime - 1].scale.setTo(0.5,0.5);
}
}
The animation happens on click; depending on which theme is clicked the list is moved left or right:
//move to next theme
function nextTheme() {
//move prime left
game.add.tween(themes[prime]).to( { x: xleft}, animationSpeed, null, true);
game.add.tween(themes[prime].scale).to( { x: 0.5 , y: 0.5}, animationSpeed, null, true);
//move right to prime
if (prime < 5) {
game.add.tween(themes[prime+1]).to( { x: xprime}, animationSpeed, null, true);
game.add.tween(themes[prime+1].scale).to( { x: 1 , y: 1}, animationSpeed, null, true);
}
//move new to right
if (prime < 4) {
themes[prime+2].x = game.width + 150;
themes[prime+2].scale.setTo(0.5,0.5);
game.add.tween(themes[prime+2]).to( { x: xright}, animationSpeed, null, true);
}
//move left out
if (prime>0) {
//themes[prime+1].x = -150;
themes[prime-1].scale.setTo(0.5,0.5);
game.add.tween(themes[prime-1]).to( { x: -150}, animationSpeed, null, true);
}
prime++;
}
//move to previous theme
function previousTheme() {
//move prime left
game.add.tween(themes[prime]).to( { x: xright}, animationSpeed, null, true);
game.add.tween(themes[prime].scale).to( { x: 0.5 , y: 0.5}, animationSpeed, null, true);
//move left to prime
if (prime > 0 ) {
game.add.tween(themes[prime-1]).to( { x: xprime}, animationSpeed, null, true);
game.add.tween(themes[prime-1].scale).to( { x: 1 , y: 1}, animationSpeed, null, true);
}
//move new to left
if (prime > 1) {
themes[prime-2].x = - 150;
themes[prime-2].scale.setTo(0.5,0.5);
game.add.tween(themes[prime-2]).to( { x: xleft}, animationSpeed, null, true);
}
//move right out
if (prime < (totalThemes-1)) {
//themes[prime+1].x = -150;
themes[prime+1].scale.setTo(0.5,0.5);
game.add.tween(themes[prime+1]).to( { x: game.width + 150}, animationSpeed, null, true);
}
prime--;
}
I tried to re create a Tinder like function.
I found this code :
var win = Titanium.UI.createWindow({
backgroundColor: "#ffffff",
title: "win"
});
// animations
var animateLeft = Ti.UI.createAnimation({
left: -520,
transform: Ti.UI.create2DMatrix({rotate: 60}),
opacity: 0,
duration: 300
});
var animateRight = Ti.UI.createAnimation({
left: 520,
transform: Ti.UI.create2DMatrix({rotate: -60}),
opacity: 0,
duration: 300
});
var curX = 0;
win.addEventListener('touchstart', function (e) {
curX = parseInt(e.x, 10);
});
win.addEventListener('touchmove', function (e) {
if (!e.source.id || e.source.id !== 'oferta') {
return;
}
// Subtracting current position to starting horizontal position
var coordinates = parseInt(e.x, 10) - curX;
// Defining coordinates as the final left position
var matrix = Ti.UI.create2DMatrix({rotate: -(coordinates / 10)});
var animate = Ti.UI.createAnimation({
left: coordinates,
transform: matrix,
duration: 20
});
e.source.animate(animate);
e.source.left = coordinates;
});
win.addEventListener('touchend', function (e) {
if (!e.source.id || e.source.id !== 'oferta') {
return;
}
// No longer moving the window
if (e.source.left >= 75) {
e.source.animate(animateRight);
} else if (e.source.left <= -75) {
e.source.animate(animateLeft);
} else {
// Repositioning the window to the left
e.source.animate({
left: 0,
transform: Ti.UI.create2DMatrix({rotate: 0}),
duration: 300
});
}
});
for (var i = 0; i < 10; i++) {
var wrap = Ti.UI.createView({
"id": 'oferta',
"width": 320,
"height": 400,
"backgroundColor": (i % 2 == 0 ? "red" : "blue")
});
var text = Ti.UI.createLabel({
text: "row: " + i,
color: "black"
});
wrap.add(text);
win.add(wrap);
}
win.open();
But there's a weird behaviour.
Indeed, When I took the wrap view from the top, everythnig is OK but if I put my finger on the bottom on the wrap view, the image becomes crazy..
Try the code and You will see strange behaviour.
I use Titanium SDK 5.2.2
and iOS 9.3.1 on an iPhone 6.
Here s a video showing the weird thing: http://tinypic.com/player.php?v=x37d5u%3E&s=9#.Vx_zDaOLQb0
(Sorry for the video size)
Thanks for your help
Use this code to convert pxToDp and vice versa:
Put following code in your lib folder and include it
with require("measurement")
instead of require("alloy/measurement")
var dpi = Ti.Platform.displayCaps.dpi, density = Ti.Platform.displayCaps.density;
exports.dpToPX = function(val) {
switch (density) {
case "xxxhigh":
return 5 * val;
case "xxhigh":
return 4 * val;
case "xhigh":
return 3 * val;
case "high":
return 2 * val;
default:
return val;
}
};
exports.pxToDP = function(val) {
switch (density) {
case "xxxhigh":
return 5 / val;
case "xxhigh":
return 4 / val;
case "xhigh":
return val / 3;
case "high":
return val / 2;
default:
return val;
}
};
exports.pointPXToDP = function(pt) {
return {
x: exports.pxToDP(pt.x),
y: exports.pxToDP(pt.y)
};
};
Many thanks to all !!! It works using this code ::
var win = Titanium.UI.createWindow({
backgroundColor: "#ffffff",
title: "win"
});
// animations
var animateLeft = Ti.UI.createAnimation({
left: -520,
transform: Ti.UI.create2DMatrix({rotate: 60}),
opacity: 0,
duration: 300
});
var animateRight = Ti.UI.createAnimation({
left: 520,
transform: Ti.UI.create2DMatrix({rotate: -60}),
opacity: 0,
duration: 300
});
Ti.include('measurement.js');
var curX = 0;
var wrap = [];
var topWrap = 100; //(Titanium.Platform.displayCaps.platformHeight - 400) / 2;
var leftWrap = 50; //(Titanium.Platform.displayCaps.platformWidth - 320) / 2;
for (var i = 0; i < 10; i++) {
wrap[i] = Ti.UI.createView({
"id": 'oferta',
"width": Titanium.Platform.displayCaps.platformWidth - 100,
"height": Titanium.Platform.displayCaps.platformHeight - 300,
image:(i % 2 == 0 ? 'principale.png' : 'principale1.png'),
"backgroundColor": (i % 2 == 0 ? "red" : "blue"),
top:topWrap,
left:leftWrap,
});
wrap[i].addEventListener('touchstart', function (e) {
// curX = parseInt(e.x, 10);
curX = pxToDP(parseInt(e.x, 10));
// curY = pxToDP(parseInt(e.Y, 10));
});
wrap[i].addEventListener('touchmove', function (e) {
// Subtracting current position to starting horizontal position
// var coordinates = parseInt(e.x, 10) - curX;
// Defining coordinates as the final left position
var coordinatesX = pxToDP(parseInt(e.x, 10)) - curX;
//var coordinatesY = pxToDP(parseInt(e.y, 10)) - curY;
var matrix = Ti.UI.create2DMatrix({rotate: -(coordinatesX / 10)});
var animate = Ti.UI.createAnimation({
left: coordinatesX,
// top: coordinatesY,
transform: matrix,
duration: 10
});
e.source.animate(animate);
e.source.left = coordinatesX;
// e.source.top = coordinatesY;
});
wrap[i].addEventListener('touchend', function (e) {
// No longer moving the window
if (e.source.left >= 75) {
e.source.animate(animateRight);
} else if (e.source.left <= -75) {
e.source.animate(animateLeft);
} else {
// Repositioning the window to the left
e.source.animate({
left: leftWrap,
transform: Ti.UI.create2DMatrix({rotate: 0}),
duration: 300
});
}
});
win.add(wrap);
}
win.open();
And the measurement.js file is :
var dpi = Ti.Platform.displayCaps.dpi, density = Ti.Platform.displayCaps.density;
function dpToPX(val) {
switch (density) {
case "xxxhigh":
return 5 * val;
case "xxhigh":
return 4 * val;
case "xhigh":
return 3 * val;
case "high":
return 2 * val;
default:
return val;
}
};
function pxToDP(val) {
switch (density) {
case "xxxhigh":
return 5 / val;
case "xxhigh":
return 4 / val;
case "xhigh":
return val / 3;
case "high":
return val / 2;
default:
return val;
}
};
function pointPXToD(pt) {
return {
x: pxToDP(pt.x),
y: pxToDP(pt.y)
};
};
You have to convert px to dp.
var measurement = require('alloy/measurement');
win.addEventListener('touchstart', function (e) {
curX = measurement.pxToDP(parseInt(e.x, 10));
Ti.API.info("touchstart curX: " + curX);
});
...
win.addEventListener('touchmove', function (e) {
if (!e.source.id || e.source.id !== 'oferta') {
return;
}
// Subtracting current position to starting horizontal position
var coordinates = measurement.pxToDP(parseInt(e.x, 10)) - curX;
...
I have a problem with segment spin, in this spin wheel from https://www.sitepoint.com/jquery-wheel-fortune-demo/ demo: http://jsfiddle.net/sNYYD/237/
window.WHEELOFFORTUNE = {
cache: {},
init: function () {
console.log('controller init...');
var _this = this;
this.cache.wheel = $('.wheel');
this.cache.wheelMarker = $('.marker');
this.cache.wheelSpinBtn = $('.wheel'); //im using the wheel as the spin button but simply change this to a button if you want.
//mapping is backwards as wheel spins clockwise //1=win
this.cache.wheelMapping = [400, 120, 80, 750, 150, 300, 60, 175, 500, 125, 75, 1000, 120, 200, 90, 600, 100, 250].reverse();
this.cache.wheelSpinBtn.on('click', function (e) {
e.preventDefault();
if (!$(this).hasClass('disabled')) _this.spin();
});
//reset wheel
this.resetSpin();
//setup prize events
this.prizeEvents();
},
spin: function () {
console.log('spinning wheel');
var _this = this;
// reset wheel
this.resetSpin();
//disable spin button while in progress
this.cache.wheelSpinBtn.addClass('disabled');
/*
Wheel has 10 sections.
Each section is 360/10 = 36deg.
*/
var deg = 1500 + Math.round(Math.random() * 1500),
duration = 6000; //optimal 6 secs
_this.cache.wheelPos = deg;
//transition queuing
//ff bug with easeOutBack
this.cache.wheel.transition({
rotate: '0deg'
}, 0)
.transition({
rotate: deg + 'deg'
}, duration, 'easeOutCubic');
//move marker
_this.cache.wheelMarker.transition({
rotate: '-20deg'
}, 0, 'snap');
//just before wheel finish
setTimeout(function () {
//reset marker
_this.cache.wheelMarker.transition({
rotate: '0deg'
}, 300, 'easeOutQuad');
}, duration - 500);
//wheel finish
setTimeout(function () {
// did it win??!?!?!
var spin = _this.cache.wheelPos,
degrees = spin % 360,
percent = (degrees / 360) * 100,
segment = Math.ceil((percent / 6)), //divided by number of segments
win = _this.cache.wheelMapping[segment - 1]; //zero based array
console.log('spin = ' + spin);
console.log('degrees = ' + degrees);
console.log('percent = ' + percent);
console.log('segment = ' + segment);
console.log('win = ' + win);
//display dialog with slight delay to realise win or not.
setTimeout(function () {
alert('you won '+win+'!');
}, 700);
//re-enable wheel spin
_this.cache.wheelSpinBtn.removeClass('disabled');
}, duration);
},
resetSpin: function () {
this.cache.wheel.transition({
rotate: '0deg'
}, 0);
this.cache.wheelPos = 0;
}
}
window.WHEELOFFORTUNE.init();
I have 18 segments and always the win number is wrong, Is the problem Math.ceil((percent / 6)) or this.cache.wheelPos = 0; ?
Thank you
I've been tempted to vote this question as duplicated...(see link)
I think your code lacks consistency: in one line there is a comment about having 10 segments, in other one you say 6, but it seems you have 18 different segments in your wheel. Fix that part (use constants!) and I think most of your issues will be solved.
UPDATED: The way you calculate the segment is incorrect, changing it with this solves the issue.
//the segment is 18 multiplied by the proportion
segment = Math.ceil((percent *18/100))-1;
I am newbie. I can't sprite animation using jquery..
What's the problem?
How can make progressing the sprite animation on the spot loop as scroll??
$(window).scroll('scroll',function(e){
parallaxScroll();
});
function parallaxScroll() {
var ani_data = [0, -120, -240, -480];
var frame_index = 0;
if ( ScrollCount == 3 ) {
ScrollCount = 1;
$('#fatherwalk').css('background-position', ani_data[frame_index] + 'px 0px');
frame_index++;
if ( frame_index >= ani_data.length ) {
frame_index = 0;
}
}
scrollcount++;
}
Why you don't get a shortcut and try SpinJS?
http://fgnass.github.io/spin.js/
It's so easy to implement and works fine.
Here is a Sample that I've made on JSFiddle
Below a quick implementation of the JS:
$.fn.spin = function (opts) {
this.each(function () {
var $this = $(this),
spinner = $this.data('spinner');
if (spinner) spinner.stop();
if (opts !== false) {
opts = $.extend({
color: $this.css('color')
}, opts);
spinner = new Spinner(opts).spin(this);
$this.data('spinner', spinner);
}
});
return this;
};
$(function () {
$(".spinner-link").click(function (e) {
e.preventDefault();
$(this).hide();
var opts = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 5, // The line thickness
radius: 10, // The radius of the inner circle
color: '#fff', // #rbg or #rrggbb
speed: 1, // Rounds per second
trail: 66, // Afterglow percentage
shadow: true // Whether to render a shadow
};
$("#spin").show().spin(opts);
});
});
Hope this helps.
I have created fixed city having few path.
On that I want to make specific path where I can move characters from start to and point.
Here is the canvas map
When I tried this http://jsfiddle.net/nathggns/HG752/light/ example code move on map Iy just show white background instead of canvas city map.
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
// Grab our context
var context = canvas.getContext('2d');
// Make sure we have a valid defintion of requestAnimationFrame
var requestAnimationFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame ||
function(callback) {
return setTimeout(callback, 16);
};
// Let's define our square
var square = {
'x': 50,
'y': 50,
'width': 10,
'height': 10,
'fill': '#000000'
};
var render = function() {
// Clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// Draw the square
context.beginPath();
context.rect(square.x, square.y, square.width, square.height);
context.fillStyle = square.fill;
context.fill();
// Redraw
requestAnimationFrame(render);
};
// Start the redrawing process
render();
var animate = function(prop, val, duration) {
// The calculations required for the step function
var start = new Date().getTime();
var end = start + duration;
var current = square[prop];
var distance = val - current;
var step = function() {
// Get our current progres
var timestamp = new Date().getTime();
var progress = Math.min((duration - (end - timestamp)) / duration, 1);
// Update the square's property
square[prop] = current + (distance * progress);
// If the animation hasn't finished, repeat the step.
if (progress < 1) requestAnimationFrame(step);
};
// Start the animation
return step();
};
animate('x', 0, 1000);
setTimeout(function() {
animate('y', 0, 1000);
setTimeout(function() {
animate('x', 50, 1000);
animate('y', 50, 1000);
}, 1000);
}, 1000);
var meta = function(e) {
// Set some initial variables
var distance = 100;
var prop = 'x';
var mult = 1;
// Just return false if the key isn't an arrow key
if (e.which < 37 || e.which > 40) {
return false;
};
// If we're going left or up, we want to set the multiplier to -1
if (e.which === 37 || e.which === 38) {
mult = -1;
}
// If we're going up or down, we want to change the property we will be animating.
if (e.which === 38 || e.which === 40) {
prop = 'y';
};
return [prop, mult * distance];
};
document.body.addEventListener('keydown', function(e) {
var info = meta(e);
if (info) {
e.preventDefault();
animate(info[0], square[info[0]] + info[1], 1000);
};
});
document.body.addEventListener('keyup', function(e) {
var info = meta(e);
if (info) {
e.preventDefault();
animate(info[0], square[info[0]], 1000);
};
});
};
Thanks in advance !
i will not give you full code, but will show you the way. Do not forget to use several layers. It is 100x faster. http://jsfiddle.net/HG752/7/
Also think about having digital smarter version of map, that you can check on every move. Like matrix where 1 block is 10x10 pixels having true/false. Also on redraw do just minimal things. For example calculating var img_back and var imgData on each redraw is big mistake. But this is just example :)
var canvas = document.getElementById('canvas');
var canvas_back = document.getElementById('canvas_back');
...
var img_back = canvas_back.getContext('2d').getImageData(0, 0, W, H);
var imgData = img_back.data;
var x = (Math.round(square.x) + Math.round(square.y)*W) * 4;
//get background color where i am
document.getElementById('log').innerHTML = imgData[x]+'+'+imgData[x+1]+'+'+imgData[x+2];