I am trying to make an image rotate when you hover over certain items on the page. It uses the solution provided here (with edits for my purposes): https://stackoverflow.com/a/10235298. You can see an example of what I am trying to achieve here: https://jsfiddle.net/t100gq25/
$(function () {
var img = $('.arrow');
if (img.length > 0) {
var offset = img.offset();
$('.animation-trigger').mouseenter(function (event) {
var element = $(this);
var elementPosition = element.offset();
var elementX = elementPosition.left + (element.width() / 2);
var elementY = elementPosition.top + (element.height() / 2);
var imgX = offset.left + (img.width() / 2);
var imgY = offset.top + (img.height() / 2);
var radians = Math.atan2(elementX - imgX, elementY - imgY);
var degrees = (radians * (180 / Math.PI) * -1) + 90;
img.css('-moz-transform', 'rotate(' + degrees + 'deg)')
.css('-webkit-transform', 'rotate(' + degrees + 'deg)')
.css('-o-transform', 'rotate(' + degrees + 'deg)')
.css('-ms-transform', 'rotate(' + degrees + 'deg)');
});
}
});
body {
padding-top: 150px;
}
.container {
height: 500px;
}
.menu-1,
.menu-2,
.menu-3,
.menu-4 {
position: absolute;
z-index: 99
}
.menu-1 {
top: 20%;
left: 20%;
}
.menu-2 {
top: 20%;
right: 20%;
}
.menu-3 {
bottom: 20%;
left: 20%;
}
.menu-4 {
bottom: 20%;
right: 20%;
}
.arrow {
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -100px;
height: 200px;
width: 200px;
-webkit-transition: all 400ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
-moz-transition: all 400ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
-o-transition: all 400ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
transition: all 400ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<a href="#" class="menu-1">
<img src="http://placehold.it/140x35&text=4" class="animation-trigger">
</a>
<a href="#" class="menu-2">
<img src="http://placehold.it/140x35&text=1" class="animation-trigger">
</a>
<a href="#" class="menu-3">
<img src="http://placehold.it/140x35&text=3" class="animation-trigger">
</a>
<a href="#" class="menu-4">
<img src="http://placehold.it/140x35&text=2" class="animation-trigger">
</a>
<img src="https://image.freepik.com/free-icon/arrow-full-shape-pointing-to-right-direction_318-32063.png" class="arrow">
It works great! However if you hover over link 1, the arrow will turn to it and then you decide to hover over link 4 and the arrow will again point to it. However it goes all the way around (clockwise) instead of taking the short route of just spinning back(anti-clockwise).
I've had a go at a few attempts but none have worked and if I come up with an idea that could work it's extremely long winded. I'm struggling to work out the best way to approach this so any help would be very much appreciated.
Please note the jsfiddle is a quick mock up example of what I am trying to achieve. Unfortunately I cannot share the actual source code due to client confidentiality. Any solutions provided I will apply to the final site.
Many thanks:)
You will need to store all elements degrees and check if arrow needs to rotate clockwise or anti-clockwise for shortest rotation.
$(function() {
var img = $('.arrow');
// Store clock wise degrees of all elements
var clockwiseElemDegrees = {};
var currentArrowAngle = 0;
// Treat initial position of arrow as element 0
var prevElem = '0';
clockwiseElemDegrees['0'] = 0;
if (img.length > 0) {
var offset = img.offset();
var imgX = offset.left + (img.width() / 2);
var imgY = offset.top + (img.height() / 2);
// Get element degrees
$('.animation-trigger').each(function() {
var element = $(this);
var elementPosition = element.offset();
var elementX = elementPosition.left + (element.width() / 2);
var elementY = elementPosition.top + (element.height() / 2);
var radians = Math.atan2(elementY - imgY, elementX - imgX);
var degrees = radians * (180 / Math.PI);
clockwiseElemDegrees[element.attr('elem')] = (degrees < 0) ? (degrees + 360) : degrees;
});
$('.animation-trigger').mouseenter(function(event) {
// Check if arrow should be rotated clockwise
var clockwiseDegreesForNextElem = clockwiseElemDegrees[$(this).attr('elem')];
var clockwiseDegreesForPrevElem = clockwiseElemDegrees[prevElem];
if (clockwiseDegreesForNextElem < clockwiseDegreesForPrevElem)
clockwiseDegreesForNextElem += 360;
var clockwiseRotationRequired = clockwiseDegreesForNextElem - clockwiseDegreesForPrevElem;
if (clockwiseRotationRequired <= 180) {
// Do clockwise rotation
currentArrowAngle += clockwiseRotationRequired;
} else {
// Do anticlockwise rotation
currentArrowAngle -= (360 - clockwiseRotationRequired);
}
prevElem = $(this).attr('elem');
img.css('-moz-transform', 'rotate(' + currentArrowAngle + 'deg)')
.css('-webkit-transform', 'rotate(' + currentArrowAngle + 'deg)')
.css('-o-transform', 'rotate(' + currentArrowAngle + 'deg)')
.css('-ms-transform', 'rotate(' + currentArrowAngle + 'deg)');
});
}
});
body {
padding-top: 150px;
}
.container {
height: 500px;
}
.menu-1,
.menu-2,
.menu-3,
.menu-4 {
position: absolute;
z-index: 99
}
.menu-1 {
top: 20%;
left: 20%;
}
.menu-2 {
top: 20%;
right: 20%;
}
.menu-3 {
bottom: 20%;
left: 20%;
}
.menu-4 {
bottom: 20%;
right: 20%;
}
.arrow {
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -100px;
height: 200px;
width: 200px;
-webkit-transition: all 400ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
-moz-transition: all 400ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
-o-transition: all 400ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
transition: all 400ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<a href="#" class="menu-1">
<img src="http://placehold.it/140x35&text=4" class="animation-trigger" elem="1">
</a>
<a href="#" class="menu-2">
<img src="http://placehold.it/140x35&text=1" class="animation-trigger" elem="2">
</a>
<a href="#" class="menu-3">
<img src="http://placehold.it/140x35&text=3" class="animation-trigger" elem="3">
</a>
<a href="#" class="menu-4">
<img src="http://placehold.it/140x35&text=2" class="animation-trigger" elem="4">
</a>
<img src="https://image.freepik.com/free-icon/arrow-full-shape-pointing-to-right-direction_318-32063.png" class="arrow">
Related
In JS I have some code that transform rotates the heads of my three sprites to follow the cursor on the screen. Additionally, I have a CSS keyframe animation I made to sort of "rattle the heads". My issue is, that this animation uses what seems to be a datum of 0deg and I want it to instead use the current angle with the mouse as the centre.
I have this value as angle1, 2, 3, in JS but not in CSS. Is there a way to use this angle in CSS? So instead my animation would do something like transform: rotate(baseAngle + 90) etc? See below for SC.
I also a feel a gif of the behaviour is pretty valuable here:
https://gyazo.com/90855776c7803c63b72d378cb4a3c194
JS for tracking mouse movement:
(function() {
document.onmousemove = handleMouseMove;
function handleMouseMove(event) {
var scrollMaxY, dot, eventDoc, doc, body, pageX, pageY;
// IE-isms
event = event || window.event;
maxY = window.innerHeight || (document.documentElement.innerHeight - document.documentElement.clientHeight)
// If pageX/Y aren't available and clientX/Y are,
if (event.pageX == null && event.clientX != null) {
eventDoc = (event.target && event.target.ownerDocument) || document;
doc = eventDoc.documentElement;
body = eventDoc.body;
event.pageX = event.clientX +
(doc && doc.scrollLeft || body && body.scrollLeft || 0) -
(doc && doc.clientLeft || body && body.clientLeft || 0);
event.pageY = event.clientY +
(doc && doc.scrollTop || body && body.scrollTop || 0) -
(doc && doc.clientTop || body && body.clientTop || 0 );
}
// TODO: Use x/y values to rotate heads
angle1 = Math.atan2( event.pageY - head1[0], event.pageX - head1[1]);
angle2 = Math.atan2( event.pageY - head2[0], event.pageX - head2[1]);
angle3 = Math.atan2( event.pageY - head3[0], event.pageX - head3[1]);
$("#kodama-head1").css("transform", "rotate(" + angle1 + "rad)");
$("#kodama-head2").css("transform", "rotate(" + angle2 + "rad)");
$("#kodama-head3").css("transform", "rotate(" + angle3 + "rad)");
}
})();
My CSS keyframes animation:
#keyframes RattleHeads {
0% {
transform: rotate(90deg);
-webkit-transition: all 600ms cubic-bezier(0.075, 0.82, 0.165, 1);
transition: all 600ms cubic-bezier(0.075, 0.82, 0.165, 1);
}
55% {
transform: rotate(-60deg);
}
69% {
transform: rotate(45deg);
}
78% {
transform: rotate(-30deg);
}
85% {
transform: rotate(20deg);
}
91% {
transform: rotate(-15deg);
}
95% {
transform: rotate(10deg);
}
98% {
transform: rotate(-5deg);
}
100% {
transform: rotate(0deg);
}
}
Lastly, the JS being used to apply rattling animation:
$("body").click(function(){
var KodamaHead;
var random = Math.random() * 3;
if (random > 2){
KodamaHead = $("#kodama-head3");
}
else if (random > 1){
KodamaHead = $("#kodama-head2");
}
else{
KodamaHead = $("#kodama-head1");
}
// add animation
KodamaHead.addClass("rattling");
// remove animation on completion
KodamaHead.one("webkitAnimationEnd oanimationend oAnimationEnd msAnimationEnd animationend",
function(e) {
$(this).removeClass("rattling");
});
});
Simply wrap your head element inside an other element.
The transform of the inner element will now be relative to the one of the wrapper.
In the following example, we apply the mouse driven rotation to the inner .head elements, while applying the CSS driven one (onclick) on the .wrapper elements.
Since here both share the same transform-origin , it could also have been done the other way around.
$("body").click(function() {
var random = Math.floor(Math.random() * 3);
// Target one of the `.wrapper` elements
var KodamaHead = $('.persona .wrapper').eq(random);
// add animation
KodamaHead.addClass("rattling");
// remove animation on completion
KodamaHead.one("webkitAnimationEnd oanimationend oAnimationEnd msAnimationEnd animationend",
function(e) {
$(this).removeClass("rattling");
});
});
(function() {
// get Elements rotation anchor
var head1 = getAnchor('#kodama-head1');
var head2 = getAnchor('#kodama-head2');
var head3 = getAnchor('#kodama-head3');
document.onmousemove = handleMouseMove;
function handleMouseMove(event) {
// removed some backward compatibility fluffs
// feel free to add it back
// calculations were off by half a π
angle1 = Math.atan2(event.pageY - head1[0], event.pageX - head1[1]) - Math.PI / 2;
angle2 = Math.atan2(event.pageY - head2[0], event.pageX - head2[1]) - Math.PI / 2;
angle3 = Math.atan2(event.pageY - head3[0], event.pageX - head3[1]) - Math.PI / 2;
$("#kodama-head1").css("transform", "rotate(" + angle1 + "rad)");
$("#kodama-head2").css("transform", "rotate(" + angle2 + "rad)");
$("#kodama-head3").css("transform", "rotate(" + angle3 + "rad)");
}
})();
// get anchor position (center, center)
function getAnchor(sel) {
var el = document.querySelector(sel),
rect = el.getBoundingClientRect();
return [rect.top + rect.height / 2, rect.left + rect.width / 2];
}
.rattling {
animation: RattleHeads 2s linear;
}
.persona {
display: inline-block;
height: 90vh;
width: 20vw;
border: 1px solid;
}
.head {
display: inline-block;
height: 20vw;
width: 20vw;
border: 1px solid;
position: relative;
}
.head::before,
.head::after {
content: '•';
color: white;
font-size: 18px;
line-height: 12px;
width: 2vmax;
height: 2vmin;
position: absolute;
top: 5vw;
left: 7vw;
background: black;
border-radius: 20%;
}
.head::after {
left: auto;
right: 7vw;
}
#keyframes RattleHeads {
0% {
transform: rotate(0deg);
}
55% {
transform: rotate(-60deg);
}
69% {
transform: rotate(45deg);
}
78% {
transform: rotate(-30deg);
}
85% {
transform: rotate(20deg);
}
91% {
transform: rotate(-15deg);
}
95% {
transform: rotate(10deg);
}
98% {
transform: rotate(-5deg);
}
100% {
transform: rotate(0deg);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="persona">
<div class="wrapper"><!-- rattling -->
<div id="kodama-head1" class="head"><!-- look-at -->
</div>
</div>
</div>
<div class="persona">
<div class="wrapper"><!-- rattling -->
<div id="kodama-head2" class="head"><!-- look-at -->
</div>
</div>
</div>
<div class="persona">
<div class="wrapper"><!-- rattling -->
<div id="kodama-head3" class="head"><!-- look-at -->
</div>
</div>
</div>
Got some math issues in my code that i can't figure out.
When you press on one of the red circles it should take the closest path (left or right) and rotate down to the bottom, it's kinda working, but there are a few issues with it.
e.g. If you start by pressing '8' and then '3', the container is only rotating 45 degrees in the wrong direction.
And the second issue is that the numbers are spinning around when the wheel is rotating.
Here is a jsfiddle to the code: https://jsfiddle.net/she4x2w6/10/
$('.item').click(function() {
var currentId = $('#container').data('id');
var nextId = $(this).data('id');
var currentRotation = (360 / items.length) * currentId - (360 / items.length);
var nextRotation = (360 / items.length) * nextId - (360 / items.length);
var deg;
if (currentRotation - nextRotation > 180 || nextRotation - currentRotation > 180) {
deg = nextRotation > 180 ? 360 - nextRotation : nextRotation - 360;
} else {
deg = -Math.abs(nextRotation);
}
var itemDeg = nextRotation <= 180 ? nextRotation : -Math.abs(360 - nextRotation);
$('#container').css({
transition: 'transform 0.6s',
transform: 'rotate(' + deg + 'deg)'
})
$('.item').css({
transition: 'transform 0.6s',
transform: 'rotate(' + itemDeg + 'deg)'
})
CSS rotate() function rotates an element to given angle while you are trying to rotate your element by a given angle.
rotate() -CSS | MDN
I had to change some of your approach to get it working:
var radius = 100; // adjust to move out items in and out
var items = $('.item'),
container = $('#container'),
width = container.width(),
height = container.height();
var angle = 0,
step = (2 * Math.PI) / items.length,
angle = Math.PI/2;
items.each(function() {
var x = Math.round(width / 2 + radius * Math.cos(angle) - $(this).width() / 2);
var y = Math.round(height / 2 + radius * Math.sin(angle) - $(this).height() / 2);
$(this).css({
left: x + 'px',
top: y + 'px'
});
angle += step;
});
$('#container').data('deg', 0);
$('.item').click(function() {
var currentId = $('#container').data('id');
var nextId = $(this).data('id');
var currentDeg =$('#container').data('deg');
var deg;
var degg = ((nextId+items.length-1)%items.length)*(360 / items.length);
if (degg>=180) {
deg = 360-degg;
} else {
deg = -degg;
}
var t = (currentDeg - deg) % 360;
if (t<0) {
t = 360+t;
}
if (t<180) {
deg = currentDeg-t;
} else {
deg = currentDeg+360-t;
}
var itemDeg = -deg;
var time = Math.abs(deg-currentDeg)/100;
$('#container').css({
transition: 'transform ' + time + 's',
transform: 'rotate(' + deg + 'deg)'
})
$('.item').css({
transition: 'transform ' + time + 's',
transform: 'rotate(' + itemDeg + 'deg)'
})
$('#container').data('id', nextId).data('deg', deg);
});
body {
padding: 2em;
}
#container {
width: 200px;
height: 200px;
margin: 10px auto;
border: 1px solid #000;
position: relative;
border-radius: 50%;
}
.item {
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
border-radius: 50%;
position: absolute;
background: #f00;
}
.item p {
margin: 0;
}
.active .item-content {
opacity: 1 !important;
transition: opacity ease 0.6s;
}
.item .item-content {
opacity: 0;
transition: opacity ease 0.3s;
margin: auto;
position: absolute;
width: 230px;
transform: translate(-50%);
left: 50%;
pointer-events: none;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container" data-id="1">
<div data-id="1" class="item">1</div>
<div data-id="2" class="item">2</div>
<div data-id="3" class="item">3</div>
<div data-id="4" class="item">4</div>
<div data-id="5" class="item">5</div>
<div data-id="6" class="item">6</div>
<div data-id="7" class="item">7</div>
<div data-id="8" class="item">8</div>
<div data-id="9" class="item">9</div>
</div>
/**
* tiltfx.js
* http://www.codrops.com
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2015, Codrops
* http://www.codrops.com
*/
;
(function(window) {
'use strict';
/**
* **************************************************************************
* utils
* **************************************************************************
*/
// from https://gist.github.com/desandro/1866474
var lastTime = 0;
var prefixes = 'webkit moz ms o'.split(' ');
// get unprefixed rAF and cAF, if present
var requestAnimationFrame = window.requestAnimationFrame;
var cancelAnimationFrame = window.cancelAnimationFrame;
// loop through vendor prefixes and get prefixed rAF and cAF
var prefix;
for (var i = 0; i < prefixes.length; i++) {
if (requestAnimationFrame && cancelAnimationFrame) {
break;
}
prefix = prefixes[i];
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame'];
cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] ||
window[prefix + 'CancelRequestAnimationFrame'];
}
// fallback to setTimeout and clearTimeout if either request/cancel is not supported
if (!requestAnimationFrame || !cancelAnimationFrame) {
requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
cancelAnimationFrame = function(id) {
window.clearTimeout(id);
};
}
function extend(a, b) {
for (var key in b) {
if (b.hasOwnProperty(key)) {
a[key] = b[key];
}
}
return a;
}
// from http://www.quirksmode.org/js/events_properties.html#position
function getMousePos(e) {
var posx = 0;
var posy = 0;
if (!e) var e = window.event;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
} else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
return {
x: posx,
y: posy
}
}
// from http://www.sberry.me/articles/javascript-event-throttling-debouncing
function throttle(fn, delay) {
var allowSample = true;
return function(e) {
if (allowSample) {
allowSample = false;
setTimeout(function() {
allowSample = true;
}, delay);
fn(e);
}
};
}
/***************************************************************************/
/**
* TiltFx fn
*/
function TiltFx(el, options) {
this.el = el;
this.options = extend({}, this.options);
extend(this.options, options);
this._init();
this._initEvents();
}
/**
* TiltFx options.
*/
TiltFx.prototype.options = {
// number of extra image elements (div with background-image) to add to the DOM - min:1, max:5 (for a higher number, it's recommended to remove the transitions of .tilt__front in the stylesheet.
extraImgs: 2,
// the opacity value for all the image elements.
opacity: 0.7,
// by default the first layer does not move.
bgfixed: true,
// image element's movement configuration
movement: {
perspective: 1000, // perspective value
translateX: -10, // a relative movement of -10px to 10px on the x-axis (setting a negative value reverses the direction)
translateY: -10, // a relative movement of -10px to 10px on the y-axis
translateZ: 20, // a relative movement of -20px to 20px on the z-axis (perspective value must be set). Also, this specific translation is done when the mouse moves vertically.
rotateX: 2, // a relative rotation of -2deg to 2deg on the x-axis (perspective value must be set)
rotateY: 2, // a relative rotation of -2deg to 2deg on the y-axis (perspective value must be set)
rotateZ: 0 // z-axis rotation; by default there's no rotation on the z-axis (perspective value must be set)
}
}
/**
* Initialize: build the necessary structure for the image elements and replace it with the HTML img element.
*/
TiltFx.prototype._init = function() {
this.tiltWrapper = document.createElement('div');
this.tiltWrapper.className = 'tilt';
// main image element.
this.tiltImgBack = document.createElement('div');
this.tiltImgBack.className = 'tilt__back';
this.tiltImgBack.style.backgroundImage = 'url(' + this.el.src + ')';
this.tiltWrapper.appendChild(this.tiltImgBack);
// image elements limit.
if (this.options.extraImgs < 1) {
this.options.extraImgs = 1;
} else if (this.options.extraImgs > 5) {
this.options.extraImgs = 5;
}
if (!this.options.movement.perspective) {
this.options.movement.perspective = 0;
}
// add the extra image elements.
this.imgElems = [];
for (var i = 0; i < this.options.extraImgs; ++i) {
var el = document.createElement('div');
el.className = 'tilt__front';
el.style.backgroundImage = 'url(' + this.el.src + ')';
el.style.opacity = this.options.opacity;
this.tiltWrapper.appendChild(el);
this.imgElems.push(el);
}
if (!this.options.bgfixed) {
this.imgElems.push(this.tiltImgBack);
++this.options.extraImgs;
}
// add it to the DOM and remove original img element.
this.el.parentNode.insertBefore(this.tiltWrapper, this.el);
this.el.parentNode.removeChild(this.el);
// tiltWrapper properties: width/height/left/top
this.view = {
width: this.tiltWrapper.offsetWidth,
height: this.tiltWrapper.offsetHeight
};
};
/**
* Initialize the events on the main wrapper.
*/
TiltFx.prototype._initEvents = function() {
var self = this,
moveOpts = self.options.movement;
// mousemove event..
this.tiltWrapper.addEventListener('mousemove', function(ev) {
requestAnimationFrame(function() {
// mouse position relative to the document.
var mousepos = getMousePos(ev),
// document scrolls.
docScrolls = {
left: document.body.scrollLeft + document.documentElement.scrollLeft,
top: document.body.scrollTop + document.documentElement.scrollTop
},
bounds = self.tiltWrapper.getBoundingClientRect(),
// mouse position relative to the main element (tiltWrapper).
relmousepos = {
x: mousepos.x - bounds.left - docScrolls.left,
y: mousepos.y - bounds.top - docScrolls.top
};
// configure the movement for each image element.
for (var i = 0, len = self.imgElems.length; i < len; ++i) {
var el = self.imgElems[i],
rotX = moveOpts.rotateX ? 2 * ((i + 1) * moveOpts.rotateX / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.rotateX / self.options.extraImgs) : 0,
rotY = moveOpts.rotateY ? 2 * ((i + 1) * moveOpts.rotateY / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateY / self.options.extraImgs) : 0,
rotZ = moveOpts.rotateZ ? 2 * ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) : 0,
transX = moveOpts.translateX ? 2 * ((i + 1) * moveOpts.translateX / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.translateX / self.options.extraImgs) : 0,
transY = moveOpts.translateY ? 2 * ((i + 1) * moveOpts.translateY / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateY / self.options.extraImgs) : 0,
transZ = moveOpts.translateZ ? 2 * ((i + 1) * moveOpts.translateZ / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateZ / self.options.extraImgs) : 0;
el.style.WebkitTransform = 'perspective(' + moveOpts.perspective + 'px) translate3d(' + transX + 'px,' + transY + 'px,' + transZ + 'px) rotate3d(1,0,0,' + rotX + 'deg) rotate3d(0,1,0,' + rotY + 'deg) rotate3d(0,0,1,' + rotZ + 'deg)';
el.style.transform = 'perspective(' + moveOpts.perspective + 'px) translate3d(' + transX + 'px,' + transY + 'px,' + transZ + 'px) rotate3d(1,0,0,' + rotX + 'deg) rotate3d(0,1,0,' + rotY + 'deg) rotate3d(0,0,1,' + rotZ + 'deg)';
}
});
});
// reset all when mouse leaves the main wrapper.
this.tiltWrapper.addEventListener('mouseleave', function(ev) {
setTimeout(function() {
for (var i = 0, len = self.imgElems.length; i < len; ++i) {
var el = self.imgElems[i];
el.style.WebkitTransform = 'perspective(' + moveOpts.perspective + 'px) translate3d(0,0,0) rotate3d(1,1,1,0deg)';
el.style.transform = 'perspective(' + moveOpts.perspective + 'px) translate3d(0,0,0) rotate3d(1,1,1,0deg)';
}
}, 60);
});
// window resize
window.addEventListener('resize', throttle(function(ev) {
// recalculate tiltWrapper properties: width/height/left/top
self.view = {
width: self.tiltWrapper.offsetWidth,
height: self.tiltWrapper.offsetHeight
};
}, 50));
};
function init() {
// search for imgs with the class "tilt-effect"
[].slice.call(document.querySelectorAll('img.tilt-effect')).forEach(function(img) {
new TiltFx(img, JSON.parse(img.getAttribute('data-tilt-options')));
});
}
init();
window.TiltFx = TiltFx;
})(window);
.tilt {
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
margin: 0 auto;
}
.tilt__back {
position: relative;
}
.tilt__front {
position: absolute;
top: 0;
left: 0;
}
.tilt__back,
.tilt__front {
width: 100%;
height: 100%;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: cover;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
<div class="megawrapper">
<div class="w-section home-page" style="transform: translateX(0px) translateY(0px);">
<div class="home_logo" style="pointer-events:none;"></div>
<div class="home_centralarea" data-ix="home-darkfield" style="opacity: 1; transition: opacity 500ms;">
<div class="home_parallaxpic_wrapper">
<div class="home_parallaxpic" data-ix="home-parallaxpic" style="opacity: 0.4; transition: opacity 1000ms;">
<img class="hero__img tilt-effect" data-tilt-options='{ "extraImgs":3, "bgfixed":false, "opacity" : 0.5, "movement": { "perspective" : 1200, "translateX" : -5, "translateY" : -5, "rotateX" : -5, "rotateY" : -5 } }' src="<?php echo get_template_directory_uri(); ?>/images/road.jpeg"
/>
</div>
</div>
</div>
</div>
</div>
I want to replicate HTML structure of this website (www.danielspatzek.com/). But I cant get my divs to center properly. The website has two main divs, .home-page which contains the fully stretched background image and .tilt which injects the tiltfx effect on the background image. The div .tilt has a scaled down height/width due to a padding of 60px applied on it by its parent div .home-page
I replicated the HTML structure but when I apply the 60px padding in .home-page all divs get pushed right/down and is no longer centered.
The original website html is:
<div class="megawrapper">
<div class="w-section home-page" style="transform: translateX(0px) translateY(0px);">
<div class="home_logo" style="pointer-events:none;"></div>
<div class="home_centralarea" data-ix="home-darkfield" style="opacity: 1; transition: opacity 500ms;">
<div class="home_parallaxpic_wrapper">
<div class="home_parallaxpic" data-ix="home-parallaxpic" style="opacity: 0.4; transition: opacity 1000ms;">
<img class="hero__img tilt-effect" data-tilt-options='{ "extraImgs":3, "bgfixed":false, "opacity" : 0.5, "movement": { "perspective" : 1200, "translateX" : -5, "translateY" : -5, "rotateX" : -5, "rotateY" : -5 } }' src="<?php echo get_template_directory_uri(); ?>/images/road.jpeg" />
</div>
</div>
</div>
</div>
</div>
The javascript file tiltfx.js removes .tilt-effect and replaces it with .tilt so the HTML is:
<div class="megawrapper">
<div class="w-section home-page" style="transform: translateX(0px) translateY(0px);">
<div class="home_logo" style="pointer-events:none;"></div>
<div class="home_centralarea" data-ix="home-darkfield" style="opacity: 1; transition: opacity 0ms;">
<div class="home_parallaxpic_wrapper">
<div class="home_parallaxpic" data-ix="home-parallaxpic" style="opacity: 0.4; transition: opacity 0ms;">
<div class="tilt"><div class="tilt__back" style="background-image: url("http://www.danielspatzek.com/themes/Theme/images/bg_home_street.jpg"); transform: perspective(1200px) translate3d(0.787151px, -0.0129973px, 0px) rotate3d(1, 0, 0, -0.0129973deg) rotate3d(0, 1, 0, 0.787151deg) rotate3d(0, 0, 1, 0deg);"></div>
</div>
</div>
</div>
</div>
My recreation HTML and CSS looks like this:
<div class="megawrapper">
<div class="home-page" style="transform: translateX(0px) translateY(0px);">
<img class="tilt-effect" data-tilt-options='{ "extraImgs":3, "bgfixed":false, "opacity" : 0.5, "movement": { "perspective" : 1200, "translateX" : -5, "translateY" : -5, "rotateX" : -5, "rotateY" : -5 } }' src="<?php echo get_template_directory_uri(); ?>/images/road.jpeg" />
</div>
.megawrapper {
position: absolute;
overflow-x: hidden;
overflow-y: hidden;
width: 100%;
height: 100%;
}
.home-page {
position: absolute;
z-index: 0;
width: 100%;
height: 100%;
background-color: #3c3c3e;
background-image: url(images/road.jpeg);
background-position: 50% 50%;
background-size: cover;
background-repeat: no-repeat;
}
.tilt {
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
margin: 0 auto;
}
.tilt__back {
position: relative;
}
.tilt__front {
position: absolute;
top: 0;
left: 0;
}
.tilt__back, .tilt__front {
width: 100%;
height: 100%;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: cover;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
I cant seem to get the same layout as the website. I dont know why .tilt would not center properly when I apply padding of 60 px on .home-page. I dont want to use flexbox to achieve the same result
use box-sizing:border-box; on your .home_page it will work fine.I'm added the snippet below.
html,body{
width:100%;
height:100%;
}
.home_page{
width:100%;
height:100%;
background-color:#3c3c3e;
background-image: url(https://i.stack.imgur.com/wwy2w.jpg);
background-position: 50% 50%;
background-size: cover;
background-repeat: no-repeat;
padding:60px;
box-sizing:border-box;
}
.tilt {
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
margin: 0 auto;
background-color:yellow;
}
<div class="home_page">
<div class="tilt"></div>
</div>
Here is a good way.
<div class="divToCenterStuffIn">
<div class="vertCenter">
Vertical Center
</div>
</div>
<div class="divToCenterStuffIn">
<div class="horzCenter">
Horizontal Center
</div>
</div>
<div class="divToCenterStuffIn">
<div class="trueCenter">
True Center
</div>
</div>
.divToCenterStuffIn {
position: relative;
display: block;
width: 10rem;
height: 10rem;
}
.vertCenter
{
position: absolute;
display: block;
top:50%;
-ms-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.horzCenter
{
position: absolute;
display: block;
left: 50%;
-ms-transform: translateX(-50%);
-moz-transform: translateX(-50%);
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.trueCenter {
position: absolute;
display: block;
left: 50%;
top: 50%;
-ms-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
Im trying to build a game where enemies jump out of the water and you fire water at them...
When the user clicks to fire I want the img src to point in the direction of the click, to achieve what I have so far I have css and js script (code below) however it looks to static, I feel having the water point in the direction of the users input would help a lot however Im not sure how to achieve this?
//bind to gun events
this.playfield.on('gun:out_of_ammo',_.bind(function(){this.outOfAmmo();},this));
this.playfield.on('gun:fire',_.bind(function(){
this.flashScreen();
},this));
...
flashScreen : function(){
$(".theFlash").css("display","block");
setTimeout(function(){
$('.theFlash').css("display","none");
},400);
}
CSS
.theFlash{
background-color : transparent;
width:900px;
height:500px;
position:relative;
margin:0 auto;
z-index:10;
display:none;
}
I put together an example below that will hopefully help you out.
You just have to specify the source from where the shoot is fired (sourceX,sourceY), calculate the angle to where the mouse is clicked (done below, so should just be to copy/paste) and adjust the transform: rotate(Xdeg); to the new angle.
Make sure to set the orgin in css with transform-origin, so that the flame rotates around the source and not the flame itself.
Try it out at the bottom.
var game,
flame,
sourceX = 310,
sourceY = 110;
window.onload = function() {
game = document.getElementById('game');
flame = document.getElementById('flame');
game.addEventListener('click', function(e) {
var targetX = e.pageX,
targetY = e.pageY,
deltaX = targetX - sourceX,
deltaY = targetY - sourceY,
rad = Math.atan2(deltaY, deltaX),
deg = rad * (180 / Math.PI),
length = Math.sqrt(deltaX*deltaX+deltaY*deltaY);
fire(deg,length);
}, false);
};
function fire(deg,length) {
flame.style.opacity = 1;
flame.style.transform = 'rotate(' + deg + 'deg)'
flame.style.width = length + 'px';
setTimeout(function() {
flame.style.opacity = 0;
},300);
};
#game {
position: relative;
width: 400px;
height: 200px;
background-color: #666;
overflow: hidden;
}
#source {
border-radius: 50%;
z-index: 101;
width: 20px;
height: 20px;
background-color: #ff0000;
position: absolute;
left: 300px;
top: 100px;
}
#flame {
width: 300px;
height: 3px;
background-color: #00ff00;
position: absolute;
left: 310px;
top: 110px;
opacity: 0;
transform-origin: 0px 0px;
transform: rotate(180deg);
transition: opacity .2s;
}
<div id="game">
<div id="source">
</div>
<div id="flame">
</div>
</div>
I would not recommend building games in this manner, Canvas and SVG are the preferred methods of building browser games, with that said it can be done.
Try this
https://jsfiddle.net/b77x4rq4/
$(document).ready(function(){
var middleOfElementTop = 250; // margin from top + half of height
var middleOfElementLeft = 125; // margin from left + half of width
$("#main").mousemove(function(e){
var mouseX = e.offsetX;
var mouseY = e.offsetY;
var angle = Math.atan2(mouseY - middleOfElementTop, mouseX - middleOfElementLeft) * 180 / Math.PI;
$(".box").css({"transform": "rotate(" + angle + "deg)"})
})
});
I am fairly new to writing in html, css, and coding in javascript.
I digress; i am trying to have an image of a gear rotate when the a user scrolls up and down the screen (i am hoping to give it an elevator effect when i add a belt).
I am using the jquery $(window).scroll(function(). I know it is working because when i use console.log("hi") it writes every time i scroll. My problem is the .animate() function that doesn't seem to work. I even tried downloading "http://jqueryrotate.com/" and using that to rotate.
Any help would be much appreciated!
## HTML ##
<div class="left_pulley">
<img src="gear2.png" />
</div>
<div class="right_pulley">
<img src="gear2.png" />
</div>
## CSS ##
.left_pulley
{
position: absolute;
margin: 0;
padding: 0;
top: 263px;
left: 87%;
height: 35px;
width: 35px;
}
.left_pulley img
{
width: 100%;
}
.right_pulley
{
position: absolute;
margin: 0;
padding: 0;
top: 263px;
left: 94.2%;
height: 35px;
width: 35px;
}
.right_pulley img
{
width: 100%;
}
## JS ##
First using .rotate({})
$(".left_pulley").rotate({bind:
$(window).scroll(function() {
if ($(this).scrollTop() > 0) {
$(.left_pulley).rotate({
angle: 0,
animateTo: 180,
})
})
})
})
Now using .animate({}) to try and just move it at all.
$(window).scroll(function() {
if ($(this).scrollTop() > 0) {
var scott = $('img');
scott.animate({
left: 180
}
}
});
$(window).scroll(function() {
if ($(this).scrollTop() > 0) {
var scott = $('img');
scott.animate({
left: 180
}
function() {
console.log("hi");
}
});
console.log("hi2");
}
});
.left_pulley {
position: absolute;
margin: 0;
padding: 0;
top: 263px;
left: 87%;
height: 35px;
width: 35px;
}
.left_pulley img {
width: 100%;
}
.right_pulley {
position: absolute;
margin: 0;
padding: 0;
top: 263px;
left: 94.2%;
height: 35px;
width: 35px;
}
.right_pulley img {
width: 100%;
}
<div class="left_pulley">
<img src="gear2.png" />
</div>
<div class="right_pulley">
<img src="gear2.png" />
</div>
[
picture of gears i want to rotate.
]1
You should look into the CSS3 transform property, more specifically the rotate() function. Here
It would also be beneficial to add a transistion property to create an animated 'tween' between rotation values. Here. Make sure to add this transition to the transition property (as this is where rotation is set).\
You can then change the rotation of the gear (with automatic animation!) using jquery by setting the css value of the transition property, for example:
#gear{
transition: transform 300ms;
transform: rotate(7deg);
transform-origin:90% 90%;
position:absolute;
left:100px;
top:100px;
font-size:10rem;
width:100px;
height:100px;
}
You can test it out here by hitting run.
https://jsfiddle.net/oc4hhons/
Borrowing heavily from https://stackoverflow.com/a/17348698/2026508
You could do something like this:
var degrees = 0;
var prevScroll = 0;
$(window).scroll(function() {
if ($(window).scrollTop() > 0) {
if (prevScroll > $(window).scrollTop()) {
$('.woo').css({
'-webkit-transform': 'rotate(' + degrees+++'deg)',
'-moz-transform': 'rotate(' + degrees+++'deg)',
'-ms-transform': 'rotate(' + degrees+++'deg)',
'transform': 'rotate(' + degrees+++'deg)'
});
console.log('prevScroll greater:', prevScroll)
} else if (prevScroll < $(window).scrollTop()) {
$('.woo').css({
'-webkit-transform': 'rotate(' + degrees--+'deg)',
'-moz-transform': 'rotate(' + degrees--+'deg)',
'-ms-transform': 'rotate(' + degrees--+'deg)',
'transform': 'rotate(' + degrees--+'deg)'
});
console.log('prevScroll less:', prevScroll)
}
prevScroll = $(window).scrollTop()
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="height: 40px; width: 100px;background-image: url(' gear2.png ');background-color:blue;" class="woo">turn</div>
JS Fiddle-Updated, now they rotate together same direction but the rotation is depending on whether the scroll is up or down:
JS:
var $gears = $('.gear'),
$i = 0,
$scrollBefore = 0;
$(window).scroll(function () {
if($(this).scrollTop() > $scrollBefore){
$scrollBefore = $(this).scrollTop();
$gears.css("transform", "rotate(" + ($i+=4) + "deg)");
}else if($(this).scrollTop() < $scrollBefore){
$scrollBefore = $(this).scrollTop();
$gears.css("transform", "rotate(" + ($i-=4) + "deg)");
}
});
this JS Fiddle 2, makes them rotate in opposite directions, and each gear direction switches depending if the scrolling is up or down:
JS:
var $gearLeft = $('.left_pulley'),
$gearRight = $('.right_pulley'),
$i = 0,
$j = 0,
$scrollBefore = 0;
$(window).scroll(function() {
if ($(this).scrollTop() > $scrollBefore) {
$scrollBefore = $(this).scrollTop();
$gearLeft.css("transform", "rotate(" + ($i += 4) + "deg)");
$gearRight.css("transform", "rotate(" + ($j -= 4) + "deg)");
} else if ($(this).scrollTop() < $scrollBefore) {
$scrollBefore = $(this).scrollTop();
$gearLeft.css("transform", "rotate(" + ($i -= 4) + "deg)");
$gearRight.css("transform", "rotate(" + ($j += 4) + "deg)");
}
});
Thanks for all the help everyone!
Just want to post my finial code in case anyone else needs help in the future.
/* Scott Louzon 11/24/15
This code is used to rotate two images of a gears when user scrolls */
/*This function see's when user scrolls then calls rotate_right & rotate_left
accordingly */
var scroll_at = 0; //variable to keep track of
//scroll postion
$(window).scroll(function() {
if ($(this).scrollTop() > 0) //if scroll postion is not at
{ //top do this
if ($(this).scrollTop() > scroll_at) //if scroll postion is > than b4
{
rotate_down();
}
else if ($(this).scrollTop() < scroll_at) //if scroll postion is < than b4
{
rotate_up();
}
scroll_at = $(this).scrollTop(); //set varible to were scroll
//postion is at now
}
})
//Both these functions call css to rotate the image of a gear
var rotation = 0;
function rotate_down()
{
rotation+= 8;
$(".left_pulley").css("transform","rotate("+ rotation +"deg)");
$(".right_pulley").css("transform","rotate("+ (-1 * rotation) +"deg)");
}
function rotate_up()
{
rotation += 8;
$(".left_pulley").css("transform","rotate("+ (-1 * rotation)+"deg)");
$(".right_pulley").css("transform","rotate("+ rotation +"deg)");
}
.left_pulley
{
position: absolute;
margin: 0;
padding: 0;
/*Used for gear rotation */
transition: transform 1ms;
transform-origin:50% 50%;
top: 263px;
left: 87%;
height: 35px;
width: 35px;
}
.left_pulley img
{
width: 100%;
}
.right_pulley
{
position: absolute;
margin: 0;
padding: 0;
/* Used for gear rotation */
transition: transform 1ms;
transform-origin:50% 50%;
top: 263px;
left: 94.2%;
height: 35px;
width: 35px;
}
.right_pulley img
{
width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="left_pulley">
<img src="gear2.png" />
</div>
<div class="right_pulley">
<img src="gear2.png" />
</div>