Skip to content

Instantly share code, notes, and snippets.

@1inus
Forked from jackiewu/Rotating 3D Slider.markdown
Created September 27, 2018 18:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 1inus/9d85a1014857a41f83a2f3d7e110d43d to your computer and use it in GitHub Desktop.
Save 1inus/9d85a1014857a41f83a2f3d7e110d43d to your computer and use it in GitHub Desktop.
Rotating 3D Slider
<div class="slider3d first">
<div class="slider3d__wrapper">
<div class="slider3d__inner">
<div class="slider3d__rotater">
<div class="slider3d__item">
<h2 class="slider3d__heading" data-text="SO HEADING">SO HEADING</h2>
</div>
<div class="slider3d__item">
<h2 class="slider3d__heading" data-text="MUCH ROTATION">MUCH ROTATION</h2>
</div>
<div class="slider3d__item">
<h2 class="slider3d__heading" data-text="VERY 3D">VERY 3D</h2>
</div>
<div class="slider3d__item">
<h2 class="slider3d__heading" data-text="SUCH JAVASCRIPT">SUCH JAVASCRIPT</h2>
</div>
<div class="slider3d__item">
<h2 class="slider3d__heading" data-text="WOW WOW!">WOW WOW!</h2>
</div>
</div>
</div>
</div>
<div class="slider3d__controls">
<div class="slider3d__handle">
<div class="slider3d__handle__inner">
<div class="slider3d__handle__rotater">
<div class="slider3d__handle__item active">Page 1</div>
<div class="slider3d__handle__item">Page 2</div>
<div class="slider3d__handle__item">Page 3</div>
<div class="slider3d__handle__item">Page 4</div>
<div class="slider3d__handle__item">Page 5</div>
</div>
</div>
</div>
<div class="slider3d__control m--up"></div>
<div class="slider3d__control m--down"></div>
</div>
</div>

Rotating 3D Slider

Sourse of inspiration - http://rdcm.com/en/

Slider not working in IE, because of transform-style: preserve-3d. Handle control is broken in FF during rotation, because FF still have this nasty bug with stacking context and translateZ, and it's simply breaks z-index order for elements.

I tried to create this slider as sort of plugin/component. It's more like a practice, so js architecture is pretty random. But it's working :) And you can use multiple sliders on page with different sizes and different settings (you can find options object in js).

Don't forget to rotate slides with control handle.

A Pen by Nikolay Talanov on CodePen.

License.

