The interface I used to create http://narrowdesign.com
Created
January 7, 2019 18:29
-
-
Save synecdocheNORTH/6c08dd959b532d5cdf710f4688ffe905 to your computer and use it in GitHub Desktop.
Scrolling Golden Spiral
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
</head> | |
<body> | |
<div class="js-spiral"> | |
<div class="js-section"> | |
<div class="message"> | |
Scroll, Use Arrow Keys or Click<br><br> | |
<h2>I used this scrolling interface to create <a href="https://narrowdesign.com" target="_blank">narrowdesign.com</a></h2> | |
</div> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
<div class="js-section"> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$(function() { | |
var WIN = $(window); | |
var sections = $('.js-section'); | |
var spiral = $('.js-spiral') | |
var _winW; | |
var _winH; | |
var smallScreen; | |
var landscape; | |
var aspect = .618033; | |
var axis = .7237; | |
var spiralOrigin; | |
var rotation = 0; | |
var sectionCount = sections.length; | |
var currentSection = 0; | |
var touchStartY = 0; | |
var touchStartX = 0; | |
var moved = 0; | |
var animRAF; | |
var animating = false; | |
var scrollTimeout; | |
var userAgent = window.navigator.userAgent.toLowerCase(), | |
firefox = userAgent.indexOf('firefox') != -1 || userAgent.indexOf('mozilla') == -1, | |
ios = /iphone|ipod|ipad/.test( userAgent ), | |
safari = (userAgent.indexOf('safari') != -1 && userAgent.indexOf('chrome') == -1) || ios, | |
linux = userAgent.indexOf('linux') != -1, | |
windows = userAgent.indexOf('windows') != -1; | |
resizeHandler(); | |
// EVENTS | |
///////// | |
WIN.on('resize',resizeHandler); | |
WIN.on('scroll',function(e){ | |
e.preventDefault(); | |
}) | |
WIN.on('wheel', function(e) { | |
var deltaY = -e.originalEvent.deltaY; | |
if (windows || linux) { | |
deltaY = e.deltaY * 5; | |
} | |
moved = -deltaY || 0; | |
rotation += moved/-10; | |
rotation = trimRotation(); | |
e.preventDefault(); | |
startScrollTimeout() | |
cancelAnimationFrame(animRAF); | |
scrollHandler(); | |
}); | |
WIN.on('touchstart', function(e) { | |
e.preventDefault() | |
var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; | |
moved = 0; | |
touchStartX = touch.pageX; | |
touchStartY = touch.pageY; | |
cancelAnimationFrame(animRAF); | |
}) | |
WIN.on('touchmove', function(e) { | |
e.preventDefault() | |
var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; | |
moved = ((touchStartY - touch.pageY)+(touchStartX - touch.pageX)) * 3; | |
touchStartX = touch.pageX; | |
touchStartY = touch.pageY; | |
rotation += moved/-10; | |
rotation = trimRotation(); | |
startScrollTimeout(); | |
cancelAnimationFrame(animRAF); | |
scrollHandler() | |
}); | |
WIN.on('touchend', function(e) { | |
animateScroll() | |
}) | |
WIN.on('keydown',function(e) { | |
if (e.keyCode === 39 || e.keyCode === 40 || e.keyCode === 32) { | |
cancelAnimationFrame(animRAF); | |
animateScroll((currentSection + 1) * -90,rotation) | |
} else if (e.keyCode === 37 || e.keyCode === 38) { | |
cancelAnimationFrame(animRAF); | |
animateScroll((currentSection - 1) * -90,rotation) | |
} | |
scrollHandler() | |
}) | |
sections.on('click',function() { | |
cancelAnimationFrame(animRAF) | |
animateScroll($(this).index() * -90,rotation); | |
}) | |
// FUNCTIONS | |
//////////// | |
function scrollHandler() { | |
requestAnimationFrame(function(){ | |
var scale = Math.pow(aspect,rotation/90); | |
currentSection = Math.min(sectionCount + 2,Math.max(-sectionCount,Math.floor((rotation-30)/-90))); | |
spiral.css({ | |
transform: 'rotate(' + rotation + 'deg) scale(' + scale + ')', | |
}) | |
sections.removeClass('active') | |
sections.eq(currentSection).addClass('active') | |
}) | |
} | |
function animateScroll(targR,startR,speed) { | |
var distance = startR - targR; | |
var mySpeed = speed || .2; | |
if (((targR || Math.abs(targR) === 0) && Math.abs(targR - rotation) > .1) || Math.abs(moved) > 1) { | |
if (targR || Math.abs(targR) === 0) { | |
rotation += mySpeed * (targR - rotation); | |
} else { | |
moved *= .98; | |
rotation += moved/-10; | |
} | |
rotation = trimRotation(); | |
scrollHandler(); | |
animRAF = requestAnimationFrame(function(){ | |
animateScroll(targR,startR,speed) | |
}); | |
} else if (targR || Math.abs(targR) === 0) { | |
cancelAnimationFrame(animRAF) | |
rotation = targR; | |
rotation = trimRotation(); | |
scrollHandler(); | |
} | |
} | |
function buildSpiral() { | |
// rotate around this point | |
spiralOrigin = Math.floor(_winW * axis) + 'px ' + Math.floor(_winW * aspect * axis) +'px'; | |
var w = _winW * aspect; | |
var h = w; // they're squares | |
if (smallScreen && !landscape) { // flip it 90deg if it's a portrait phone | |
spiralOrigin = Math.floor((_winW/aspect) * aspect * (1 - axis)) +'px ' + Math.floor((_winW/aspect) * axis) + 'px '; | |
w = _winW; | |
h = _winW; | |
} | |
// HACK to smooth out Chrome vs Safari/Firefox | |
var translate = ''; | |
if (safari || firefox) { | |
translate = 'translate3d(0,0,0)' | |
} | |
// END HACK | |
spiral.css({ | |
transformOrigin: spiralOrigin, | |
backfaceVisiblity: 'hidden' | |
}) | |
sections.each(function(i){ | |
var myRot = Math.floor(90*i); | |
var scale = Math.pow(aspect, i); | |
$(this).css({ | |
width: w, | |
height: h, | |
transformOrigin: spiralOrigin, | |
backfaceVisiblity: 'hidden', | |
backgroundColor: 'rgb(' + Math.floor(255-i*(255/sectionCount)) + ',50,50)', | |
transform: 'rotate(' + myRot + 'deg) scale(' + Math.pow(aspect, i) + ') ' + translate | |
}) | |
}) | |
scrollHandler(); | |
} | |
function resizeHandler () { // Set the size of images and preload them | |
_winW = window.innerWidth/(1000/window.innerHeight); | |
_winH = window.innerHeight; | |
smallScreen = _winW < 960; | |
landscape = _winH < _winW; | |
buildSpiral() | |
} | |
// keep it from getting too small or too big | |
function trimRotation() { | |
return Math.max(-1500, Math.min(1200, rotation)) | |
} | |
// if no scrolling happens for 200ms, animate to the closest section | |
function startScrollTimeout () { | |
clearTimeout(scrollTimeout) | |
if (currentSection > -1 && currentSection < sectionCount) { | |
scrollTimeout = setTimeout(function(){ | |
cancelAnimationFrame(animRAF); | |
animateScroll(currentSection * -90,rotation,.15); | |
},200); | |
} | |
} | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
padding: 0; | |
margin: 0; | |
background-color: #113232; | |
color: #fff; | |
} | |
a { | |
color: #fff; | |
} | |
.js-spiral { | |
position: fixed; | |
} | |
.js-section { | |
position: absolute; | |
left: -100%; | |
box-sizing: border-box; | |
transition: .2s border ease-out; | |
border: 2px solid #113232; | |
} | |
.js-section:hover { | |
border-radius: 5%; | |
border: 10px solid #113232; | |
} | |
.message { | |
position: absolute; | |
width: 50%; | |
left: 5vh; | |
bottom: 10vh; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment