Skip to content

Instantly share code, notes, and snippets.

@uxder
Created August 21, 2019 18:52
Show Gist options
  • Save uxder/5db18b0ee020920d133b6c73d8f7762f to your computer and use it in GitHub Desktop.
Save uxder/5db18b0ee020920d133b6c73d8f7762f to your computer and use it in GitHub Desktop.
Mouse parallaxer
import { MouseTracker } from './mousetracker';
/**
* A class that creates a parallax effect based on the mouse position.
* @hidden
*/
export class Parallaxer {
private animate_: boolean;
private mousePosition_: any;
private rotationSensitivity: any;
private translateSensitivity: any;
private transformValues: any;
private pivotElement_: HTMLElement | undefined;
private rootElement_: HTMLElement;
private mouseTracker_: MouseTracker;
/**
* @param {HTMLElement} rootElement The root element to apply parallax effects to.
* @param {Object} rotationSentivity x,y object with rotation sensitivity.
* @param {Object} translateSentitivy x,y object with translate senstiivity.
* @param {HTMLElement} pivotElement Optional element to make the pixot center.
* @constructor
* TODO(uxder) Clean this up.
*/
constructor(rootElement: HTMLElement, rotationSensitivity: any,
translateSensitity: any, pivotElement?: HTMLElement) {
/**
* Flag to allow animation.
* @type {boolean}
*/
this.animate_ = false;
/**
* The current mouse position data acquired from the mouse tracker.
* @type {Object}
*/
this.mousePosition_ = null;
/**
* The rotation sensitivity of the parallax effect.
*/
this.rotationSensitivity = rotationSensitivity || {
x: 0.2,
y: 0.2
};
/**
* The translate sensitivity of the parallax effect.
*/
this.translateSensitivity = translateSensitity || {
x: 1,
y: 1
};
/**
* The current transform values.
*/
this.transformValues = {
xDeg: 0,
yDeg: 0,
zDeg: 0,
xTrans: 0,
yTrans: 0
};
/**
* The pivot element if defined.
* @type {Element}
*/
this.pivotElement_ = pivotElement;
/**
* The root element to manipulate.
* @type {Element}
*/
this.rootElement_ = rootElement;
this.mouseTracker_ = new MouseTracker(
this.pivotElement_ || document.body,
(mousePosition: any) => {
this.mousePosition_ = mousePosition;
},
false
);
}
/**
* Runs the animation.
*/
run() {
this.animate_ = true;
this.rafLoop_();
}
/**
* Stops the animation.
*/
stop() {
this.animate_ = false;
}
/**
* Internal animation cycle.
*/
rafLoop_() {
if (!this.animate_) {
return;
}
window.requestAnimationFrame(() => {
this.rafLoop_();
});
this.render_();
}
/**
* Internal render cycle.
*/
render_() {
if (!this.mousePosition_) {
return;
}
const xDegree = (this.mousePosition_.percentageX) * this.rotationSensitivity.x;
const yDegree = (this.mousePosition_.percentageY) * this.rotationSensitivity.y;
const xTrans = -(this.mousePosition_.percentageX) * this.translateSensitivity.x;
const yTrans = -(this.mousePosition_.percentageY) * this.translateSensitivity.y;
// TODO(uxder): Add complex easing.
this.transformValues.xDeg += (xDegree - this.transformValues.xDeg) * 0.03;
this.transformValues.yDeg += (yDegree - this.transformValues.yDeg) * 0.03;
this.transformValues.xTrans += (xTrans - this.transformValues.xTrans) * 0.03;
this.transformValues.yTrans += (yTrans - this.transformValues.yTrans) * 0.03;
const transformString =
'rotateX(' + this.transformValues.yDeg + 'deg) rotateY(' +
-this.transformValues.xDeg + 'deg) rotateZ(0deg)' +
' translate(' + -this.transformValues.xTrans + 'px, ' +
this.transformValues.yTrans + 'px)';
// console.log(transformString, this.mousePosition_);
this.rootElement_.style.perspectiveOrigin = '50% 50%';
this.rootElement_.style.transform = transformString;
this.rootElement_.style.transformOrigin = '50% 50%';
}
}
declare function require(x: string): any;
import {math} from '../math';
import {detector} from '../detector';
/**
* Class that helps with mouse tracking.
*/
export class MouseTracker {
/**
* The root element to calculate the center position of the effect.
*/
private rootElement_:Element;
/**
* The basic dimensions of the root element.
* @type {Object}
*/
private dimensions_:any;
/**
* The callback for when there is mouse movement.
*/
private moveCallBack_:Function;
/**
* The current mouse position data.
*/
private mousePosition_:Object;
/**
* @constructor
*/
constructor(rootElement:Element, moveCallBack:Function, disableMobile:boolean) {
this.rootElement_ = rootElement;
this.dimensions_ = null;
this.moveCallBack_ = moveCallBack;
this.mousePosition_ = {};
this.calculateRootElementDimensions_();
window.addEventListener('resize', () => {
this.calculateRootElementDimensions_();
});
if(!disableMobile && detector.allowDeviceOrientation()) {
window.addEventListener('deviceorientation', (e) => {
this.onDeviceOrientation_(e);
});
}
document.body.addEventListener('mousemove', (e) => {
this.onMouseMove_(e);
}, false);
}
/**
* Calculates the base dimensions of the rootElement.
*/
calculateRootElementDimensions_() {
let docRect = document.body.getBoundingClientRect();
let rect = this.rootElement_.getBoundingClientRect();
// Calculate the center point.
let xCenter = rect.left + rect.width / 2;
let yCenter = rect.top + rect.height / 2;
this.dimensions_ = {
width: rect.width,
height: rect.height,
halfWidth: rect.width / 2,
halfHeight: rect.height / 2,
top: rect.top,
left: rect.left,
xCenter: xCenter,
yCenter: yCenter,
docWidth: docRect.width,
docHeight: docRect.height
}
}
/**
* Handles the mouseRootElement move.
* @type {MouseEvent}
*/
onMouseMove_(e:any) {
let x = e.pageX || e.clientX;
let y = e.pageY || e.clientY;
this.mousePosition_ = {
x: x,
y: y,
deltaX: x - this.dimensions_.xCenter,
deltaY: y - this.dimensions_.yCenter,
percentageX: (x - this.dimensions_.xCenter) /
(this.dimensions_.docWidth) * 100,
percentageY: (y - this.dimensions_.yCenter) /
(this.dimensions_.docHeight) * 100,
}
this.moveCallBack_(this.mousePosition_);
}
/**
* Handles the device orientation.
* @type {MouseEvent}
*/
onDeviceOrientation_(event:any) {
let x = math.limitRange(-50, 50, event.gamma);
let y = math.limitRange(-50, 50, event.beta);
this.mousePosition_ = {
x: 0,
y: 0,
deltaX: 0,
deltaY: 0,
percentageX: x,
percentageY: y
}
this.moveCallBack_(this.mousePosition_);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment