Smooth DeviceOrientation Values - javascript

I'm trying to shift an image around based on the device orientation. But the values are very jumpy at rest, going between -1 to +2 with no movement, and I need a way to smooth it out a bit.
Is there an easy way to make this less jittery by averaging it out or something?
init();
var count = 0;
function init() {
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', function(eventData) {
// gamma is the left-to-right tilt in degrees, where right is positive
var tiltLR = eventData.gamma;
// beta is the front-to-back tilt in degrees, where front is positive
var tiltFB = eventData.beta;
// alpha is the compass direction the device is facing in degrees
var dir = eventData.alpha
// call our orientation event handler
deviceOrientationHandler(tiltLR, tiltFB, dir);
}, false);
}
}
function deviceOrientationHandler(tiltLR, tiltFB, dir) {
var logo = document.getElementById("imgLogo");
logo.style.webkitTransform = "rotate("+ tiltLR +"deg) rotate3d(1,0,0, "+ (tiltFB*-1)+"deg)";
logo.style.MozTransform = "rotate("+ tiltLR +"deg)";
logo.style.transform = "rotate("+ tiltLR +"deg) rotate3d(1,0,0, "+ (tiltFB*-1)+"deg)";
}
http://codepen.io/picard102/pen/zvOVLx

Use CSS transitions to smooth out setting CSS values.
You can try adding transition: all 0.5s;-webkit-transition: all 0.5s; to your logo. This will cause the browser to smoothly transition from one transform state to the next.
You might need to experiment a bit with this setting; and you may have to implement your own smoothing instead (in JavaScript, using JavaScript-based animation) if you're not happy with the results of CSS transition.

Related

Animate segments and position in Paper.js

I need to develop 2 animations on a polygon:
automatic rotation of each segments
the polygon follows the mouse movements
I'm trying to do that with this code:
// onMouseMove
tool.onMouseMove = function (event) {
mousePoint = event.point;
};
// onFrame
view.onFrame = function (event) {
// Animation 1: Automatic circular rotation of each segment
for (var i = 0; i < polygon.segments.length; i++) {
var offsetRotation = new Point(Math.cos(event.time + i * 2), Math.sin(event.time + i * 2)).multiply(10);
polygon.segments[i].point = polygonCached.segments[i].point.add(offsetRotation);
}
// Animation 2: the polygon moves following the mouse movements with transition
var delta = mousePoint.subtract(polygon.position).divide(15);
polygon.position = polygon.position.add(delta);
};
Here is the whole code: https://codepen.io/anon/pen/YMgEEe?editors=0010
With the above code the automatic rotation of each segments works and the polygon doesn't follow the mouse at all and also without the transition.
Instead, commenting the automatic rotation animation it correctly follows the mouse with transition.
To check if transition works I move the mouse cursor outside of browser window and then go back from another point. Now you'll see no transition when the polygon moves.
Where I'm wrong?
Just move the polygonCached as well.
polygonCached.position = polygonCached.position.add(delta);
https://codepen.io/arthursw/pen/LvKPXo
The cached version of the polygon was not moving, so each time you rotated your points, their position was reset.

Adding a scale to canvas image zoom

I'm using a some code from https://github.com/dimxasnewfrozen/Panning-Zooming-Canvas-Demos/blob/master/demo12/main.js (demo at http://dayobject.me/canvas/demo12/) to zoom in on an image using the Canvas element.
However, when zooming the jump between one zoom level and the next is too large, so I need to add a scale parameter.
How would I got about doing this?
In your main.js, you can change your zoomLevel here,
mouseWheel: function (e) {
e.preventDefault() // Please add this, coz the scroll event bubbles up to document.
var zoomLevel = 2;
...
if (delta > 0)
{
// ZOOMING IN
var zoomedX = canvasPos.deltaX - (canvasZoomX - canvasPos.deltaX);
var zoomedY = canvasPos.deltaY - (canvasZoomY - canvasPos.deltaY);
// scale the image up by 2
initialImageWidth = initialImageWidth * zoomLevel;
}
else
{
// ZOOMING OUT
var zoomedX = (canvasPos.deltaX + canvasZoomX);
var zoomedY = (canvasPos.deltaY + canvasZoomY);
// scale the image down by 2
initialImageWidth = initialImageWidth / zoomLevel;
}
}
Disclaimer: this ruins the zoomedX and zoomedY values. You gotta fix them :)
It seams to me as if the algorithm always takes half of the dimension befor the zoom. At the end of you code you see it in main.js the mouseWheel function:
initialImageWidth = initialImageWidth * 2;
the width is divided by 2 so just change the used value.
You said the step used to zoom in and out is too big.
So I suggest that you generate the new value by using the dimensions of the image you want to zoom. For example you take a percentage of the biggest dimension of the current image.
That's how you can implement a zoom function that zooms according to the dimensions of the image

Detect initial device orientation values

I'm trying to manually create a parallax effect of sorts, and so far here's my JavaScript:
var bottom = document.getElementById("bottom");
var top = document.getElementById("top");
window.addEventListener("deviceorientation", function(e) {
var gamma = e.gamma;
var beta = e.beta;
$(bottom).css('left',(gamma/2)+'px').css('top',(beta/2)+'px');
$(top).css('left',(gamma)+'px').css('top',(beta)+'px');
});
So far its working great and I have the effect I want, but the starting position of the device is not quite what I want. Currently the alpha, beta, and gamma values are only at 0,0,0 if the device is flat on the table. What I want to do is that when you load the page, that position is taken as 0,0,0.
For example, if I am reading my phone in my hand, then of course my phone is going to be at an angle already, and I want to take this starting position as 0,0,0 when the page is loaded.
So to put that into some sort of pseudo code, here's what I'm trying to achieve:
gammaOnLoad and betaOnLoad = initial device orientation
gammaCurrent and betaCurrent = e.gamma and e.beta (from event listener)
gammaDifference and betaDifference = Math.abs(gammaOnLoad - gammaCurrent)
$(elem).css('left', gammaDifference + 'px').css('top', betaDifference + 'px');
So essentially you take in the values when loading the page and use those as 0, your point of origin. This means that whatever angle your phone is at, when you load the page the image will always look normal and from there it will begin the parallax effect.
I wanted to do the same thing as you. This is very basic, but it seems to work:
$(document).ready(function() {
var origLR, origFB;
function setOrigin(eventData) {
origLR = eventData.gamma;
origFB = eventData.beta;
}
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', setOrigin, false);
setTimeout(function() {
window.removeEventListener('deviceorientation', setOrigin, false);
window.addEventListener('deviceorientation', function(eventData) {
var tiltLR = eventData.gamma,
tiltFB = eventData.beta;
tiltLR = (origLR - tiltLR);
tiltFB = (origFB - tiltFB);
deviceOrientationHandler(tiltLR, tiltFB);
}, false);
}, 100);
};
function deviceOrientationHandler(tiltLR, tiltFB) {
$('.bottom').css('transform','translateX(' + (tiltLR/5) + 'px) translateY(' + (tiltFB/5) + 'px)');
$('.top').css('transform','translateX(' + (tiltLR/2.5) + 'px) translateY(' + (tiltFB/2.5) + 'px)');
}
});
I added an event listener for 100ms that sets the initial device orientation values, then removed it and replaced it with one that calculates the difference between initial and current.
This can probably be more efficient, I'm not a particularly experienced programmer.

SVG: Scale one element of group from specified anchor point

OK, so I have a group of four elements rotating 90 degrees as I want them to, around an origin point in the middle of the four elements.
I would like to scale the top left block before and after spinning as well, outward from said origin point, but I'm having much difficulty doing so.
Here is a fiddle for my sample (read: overly simplified) progress so far:
http://jsfiddle.net/Vac2Q/2843/
The fiddle's javascript:
/* create an svg drawing */
var draw = SVG('drawing')
/* draw rectangle */
var dial = draw.circle(60)
.move(125,125)
.fill('#0099ff')
var rect_yellow = draw.rect(50,50)
.move(100,100)
.fill('gold')
var rect_blue = draw.rect(50,50)
.move(160,100)
.fill('navy')
var rect_black = draw.rect(50,50)
.move(160,160)
.fill('black')
var rect_green = draw.rect(50,50)
.move(100,160)
.fill('green')
var blades = draw.group()
.add(rect_yellow)
.add(rect_blue)
.add(rect_black)
.add(rect_green)
.back()
var angle = 0
var rotation = 90
var spin = document.getElementById('spin')
var spun = 0
/* make rectangle jump and change color on mouse over */
spin.addEventListener('click', function() {
/* calculate new ending orientation for blades */
angle += rotation
var new_rotate = angle
/* rotate the blade group */
blades.animate(1000, '>')
.rotate(new_rotate, 155, 155)
++spun
})
And here is a slightly more glamorous example of what I'm trying to do re: scaling:
The first issue is being able to determine which blade is in the top left position after a given rotation. The second issue is scaling itself; I've gotten the blade to scale, but then it goes crazy and moves off the screen at the same time. I'm not sure how to get it to scale properly from the specified origin point (the middle of the center circle).
You can use the .after() function to chain animations.
I'm not sure if I am using svg.js correctly, but here's what I did:
var rects = [rect_yellow, rect_green, rect_black, rect_blue];
// define the animations
var enlarge_blade = function() {
rects[spun % 4].animate(250, '<')
.scale(1.25, 1.25)
.translate(-38,-38);
};
function spin_anim() {
rects[spun % 4].animate(250, '>')
.scale(1, 1)
.translate(0,0)
.after(rotate_blades);
};
var rotate_blades = function() {
blades.animate(1000, '>')
.rotate(angle, 155, 155)
.after(function() {
++spun;
enlarge_blade();
title.text('spun ' + spun + ' times');
});
};
// Pre-enlarge the first (yellow) rect
enlarge_blade();
/* make rectangle jump and change color on mouse over */
spin.addEventListener('click', function() {
angle += rotation
spin_anim();
})
Demo here
I see you're using svg.js. I don't know how it treats transforms internally. But in any case. To scale an element, you typically use its center point as a reference. Therefore you should find the center point of each rect and scale it using that point. (I assume svg.js performs the required translation internally).

Animation starts moving out of position after some time

I am trying to create a sort of slideshow animation. I have the codes here: jsFiddle.
These tablets would rotate around.
The problem is that, at random times, the animation will move out of line. The wrong tablets undergo wrong animations. Here are the screenshots:
And this is how it looks like when the animations goes wrong
The main problem is I don't understand why the animation would go wrong random times. In my computer it will run properly for hours, but in other cases (especially on Safari).
You could store the expected final css values for each animated el and then in the animate callback set these values, so for each animated el something like
var el = $(selector);
el.data("finalCSS", { your expected final CSS values })
$("selector").animate({animation properties}, function() {
el.css(el.data("finalCSS")).data("finalCSS", undefined);
})
This doesn't help with figuring out why it's happening (but I can't recreate the issue myself), but provides a failsafe to make sure the layout doesn't break;
I believe this happens when you try to animate before the previous animation has ended. Use jQuery stop() just before you animate. For example:
$('#animatingDiv').stop(false, true).animate({height:300}, 200, callback);
The first param(false) will empty the animation queue on that element and the second param(true) will jumps to the end of current animation before starting a new animation.
You can do this with far less code and far fewer headaches.
1. Store your tablet position attributes in classes
.tablet1{
height:100px;
width:140px;
margin-left:-540px;
top: 200px;
z-index:10;
}
2. Use a general function to handle all your transitions.
JQuery UI will do all the work for you if you use switchClass
switchTabletsRight = function(){
var i, next, max = 5;
for(i = 1; i <= max; i++){
next = (i < max)? i + 1 : 1;
$(".tablet" + i).switchClass("tablet" + i, "tablet" + next);
}
};​
Here's the JSfiddle proof of concept: http://jsfiddle.net/nRHag/4/
You are setting CSS positions to decimal values.
img_w = $("#tablet"+num+" img").width();
img_w = img_w *140 / 600;
img_h = $("#tablet"+num+" img").height();
img_h = img_h *140 /600;
...
var new_width = $(this).width() * 140 / 600;
$(this).css('width', new_width);
var new_height = $(this).height() * 140 / 600;
$(this).css('height', new_height);
Your division could be cause decimal results which have different effects in different browsers. Sub pixel CSS positioning may be creating your unintended errors.

Categories