converting accelerometer/gyroscope values to x/y - javascript

I'm using document.mousemove to animate a gradient. I'd like to use the same function on mobile devices with an accelerometer/gyroscope, but I can't seem to translate the values.
I've tried various equations but can't seem to get things to work.
Here's my JS:
$(document).mousemove(function(event) {
windowWidth = $(window).width();
windowHeight = $(window).height();
mouseXpercentage = Math.round(event.pageX / windowWidth * 100);
mouseYpercentage = Math.round(event.pageY / windowHeight * 100);
$('.radial-gradient').css('background', 'radial-gradient(at ' + mouseXpercentage + '% ' + mouseYpercentage + '%, #72c0d4, #03373d)');
});

Related

On mousemove translate div position within a specified range

I have a wrapper called #mousearea and I have a div called #mouseshift what I would like to do is when I hover over #mousearea I would like to shift the translate3d(0,230%,0) value between a particular range.
I have got the mousemove working but I currently end up with something like translate3d(7881%,230%,0) it's just too sensetive I would like it to translate the X co-ordinate between something like 0-60% so it's far more subtle.
Here is what I have so far:
jQuery(document).ready(function($){
$('#mousearea').mousemove(function (e) {
var shiftAmount = 1;
$('#mouseshift').css(
'transform', 'rotate(90deg) translate3d(' + -e.pageY + shiftAmount + '%,230%,0)'
);
});
});
Update:
This is a little closer, except it logs the correct translate3d but doesn't apply it to #mouseshift.
$('#mousearea').mousemove(function(e){
var x = e.pageY - this.offsetTop;
var transfromPosition = 'translate3d(' + x + ', 230%, 0)';
console.log(transfromPosition);
if ((x <= 800)) {
//$('#mouseshift').css({'top': x});
$('#mouseshift').css('transform', transfromPosition);
}
});
Final Solution:
jQuery(document).ready(function($){
$('#mousearea').mousemove(function(e){
var min = 50;
var max = 70;
var x = e.pageY;
var windowHeight = window.innerHeight;
scrolled = (x / windowHeight);
percentageScrolled = scrolled * 100;
offsetScroll = max - min;
offsetPercentage = scrolled * 20;
translateX = min + offsetPercentage;
console.log(x + 'px');
console.log(windowHeight + 'px window height');
console.log(percentageScrolled + '% scrolled');
console.log(offsetScroll + 'offset scroll');
console.log(offsetPercentage + '% offset percentage');
var transfromPosition = 'rotate(90deg) translate3d(' + translateX + '%, 230%, 0)';
$('#mouseshift h1').css('transform', transfromPosition);
});
});
Convert to a reusable plugin I would like to extend this to work with more than one object now and each object would have a different max and min value:
This is what I have but it seems to effect all the items on only use on elements max and min.
$(function () {
$('#mouseshift-1, #mouseshift-2').mouseShift();
});
(function ($) {
$.fn.mouseShift = function () {
return this.each(function () {
var myEl = $(this);
var min = $(this).data('min');
var max = $(this).data('max');
$('#mousearea').mousemove(function (e) {
var yPosition = e.pageY;
var windowHeight = window.innerHeight;
scrolled = (yPosition / windowHeight);
//percentageScrolled = scrolled * 100;
offsetRange = max - min;
offsetRangePercentage = scrolled * 20;
offset = min + offsetRangePercentage;
//// Debug
console.log('max: ' + max + ', Min:' + min);
console.log(yPosition + 'px');
console.log(windowHeight + 'px window height');
//console.log(percentageScrolled + '% scrolled');
console.log(offsetRange + 'px offset scroll');
console.log(offsetRangePercentage + '% offset percentage');
var transfromPosition = 'rotate(90deg) translate3d(' + offset + '%, 230%, 0)';
myEl.css('transform', transfromPosition);
});
});
};
})(jQuery);
And some HTML for clarity:
<div class="column"><h1 id="mouseshift-1" data-min="50" data-max="70">boo</h1></div>
<div class="column"><h1 id="mouseshift-2" data-min="20" data-max="90">bah</h1></div>
<div class="column"><h1 id="mouseshift-3" data-min="80" data-max="100">bing</h1></div>
I think what you are looking for is finding an average that your can distribute. The best way to do this is to divide by the maximum amount it can move, and multiply it by the maximum value it can have, so basically:
position / maxposition * maxvalue
The first bit will return a number between 0 and 1, while the last bit will make it the value between 0 and 60. Below I have built a simply (jquery-less) version of it to show how this would work:
var mousePointer = document.getElementById('test')
document.addEventListener('mousemove', function(e){
var x = e.pageX / window.innerHeight;
x = x * -60;
mousePointer.style.webkitTransform = 'translateX(' + x + '%)';
mousePointer.style.transform = 'translateX(' + x + '%)';
})
#test {
position: absolute;
left: 50%;
top: 50%;
width: 20px;
height: 20px;
background: red;
}
<div id="test"></div>
Update: Reusable Snippet
I don't really like using jQuery, so once again it will be vanilla javascript (but it's pretty simple). Is that what you were - sort of - trying to do with the reusable plugin?
var divs = Array.prototype.slice.call(document.querySelectorAll('[data-range]'));
document.addEventListener('mousemove', function(e){
var eased = e.pageX / window.innerWidth;
divs.forEach(function(div){
var range = div.getAttribute('data-range').split(',');
var min = parseFloat(range[0]);
var max = parseFloat(range[1]);
var ease = min + (eased * (max - min));
div.style.webkitTransform = 'translateX(' + ease + '%)';
div.style.transform = 'translateX(' + ease + '%)';
});
});
div {
position: absolute;
left: 50%;
top: 50%;
width: 200px;
height: 200px;
background: gray;
}
#d2 { background: yellow; }
#d3 { background: #666; }
<div data-range="60,70" id="d1"></div>
<div data-range="-70,70" id="d2"></div>
<div data-range="-60,-70" id="d3"></div>
From simple reading, I see that you're missing a % sign. Should be like this:
$('#mousearea').mousemove(function(e){
var x = e.pageY - this.offsetTop;
var transfromPosition = 'translate3d(' + x + '%, 230%, 0)';
console.log(transfromPosition);
if ((x <= 800)) {
//$('#mouseshift').css({'top': x});
$('#mouseshift').css('transform', transfromPosition);
}
});
This should be working like your first example, where you do use % for both values inside the translate3d string.
Update:
To coerce your x Value to something between 0 and 60, you need to find a pair of possible min and max values for x. Then you can do something like what's shown in this answer:
Convert a number range to another range, maintaining ratio

Need to fit application width to device width

What do i have?
Web app(just html,css,js), application has fixed width and height (1024*768);
Android application created with cordova by web application;
Testing android application on htc desire 500 (android version 4.1.2)
Problem:
I need width of application fit to device width on all android devices. Now my application is bigger then device width.
What i tried to do?
Changed viewport meta tag in different ways like
<meta name="viewport" content="width=device-width, user-scalable=no" />
Used javascript to change app zoom (on deviceredy event)
var contentWidth = document.body.scrollWidth,
windowWidth = window.innerWidth,
newScale = windowWidth / contentWidth;
document.body.style.zoom = newScale;
Used javascript to change viewport
var ww = (jQuery(window).width() < window.screen.width) ?
jQuery(window).width() : window.screen.width;
// min width of site
var mw = 1020;
//calculate ratio
var ratio = ww / mw;
if (ww < mw) {
jQuery('meta[type="viewport"]').attr('content', 'initial-scale=' + ratio + ', maximum-scale=' + ratio + ', minimum-scale=' + ratio + ', user-scalable=yes, width=' + ww);
} else {
jQuery('meta[type="viewport"]').attr('content', 'initial-scale=1.0, maximum-scale=2, minimum-scale=1.0, user-scalable=yes, width=' + ww);
}
But solutions that i describe above can`t help. Do anyone knows solution that can help do that i need?
I have solved problem by using css transform, this css property is similar to zoom but it is supported by all modern browsers.
Notice: This solution appropriate just for fixed size layouts
Function that i wrote to solve my problem (Just put body as element, and it initial size as height and width):
/**
* #param {string} element - element to apply zooming
* #param {int} width - initial element width
* #param {int} height - initial element heigth
* #param {float} desiredZoom - which zoom you need, default value = 1
*/
function zoomElement(element, width, height, desiredZoom) {
desiredZoom = desiredZoom || 1;
var zoomX = (jQuery(window).width() * desiredZoom) / width,
zoomY = (jQuery(window).height() * desiredZoom) / height,
zoom = (zoomX < zoomY) ? zoomX : zoomY;
jQuery(element)
.css('transform', 'scale(' + zoom + ')')
.css('transform-origin', '0 0')
// Internet Explorer
.css('-ms-transform', 'scale(' + zoom + ')')
.css('-ms-transform-origin', '0 0')
// Firefox
.css('-moz-transform', 'scale(' + zoom + ')')
.css('-moz-transform-origin', '0 0')
// Opera
.css('-o-transform', 'scale(' + zoom + ')')
.css('-o-transform-origin', '0 0')
// WebKit
.css('-webkit-transform', 'scale(' + zoom + ')')
.css('-webkit-transform-origin', '0 0');
// Center element in it`s parent
(function () {
var $element = jQuery(element);
// Remove previous timeout
if ($element.data('center.timeout')) {
console.log("clear timeout");
clearTimeout($element.data('center.timeout'));
}
var timeout = setTimeout(function () {
$element.data('center.timeout', timeout);
var parentSize = {
'height' : $element.parent().height(),
'width' : $element.parent().width()
},
rect = element.get(0).getBoundingClientRect();
element.css({
'marginTop' : 0,
'marginLeft' : 0
});
// Center vertically
if (parentSize.height > rect.height) {
var marginTop = (parentSize.height - rect.height) / 2;
element.css('marginTop', marginTop);
}
// Center horizontally
if (parentSize.width > rect.width) {
var marginLeft = (parentSize.width - rect.width) / 2;
element.css('marginLeft', marginLeft);
}
}, 300);
})();
}

Viewport height and .css()

What I'm trying to achieve is to get the browser's viewport height and add it to several classes of my css. So far I have this:
Get viewport height:
var width = $(window).width();
var height = $(window).height();
Add to css
$('divOne').css({"height": " *viewport height* "});
$('divTwo').css({"top": " *viewport height* "});
$('divThree').css({"top": " *viewport height* + 200px"});
$('divTwo').css({"top": " *viewport height* + 400px "});
Sample:
It would be really great if someone could provide some working piece of code here. My coding skills are very limited.
Your code looks about right to me, except you have to do the math outside of the string literals, and because you're using classes, you need a class selector (e.g., ".divOne", not "divOne"), e.g.:
var width = $(window).width();
var height = $(window).height();
$('.divOne').css({"height": height + "px"});
$('.divTwo').css({"top": height + "px"});
$('.divThree').css({"top": (height + 200) + "px"});
$('.divTwo').css({"top": (height + 400) + "px"});
You probably also want to give divs two through four height, because otherwise they'll only be as tall as their content. And you need to be certain that the script operating on the divs is after the divs in the markup, so that they exist when the code runs. (Or use jQuery's ready event, but there's no need for that if you control where the script tags go.)
Here's an example that adds heights, etc.: Live Copy | Live Source
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Div Height And Such</title>
</head>
<body>
<div class="divOne">divOne</div>
<div class="divTwo">divTwo</div>
<div class="divThree">divThree</div>
<div class="divFour">divFour</div>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>
var width = $(window).width();
var height = $(window).height();
$('.divOne').css({"height": height + "px"});
$('.divTwo').css({
"top": height + "px",
"height": "200px"
});
$('.divThree').css({
"top": (height + 200) + "px",
"height": "200px"
});
$('.divTwo').css({
"top": (height + 400) + "px",
"height": "200px"
});
</script>
</body>
</html>
$('.divOne').css({
"height": $(window).height()
})
Try that... Remember the . Before divOne
Is that what you're asking for?
var height = $(window).height();
$('.divOne').css({"height": height+"px"});
$('.divTwo').css({"height": height+"px"});
$('.divTwo').css({"top": height+"px"});
$('.divThree').css({"top": height+200});
$('.divTwo').css({"top": height + 400});
Choose whichever suits you the best. I suggest pure JavaScript with variables.
// NO VARIABLES
// pure JavaScript
document.getElementById("divOne").style.height =
document.documentElement.clientHeight;
document.getElementById("divOne").style.height =
document.documentElement.clientHeight;
document.getElementById("divOne").style.height =
parseFloat(document.documentElement.clientHeight) + 200 + "px";
document.getElementById("divOne").style.height =
parseFloat(document.documentElement.clientHeight) + 400 + "px";
// jQuery
$("#divOne").style.height = $(window).height();
$("#divTwo").style.height = $(window).height();
$("#divThree").style.height = parseFloat($(window).height()) + 200 + "px";
$("#divFour").style.height = parseFloat($(window).height()) + 200 + "px";
// WITH VARIBLES
// pure JavaScript <-- SUGGESTED
var viewportHeight = parseFloat(document.documentElement.clientHeight);
document.getElementById("divOne").style.height = viewportHeight + "px";
document.getElementById("divTwo").style.height = viewportHeight + "px";
document.getElementById("divThree").style.height =
viewportHeight + 200 + "px";
document.getElementById("divFour").style.height =
viewportHeight + 400 + "px";
// jQuery
var viewportHeight = parseFloat($(window).height());
$("#divOne").style.height = viewportHeight + "px";
$("#divTwo").style.height = viewportHeight + "px";
$("#divThree").style.height = viewportHeight + 200 + "px";
$("#divFour").style.height = viewportHeight + 400 + "px";

Pinch to zoom with CSS3

I'm trying to implement pinch-to-zoom gestures exactly as in Google Maps. I watched a talk by Stephen Woods - "Creating Responsive HTML5 Touch Interfaces” - about the issue and used the technique mentioned. The idea is to set the transform origin of the target element at (0, 0) and scale at the point of the transform. Then translate the image to keep it centered at the point of transform.
In my test code scaling works fine. The image zooms in and out fine between subsequent translations. The problem is I am not calculating the translation values properly. I am using jQuery and Hammer.js for touch events. How can I adjust my calculation in the transform callback so that the image stays centered at the point of transform?
The CoffeeScript (#test-resize is a div with a background image)
image = $('#test-resize')
hammer = image.hammer ->
prevent_default: true
scale_treshold: 0
width = image.width()
height = image.height()
toX = 0
toY = 0
translateX = 0
translateY = 0
prevScale = 1
scale = 1
hammer.bind 'transformstart', (event) ->
toX = (event.touches[0].x + event.touches[0].x) / 2
toY = (event.touches[1].y + event.touches[1].y) / 2
hammer.bind 'transform', (event) ->
scale = prevScale * event.scale
shiftX = toX * ((image.width() * scale) - width) / (image.width() * scale)
shiftY = toY * ((image.height() * scale) - height) / (image.height() * scale)
width = image.width() * scale
height = image.height() * scale
translateX -= shiftX
translateY -= shiftY
css = 'translateX(' + #translateX + 'px) translateY(' + #translateY + 'px) scale(' + scale + ')'
image.css '-webkit-transform', css
image.css '-webkit-transform-origin', '0 0'
hammer.bind 'transformend', () ->
prevScale = scale
I managed to get it working.
jsFiddle demo
In the jsFiddle demo, clicking on the image represents a pinch gesture centred at the click point. Subsequent clicks increase the scale factor by a constant amount. To make this useful, you would want to make the scale and translate computations much more often on a transform event (hammer.js provides one).
The key to getting it to work was to correctly compute the point of scale coordinates relative to the image. I used event.clientX/Y to get the screen coordinates. The following lines convert from screen to image coordinates:
x -= offset.left + newX
y -= offset.top + newY
Then we compute a new size for the image and find the distances to translate by. The translation equation is taken from Stephen Woods' talk.
newWidth = image.width() * scale
newHeight = image.height() * scale
newX += -x * (newWidth - image.width) / newWidth
newY += -y * (newHeight - image.height) / newHeight
Finally, we scale and translate
image.css '-webkit-transform', "scale3d(#{scale}, #{scale}, 1)"
wrap.css '-webkit-transform', "translate3d(#{newX}px, #{newY}px, 0)"
We do all our translations on a wrapper element to ensure that the translate-origin stays at the top left of our image.
I successfully used that snippet to resize images on phonegap, using hammer and jquery.
If it interests someone, i translated this to JS.
function attachPinch(wrapperID,imgID)
{
var image = $(imgID);
var wrap = $(wrapperID);
var width = image.width();
var height = image.height();
var newX = 0;
var newY = 0;
var offset = wrap.offset();
$(imgID).hammer().on("pinch", function(event) {
var photo = $(this);
newWidth = photo.width() * event.gesture.scale;
newHeight = photo.height() * event.gesture.scale;
// Convert from screen to image coordinates
var x;
var y;
x -= offset.left + newX;
y -= offset.top + newY;
newX += -x * (newWidth - width) / newWidth;
newY += -y * (newHeight - height) / newHeight;
photo.css('-webkit-transform', "scale3d("+event.gesture.scale+", "+event.gesture.scale+", 1)");
wrap.css('-webkit-transform', "translate3d("+newX+"px, "+newY+"px, 0)");
width = newWidth;
height = newHeight;
});
}
I looked all over the internet, and outernet whatever, until I came across the only working plugin/library - http://cubiq.org/iscroll-4
var myScroll;
myScroll = new iScroll('wrapper');
where wrapper is your id as in id="wrapper"
<div id="wrapper">
<img src="smth.jpg" />
</div>
Not a real answer, but a link to a plug=in that does it all for you. Great work!
https://github.com/timmywil/jquery.panzoom
(Thanks 'Timmywil', who-ever you are)
This is something I wrote a few years back in Java and recently converted to JavaScript
function View()
{
this.pos = {x:0,y:0};
this.Z = 0;
this.zoom = 1;
this.scale = 1.1;
this.Zoom = function(delta,x,y)
{
var X = x-this.pos.x;
var Y = y-this.pos.y;
var scale = this.scale;
if(delta>0) this.Z++;
else
{
this.Z--;
scale = 1/scale;
}
this.zoom = Math.pow(this.scale, this.Z);
this.pos.x+=X-scale*X;
this.pos.y+=Y-scale*Y;
}
}
The this.Zoom = function(delta,x,y) takes:
delta = zoom in or out
x = x position of the zoom origin
y = y position of the zoom origin
A small example:
<script>
var view = new View();
var DivStyle = {x:-123,y:-423,w:300,h:200};
function OnMouseWheel(event)
{
event.preventDefault();
view.Zoom(event.wheelDelta,event.clientX,event.clientY);
div.style.left = (DivStyle.x*view.zoom+view.pos.x)+"px";
div.style.top = (DivStyle.y*view.zoom+view.pos.y)+"px";
div.style.width = (DivStyle.w*view.zoom)+"px";
div.style.height = (DivStyle.h*view.zoom)+"px";
}
function OnMouseMove(event)
{
view.pos = {x:event.clientX,y:event.clientY};
div.style.left = (DivStyle.x*view.zoom+view.pos.x)+"px";
div.style.top = (DivStyle.y*view.zoom+view.pos.y)+"px";
div.style.width = (DivStyle.w*view.zoom)+"px";
div.style.height = (DivStyle.h*view.zoom)+"px";
}
</script>
<body onmousewheel="OnMouseWheel(event)" onmousemove="OnMouseMove(event)">
<div id="div" style="position:absolute;left:-123px;top:-423px;width:300px;height:200px;border:1px solid;"></div>
</body>
This was made with the intention of being used with a canvas and graphics, but it should work perfectly for normal HTML layout

Mouse on left of screen move image to left, same when mouse on right of screen

I'm trying to get an image that is around 1920x1200px to pan around on a 800x600px browser window.
So if my mouse is on the top-left of the browser window the image is alined so it's top-left margins are on the top-left of the browser window. The same goes for the bottum-right.
So if the mouse is in the centre of the screen the image should be centered too.
Im not sure what calculations are needed as my math is a bit rusty.
Currently I'm using a bit of javascript that just moves the image using CSS's top/left properties but without much success as it's just moving the picture around from it's top/left corner.
I'v also set the image's position to absolute in css.
function updateImgPosition( e )
{
var avatar = document.getElementById("avatar");
// Width
var windowWidth = window.innerWidth;
var mouseWidthLocation = e.x;
var percentOfWidth = (100 / windowWidth) * mouseWidthLocation;
// Height
var windowHeight = window.innerHeight;
var mouseHeightLocation = e.y;
var percentOfHeight = (100 / windowHeight) * mouseHeightLocation;
avatar.style.top = percentOfHeight + "%";
avatar.style.left = percentOfWidth + "%";
}
document.onmousemove = updateImgPosition;
This is a demo of what I have: http://jsfiddle.net/uQAmQ/1/
Fiddle: http://jsfiddle.net/uQAmQ/2/
You should not "pan" on an absolutely positioned element, because the window's width and height keep changing according to the image. A smoother solution involves using a background image. See the middle of my answer for the used logic.
Consider this JavaScript (read comments; HTML + CSS at fiddle):
(function(){ //Anonymous function wrapper for private variables
/* Static variables: Get the true width and height of the image*/
var avatar = document.getElementById("avatar");
var avatarWidth = avatar.width;
var avatarHeight = avatar.height;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
/* Logic: Move */
var ratioY = (avatarHeight - windowHeight) / windowHeight;
var ratioX = (avatarWidth - windowWidth) / windowWidth;
function updateImgPosition( e ) {
var mouseY = e.pageX; //e.pageX, NOT e.x
var mouseX = e.pageY;
var imgTop = ratioY*(-mouseY);
var imgLeft = ratioX*(-mouseX);
document.body.style.backgroundPosition = imgLeft + "px " + imgTop + "px";
}
/* Add event to WINDOW, NOT "document"! */
window.onmousemove = updateImgPosition;
})();
The logic behind it:
Relative units cannot be used, because the image size is specified in absolute units.
The offsets should change according to a specific ratio, which is similar to: image size divided by window size.However, this ratio is not complete: The image would disappear at the bottom/left corner of the window. To fix this, substract the window's size from the image's size. The result can be found in the code at variable ratioX and ratioY.
The previous code had to be loaded at the window.onload event, because the image's size was dynamically calculated. For this reason, a HTML element was also included in the body.
The same code can be written much smaller and efficient, by specifying the size of the background in the code. See this improved code. Fiddle: http://jsfiddle.net/uQAmQ/3/
(function(){ //Anonymous function wrapper for private variables
/* Static variables: Get the true width and height of the image*/
var avatarWidth = 1690;
var avatarHeight = 1069;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
/* Logic: Move */
var ratioY = (avatarHeight - windowHeight) / windowHeight;
var ratioX = (avatarWidth - windowWidth) / windowWidth;
function updateImgPosition( e ) {
var mouseX = e.pageX; //e.pageX, NOT e.x
var mouseY = e.pageY;
var imgTop = ratioY*(-mouseY);
var imgLeft = ratioX*(-mouseX);
document.body.style.backgroundPosition = imgLeft + "px " + imgTop + "px";
}
/* Add event to WINDOW, NOT "document"! */
window.onmousemove = updateImgPosition;
})();
If you don't mind a decreased code readability, the following code is the best solution, Fiddle: http://jsfiddle.net/uQAmQ/4/:
(function(){ //Anonymous function wrapper for private variables
/* Static variables: Get the true width and height of the image*/
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var ratioY = (windowHeight - 1069) / windowHeight;
var ratioX = (windowWidth - 1690) / windowWidth;
window.onmousemove = function( e ) {
document.body.style.backgroundPosition = ratioX * e.pageX + "px " + ratioY * e.pageY + "px";
}
})();

Categories

Resources