(function() {
var rotatingSlider = function(selector, options) {
function initSingleSlider($el, options) {
var $slider, $rotaters,
$handle, $handleItems,
numOfItems,
angle, currentAngle = 0,
prefix = ".slider3d__",
handlePrefix = prefix + "handle__",
rotating = false;
var defaultOptions = {
speed: 1100,
dragSpeedCoef: 0.7,
handleSpeedCoef: 6,
easing: "ease",
persMult: 1.6,
handlePersMult: 3,
scrollRotation: true,
keysRotation: true,
globalDragRotation: false,
withControls: true,
handleAndGlobalDrag: false,
allowDragDuringAnim: false,
allowScrollDuringAnim: false,
allowKeysDuringAnim: false,
allowControlsDuringAnim: false
};
var __opts = $.extend(defaultOptions, options);
function handleActiveItem() {
if (!__opts.withHandle) return;
$handleItems.removeClass("active");
var a = currentAngle % 360 / angle;
if (a < 0) a = numOfItems + a;
if (a > 0) a = a + 1;
if (!a) a = 1;
$handleItems.eq(a - 1).addClass("active");
};
function rotateSlider(delta) {
var newAngle = currentAngle + delta * angle;
$rotaters.css({"transform": "rotateX("+ newAngle +"deg)",
"transition": "transform " + __opts.speed / 1000 + "s " + __opts.easing});
currentAngle = newAngle;
setTimeout(function() {
$rotaters.css("transition", "transform 0s");
handleActiveItem();
rotating = false;
}, __opts.speed);
};
function navigateUp() {
rotateSlider(-1);
};
function navigateDown() {
rotateSlider(1);
};
function scrollHandler(e) {
if (rotating && !__opts.allowScrolluringAnim) return;
rotating = true;
var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail;
if (delta > 0) {
navigateUp();
} else if (delta < 0) {
navigateDown();
}
};
function keydownHandler(e) {
if (rotating && !__opts.allowKeysDuringAnim) return;
rotating = true;
if (e.which === 38) {
navigateUp();
} else if (e.which === 40) {
navigateDown();
}
}
function dragRotationHandler(e) {
if (rotating && !__opts.allowDragDuringAnim) return;
rotating = true;
$slider.addClass("no-select");
var startY = e.pageY || e.originalEvent.touches[0].pageY;
var sliderH = $slider.height();
var deltaY = 0;
var newAngle;
var angleDelta;
var isHandle = $(this).hasClass("js-handle");
var rotationCoef;
if (isHandle) {
rotationCoef = __opts.handleSpeedCoef;
} else {
rotationCoef = __opts.dragSpeedCoef;
}
if (__opts.scrollRotation) {
$slider.off("mousewheel DOMMouseScroll", scrollHandler);
}
$(document).on("mousemove touchmove", function(e) {
var y = e.pageY || e.originalEvent.touches[0].pageY;
deltaY = (startY - y) / sliderH * rotationCoef;
newAngle = currentAngle + deltaY * angle;
angleDelta = newAngle - currentAngle;
$rotaters.css("transform", "rotateX("+ newAngle +"deg)");
});
$(document).on("mouseup touchend", function(e) {
$(document).off("mousemove touchmove mouseup touchend");
$slider.removeClass("no-select");
if (!deltaY) {
rotating = false;
if (__opts.scrollRotation) {
$slider.on("mousewheel DOMMouseScroll", scrollHandler);
}
return;
}
var slidesRotated = Math.round(angleDelta / angle);
rotateSlider(slidesRotated);
deltaY = 0;
setTimeout(function() {
if (__opts.scrollRotation) {
$slider.on("mousewheel DOMMouseScroll", scrollHandler);
}
}, __opts.speed);
});
};
function initControls() {
$handle = $(prefix + "handle", $slider);
var $handleInner = $(handlePrefix + "inner", $handle);
$handleItems = $(handlePrefix + "item", $handle);
var h = $handle.height();
var pers = h * __opts.handlePersMult;
var depth = h / 2 / Math.tan(angle / 2 * Math.PI/180);
$slider.addClass("with-controls");
$handle.css({"-webkit-perspective": pers + "px",
"perspective": pers + "px"})
.addClass("js-handle");
$handleInner.css("transform", "translateZ(-"+ depth +"px)");
$handleItems.each(function(index) {
$(this).css("transform", "rotateX(-"+ (index * angle) +"deg) translateZ("+ depth +"px)");
});
$rotaters = $(prefix + "rotater, "+ handlePrefix + "rotater", $slider);
$handle.on("mousedown touchstart", dragRotationHandler);
$(document).on("click", ".slider3d__control", function() {
if (rotating && !__opts.allowControlsDuringAnim) return;
rotating = true;
if ($(this).hasClass("m--up")) {
navigateUp();
} else {
navigateDown();
}
});
};
function initSlider($el) {
$slider = $el;
var $wrapper = $(prefix + "wrapper", $slider);
var $inner = $(prefix + "inner", $slider);
var $items = $(prefix + "item", $slider);
numOfItems = $items.length;
angle = 360 / numOfItems;
var h = $slider.height();
var pers = h * __opts.persMult;
var depth = h / 2 / Math.tan(angle / 2 * Math.PI/180);
$wrapper.css({"-webkit-perspective": pers + "px",
"perspective": pers + "px"});
$inner.css("transform", "translateZ(-"+ depth +"px)");
$items.each(function(index) {
$(this).css("transform", "rotateX(-"+ (index * angle) +"deg) translateZ("+ depth +"px)");
});
$slider.addClass("slider-ready");
$rotaters = $(prefix + "rotater", $slider);
if (__opts.scrollRotation) {
$slider.on("mousewheel DOMMouseScroll", scrollHandler);
}
if (__opts.keysRotation) {
if (!$slider.attr("tabindex")) {
$slider.attr("tabindex", 1);
}
$slider.on("keydown", keydownHandler);
}
if (__opts.globalDragRotation) {
$slider.on("mousedown touchstart", dragRotationHandler);
}
if (__opts.withControls) {
initControls();
}
};
initSlider($el);
}
function globalInit() {
$(selector).each(function() {
initSingleSlider($(this), options);
});
};
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
var resizeFn = debounce(function() {
globalInit();
}, 100);
$(window).on("resize", resizeFn);
globalInit();
};
window.rotatingSlider = rotatingSlider;
}());
$(document).ready(function() {
rotatingSlider(".slider3d");
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
*, *:before, *:after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
font-size: 62.5%;
@media (max-width: 991px) {
font-size: 50%;
}
@media (max-width: 768px) {
font-size: 40%;
}
}
body {
background: #777;
}
$openSans: 'Open Sans', Helvetica, Arial, sans-serif;
// usage example - text-shadow: text3d(#fff, 38, 0.3, 6%);
@function text3d($color, $depth: 20, $colorStep: 1, $colorOffset: 10%, $xStep: 0.02rem, $yStep: -0.03rem) {
$startColor: darken($color, $colorOffset);
$ts: ();
@for $i from 1 through $depth {
$c: darken($startColor, $colorStep * $i * 1%);
$x: $xStep * $i;
$y: $yStep * $i;
$ts: append($ts, $x $y 0 $c, comma);
}
@return $ts;
}
%fullHeightEl {
position: relative;
height: 100%;
transform-style: preserve-3d;
}
.slider3d {
$sliderHeight: 100vh;
overflow: hidden;
position: relative;
height: $sliderHeight;
font-family: $openSans;
&.no-select {
user-select: none;
}
&__wrapper {
z-index: 1;
position: relative;
height: 100%;
}
&__inner {
@extend %fullHeightEl;
}
&__rotater {
@extend %fullHeightEl;
}
&__item {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-size: cover;
backface-visibility: hidden;
background-color: #000;
transform-style: preserve-3d;
&:nth-child(1) {
background-image: url('http://i.imgur.com/3pu2X8D.jpg');
}
&:nth-child(2) {
background-image: url('http://i.imgur.com/YAdjqmQ.jpg');
}
&:nth-child(3) {
background-image: url('http://i.imgur.com/1HeKcko.jpg');
}
&:nth-child(4) {
background-image: url('http://i.imgur.com/njcLNVE.jpg');
}
&:nth-child(5) {
background-image: url('http://i.imgur.com/UP7fWfg.jpg');
}
}
&__heading {
position: absolute;
left: 0;
top: 50%;
width: 100%;
margin-top: -6rem;
text-align: center;
font-size: 12rem;
line-height: 1;
text-transform: uppercase;
color: #ffffff;
transform: translateZ(3rem) scale(0.5);
opacity: 0;
text-shadow: text3d(#fff, 38, 0.3, 6%);
transition: transform 0.4s, opacity 0.4s;
transition-delay: 0.2s;
transition-timing-function: cubic-bezier(.71,.59,.4,1.5);
.slider-ready & {
transform: translateZ(3rem);
opacity: 1;
}
}
&__controls {
display: none;
.slider3d.with-controls & {
display: block;
}
}
&__handle {
z-index: 2;
position: absolute;
right: -2rem;
top: 50%;
width: 17rem;
height: 7rem;
margin-top: -3.5rem;
cursor: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyNCAyNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkuNCA0LjhsLTIuOS0yLjhoOC41djguNWwtMi44LTIuOHMtMS4yIDEuNC0xLjIgNC4zYzAgMy4xIDEuMiA0LjQgMS4yIDQuNGwyLjgtMi45djguNWgtOC41bDIuOC0yLjhzLTIuMy0yLjItMi4zLTcuMmMwLTQuOSAyLjQtNy4yIDIuNC03LjJ6Ii8+PHBhdGggZD0iTTEyLjIgNi4zcy0yLjIgMS44LTIuMiA1LjdjMCA0LjEgMi4xIDUuOCAyLjEgNS44bDEuOC0xLjh2NWgtNWwxLjgtMS44cy0yLjctMi4xLTIuNy03LjJjMC01IDIuOC03LjEgMi44LTcuMWwtMS45LTEuOWg1LjF2NS4xbC0xLjgtMS44Ii8+PC9zdmc+'), ns-resize;
&__inner {
@extend %fullHeightEl;
}
&__rotater {
@extend %fullHeightEl;
}
&__item {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
padding-right: 2rem;
background: #000;
text-align: center;
font-size: 1.8rem;
line-height: 7rem;
text-transform: uppercase;
font-weight: bold;
color: #fff;
user-select: none;
&:after {
content: "";
z-index: -1;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255,255,255,0.1);
transition: opacity 0.3s;
}
&.active {
&:after {
opacity: 0;
}
}
}
}
&__control {
z-index: 3;
position: absolute;
right: 0;
top: 50%;
width: 15rem;
height: 4rem;
margin-top: -2rem;
cursor: pointer;
&:after {
content: "";
position: absolute;
left: 50%;
top: 50%;
width: 1rem;
height: 1rem;
margin-left: -0.5rem;
margin-top: -0.5rem;
border: 2px solid #fff;
border-left: none;
border-bottom: none;
}
&.m--up {
transform: translateY(-6rem);
&:after {
transform: rotate(-45deg);
}
}
&.m--down {
transform: translateY(6rem);
&:after {
transform: rotate(135deg);
}
}
}
}
<link href="http://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment