Update
BIN
education.png
Before Width: | Height: | Size: 3.4 KiB |
BIN
experience.png
Before Width: | Height: | Size: 3.5 KiB |
BIN
favicon.ico
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 106 KiB |
BIN
header2.png
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
BIN
illusions/black-cat.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
illusions/construction.gif
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
illusions/life.jpg
Normal file
After Width: | Height: | Size: 170 KiB |
367
illusions/london-skyline.svg
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
illusions/purple-cat.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
illusions/stars.jpg
Normal file
After Width: | Height: | Size: 775 KiB |
377
index.html
@ -1,219 +1,158 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="fi" xml:lang="fi">
|
||||
|
||||
<!--
|
||||
|
||||
. . IMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
|
||||
.IMMMMMMMMMMMMMM8I . ... . =MMMM
|
||||
:MMMMMMMMMZ . 7MMMMZ . 7MD . IMMD .
|
||||
MMMMM. . . . .~ .M, . MMM .
|
||||
MMMM, N. .IDMMMO777ZNMMMMMO =MM . M:. NMM.
|
||||
. ZMMM . . :7NMMDI= . MM IM MMM
|
||||
MMM IMM77IDMMM, . M8 ..MM M ,N MMM
|
||||
M8 M M . M ,O . 7. MM
|
||||
.M8 D ,. ... M 7 MM
|
||||
MM. 7 = . ~MMMMMN, . 7MM
|
||||
MMM .. N. MMMMMMMMMMMMMMMO. MMM
|
||||
.MMM MMMMMMMMM+. ZMMMZ $MMMMMMMMMMM.. MMM
|
||||
MMMD. . ..ZMMM78MMMMMMMMM MMM. .. DMMMMMMMMMMM8MM MM7 . OMMMM .
|
||||
MMM MM:. . MMMMMMMMMMMMMMMMM IMM MMMMMMO .DMMMMM.. . . +O MMM.
|
||||
.MMM ?D OMMMMM .,MMMMM+ MM MMMMMMMM. ?.MM..
|
||||
MMM M :M. .7M8 MM . MMMN .. =MMMMM. . :MMM :.MMM.
|
||||
MMM. 8. MMMMMMMMMZ. MM MMMMMMMMMMMM~ M MM. MM$
|
||||
.MMOM M . .. MMMMMM$ . MMM . MM .MM MM
|
||||
NMMM M 8M O88I MMMM 7~ . . .:MMMMMM MM MM
|
||||
MMM $ . MM . MMM~ ~MMMMMMM MMMMM=.7MMMM MM . MM
|
||||
NM7I M MMM: MMMMM MM MMMMMM . MMMZMMM.MM. 8 MM
|
||||
MM MM .+MMMM =M M,MMD MMMMMMM $MM DMMMMMM.. ZMM. .MM .8..MMM.
|
||||
MM? :M MMMMMM .. . . MM . . . MMM .MMMMMMMI=MM MMMM M N MMM
|
||||
.MM MMMMMMMMM 8MMMM .ZMMMMMM? . MMM. ,MMMMMM . =. MMM
|
||||
MMM. MMMM MMMMMMM8 . MM . :MMMMMMMMM NMMMMMMMMMMM .MMM.
|
||||
.MM IMMM= MM ?MMMMMMMMMMMMMMMMMMMMMMM8 . MM . MMMMMMM . MMN 8 MM8
|
||||
MM 7MMM MM .MM $MMMMM7 .MM.. .MM. MMMMMMMMMMD. MM~ MMM
|
||||
7M ..=MMMMMMM?. MMI MMM MM . ?MMMMMMMMMM MM .MMI . MMM.
|
||||
M= MMMMMMMMMMMMMMN~ .8M= MM 7MMMMMMMMMMMM, MM8MMM .,MM
|
||||
M= MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM8 MMMM . MM.
|
||||
=M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM+ 8MM MMM$ MM
|
||||
.8M. MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MM . =MMMM. 7MM.
|
||||
MM MM.MM MM.ZMMMM7=MMMM . MM ZMM MMMMM MMM.
|
||||
MM MMZMM ~MM MMM ..~MM MM MMMMMMM . $MM$
|
||||
MM ~MMM, MMM MM=. MM MM MMMMMMZ .M7 .MM ~MMM
|
||||
,MM MMMMMMMMD. MM MM MMO~.7MMMMMMMM=.. NM.. MM DMMM
|
||||
MMI . =MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM~. .M?. ,MM =MMMM
|
||||
MM. D. . .. . . . .M= . ZMD . MMMM
|
||||
MM. M M . .8MMMMMMMMMMMMM. MZ MM? . =MMMM
|
||||
MM. I .MM ... .MM= .MM. ZMMMM
|
||||
MM ,N . ,+777- -, ... ?MM MMMMM
|
||||
MM. MMO. .. . . . 7MO . ?MMMM
|
||||
MMZ .. .==~=. . . MMMM.
|
||||
MM . . MMMM
|
||||
MMM .. MMMMMMMMMM
|
||||
.MMM7 ZMMMMMMMMN:
|
||||
DMMMMMMMMMMMMMMMMMMMMMMMM? . .
|
||||
. 7MMMMMMMMMMMMZ. . ..
|
||||
|
||||
-->
|
||||
|
||||
<head>
|
||||
<title>Martti Malmi</title>
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
text-align: center;
|
||||
padding: 0px 0px 50px 0px;
|
||||
margin:0px;
|
||||
font: 12px/18px "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
div.main {
|
||||
text-align: left;
|
||||
margin: 30px auto;
|
||||
background-color: #FFFFFF;
|
||||
border-right: 0px solid #EEE;
|
||||
border-left: 0px solid #EEE;
|
||||
max-width: 800px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
a { color: #A22; text-decoration: none; }
|
||||
a:hover { color: #A22; text-decoration: underline; }
|
||||
|
||||
img { border: 0px; }
|
||||
|
||||
#pic img { float: left; margin-right: 25px; }
|
||||
#content { clear: both; padding-top: 20px; border-bottom: 1px solid #EEE; }
|
||||
#header { color: #555; padding: 32px 0px; font-size: 18px; border-top: 1px solid #EEE; border-bottom: 1px solid #EEE; }
|
||||
#header li { margin: 0px 0px 10px 0px; }
|
||||
|
||||
h1 { font-size: 36px; margin: 50px 0px 20px 0px; }
|
||||
h2 {
|
||||
margin:0px;
|
||||
float: left;
|
||||
color: #000;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
ul { list-style-type: none; }
|
||||
li { margin: 0px 0px 18px 0px; }
|
||||
|
||||
.clear { clear:both; }
|
||||
|
||||
.block { clear:both; margin-bottom: 60px; }
|
||||
.block ul { margin-left: 160px; }
|
||||
.block ul b { margin-right: 5px; }
|
||||
.block ul img { margin: 10px 0px;}
|
||||
|
||||
@media (max-width: 799px) {
|
||||
#header { text-align:center; padding: 10px 0px; }
|
||||
#header ul { margin:0; padding:0;}
|
||||
#pic img { float:none; max-width:20%; margin:0; }
|
||||
h2 { float:none; margin-left:5px; }
|
||||
.block ul { margin-left:0px; }
|
||||
img { max-width: 90%; }
|
||||
h2 img{max-width:100%;}
|
||||
h1 { margin: 20px 0 }
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main">
|
||||
<div id="header">
|
||||
<div id="pic"><img alt="Lily!" src="lily.png"/></div>
|
||||
<h1><img alt="Martti Malmi" src="title9.png" /></h1>
|
||||
<ul>
|
||||
<li>Software developer, digital culture enthusiast</li>
|
||||
<li><a href="mailto:martti.malmi@aalto.fi">martti.malmi@aalto.fi</a> (<a href="mmalmi.pgp">PGP</a>)</li>
|
||||
<li><a href="https://github.com/mmalmi">GitHub</a>
|
||||
<li><a href="http://fi.linkedin.com/pub/martti-malmi/11/25/102"><img alt="LinkedIn Profile" src="linkedin3.png"/></a></li>
|
||||
</ul>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<div class="block">
|
||||
<h2><img alt="Me" src="me.png"/></h2>
|
||||
<ul>
|
||||
<li>Born in Rovaniemi, Finland, 1988 A.D.</li>
|
||||
<li>I like playing guitar and keyboards, LAN parties, FPS and RTS games, indoor climbing, latino dances, imageboards, funny Youtube videos and bad action movies.</li>
|
||||
<li>I also like Japan! Check out my 2011 travel blog <a href="http://morzenjapan.blogspot.com">Mårzen in Japan</a> (in Finnish).</li>
|
||||
<li>I'm interested in topics such as music, languages, cultural evolution, Internet memes, economics and society. As for technology, I'm more interested in its human implications than technical intricacies.</li>
|
||||
<li>Open-minded <a href="http://en.wikipedia.org/wiki/INTP">INTP</a> personality.</li>
|
||||
<li><img src="fillari2-small.jpg" alt="Travelling in Fukuoka, Japan"/></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<h2><img alt="Education" src="education.png"/></h2>
|
||||
<ul>
|
||||
<li><b>2003</b> Finnish National Board of Education: Award from improving IT usage in educational institute (Mankkaa school).</li>
|
||||
<li><b>2007</b> Ylioppilastutkinto (The Finnish Matriculation Examination), Olari high school.</li>
|
||||
<li><b>2007 - 2009</b> Computer science studies at Helsinki University of Technology. Mostly programming courses.</li>
|
||||
<li><b>2011</b> 9 weeks of Japanese studies at <a href="http://www.genkijacs.com/">GenkiJACS</a>, Fukuoka, Japan.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<h2><img alt="Experience" src="experience.png"/></h2>
|
||||
<ul>
|
||||
<li><b>2004</b> Verkkokauppa.com, junior high school traineeship. 2 weeks of mostly warehouse work, but my friend and I also spent a day coding a PHP script that parsed warehouse receipts and searched product codes for the listed items. The script saved a lot of manual work so they rewarded us with gift cards.</li>
|
||||
<li><b>2007 - 2010</b> Various part time jobs at warehouses and construction sites.</li>
|
||||
<li><b>2009 - 2011</b> Developer of the P2P virtual currency <a
|
||||
href="http://www.bitcoin.org/">Bitcoin</a>. I was the first person to join the project and had the privilege to work with the infamous man of mystery, <a href="http://en.wikipedia.org/wiki/Satoshi_Nakamoto#Creator">Satoshi Nakamoto</a>. My tasks included community building, project organization, web design, web app development, server administration, C++ programming and documentation in English. Check out my interviews by <a href="http://www.businessinsider.com/bitcoins-martti-malmi-not-worried-about-liberty-reserve-2013-5">Business Insider</a>, <a href="http://www.iltasanomat.fi/digi/art-1288496063056.html">Ilta-Sanomat</a> (in Finnish) and <a href="http://www.talouselama.fi/uutiset/bitcoin+mullistaa+maksuliikennetta/a729735">Tietoviikko</a> (in Finnish).</li>
|
||||
<li><b>8.3. - 30.6.2010</b> Siemens, trainee at the corporate communications department. Compilation of the company website content using a CMS. The work included presentation logic planning, illustration using Adobe Photoshop, proof-reading, co-working with product managers, some CMS user support and a lot of ctrl+c & ctrl+v.</li>
|
||||
<li><b>9.9.2010 - 24.8.2011</b> <a href="http://www.whitevector.com/">Whitevector</a>, software developer. Worked in a small agile team that developed and maintained a social media monitoring and analysing product. Technologies used included Java (Eclipse IDE), Lucene, PostgreSQL and Ruby on Rails among others.</li>
|
||||
<li><b>5.6.-31.7.2012</b> <a href="https://www.kuvaverkko.fi">Kuvaverkko</a>, Billing system upgrade project. PHP & MySQL development.</li>
|
||||
<li><b>8.8.2012 -</b> <a href="http://sc5.fi">SC5</a>, Front & back-end web development.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<h2><img alt="Skills" src="skills.png"/></h2>
|
||||
<ul>
|
||||
<li>I'm good at writing grammatically correct English and Finnish and expressing things clearly. I can communicate basic things in Swedish and Japanese.</li>
|
||||
<li>I have an eye for aesthetics in web sites and user interfaces. I can create layouts using Photoshop, CSS and HTML. I have played around a little with Qt, wxWidgets and Swing.</li>
|
||||
<li>I have worked with Java, C++, Eclipse, SVN, Apache, SQL, RoR, Django, PHP, HTML5, JSON, XML and Javascript (JQuery, Mootools).</li>
|
||||
<li>I have maintained hobby Linux servers since I was 14 and production servers since 2009.</li>
|
||||
<li>I understand not only code, but also user experience and business aspects. In addition to thinking about <i>what</i> and <i>how</i> you do, it's good to know <i>why</i> you do things.</li>
|
||||
<li>I'm good at speed typing!<br/>
|
||||
<a href="http://speedtest.10fastfingers.com"><img src="1_wpm_score_DK.png" alt="Typing Test Score" /></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="block">
|
||||
<h2><img alt="Old stuff" src="work_samples.png"/></h2>
|
||||
<ul>
|
||||
<li><b>2007</b> Saving Princess Adeleine (<a href="adventure.jar">jar</a>/<a
|
||||
href="adventure.exe">exe</a>), a simple
|
||||
text-adventure game I made for a programming course. It was chosen as one
|
||||
of the model solutions for the exercise. You can find a "cheater's
|
||||
map" of the game world <a href="cheatermap.GIF">here</a>.</li>
|
||||
<li><b>2008</b> <a href="tetris.html">Tetris</a>, a Java-applet.</li>
|
||||
<li><b>2009</b> Mökki (<a href="moekki1.1.jar">jar</a>/<a href="samples/Moekki.html">source code</a>). A game where you
|
||||
place sticks on a grid, and get a point and a new turn for each triangle you
|
||||
complete. Can be played against the computer or another human player. Made
|
||||
as a project work for the programming course T-106.1240 Ohjelmoinnin
|
||||
jatkokurssi T1.</li>
|
||||
<li><b>2010</b> Inverted Index (<a href="samples/InvertedIndex.html">source code</a>), a standalone Java program made as a work sample for a job application.</li>
|
||||
<li><b>2012</b> <a href="http://www.flowdock.com">Flowdock</a> plugin for <a href="http://www.redmine.org">Redmine</a> (<a href="samples/RedmineFlowdockPlugin.html">source code</a>). Posts newly created issues and issue status updates from Redmine to Flowdock using the Flowdock API.</li>
|
||||
<!-- <li><b>2012</b> <a href="https://eurobtc.com">EuroBTC</a> (<a href="samples/eurobtc.html">source code</a>), a service that lets you buy and sell bitcoins for cash in the snail mail. Written in PHP.</li> -->
|
||||
<li><b>2012</b> <a href="samples/html5tetris.html">Neon Shade Tetris</a> (<a href="http://github.com/mmalmi/neonshadetetris">GitHub</a>), a JavaScript/HTML5 tetris game.</li>
|
||||
<li><b>2012</b> <a href="gamewheel">Gamewheel</a> (<a href="http://github.com/mmalmi/gamewheel">GitHub</a>), wheel of fortune for choosing the next game at LAN parties.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer"><img alt="" src="lily-small3.png"/></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!--
|
||||
|
||||
. . IMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
|
||||
.IMMMMMMMMMMMMMM8I . ... . =MMMM
|
||||
:MMMMMMMMMZ . 7MMMMZ . 7MD . IMMD .
|
||||
MMMMM. . . . .~ .M, . MMM .
|
||||
MMMM, N. .IDMMMO777ZNMMMMMO =MM . M:. NMM.
|
||||
. ZMMM . . :7NMMDI= . MM IM MMM
|
||||
MMM IMM77IDMMM, . M8 ..MM M ,N MMM
|
||||
M8 M M . M ,O . 7. MM
|
||||
.M8 D ,. ... M 7 MM
|
||||
MM. 7 = . ~MMMMMN, . 7MM
|
||||
MMM .. N. MMMMMMMMMMMMMMMO. MMM
|
||||
.MMM MMMMMMMMM+. ZMMMZ $MMMMMMMMMMM.. MMM
|
||||
MMMD. . ..ZMMM78MMMMMMMMM MMM. .. DMMMMMMMMMMM8MM MM7 . OMMMM .
|
||||
MMM MM:. . MMMMMMMMMMMMMMMMM IMM MMMMMMO .DMMMMM.. . . +O MMM.
|
||||
.MMM ?D OMMMMM .,MMMMM+ MM MMMMMMMM. ?.MM..
|
||||
MMM M :M. .7M8 MM . MMMN .. =MMMMM. . :MMM :.MMM.
|
||||
MMM. 8. MMMMMMMMMZ. MM MMMMMMMMMMMM~ M MM. MM$
|
||||
.MMOM M . .. MMMMMM$ . MMM . MM .MM MM
|
||||
NMMM M 8M O88I MMMM 7~ . . .:MMMMMM MM MM
|
||||
MMM $ . MM . MMM~ ~MMMMMMM MMMMM=.7MMMM MM . MM
|
||||
NM7I M MMM: MMMMM MM MMMMMM . MMMZMMM.MM. 8 MM
|
||||
MM MM .+MMMM =M M,MMD MMMMMMM $MM DMMMMMM.. ZMM. .MM .8..MMM.
|
||||
MM? :M MMMMMM .. . . MM . . . MMM .MMMMMMMI=MM MMMM M N MMM
|
||||
.MM MMMMMMMMM 8MMMM .ZMMMMMM? . MMM. ,MMMMMM . =. MMM
|
||||
MMM. MMMM MMMMMMM8 . MM . :MMMMMMMMM NMMMMMMMMMMM .MMM.
|
||||
.MM IMMM= MM ?MMMMMMMMMMMMMMMMMMMMMMM8 . MM . MMMMMMM . MMN 8 MM8
|
||||
MM 7MMM MM .MM $MMMMM7 .MM.. .MM. MMMMMMMMMMD. MM~ MMM
|
||||
7M ..=MMMMMMM?. MMI MMM MM . ?MMMMMMMMMM MM .MMI . MMM.
|
||||
M= MMMMMMMMMMMMMMN~ .8M= MM 7MMMMMMMMMMMM, MM8MMM .,MM
|
||||
M= MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM8 MMMM . MM.
|
||||
=M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM+ 8MM MMM$ MM
|
||||
.8M. MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MM . =MMMM. 7MM.
|
||||
MM MM.MM MM.ZMMMM7=MMMM . MM ZMM MMMMM MMM.
|
||||
MM MMZMM ~MM MMM ..~MM MM MMMMMMM . $MM$
|
||||
MM ~MMM, MMM MM=. MM MM MMMMMMZ .M7 .MM ~MMM
|
||||
,MM MMMMMMMMD. MM MM MMO~.7MMMMMMMM=.. NM.. MM DMMM
|
||||
MMI . =MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM~. .M?. ,MM =MMMM
|
||||
MM. D. . .. . . . .M= . ZMD . MMMM
|
||||
MM. M M . .8MMMMMMMMMMMMM. MZ MM? . =MMMM
|
||||
MM. I .MM ... .MM= .MM. ZMMMM
|
||||
MM ,N . ,+777- -, ... ?MM MMMMM
|
||||
MM. MMO. .. . . . 7MO . ?MMMM
|
||||
MMZ .. .==~=. . . MMMM.
|
||||
MM . . MMMM
|
||||
MMM .. MMMMMMMMMM
|
||||
.MMM7 ZMMMMMMMMN:
|
||||
DMMMMMMMMMMMMMMMMMMMMMMMM? . .
|
||||
. 7MMMMMMMMMMMMZ. . ..
|
||||
|
||||
-->
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<title>siri.us</title>
|
||||
<link rel="stylesheet" type="text/css" href="per.css">
|
||||
<link href='http://fonts.googleapis.com/css?family=Lato|Uncial+Antiqua|Slabo+27px' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
|
||||
<link rel="icon" type="image/x-icon" href="illusions/purple-cat.ico" />
|
||||
<script type="text/javascript" src="sorcery/instafeed.min.js"></script>
|
||||
<script type="text/javascript" src="sorcery/jquery-1.11.2.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
var $root = $('html, body');
|
||||
$('a').click(function() {
|
||||
var href = $.attr(this, 'href');
|
||||
$root.animate({
|
||||
scrollTop: $(href).offset().top
|
||||
}, 500, function () {
|
||||
window.location.hash = href;
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<ul>
|
||||
<li><a href="#cover"><span class="fa fa-star"></span></a></li>
|
||||
<!--<li><a href="#design">Design</a></li>-->
|
||||
<li><a href="#photography">Photography</a></li>
|
||||
<li><a href="#writing">Writing</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
|
||||
<section id="cover">
|
||||
<div class="content layer" data-depth="0.00">
|
||||
<h1>Sirius Business</h1>
|
||||
<div id="contact">
|
||||
<ul>
|
||||
<li><a href="https://twitter.com/marttimalmi"><span class="fa fa-twitter"></span></a></li>
|
||||
<li><a href="https://www.facebook.com/mmalmi"><span class="fa fa-facebook"></span></a></li>
|
||||
<li><a href="https://www.linkedin.com/in/marttimalmi"><span class="fa fa-linkedin"></span></a></li>
|
||||
<li><a href="https://instagram.com/mmalmi"><span class="fa fa-instagram"></span></a></li>
|
||||
<li><a href="mailto:sirius@iki.fi"><span class="fa fa-at"></span></a></li>
|
||||
<li><a href="https://github.com/mmalmi"><span class="fa fa-github"></span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="photography">
|
||||
<h1>Photography <small>— AFK screenshots</small></h1>
|
||||
<div id="instafeed"></div>
|
||||
</section>
|
||||
|
||||
<!--<section id="design">
|
||||
<h1>Design <small>is the meaning of life</small></h1>
|
||||
<div></div>
|
||||
</section> -->
|
||||
|
||||
<section id="writing">
|
||||
<h1>Writing <small>is a art</small></h1>
|
||||
|
||||
<div>
|
||||
<a class="twitter-timeline" href="https://twitter.com/marttimalmi" data-widget-id="592795935392030721">Twiittejä käyttäjältä @marttimalmi</a>
|
||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<a href="http://speedtest.10fastfingers.com"><img src="illusions/1_wpm_score_DK.png" alt="Typing Test Score"></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="http://siriusbisnes.blogspot.fi">Blog: Sirius Business (in Finnish)</a>
|
||||
</p>
|
||||
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<!--<p>
|
||||
"Man who <span class="spoiler">puts dick in peanut butter</span> is fucking nuts." — Confucius
|
||||
</p>-->
|
||||
|
||||
<p>
|
||||
<img src="illusions/construction.gif">
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript">
|
||||
var userFeed = new Instafeed({
|
||||
get: 'user',
|
||||
userId: 313386739,
|
||||
accessToken: '313386739.9038401.550f95a9937643cc95fb5ec141e583cb'
|
||||
});
|
||||
userFeed.run();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
BIN
lily-small3.png
Before Width: | Height: | Size: 4.6 KiB |
BIN
linkedin3.png
Before Width: | Height: | Size: 511 B |
148
per.css
Normal file
@ -0,0 +1,148 @@
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Lato';
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
header {
|
||||
z-index: 1;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
padding: 1em 0;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 3em 0;
|
||||
}
|
||||
|
||||
header ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
header li {
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
section h1 {
|
||||
font-size: 3em;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 10;
|
||||
}
|
||||
|
||||
h1 small {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#scroller {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
section {
|
||||
background-color: black;
|
||||
min-height: 100%;
|
||||
padding: 0 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
#cover h1 {
|
||||
font-size: 2em;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 20;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
#cover h1 {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
#cover {
|
||||
font-size: 3em;
|
||||
letter-spacing: 20;
|
||||
//text-shadow: 0 0 1px black;
|
||||
background: url(illusions/life.jpg) no-repeat center center;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#cover .content {
|
||||
position: relative;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#cover ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#cover li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#writing {
|
||||
background-color: #ffffff;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
#writing a {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
#writing a:hover {
|
||||
color: #999999;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: 150px 20px;
|
||||
background: #fff url(illusions/london-skyline.svg) repeat-x center 0;
|
||||
//background-size: cover;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #C262D3;
|
||||
}
|
||||
|
||||
h1 {
|
||||
}
|
||||
|
||||
.spoiler {
|
||||
transition: background 3s ease;
|
||||
background: #ffffff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.spoiler:hover {
|
||||
background: none;
|
||||
color: inherit;
|
||||
}
|
BIN
skills.png
Before Width: | Height: | Size: 3.2 KiB |
2
sorcery/instafeed.min.js
vendored
Normal file
1584
sorcery/iscroll-infinite.js
Normal file
944
sorcery/iscroll-lite.js
Normal file
@ -0,0 +1,944 @@
|
||||
/*! iScroll v5.1.3 ~ (c) 2008-2014 Matteo Spinelli ~ http://cubiq.org/license */
|
||||
(function (window, document, Math) {
|
||||
var rAF = window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.oRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function (callback) { window.setTimeout(callback, 1000 / 60); };
|
||||
|
||||
var utils = (function () {
|
||||
var me = {};
|
||||
|
||||
var _elementStyle = document.createElement('div').style;
|
||||
var _vendor = (function () {
|
||||
var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
|
||||
transform,
|
||||
i = 0,
|
||||
l = vendors.length;
|
||||
|
||||
for ( ; i < l; i++ ) {
|
||||
transform = vendors[i] + 'ransform';
|
||||
if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
|
||||
}
|
||||
|
||||
return false;
|
||||
})();
|
||||
|
||||
function _prefixStyle (style) {
|
||||
if ( _vendor === false ) return false;
|
||||
if ( _vendor === '' ) return style;
|
||||
return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
|
||||
}
|
||||
|
||||
me.getTime = Date.now || function getTime () { return new Date().getTime(); };
|
||||
|
||||
me.extend = function (target, obj) {
|
||||
for ( var i in obj ) {
|
||||
target[i] = obj[i];
|
||||
}
|
||||
};
|
||||
|
||||
me.addEvent = function (el, type, fn, capture) {
|
||||
el.addEventListener(type, fn, !!capture);
|
||||
};
|
||||
|
||||
me.removeEvent = function (el, type, fn, capture) {
|
||||
el.removeEventListener(type, fn, !!capture);
|
||||
};
|
||||
|
||||
me.prefixPointerEvent = function (pointerEvent) {
|
||||
return window.MSPointerEvent ?
|
||||
'MSPointer' + pointerEvent.charAt(9).toUpperCase() + pointerEvent.substr(10):
|
||||
pointerEvent;
|
||||
};
|
||||
|
||||
me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
|
||||
var distance = current - start,
|
||||
speed = Math.abs(distance) / time,
|
||||
destination,
|
||||
duration;
|
||||
|
||||
deceleration = deceleration === undefined ? 0.0006 : deceleration;
|
||||
|
||||
destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
|
||||
duration = speed / deceleration;
|
||||
|
||||
if ( destination < lowerMargin ) {
|
||||
destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
|
||||
distance = Math.abs(destination - current);
|
||||
duration = distance / speed;
|
||||
} else if ( destination > 0 ) {
|
||||
destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
|
||||
distance = Math.abs(current) + destination;
|
||||
duration = distance / speed;
|
||||
}
|
||||
|
||||
return {
|
||||
destination: Math.round(destination),
|
||||
duration: duration
|
||||
};
|
||||
};
|
||||
|
||||
var _transform = _prefixStyle('transform');
|
||||
|
||||
me.extend(me, {
|
||||
hasTransform: _transform !== false,
|
||||
hasPerspective: _prefixStyle('perspective') in _elementStyle,
|
||||
hasTouch: 'ontouchstart' in window,
|
||||
hasPointer: window.PointerEvent || window.MSPointerEvent, // IE10 is prefixed
|
||||
hasTransition: _prefixStyle('transition') in _elementStyle
|
||||
});
|
||||
|
||||
// This should find all Android browsers lower than build 535.19 (both stock browser and webview)
|
||||
me.isBadAndroid = /Android /.test(window.navigator.appVersion) && !(/Chrome\/\d/.test(window.navigator.appVersion));
|
||||
|
||||
me.extend(me.style = {}, {
|
||||
transform: _transform,
|
||||
transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
|
||||
transitionDuration: _prefixStyle('transitionDuration'),
|
||||
transitionDelay: _prefixStyle('transitionDelay'),
|
||||
transformOrigin: _prefixStyle('transformOrigin')
|
||||
});
|
||||
|
||||
me.hasClass = function (e, c) {
|
||||
var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
|
||||
return re.test(e.className);
|
||||
};
|
||||
|
||||
me.addClass = function (e, c) {
|
||||
if ( me.hasClass(e, c) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var newclass = e.className.split(' ');
|
||||
newclass.push(c);
|
||||
e.className = newclass.join(' ');
|
||||
};
|
||||
|
||||
me.removeClass = function (e, c) {
|
||||
if ( !me.hasClass(e, c) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
|
||||
e.className = e.className.replace(re, ' ');
|
||||
};
|
||||
|
||||
me.offset = function (el) {
|
||||
var left = -el.offsetLeft,
|
||||
top = -el.offsetTop;
|
||||
|
||||
// jshint -W084
|
||||
while (el = el.offsetParent) {
|
||||
left -= el.offsetLeft;
|
||||
top -= el.offsetTop;
|
||||
}
|
||||
// jshint +W084
|
||||
|
||||
return {
|
||||
left: left,
|
||||
top: top
|
||||
};
|
||||
};
|
||||
|
||||
me.preventDefaultException = function (el, exceptions) {
|
||||
for ( var i in exceptions ) {
|
||||
if ( exceptions[i].test(el[i]) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
me.extend(me.eventType = {}, {
|
||||
touchstart: 1,
|
||||
touchmove: 1,
|
||||
touchend: 1,
|
||||
|
||||
mousedown: 2,
|
||||
mousemove: 2,
|
||||
mouseup: 2,
|
||||
|
||||
pointerdown: 3,
|
||||
pointermove: 3,
|
||||
pointerup: 3,
|
||||
|
||||
MSPointerDown: 3,
|
||||
MSPointerMove: 3,
|
||||
MSPointerUp: 3
|
||||
});
|
||||
|
||||
me.extend(me.ease = {}, {
|
||||
quadratic: {
|
||||
style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
||||
fn: function (k) {
|
||||
return k * ( 2 - k );
|
||||
}
|
||||
},
|
||||
circular: {
|
||||
style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
|
||||
fn: function (k) {
|
||||
return Math.sqrt( 1 - ( --k * k ) );
|
||||
}
|
||||
},
|
||||
back: {
|
||||
style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
|
||||
fn: function (k) {
|
||||
var b = 4;
|
||||
return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
|
||||
}
|
||||
},
|
||||
bounce: {
|
||||
style: '',
|
||||
fn: function (k) {
|
||||
if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
|
||||
return 7.5625 * k * k;
|
||||
} else if ( k < ( 2 / 2.75 ) ) {
|
||||
return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
|
||||
} else if ( k < ( 2.5 / 2.75 ) ) {
|
||||
return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
|
||||
} else {
|
||||
return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
|
||||
}
|
||||
}
|
||||
},
|
||||
elastic: {
|
||||
style: '',
|
||||
fn: function (k) {
|
||||
var f = 0.22,
|
||||
e = 0.4;
|
||||
|
||||
if ( k === 0 ) { return 0; }
|
||||
if ( k == 1 ) { return 1; }
|
||||
|
||||
return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.tap = function (e, eventName) {
|
||||
var ev = document.createEvent('Event');
|
||||
ev.initEvent(eventName, true, true);
|
||||
ev.pageX = e.pageX;
|
||||
ev.pageY = e.pageY;
|
||||
e.target.dispatchEvent(ev);
|
||||
};
|
||||
|
||||
me.click = function (e) {
|
||||
var target = e.target,
|
||||
ev;
|
||||
|
||||
if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
|
||||
ev = document.createEvent('MouseEvents');
|
||||
ev.initMouseEvent('click', true, true, e.view, 1,
|
||||
target.screenX, target.screenY, target.clientX, target.clientY,
|
||||
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
|
||||
0, null);
|
||||
|
||||
ev._constructed = true;
|
||||
target.dispatchEvent(ev);
|
||||
}
|
||||
};
|
||||
|
||||
return me;
|
||||
})();
|
||||
|
||||
function IScroll (el, options) {
|
||||
this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
|
||||
this.scroller = this.wrapper.children[0];
|
||||
this.scrollerStyle = this.scroller.style; // cache style for better performance
|
||||
|
||||
this.options = {
|
||||
|
||||
// INSERT POINT: OPTIONS
|
||||
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
scrollY: true,
|
||||
directionLockThreshold: 5,
|
||||
momentum: true,
|
||||
|
||||
bounce: true,
|
||||
bounceTime: 600,
|
||||
bounceEasing: '',
|
||||
|
||||
preventDefault: true,
|
||||
preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ },
|
||||
|
||||
HWCompositing: true,
|
||||
useTransition: true,
|
||||
useTransform: true
|
||||
};
|
||||
|
||||
for ( var i in options ) {
|
||||
this.options[i] = options[i];
|
||||
}
|
||||
|
||||
// Normalize options
|
||||
this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
|
||||
|
||||
this.options.useTransition = utils.hasTransition && this.options.useTransition;
|
||||
this.options.useTransform = utils.hasTransform && this.options.useTransform;
|
||||
|
||||
this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
|
||||
this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
|
||||
|
||||
// If you want eventPassthrough I have to lock one of the axes
|
||||
this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
|
||||
this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
|
||||
|
||||
// With eventPassthrough we also need lockDirection mechanism
|
||||
this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
|
||||
this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
|
||||
|
||||
this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
|
||||
|
||||
this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
|
||||
|
||||
if ( this.options.tap === true ) {
|
||||
this.options.tap = 'tap';
|
||||
}
|
||||
|
||||
// INSERT POINT: NORMALIZATION
|
||||
|
||||
// Some defaults
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.directionX = 0;
|
||||
this.directionY = 0;
|
||||
this._events = {};
|
||||
|
||||
// INSERT POINT: DEFAULTS
|
||||
|
||||
this._init();
|
||||
this.refresh();
|
||||
|
||||
this.scrollTo(this.options.startX, this.options.startY);
|
||||
this.enable();
|
||||
}
|
||||
|
||||
IScroll.prototype = {
|
||||
version: '5.1.3',
|
||||
|
||||
_init: function () {
|
||||
this._initEvents();
|
||||
|
||||
// INSERT POINT: _init
|
||||
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this._initEvents(true);
|
||||
|
||||
this._execEvent('destroy');
|
||||
},
|
||||
|
||||
_transitionEnd: function (e) {
|
||||
if ( e.target != this.scroller || !this.isInTransition ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._transitionTime();
|
||||
if ( !this.resetPosition(this.options.bounceTime) ) {
|
||||
this.isInTransition = false;
|
||||
this._execEvent('scrollEnd');
|
||||
}
|
||||
},
|
||||
|
||||
_start: function (e) {
|
||||
// React to left mouse button only
|
||||
if ( utils.eventType[e.type] != 1 ) {
|
||||
if ( e.button !== 0 ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
var point = e.touches ? e.touches[0] : e,
|
||||
pos;
|
||||
|
||||
this.initiated = utils.eventType[e.type];
|
||||
this.moved = false;
|
||||
this.distX = 0;
|
||||
this.distY = 0;
|
||||
this.directionX = 0;
|
||||
this.directionY = 0;
|
||||
this.directionLocked = 0;
|
||||
|
||||
this._transitionTime();
|
||||
|
||||
this.startTime = utils.getTime();
|
||||
|
||||
if ( this.options.useTransition && this.isInTransition ) {
|
||||
this.isInTransition = false;
|
||||
pos = this.getComputedPosition();
|
||||
this._translate(Math.round(pos.x), Math.round(pos.y));
|
||||
this._execEvent('scrollEnd');
|
||||
} else if ( !this.options.useTransition && this.isAnimating ) {
|
||||
this.isAnimating = false;
|
||||
this._execEvent('scrollEnd');
|
||||
}
|
||||
|
||||
this.startX = this.x;
|
||||
this.startY = this.y;
|
||||
this.absStartX = this.x;
|
||||
this.absStartY = this.y;
|
||||
this.pointX = point.pageX;
|
||||
this.pointY = point.pageY;
|
||||
|
||||
this._execEvent('beforeScrollStart');
|
||||
},
|
||||
|
||||
_move: function (e) {
|
||||
if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.options.preventDefault ) { // increases performance on Android? TODO: check!
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
var point = e.touches ? e.touches[0] : e,
|
||||
deltaX = point.pageX - this.pointX,
|
||||
deltaY = point.pageY - this.pointY,
|
||||
timestamp = utils.getTime(),
|
||||
newX, newY,
|
||||
absDistX, absDistY;
|
||||
|
||||
this.pointX = point.pageX;
|
||||
this.pointY = point.pageY;
|
||||
|
||||
this.distX += deltaX;
|
||||
this.distY += deltaY;
|
||||
absDistX = Math.abs(this.distX);
|
||||
absDistY = Math.abs(this.distY);
|
||||
|
||||
// We need to move at least 10 pixels for the scrolling to initiate
|
||||
if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If you are scrolling in one direction lock the other
|
||||
if ( !this.directionLocked && !this.options.freeScroll ) {
|
||||
if ( absDistX > absDistY + this.options.directionLockThreshold ) {
|
||||
this.directionLocked = 'h'; // lock horizontally
|
||||
} else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
|
||||
this.directionLocked = 'v'; // lock vertically
|
||||
} else {
|
||||
this.directionLocked = 'n'; // no lock
|
||||
}
|
||||
}
|
||||
|
||||
if ( this.directionLocked == 'h' ) {
|
||||
if ( this.options.eventPassthrough == 'vertical' ) {
|
||||
e.preventDefault();
|
||||
} else if ( this.options.eventPassthrough == 'horizontal' ) {
|
||||
this.initiated = false;
|
||||
return;
|
||||
}
|
||||
|
||||
deltaY = 0;
|
||||
} else if ( this.directionLocked == 'v' ) {
|
||||
if ( this.options.eventPassthrough == 'horizontal' ) {
|
||||
e.preventDefault();
|
||||
} else if ( this.options.eventPassthrough == 'vertical' ) {
|
||||
this.initiated = false;
|
||||
return;
|
||||
}
|
||||
|
||||
deltaX = 0;
|
||||
}
|
||||
|
||||
deltaX = this.hasHorizontalScroll ? deltaX : 0;
|
||||
deltaY = this.hasVerticalScroll ? deltaY : 0;
|
||||
|
||||
newX = this.x + deltaX;
|
||||
newY = this.y + deltaY;
|
||||
|
||||
// Slow down if outside of the boundaries
|
||||
if ( newX > 0 || newX < this.maxScrollX ) {
|
||||
newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
|
||||
}
|
||||
if ( newY > 0 || newY < this.maxScrollY ) {
|
||||
newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
|
||||
}
|
||||
|
||||
this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
|
||||
this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
|
||||
|
||||
if ( !this.moved ) {
|
||||
this._execEvent('scrollStart');
|
||||
}
|
||||
|
||||
this.moved = true;
|
||||
|
||||
this._translate(newX, newY);
|
||||
|
||||
/* REPLACE START: _move */
|
||||
|
||||
if ( timestamp - this.startTime > 300 ) {
|
||||
this.startTime = timestamp;
|
||||
this.startX = this.x;
|
||||
this.startY = this.y;
|
||||
}
|
||||
|
||||
/* REPLACE END: _move */
|
||||
|
||||
},
|
||||
|
||||
_end: function (e) {
|
||||
if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
var point = e.changedTouches ? e.changedTouches[0] : e,
|
||||
momentumX,
|
||||
momentumY,
|
||||
duration = utils.getTime() - this.startTime,
|
||||
newX = Math.round(this.x),
|
||||
newY = Math.round(this.y),
|
||||
distanceX = Math.abs(newX - this.startX),
|
||||
distanceY = Math.abs(newY - this.startY),
|
||||
time = 0,
|
||||
easing = '';
|
||||
|
||||
this.isInTransition = 0;
|
||||
this.initiated = 0;
|
||||
this.endTime = utils.getTime();
|
||||
|
||||
// reset if we are outside of the boundaries
|
||||
if ( this.resetPosition(this.options.bounceTime) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scrollTo(newX, newY); // ensures that the last position is rounded
|
||||
|
||||
// we scrolled less than 10 pixels
|
||||
if ( !this.moved ) {
|
||||
if ( this.options.tap ) {
|
||||
utils.tap(e, this.options.tap);
|
||||
}
|
||||
|
||||
if ( this.options.click ) {
|
||||
utils.click(e);
|
||||
}
|
||||
|
||||
this._execEvent('scrollCancel');
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
|
||||
this._execEvent('flick');
|
||||
return;
|
||||
}
|
||||
|
||||
// start momentum animation if needed
|
||||
if ( this.options.momentum && duration < 300 ) {
|
||||
momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
|
||||
momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 };
|
||||
newX = momentumX.destination;
|
||||
newY = momentumY.destination;
|
||||
time = Math.max(momentumX.duration, momentumY.duration);
|
||||
this.isInTransition = 1;
|
||||
}
|
||||
|
||||
// INSERT POINT: _end
|
||||
|
||||
if ( newX != this.x || newY != this.y ) {
|
||||
// change easing function when scroller goes out of the boundaries
|
||||
if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
|
||||
easing = utils.ease.quadratic;
|
||||
}
|
||||
|
||||
this.scrollTo(newX, newY, time, easing);
|
||||
return;
|
||||
}
|
||||
|
||||
this._execEvent('scrollEnd');
|
||||
},
|
||||
|
||||
_resize: function () {
|
||||
var that = this;
|
||||
|
||||
clearTimeout(this.resizeTimeout);
|
||||
|
||||
this.resizeTimeout = setTimeout(function () {
|
||||
that.refresh();
|
||||
}, this.options.resizePolling);
|
||||
},
|
||||
|
||||
resetPosition: function (time) {
|
||||
var x = this.x,
|
||||
y = this.y;
|
||||
|
||||
time = time || 0;
|
||||
|
||||
if ( !this.hasHorizontalScroll || this.x > 0 ) {
|
||||
x = 0;
|
||||
} else if ( this.x < this.maxScrollX ) {
|
||||
x = this.maxScrollX;
|
||||
}
|
||||
|
||||
if ( !this.hasVerticalScroll || this.y > 0 ) {
|
||||
y = 0;
|
||||
} else if ( this.y < this.maxScrollY ) {
|
||||
y = this.maxScrollY;
|
||||
}
|
||||
|
||||
if ( x == this.x && y == this.y ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.scrollTo(x, y, time, this.options.bounceEasing);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
disable: function () {
|
||||
this.enabled = false;
|
||||
},
|
||||
|
||||
enable: function () {
|
||||
this.enabled = true;
|
||||
},
|
||||
|
||||
refresh: function () {
|
||||
var rf = this.wrapper.offsetHeight; // Force reflow
|
||||
|
||||
this.wrapperWidth = this.wrapper.clientWidth;
|
||||
this.wrapperHeight = this.wrapper.clientHeight;
|
||||
|
||||
/* REPLACE START: refresh */
|
||||
|
||||
this.scrollerWidth = this.scroller.offsetWidth;
|
||||
this.scrollerHeight = this.scroller.offsetHeight;
|
||||
|
||||
this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
|
||||
this.maxScrollY = this.wrapperHeight - this.scrollerHeight;
|
||||
|
||||
/* REPLACE END: refresh */
|
||||
|
||||
this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
|
||||
this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;
|
||||
|
||||
if ( !this.hasHorizontalScroll ) {
|
||||
this.maxScrollX = 0;
|
||||
this.scrollerWidth = this.wrapperWidth;
|
||||
}
|
||||
|
||||
if ( !this.hasVerticalScroll ) {
|
||||
this.maxScrollY = 0;
|
||||
this.scrollerHeight = this.wrapperHeight;
|
||||
}
|
||||
|
||||
this.endTime = 0;
|
||||
this.directionX = 0;
|
||||
this.directionY = 0;
|
||||
|
||||
this.wrapperOffset = utils.offset(this.wrapper);
|
||||
|
||||
this._execEvent('refresh');
|
||||
|
||||
this.resetPosition();
|
||||
|
||||
// INSERT POINT: _refresh
|
||||
|
||||
},
|
||||
|
||||
on: function (type, fn) {
|
||||
if ( !this._events[type] ) {
|
||||
this._events[type] = [];
|
||||
}
|
||||
|
||||
this._events[type].push(fn);
|
||||
},
|
||||
|
||||
off: function (type, fn) {
|
||||
if ( !this._events[type] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = this._events[type].indexOf(fn);
|
||||
|
||||
if ( index > -1 ) {
|
||||
this._events[type].splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
_execEvent: function (type) {
|
||||
if ( !this._events[type] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var i = 0,
|
||||
l = this._events[type].length;
|
||||
|
||||
if ( !l ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( ; i < l; i++ ) {
|
||||
this._events[type][i].apply(this, [].slice.call(arguments, 1));
|
||||
}
|
||||
},
|
||||
|
||||
scrollBy: function (x, y, time, easing) {
|
||||
x = this.x + x;
|
||||
y = this.y + y;
|
||||
time = time || 0;
|
||||
|
||||
this.scrollTo(x, y, time, easing);
|
||||
},
|
||||
|
||||
scrollTo: function (x, y, time, easing) {
|
||||
easing = easing || utils.ease.circular;
|
||||
|
||||
this.isInTransition = this.options.useTransition && time > 0;
|
||||
|
||||
if ( !time || (this.options.useTransition && easing.style) ) {
|
||||
this._transitionTimingFunction(easing.style);
|
||||
this._transitionTime(time);
|
||||
this._translate(x, y);
|
||||
} else {
|
||||
this._animate(x, y, time, easing.fn);
|
||||
}
|
||||
},
|
||||
|
||||
scrollToElement: function (el, time, offsetX, offsetY, easing) {
|
||||
el = el.nodeType ? el : this.scroller.querySelector(el);
|
||||
|
||||
if ( !el ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pos = utils.offset(el);
|
||||
|
||||
pos.left -= this.wrapperOffset.left;
|
||||
pos.top -= this.wrapperOffset.top;
|
||||
|
||||
// if offsetX/Y are true we center the element to the screen
|
||||
if ( offsetX === true ) {
|
||||
offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
|
||||
}
|
||||
if ( offsetY === true ) {
|
||||
offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
|
||||
}
|
||||
|
||||
pos.left -= offsetX || 0;
|
||||
pos.top -= offsetY || 0;
|
||||
|
||||
pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
|
||||
pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top;
|
||||
|
||||
time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
|
||||
|
||||
this.scrollTo(pos.left, pos.top, time, easing);
|
||||
},
|
||||
|
||||
_transitionTime: function (time) {
|
||||
time = time || 0;
|
||||
|
||||
this.scrollerStyle[utils.style.transitionDuration] = time + 'ms';
|
||||
|
||||
if ( !time && utils.isBadAndroid ) {
|
||||
this.scrollerStyle[utils.style.transitionDuration] = '0.001s';
|
||||
}
|
||||
|
||||
// INSERT POINT: _transitionTime
|
||||
|
||||
},
|
||||
|
||||
_transitionTimingFunction: function (easing) {
|
||||
this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
|
||||
|
||||
// INSERT POINT: _transitionTimingFunction
|
||||
|
||||
},
|
||||
|
||||
_translate: function (x, y) {
|
||||
if ( this.options.useTransform ) {
|
||||
|
||||
/* REPLACE START: _translate */
|
||||
|
||||
this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
|
||||
|
||||
/* REPLACE END: _translate */
|
||||
|
||||
} else {
|
||||
x = Math.round(x);
|
||||
y = Math.round(y);
|
||||
this.scrollerStyle.left = x + 'px';
|
||||
this.scrollerStyle.top = y + 'px';
|
||||
}
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
// INSERT POINT: _translate
|
||||
|
||||
},
|
||||
|
||||
_initEvents: function (remove) {
|
||||
var eventType = remove ? utils.removeEvent : utils.addEvent,
|
||||
target = this.options.bindToWrapper ? this.wrapper : window;
|
||||
|
||||
eventType(window, 'orientationchange', this);
|
||||
eventType(window, 'resize', this);
|
||||
|
||||
if ( this.options.click ) {
|
||||
eventType(this.wrapper, 'click', this, true);
|
||||
}
|
||||
|
||||
if ( !this.options.disableMouse ) {
|
||||
eventType(this.wrapper, 'mousedown', this);
|
||||
eventType(target, 'mousemove', this);
|
||||
eventType(target, 'mousecancel', this);
|
||||
eventType(target, 'mouseup', this);
|
||||
}
|
||||
|
||||
if ( utils.hasPointer && !this.options.disablePointer ) {
|
||||
eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
|
||||
eventType(target, utils.prefixPointerEvent('pointermove'), this);
|
||||
eventType(target, utils.prefixPointerEvent('pointercancel'), this);
|
||||
eventType(target, utils.prefixPointerEvent('pointerup'), this);
|
||||
}
|
||||
|
||||
if ( utils.hasTouch && !this.options.disableTouch ) {
|
||||
eventType(this.wrapper, 'touchstart', this);
|
||||
eventType(target, 'touchmove', this);
|
||||
eventType(target, 'touchcancel', this);
|
||||
eventType(target, 'touchend', this);
|
||||
}
|
||||
|
||||
eventType(this.scroller, 'transitionend', this);
|
||||
eventType(this.scroller, 'webkitTransitionEnd', this);
|
||||
eventType(this.scroller, 'oTransitionEnd', this);
|
||||
eventType(this.scroller, 'MSTransitionEnd', this);
|
||||
},
|
||||
|
||||
getComputedPosition: function () {
|
||||
var matrix = window.getComputedStyle(this.scroller, null),
|
||||
x, y;
|
||||
|
||||
if ( this.options.useTransform ) {
|
||||
matrix = matrix[utils.style.transform].split(')')[0].split(', ');
|
||||
x = +(matrix[12] || matrix[4]);
|
||||
y = +(matrix[13] || matrix[5]);
|
||||
} else {
|
||||
x = +matrix.left.replace(/[^-\d.]/g, '');
|
||||
y = +matrix.top.replace(/[^-\d.]/g, '');
|
||||
}
|
||||
|
||||
return { x: x, y: y };
|
||||
},
|
||||
|
||||
_animate: function (destX, destY, duration, easingFn) {
|
||||
var that = this,
|
||||
startX = this.x,
|
||||
startY = this.y,
|
||||
startTime = utils.getTime(),
|
||||
destTime = startTime + duration;
|
||||
|
||||
function step () {
|
||||
var now = utils.getTime(),
|
||||
newX, newY,
|
||||
easing;
|
||||
|
||||
if ( now >= destTime ) {
|
||||
that.isAnimating = false;
|
||||
that._translate(destX, destY);
|
||||
|
||||
if ( !that.resetPosition(that.options.bounceTime) ) {
|
||||
that._execEvent('scrollEnd');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
now = ( now - startTime ) / duration;
|
||||
easing = easingFn(now);
|
||||
newX = ( destX - startX ) * easing + startX;
|
||||
newY = ( destY - startY ) * easing + startY;
|
||||
that._translate(newX, newY);
|
||||
|
||||
if ( that.isAnimating ) {
|
||||
rAF(step);
|
||||
}
|
||||
}
|
||||
|
||||
this.isAnimating = true;
|
||||
step();
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
switch ( e.type ) {
|
||||
case 'touchstart':
|
||||
case 'pointerdown':
|
||||
case 'MSPointerDown':
|
||||
case 'mousedown':
|
||||
this._start(e);
|
||||
break;
|
||||
case 'touchmove':
|
||||
case 'pointermove':
|
||||
case 'MSPointerMove':
|
||||
case 'mousemove':
|
||||
this._move(e);
|
||||
break;
|
||||
case 'touchend':
|
||||
case 'pointerup':
|
||||
case 'MSPointerUp':
|
||||
case 'mouseup':
|
||||
case 'touchcancel':
|
||||
case 'pointercancel':
|
||||
case 'MSPointerCancel':
|
||||
case 'mousecancel':
|
||||
this._end(e);
|
||||
break;
|
||||
case 'orientationchange':
|
||||
case 'resize':
|
||||
this._resize();
|
||||
break;
|
||||
case 'transitionend':
|
||||
case 'webkitTransitionEnd':
|
||||
case 'oTransitionEnd':
|
||||
case 'MSTransitionEnd':
|
||||
this._transitionEnd(e);
|
||||
break;
|
||||
case 'wheel':
|
||||
case 'DOMMouseScroll':
|
||||
case 'mousewheel':
|
||||
this._wheel(e);
|
||||
break;
|
||||
case 'keydown':
|
||||
this._key(e);
|
||||
break;
|
||||
case 'click':
|
||||
if ( !e._constructed ) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
IScroll.utils = utils;
|
||||
|
||||
if ( typeof module != 'undefined' && module.exports ) {
|
||||
module.exports = IScroll;
|
||||
} else {
|
||||
window.IScroll = IScroll;
|
||||
}
|
||||
|
||||
})(window, document, Math);
|
2038
sorcery/iscroll-probe.js
Normal file
2195
sorcery/iscroll-zoom.js
Normal file
2011
sorcery/iscroll.js
Normal file
4
sorcery/jquery-1.11.2.min.js
vendored
Normal file
564
sorcery/jquery.parallax.js
Normal file
@ -0,0 +1,564 @@
|
||||
//============================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright (C) 2014 Matthew Wagerfield - @wagerfield
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any
|
||||
// person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the
|
||||
// Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute,
|
||||
// sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
|
||||
// OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//============================================================
|
||||
|
||||
/**
|
||||
* jQuery || Zepto Parallax Plugin
|
||||
* @author Matthew Wagerfield - @wagerfield
|
||||
* @description Creates a parallax effect between an array of layers,
|
||||
* driving the motion from the gyroscope output of a smartdevice.
|
||||
* If no gyroscope is available, the cursor position is used.
|
||||
*/
|
||||
;(function($, window, document, undefined) {
|
||||
|
||||
// Strict Mode
|
||||
'use strict';
|
||||
|
||||
// Constants
|
||||
var NAME = 'parallax';
|
||||
var MAGIC_NUMBER = 30;
|
||||
var DEFAULTS = {
|
||||
relativeInput: false,
|
||||
clipRelativeInput: false,
|
||||
calibrationThreshold: 100,
|
||||
calibrationDelay: 500,
|
||||
supportDelay: 500,
|
||||
calibrateX: false,
|
||||
calibrateY: true,
|
||||
invertX: true,
|
||||
invertY: true,
|
||||
limitX: false,
|
||||
limitY: false,
|
||||
scalarX: 10.0,
|
||||
scalarY: 10.0,
|
||||
frictionX: 0.1,
|
||||
frictionY: 0.1,
|
||||
originX: 0.5,
|
||||
originY: 0.5
|
||||
};
|
||||
|
||||
function Plugin(element, options) {
|
||||
|
||||
// DOM Context
|
||||
this.element = element;
|
||||
|
||||
// Selections
|
||||
this.$context = $(element).data('api', this);
|
||||
this.$layers = this.$context.find('.layer');
|
||||
|
||||
// Data Extraction
|
||||
var data = {
|
||||
calibrateX: this.$context.data('calibrate-x') || null,
|
||||
calibrateY: this.$context.data('calibrate-y') || null,
|
||||
invertX: this.$context.data('invert-x') || null,
|
||||
invertY: this.$context.data('invert-y') || null,
|
||||
limitX: parseFloat(this.$context.data('limit-x')) || null,
|
||||
limitY: parseFloat(this.$context.data('limit-y')) || null,
|
||||
scalarX: parseFloat(this.$context.data('scalar-x')) || null,
|
||||
scalarY: parseFloat(this.$context.data('scalar-y')) || null,
|
||||
frictionX: parseFloat(this.$context.data('friction-x')) || null,
|
||||
frictionY: parseFloat(this.$context.data('friction-y')) || null,
|
||||
originX: parseFloat(this.$context.data('origin-x')) || null,
|
||||
originY: parseFloat(this.$context.data('origin-y')) || null
|
||||
};
|
||||
|
||||
// Delete Null Data Values
|
||||
for (var key in data) {
|
||||
if (data[key] === null) delete data[key];
|
||||
}
|
||||
|
||||
// Compose Settings Object
|
||||
$.extend(this, DEFAULTS, options, data);
|
||||
|
||||
// States
|
||||
this.calibrationTimer = null;
|
||||
this.calibrationFlag = true;
|
||||
this.enabled = false;
|
||||
this.depths = [];
|
||||
this.raf = null;
|
||||
|
||||
// Element Bounds
|
||||
this.bounds = null;
|
||||
this.ex = 0;
|
||||
this.ey = 0;
|
||||
this.ew = 0;
|
||||
this.eh = 0;
|
||||
|
||||
// Element Center
|
||||
this.ecx = 0;
|
||||
this.ecy = 0;
|
||||
|
||||
// Element Range
|
||||
this.erx = 0;
|
||||
this.ery = 0;
|
||||
|
||||
// Calibration
|
||||
this.cx = 0;
|
||||
this.cy = 0;
|
||||
|
||||
// Input
|
||||
this.ix = 0;
|
||||
this.iy = 0;
|
||||
|
||||
// Motion
|
||||
this.mx = 0;
|
||||
this.my = 0;
|
||||
|
||||
// Velocity
|
||||
this.vx = 0;
|
||||
this.vy = 0;
|
||||
|
||||
// Callbacks
|
||||
this.onMouseMove = this.onMouseMove.bind(this);
|
||||
this.onDeviceOrientation = this.onDeviceOrientation.bind(this);
|
||||
this.onOrientationTimer = this.onOrientationTimer.bind(this);
|
||||
this.onCalibrationTimer = this.onCalibrationTimer.bind(this);
|
||||
this.onAnimationFrame = this.onAnimationFrame.bind(this);
|
||||
this.onWindowResize = this.onWindowResize.bind(this);
|
||||
|
||||
// Initialise
|
||||
this.initialise();
|
||||
}
|
||||
|
||||
Plugin.prototype.transformSupport = function(value) {
|
||||
var element = document.createElement('div');
|
||||
var propertySupport = false;
|
||||
var propertyValue = null;
|
||||
var featureSupport = false;
|
||||
var cssProperty = null;
|
||||
var jsProperty = null;
|
||||
for (var i = 0, l = this.vendors.length; i < l; i++) {
|
||||
if (this.vendors[i] !== null) {
|
||||
cssProperty = this.vendors[i][0] + 'transform';
|
||||
jsProperty = this.vendors[i][1] + 'Transform';
|
||||
} else {
|
||||
cssProperty = 'transform';
|
||||
jsProperty = 'transform';
|
||||
}
|
||||
if (element.style[jsProperty] !== undefined) {
|
||||
propertySupport = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch(value) {
|
||||
case '2D':
|
||||
featureSupport = propertySupport;
|
||||
break;
|
||||
case '3D':
|
||||
if (propertySupport) {
|
||||
var body = document.body || document.createElement('body');
|
||||
var documentElement = document.documentElement;
|
||||
var documentOverflow = documentElement.style.overflow;
|
||||
if (!document.body) {
|
||||
documentElement.style.overflow = 'hidden';
|
||||
documentElement.appendChild(body);
|
||||
body.style.overflow = 'hidden';
|
||||
body.style.background = '';
|
||||
}
|
||||
body.appendChild(element);
|
||||
element.style[jsProperty] = 'translate3d(1px,1px,1px)';
|
||||
propertyValue = window.getComputedStyle(element).getPropertyValue(cssProperty);
|
||||
featureSupport = propertyValue !== undefined && propertyValue.length > 0 && propertyValue !== "none";
|
||||
documentElement.style.overflow = documentOverflow;
|
||||
body.removeChild(element);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return featureSupport;
|
||||
};
|
||||
|
||||
Plugin.prototype.ww = null;
|
||||
Plugin.prototype.wh = null;
|
||||
Plugin.prototype.wcx = null;
|
||||
Plugin.prototype.wcy = null;
|
||||
Plugin.prototype.wrx = null;
|
||||
Plugin.prototype.wry = null;
|
||||
Plugin.prototype.portrait = null;
|
||||
Plugin.prototype.desktop = !navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|mobi|tablet|opera mini|nexus 7)/i);
|
||||
Plugin.prototype.vendors = [null,['-webkit-','webkit'],['-moz-','Moz'],['-o-','O'],['-ms-','ms']];
|
||||
Plugin.prototype.motionSupport = !!window.DeviceMotionEvent;
|
||||
Plugin.prototype.orientationSupport = !!window.DeviceOrientationEvent;
|
||||
Plugin.prototype.orientationStatus = 0;
|
||||
Plugin.prototype.transform2DSupport = Plugin.prototype.transformSupport('2D');
|
||||
Plugin.prototype.transform3DSupport = Plugin.prototype.transformSupport('3D');
|
||||
Plugin.prototype.propertyCache = {};
|
||||
|
||||
Plugin.prototype.initialise = function() {
|
||||
|
||||
// Configure Styles
|
||||
if (this.$context.css('position') === 'static') {
|
||||
this.$context.css({
|
||||
position:'relative'
|
||||
});
|
||||
}
|
||||
|
||||
// Hardware Accelerate Context
|
||||
this.accelerate(this.$context);
|
||||
|
||||
// Setup
|
||||
this.updateLayers();
|
||||
this.updateDimensions();
|
||||
this.enable();
|
||||
this.queueCalibration(this.calibrationDelay);
|
||||
};
|
||||
|
||||
Plugin.prototype.updateLayers = function() {
|
||||
|
||||
// Cache Layer Elements
|
||||
this.$layers = this.$context.find('.layer');
|
||||
this.depths = [];
|
||||
|
||||
// Configure Layer Styles
|
||||
this.$layers.css({
|
||||
position:'absolute',
|
||||
display:'block',
|
||||
left: 0,
|
||||
top: 0
|
||||
});
|
||||
this.$layers.first().css({
|
||||
position:'relative'
|
||||
});
|
||||
|
||||
// Hardware Accelerate Layers
|
||||
this.accelerate(this.$layers);
|
||||
|
||||
// Cache Depths
|
||||
this.$layers.each($.proxy(function(index, element) {
|
||||
this.depths.push($(element).data('depth') || 0);
|
||||
}, this));
|
||||
};
|
||||
|
||||
Plugin.prototype.updateDimensions = function() {
|
||||
this.ww = window.innerWidth;
|
||||
this.wh = window.innerHeight;
|
||||
this.wcx = this.ww * this.originX;
|
||||
this.wcy = this.wh * this.originY;
|
||||
this.wrx = Math.max(this.wcx, this.ww - this.wcx);
|
||||
this.wry = Math.max(this.wcy, this.wh - this.wcy);
|
||||
};
|
||||
|
||||
Plugin.prototype.updateBounds = function() {
|
||||
this.bounds = this.element.getBoundingClientRect();
|
||||
this.ex = this.bounds.left;
|
||||
this.ey = this.bounds.top;
|
||||
this.ew = this.bounds.width;
|
||||
this.eh = this.bounds.height;
|
||||
this.ecx = this.ew * this.originX;
|
||||
this.ecy = this.eh * this.originY;
|
||||
this.erx = Math.max(this.ecx, this.ew - this.ecx);
|
||||
this.ery = Math.max(this.ecy, this.eh - this.ecy);
|
||||
};
|
||||
|
||||
Plugin.prototype.queueCalibration = function(delay) {
|
||||
clearTimeout(this.calibrationTimer);
|
||||
this.calibrationTimer = setTimeout(this.onCalibrationTimer, delay);
|
||||
};
|
||||
|
||||
Plugin.prototype.enable = function() {
|
||||
if (!this.enabled) {
|
||||
this.enabled = true;
|
||||
if (this.orientationSupport) {
|
||||
this.portrait = null;
|
||||
window.addEventListener('deviceorientation', this.onDeviceOrientation);
|
||||
setTimeout(this.onOrientationTimer, this.supportDelay);
|
||||
} else {
|
||||
this.cx = 0;
|
||||
this.cy = 0;
|
||||
this.portrait = false;
|
||||
window.addEventListener('mousemove', this.onMouseMove);
|
||||
}
|
||||
window.addEventListener('resize', this.onWindowResize);
|
||||
this.raf = requestAnimationFrame(this.onAnimationFrame);
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.disable = function() {
|
||||
if (this.enabled) {
|
||||
this.enabled = false;
|
||||
if (this.orientationSupport) {
|
||||
window.removeEventListener('deviceorientation', this.onDeviceOrientation);
|
||||
} else {
|
||||
window.removeEventListener('mousemove', this.onMouseMove);
|
||||
}
|
||||
window.removeEventListener('resize', this.onWindowResize);
|
||||
cancelAnimationFrame(this.raf);
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.calibrate = function(x, y) {
|
||||
this.calibrateX = x === undefined ? this.calibrateX : x;
|
||||
this.calibrateY = y === undefined ? this.calibrateY : y;
|
||||
};
|
||||
|
||||
Plugin.prototype.invert = function(x, y) {
|
||||
this.invertX = x === undefined ? this.invertX : x;
|
||||
this.invertY = y === undefined ? this.invertY : y;
|
||||
};
|
||||
|
||||
Plugin.prototype.friction = function(x, y) {
|
||||
this.frictionX = x === undefined ? this.frictionX : x;
|
||||
this.frictionY = y === undefined ? this.frictionY : y;
|
||||
};
|
||||
|
||||
Plugin.prototype.scalar = function(x, y) {
|
||||
this.scalarX = x === undefined ? this.scalarX : x;
|
||||
this.scalarY = y === undefined ? this.scalarY : y;
|
||||
};
|
||||
|
||||
Plugin.prototype.limit = function(x, y) {
|
||||
this.limitX = x === undefined ? this.limitX : x;
|
||||
this.limitY = y === undefined ? this.limitY : y;
|
||||
};
|
||||
|
||||
Plugin.prototype.origin = function(x, y) {
|
||||
this.originX = x === undefined ? this.originX : x;
|
||||
this.originY = y === undefined ? this.originY : y;
|
||||
};
|
||||
|
||||
Plugin.prototype.clamp = function(value, min, max) {
|
||||
value = Math.max(value, min);
|
||||
value = Math.min(value, max);
|
||||
return value;
|
||||
};
|
||||
|
||||
Plugin.prototype.css = function(element, property, value) {
|
||||
var jsProperty = this.propertyCache[property];
|
||||
if (!jsProperty) {
|
||||
for (var i = 0, l = this.vendors.length; i < l; i++) {
|
||||
if (this.vendors[i] !== null) {
|
||||
jsProperty = $.camelCase(this.vendors[i][1] + '-' + property);
|
||||
} else {
|
||||
jsProperty = property;
|
||||
}
|
||||
if (element.style[jsProperty] !== undefined) {
|
||||
this.propertyCache[property] = jsProperty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
element.style[jsProperty] = value;
|
||||
};
|
||||
|
||||
Plugin.prototype.accelerate = function($element) {
|
||||
for (var i = 0, l = $element.length; i < l; i++) {
|
||||
var element = $element[i];
|
||||
this.css(element, 'transform', 'translate3d(0,0,0)');
|
||||
this.css(element, 'transform-style', 'preserve-3d');
|
||||
this.css(element, 'backface-visibility', 'hidden');
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.setPosition = function(element, x, y) {
|
||||
x += 'px';
|
||||
y += 'px';
|
||||
if (this.transform3DSupport) {
|
||||
this.css(element, 'transform', 'translate3d('+x+','+y+',0)');
|
||||
} else if (this.transform2DSupport) {
|
||||
this.css(element, 'transform', 'translate('+x+','+y+')');
|
||||
} else {
|
||||
element.style.left = x;
|
||||
element.style.top = y;
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.onOrientationTimer = function(event) {
|
||||
if (this.orientationSupport && this.orientationStatus === 0) {
|
||||
this.disable();
|
||||
this.orientationSupport = false;
|
||||
this.enable();
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.onCalibrationTimer = function(event) {
|
||||
this.calibrationFlag = true;
|
||||
};
|
||||
|
||||
Plugin.prototype.onWindowResize = function(event) {
|
||||
this.updateDimensions();
|
||||
};
|
||||
|
||||
Plugin.prototype.onAnimationFrame = function() {
|
||||
this.updateBounds();
|
||||
var dx = this.ix - this.cx;
|
||||
var dy = this.iy - this.cy;
|
||||
if ((Math.abs(dx) > this.calibrationThreshold) || (Math.abs(dy) > this.calibrationThreshold)) {
|
||||
this.queueCalibration(0);
|
||||
}
|
||||
if (this.portrait) {
|
||||
this.mx = this.calibrateX ? dy : this.iy;
|
||||
this.my = this.calibrateY ? dx : this.ix;
|
||||
} else {
|
||||
this.mx = this.calibrateX ? dx : this.ix;
|
||||
this.my = this.calibrateY ? dy : this.iy;
|
||||
}
|
||||
this.mx *= this.ew * (this.scalarX / 100);
|
||||
this.my *= this.eh * (this.scalarY / 100);
|
||||
if (!isNaN(parseFloat(this.limitX))) {
|
||||
this.mx = this.clamp(this.mx, -this.limitX, this.limitX);
|
||||
}
|
||||
if (!isNaN(parseFloat(this.limitY))) {
|
||||
this.my = this.clamp(this.my, -this.limitY, this.limitY);
|
||||
}
|
||||
this.vx += (this.mx - this.vx) * this.frictionX;
|
||||
this.vy += (this.my - this.vy) * this.frictionY;
|
||||
for (var i = 0, l = this.$layers.length; i < l; i++) {
|
||||
var depth = this.depths[i];
|
||||
var layer = this.$layers[i];
|
||||
var xOffset = this.vx * depth * (this.invertX ? -1 : 1);
|
||||
var yOffset = this.vy * depth * (this.invertY ? -1 : 1);
|
||||
this.setPosition(layer, xOffset, yOffset);
|
||||
}
|
||||
this.raf = requestAnimationFrame(this.onAnimationFrame);
|
||||
};
|
||||
|
||||
Plugin.prototype.onDeviceOrientation = function(event) {
|
||||
|
||||
// Validate environment and event properties.
|
||||
if (!this.desktop && event.beta !== null && event.gamma !== null) {
|
||||
|
||||
// Set orientation status.
|
||||
this.orientationStatus = 1;
|
||||
|
||||
// Extract Rotation
|
||||
var x = (event.beta || 0) / MAGIC_NUMBER; // -90 :: 90
|
||||
var y = (event.gamma || 0) / MAGIC_NUMBER; // -180 :: 180
|
||||
|
||||
// Detect Orientation Change
|
||||
var portrait = window.innerHeight > window.innerWidth;
|
||||
if (this.portrait !== portrait) {
|
||||
this.portrait = portrait;
|
||||
this.calibrationFlag = true;
|
||||
}
|
||||
|
||||
// Set Calibration
|
||||
if (this.calibrationFlag) {
|
||||
this.calibrationFlag = false;
|
||||
this.cx = x;
|
||||
this.cy = y;
|
||||
}
|
||||
|
||||
// Set Input
|
||||
this.ix = x;
|
||||
this.iy = y;
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.onMouseMove = function(event) {
|
||||
|
||||
// Cache mouse coordinates.
|
||||
var clientX = event.clientX;
|
||||
var clientY = event.clientY;
|
||||
|
||||
// Calculate Mouse Input
|
||||
if (!this.orientationSupport && this.relativeInput) {
|
||||
|
||||
// Clip mouse coordinates inside element bounds.
|
||||
if (this.clipRelativeInput) {
|
||||
clientX = Math.max(clientX, this.ex);
|
||||
clientX = Math.min(clientX, this.ex + this.ew);
|
||||
clientY = Math.max(clientY, this.ey);
|
||||
clientY = Math.min(clientY, this.ey + this.eh);
|
||||
}
|
||||
|
||||
// Calculate input relative to the element.
|
||||
this.ix = (clientX - this.ex - this.ecx) / this.erx;
|
||||
this.iy = (clientY - this.ey - this.ecy) / this.ery;
|
||||
|
||||
} else {
|
||||
|
||||
// Calculate input relative to the window.
|
||||
this.ix = (clientX - this.wcx) / this.wrx;
|
||||
this.iy = (clientY - this.wcy) / this.wry;
|
||||
}
|
||||
};
|
||||
|
||||
var API = {
|
||||
enable: Plugin.prototype.enable,
|
||||
disable: Plugin.prototype.disable,
|
||||
updateLayers: Plugin.prototype.updateLayers,
|
||||
calibrate: Plugin.prototype.calibrate,
|
||||
friction: Plugin.prototype.friction,
|
||||
invert: Plugin.prototype.invert,
|
||||
scalar: Plugin.prototype.scalar,
|
||||
limit: Plugin.prototype.limit,
|
||||
origin: Plugin.prototype.origin
|
||||
};
|
||||
|
||||
$.fn[NAME] = function (value) {
|
||||
var args = arguments;
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var plugin = $this.data(NAME);
|
||||
if (!plugin) {
|
||||
plugin = new Plugin(this, value);
|
||||
$this.data(NAME, plugin);
|
||||
}
|
||||
if (API[value]) {
|
||||
plugin[value].apply(plugin, Array.prototype.slice.call(args, 1));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})(window.jQuery || window.Zepto, window, document);
|
||||
|
||||
/**
|
||||
* Request Animation Frame Polyfill.
|
||||
* @author Tino Zijdel
|
||||
* @author Paul Irish
|
||||
* @see https://gist.github.com/paulirish/1579671
|
||||
*/
|
||||
;(function() {
|
||||
|
||||
var lastTime = 0;
|
||||
var vendors = ['ms', 'moz', 'webkit', 'o'];
|
||||
|
||||
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
|
||||
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame) {
|
||||
window.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;
|
||||
};
|
||||
}
|
||||
|
||||
if (!window.cancelAnimationFrame) {
|
||||
window.cancelAnimationFrame = function(id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
}
|
||||
|
||||
}());
|
1
sorcery/jquery.parallax.min.js
vendored
Normal file
561
sorcery/parallax.js
Normal file
@ -0,0 +1,561 @@
|
||||
//============================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright (C) 2014 Matthew Wagerfield - @wagerfield
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any
|
||||
// person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the
|
||||
// Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute,
|
||||
// sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do
|
||||
// so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice
|
||||
// shall be included in all copies or substantial portions
|
||||
// of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
|
||||
// OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
// OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//============================================================
|
||||
|
||||
/**
|
||||
* Parallax.js
|
||||
* @author Matthew Wagerfield - @wagerfield
|
||||
* @description Creates a parallax effect between an array of layers,
|
||||
* driving the motion from the gyroscope output of a smartdevice.
|
||||
* If no gyroscope is available, the cursor position is used.
|
||||
*/
|
||||
;(function(window, document, undefined) {
|
||||
|
||||
// Strict Mode
|
||||
'use strict';
|
||||
|
||||
// Constants
|
||||
var NAME = 'Parallax';
|
||||
var MAGIC_NUMBER = 30;
|
||||
var DEFAULTS = {
|
||||
relativeInput: false,
|
||||
clipRelativeInput: false,
|
||||
calibrationThreshold: 100,
|
||||
calibrationDelay: 500,
|
||||
supportDelay: 500,
|
||||
calibrateX: false,
|
||||
calibrateY: true,
|
||||
invertX: true,
|
||||
invertY: true,
|
||||
limitX: false,
|
||||
limitY: false,
|
||||
scalarX: 10.0,
|
||||
scalarY: 10.0,
|
||||
frictionX: 0.1,
|
||||
frictionY: 0.1,
|
||||
originX: 0.5,
|
||||
originY: 0.5
|
||||
};
|
||||
|
||||
function Parallax(element, options) {
|
||||
|
||||
// DOM Context
|
||||
this.element = element;
|
||||
this.layers = element.getElementsByClassName('layer');
|
||||
|
||||
// Data Extraction
|
||||
var data = {
|
||||
calibrateX: this.data(this.element, 'calibrate-x'),
|
||||
calibrateY: this.data(this.element, 'calibrate-y'),
|
||||
invertX: this.data(this.element, 'invert-x'),
|
||||
invertY: this.data(this.element, 'invert-y'),
|
||||
limitX: this.data(this.element, 'limit-x'),
|
||||
limitY: this.data(this.element, 'limit-y'),
|
||||
scalarX: this.data(this.element, 'scalar-x'),
|
||||
scalarY: this.data(this.element, 'scalar-y'),
|
||||
frictionX: this.data(this.element, 'friction-x'),
|
||||
frictionY: this.data(this.element, 'friction-y'),
|
||||
originX: this.data(this.element, 'origin-x'),
|
||||
originY: this.data(this.element, 'origin-y')
|
||||
};
|
||||
|
||||
// Delete Null Data Values
|
||||
for (var key in data) {
|
||||
if (data[key] === null) delete data[key];
|
||||
}
|
||||
|
||||
// Compose Settings Object
|
||||
this.extend(this, DEFAULTS, options, data);
|
||||
|
||||
// States
|
||||
this.calibrationTimer = null;
|
||||
this.calibrationFlag = true;
|
||||
this.enabled = false;
|
||||
this.depths = [];
|
||||
this.raf = null;
|
||||
|
||||
// Element Bounds
|
||||
this.bounds = null;
|
||||
this.ex = 0;
|
||||
this.ey = 0;
|
||||
this.ew = 0;
|
||||
this.eh = 0;
|
||||
|
||||
// Element Center
|
||||
this.ecx = 0;
|
||||
this.ecy = 0;
|
||||
|
||||
// Element Range
|
||||
this.erx = 0;
|
||||
this.ery = 0;
|
||||
|
||||
// Calibration
|
||||
this.cx = 0;
|
||||
this.cy = 0;
|
||||
|
||||
// Input
|
||||
this.ix = 0;
|
||||
this.iy = 0;
|
||||
|
||||
// Motion
|
||||
this.mx = 0;
|
||||
this.my = 0;
|
||||
|
||||
// Velocity
|
||||
this.vx = 0;
|
||||
this.vy = 0;
|
||||
|
||||
// Callbacks
|
||||
this.onMouseMove = this.onMouseMove.bind(this);
|
||||
this.onDeviceOrientation = this.onDeviceOrientation.bind(this);
|
||||
this.onOrientationTimer = this.onOrientationTimer.bind(this);
|
||||
this.onCalibrationTimer = this.onCalibrationTimer.bind(this);
|
||||
this.onAnimationFrame = this.onAnimationFrame.bind(this);
|
||||
this.onWindowResize = this.onWindowResize.bind(this);
|
||||
|
||||
// Initialise
|
||||
this.initialise();
|
||||
}
|
||||
|
||||
Parallax.prototype.extend = function() {
|
||||
if (arguments.length > 1) {
|
||||
var master = arguments[0];
|
||||
for (var i = 1, l = arguments.length; i < l; i++) {
|
||||
var object = arguments[i];
|
||||
for (var key in object) {
|
||||
master[key] = object[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Parallax.prototype.data = function(element, name) {
|
||||
return this.deserialize(element.getAttribute('data-'+name));
|
||||
};
|
||||
|
||||
Parallax.prototype.deserialize = function(value) {
|
||||
if (value === "true") {
|
||||
return true;
|
||||
} else if (value === "false") {
|
||||
return false;
|
||||
} else if (value === "null") {
|
||||
return null;
|
||||
} else if (!isNaN(parseFloat(value)) && isFinite(value)) {
|
||||
return parseFloat(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
Parallax.prototype.camelCase = function(value) {
|
||||
return value.replace(/-+(.)?/g, function(match, character){
|
||||
return character ? character.toUpperCase() : '';
|
||||
});
|
||||
};
|
||||
|
||||
Parallax.prototype.transformSupport = function(value) {
|
||||
var element = document.createElement('div');
|
||||
var propertySupport = false;
|
||||
var propertyValue = null;
|
||||
var featureSupport = false;
|
||||
var cssProperty = null;
|
||||
var jsProperty = null;
|
||||
for (var i = 0, l = this.vendors.length; i < l; i++) {
|
||||
if (this.vendors[i] !== null) {
|
||||
cssProperty = this.vendors[i][0] + 'transform';
|
||||
jsProperty = this.vendors[i][1] + 'Transform';
|
||||
} else {
|
||||
cssProperty = 'transform';
|
||||
jsProperty = 'transform';
|
||||
}
|
||||
if (element.style[jsProperty] !== undefined) {
|
||||
propertySupport = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch(value) {
|
||||
case '2D':
|
||||
featureSupport = propertySupport;
|
||||
break;
|
||||
case '3D':
|
||||
if (propertySupport) {
|
||||
var body = document.body || document.createElement('body');
|
||||
var documentElement = document.documentElement;
|
||||
var documentOverflow = documentElement.style.overflow;
|
||||
if (!document.body) {
|
||||
documentElement.style.overflow = 'hidden';
|
||||
documentElement.appendChild(body);
|
||||
body.style.overflow = 'hidden';
|
||||
body.style.background = '';
|
||||
}
|
||||
body.appendChild(element);
|
||||
element.style[jsProperty] = 'translate3d(1px,1px,1px)';
|
||||
propertyValue = window.getComputedStyle(element).getPropertyValue(cssProperty);
|
||||
featureSupport = propertyValue !== undefined && propertyValue.length > 0 && propertyValue !== "none";
|
||||
documentElement.style.overflow = documentOverflow;
|
||||
body.removeChild(element);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return featureSupport;
|
||||
};
|
||||
|
||||
Parallax.prototype.ww = null;
|
||||
Parallax.prototype.wh = null;
|
||||
Parallax.prototype.wcx = null;
|
||||
Parallax.prototype.wcy = null;
|
||||
Parallax.prototype.wrx = null;
|
||||
Parallax.prototype.wry = null;
|
||||
Parallax.prototype.portrait = null;
|
||||
Parallax.prototype.desktop = !navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|mobi|tablet|opera mini|nexus 7)/i);
|
||||
Parallax.prototype.vendors = [null,['-webkit-','webkit'],['-moz-','Moz'],['-o-','O'],['-ms-','ms']];
|
||||
Parallax.prototype.motionSupport = !!window.DeviceMotionEvent;
|
||||
Parallax.prototype.orientationSupport = !!window.DeviceOrientationEvent;
|
||||
Parallax.prototype.orientationStatus = 0;
|
||||
Parallax.prototype.transform2DSupport = Parallax.prototype.transformSupport('2D');
|
||||
Parallax.prototype.transform3DSupport = Parallax.prototype.transformSupport('3D');
|
||||
Parallax.prototype.propertyCache = {};
|
||||
|
||||
Parallax.prototype.initialise = function() {
|
||||
|
||||
// Configure Context Styles
|
||||
if (this.transform3DSupport) this.accelerate(this.element);
|
||||
var style = window.getComputedStyle(this.element);
|
||||
if (style.getPropertyValue('position') === 'static') {
|
||||
this.element.style.position = 'relative';
|
||||
}
|
||||
|
||||
// Setup
|
||||
this.updateLayers();
|
||||
this.updateDimensions();
|
||||
this.enable();
|
||||
this.queueCalibration(this.calibrationDelay);
|
||||
};
|
||||
|
||||
Parallax.prototype.updateLayers = function() {
|
||||
|
||||
// Cache Layer Elements
|
||||
this.layers = this.element.getElementsByClassName('layer');
|
||||
this.depths = [];
|
||||
|
||||
// Configure Layer Styles
|
||||
for (var i = 0, l = this.layers.length; i < l; i++) {
|
||||
var layer = this.layers[i];
|
||||
if (this.transform3DSupport) this.accelerate(layer);
|
||||
layer.style.position = i ? 'absolute' : 'relative';
|
||||
layer.style.display = 'block';
|
||||
layer.style.left = 0;
|
||||
layer.style.top = 0;
|
||||
|
||||
// Cache Layer Depth
|
||||
this.depths.push(this.data(layer, 'depth') || 0);
|
||||
}
|
||||
};
|
||||
|
||||
Parallax.prototype.updateDimensions = function() {
|
||||
this.ww = window.innerWidth;
|
||||
this.wh = window.innerHeight;
|
||||
this.wcx = this.ww * this.originX;
|
||||
this.wcy = this.wh * this.originY;
|
||||
this.wrx = Math.max(this.wcx, this.ww - this.wcx);
|
||||
this.wry = Math.max(this.wcy, this.wh - this.wcy);
|
||||
};
|
||||
|
||||
Parallax.prototype.updateBounds = function() {
|
||||
this.bounds = this.element.getBoundingClientRect();
|
||||
this.ex = this.bounds.left;
|
||||
this.ey = this.bounds.top;
|
||||
this.ew = this.bounds.width;
|
||||
this.eh = this.bounds.height;
|
||||
this.ecx = this.ew * this.originX;
|
||||
this.ecy = this.eh * this.originY;
|
||||
this.erx = Math.max(this.ecx, this.ew - this.ecx);
|
||||
this.ery = Math.max(this.ecy, this.eh - this.ecy);
|
||||
};
|
||||
|
||||
Parallax.prototype.queueCalibration = function(delay) {
|
||||
clearTimeout(this.calibrationTimer);
|
||||
this.calibrationTimer = setTimeout(this.onCalibrationTimer, delay);
|
||||
};
|
||||
|
||||
Parallax.prototype.enable = function() {
|
||||
if (!this.enabled) {
|
||||
this.enabled = true;
|
||||
if (this.orientationSupport) {
|
||||
this.portrait = null;
|
||||
window.addEventListener('deviceorientation', this.onDeviceOrientation);
|
||||
setTimeout(this.onOrientationTimer, this.supportDelay);
|
||||
} else {
|
||||
this.cx = 0;
|
||||
this.cy = 0;
|
||||
this.portrait = false;
|
||||
window.addEventListener('mousemove', this.onMouseMove);
|
||||
}
|
||||
window.addEventListener('resize', this.onWindowResize);
|
||||
this.raf = requestAnimationFrame(this.onAnimationFrame);
|
||||
}
|
||||
};
|
||||
|
||||
Parallax.prototype.disable = function() {
|
||||
if (this.enabled) {
|
||||
this.enabled = false;
|
||||
if (this.orientationSupport) {
|
||||
window.removeEventListener('deviceorientation', this.onDeviceOrientation);
|
||||
} else {
|
||||
window.removeEventListener('mousemove', this.onMouseMove);
|
||||
}
|
||||
window.removeEventListener('resize', this.onWindowResize);
|
||||
cancelAnimationFrame(this.raf);
|
||||
}
|
||||
};
|
||||
|
||||
Parallax.prototype.calibrate = function(x, y) {
|
||||
this.calibrateX = x === undefined ? this.calibrateX : x;
|
||||
this.calibrateY = y === undefined ? this.calibrateY : y;
|
||||
};
|
||||
|
||||
Parallax.prototype.invert = function(x, y) {
|
||||
this.invertX = x === undefined ? this.invertX : x;
|
||||
this.invertY = y === undefined ? this.invertY : y;
|
||||
};
|
||||
|
||||
Parallax.prototype.friction = function(x, y) {
|
||||
this.frictionX = x === undefined ? this.frictionX : x;
|
||||
this.frictionY = y === undefined ? this.frictionY : y;
|
||||
};
|
||||
|
||||
Parallax.prototype.scalar = function(x, y) {
|
||||
this.scalarX = x === undefined ? this.scalarX : x;
|
||||
this.scalarY = y === undefined ? this.scalarY : y;
|
||||
};
|
||||
|
||||
Parallax.prototype.limit = function(x, y) {
|
||||
this.limitX = x === undefined ? this.limitX : x;
|
||||
this.limitY = y === undefined ? this.limitY : y;
|
||||
};
|
||||
|
||||
Parallax.prototype.origin = function(x, y) {
|
||||
this.originX = x === undefined ? this.originX : x;
|
||||
this.originY = y === undefined ? this.originY : y;
|
||||
};
|
||||
|
||||
Parallax.prototype.clamp = function(value, min, max) {
|
||||
value = Math.max(value, min);
|
||||
value = Math.min(value, max);
|
||||
return value;
|
||||
};
|
||||
|
||||
Parallax.prototype.css = function(element, property, value) {
|
||||
var jsProperty = this.propertyCache[property];
|
||||
if (!jsProperty) {
|
||||
for (var i = 0, l = this.vendors.length; i < l; i++) {
|
||||
if (this.vendors[i] !== null) {
|
||||
jsProperty = this.camelCase(this.vendors[i][1] + '-' + property);
|
||||
} else {
|
||||
jsProperty = property;
|
||||
}
|
||||
if (element.style[jsProperty] !== undefined) {
|
||||
this.propertyCache[property] = jsProperty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
element.style[jsProperty] = value;
|
||||
};
|
||||
|
||||
Parallax.prototype.accelerate = function(element) {
|
||||
this.css(element, 'transform', 'translate3d(0,0,0)');
|
||||
this.css(element, 'transform-style', 'preserve-3d');
|
||||
this.css(element, 'backface-visibility', 'hidden');
|
||||
};
|
||||
|
||||
Parallax.prototype.setPosition = function(element, x, y) {
|
||||
x += 'px';
|
||||
y += 'px';
|
||||
if (this.transform3DSupport) {
|
||||
this.css(element, 'transform', 'translate3d('+x+','+y+',0)');
|
||||
} else if (this.transform2DSupport) {
|
||||
this.css(element, 'transform', 'translate('+x+','+y+')');
|
||||
} else {
|
||||
element.style.left = x;
|
||||
element.style.top = y;
|
||||
}
|
||||
};
|
||||
|
||||
Parallax.prototype.onOrientationTimer = function(event) {
|
||||
if (this.orientationSupport && this.orientationStatus === 0) {
|
||||
this.disable();
|
||||
this.orientationSupport = false;
|
||||
this.enable();
|
||||
}
|
||||
};
|
||||
|
||||
Parallax.prototype.onCalibrationTimer = function(event) {
|
||||
this.calibrationFlag = true;
|
||||
};
|
||||
|
||||
Parallax.prototype.onWindowResize = function(event) {
|
||||
this.updateDimensions();
|
||||
};
|
||||
|
||||
Parallax.prototype.onAnimationFrame = function() {
|
||||
this.updateBounds();
|
||||
var dx = this.ix - this.cx;
|
||||
var dy = this.iy - this.cy;
|
||||
if ((Math.abs(dx) > this.calibrationThreshold) || (Math.abs(dy) > this.calibrationThreshold)) {
|
||||
this.queueCalibration(0);
|
||||
}
|
||||
if (this.portrait) {
|
||||
this.mx = this.calibrateX ? dy : this.iy;
|
||||
this.my = this.calibrateY ? dx : this.ix;
|
||||
} else {
|
||||
this.mx = this.calibrateX ? dx : this.ix;
|
||||
this.my = this.calibrateY ? dy : this.iy;
|
||||
}
|
||||
this.mx *= this.ew * (this.scalarX / 100);
|
||||
this.my *= this.eh * (this.scalarY / 100);
|
||||
if (!isNaN(parseFloat(this.limitX))) {
|
||||
this.mx = this.clamp(this.mx, -this.limitX, this.limitX);
|
||||
}
|
||||
if (!isNaN(parseFloat(this.limitY))) {
|
||||
this.my = this.clamp(this.my, -this.limitY, this.limitY);
|
||||
}
|
||||
this.vx += (this.mx - this.vx) * this.frictionX;
|
||||
this.vy += (this.my - this.vy) * this.frictionY;
|
||||
for (var i = 0, l = this.layers.length; i < l; i++) {
|
||||
var layer = this.layers[i];
|
||||
var depth = this.depths[i];
|
||||
var xOffset = this.vx * depth * (this.invertX ? -1 : 1);
|
||||
var yOffset = this.vy * depth * (this.invertY ? -1 : 1);
|
||||
this.setPosition(layer, xOffset, yOffset);
|
||||
}
|
||||
this.raf = requestAnimationFrame(this.onAnimationFrame);
|
||||
};
|
||||
|
||||
Parallax.prototype.onDeviceOrientation = function(event) {
|
||||
|
||||
// Validate environment and event properties.
|
||||
if (!this.desktop && event.beta !== null && event.gamma !== null) {
|
||||
|
||||
// Set orientation status.
|
||||
this.orientationStatus = 1;
|
||||
|
||||
// Extract Rotation
|
||||
var x = (event.beta || 0) / MAGIC_NUMBER; // -90 :: 90
|
||||
var y = (event.gamma || 0) / MAGIC_NUMBER; // -180 :: 180
|
||||
|
||||
// Detect Orientation Change
|
||||
var portrait = this.wh > this.ww;
|
||||
if (this.portrait !== portrait) {
|
||||
this.portrait = portrait;
|
||||
this.calibrationFlag = true;
|
||||
}
|
||||
|
||||
// Set Calibration
|
||||
if (this.calibrationFlag) {
|
||||
this.calibrationFlag = false;
|
||||
this.cx = x;
|
||||
this.cy = y;
|
||||
}
|
||||
|
||||
// Set Input
|
||||
this.ix = x;
|
||||
this.iy = y;
|
||||
}
|
||||
};
|
||||
|
||||
Parallax.prototype.onMouseMove = function(event) {
|
||||
|
||||
// Cache mouse coordinates.
|
||||
var clientX = event.clientX;
|
||||
var clientY = event.clientY;
|
||||
|
||||
// Calculate Mouse Input
|
||||
if (!this.orientationSupport && this.relativeInput) {
|
||||
|
||||
// Clip mouse coordinates inside element bounds.
|
||||
if (this.clipRelativeInput) {
|
||||
clientX = Math.max(clientX, this.ex);
|
||||
clientX = Math.min(clientX, this.ex + this.ew);
|
||||
clientY = Math.max(clientY, this.ey);
|
||||
clientY = Math.min(clientY, this.ey + this.eh);
|
||||
}
|
||||
|
||||
// Calculate input relative to the element.
|
||||
this.ix = (clientX - this.ex - this.ecx) / this.erx;
|
||||
this.iy = (clientY - this.ey - this.ecy) / this.ery;
|
||||
|
||||
} else {
|
||||
|
||||
// Calculate input relative to the window.
|
||||
this.ix = (clientX - this.wcx) / this.wrx;
|
||||
this.iy = (clientY - this.wcy) / this.wry;
|
||||
}
|
||||
};
|
||||
|
||||
// Expose Parallax
|
||||
window[NAME] = Parallax;
|
||||
|
||||
})(window, document);
|
||||
|
||||
/**
|
||||
* Request Animation Frame Polyfill.
|
||||
* @author Tino Zijdel
|
||||
* @author Paul Irish
|
||||
* @see https://gist.github.com/paulirish/1579671
|
||||
*/
|
||||
;(function() {
|
||||
|
||||
var lastTime = 0;
|
||||
var vendors = ['ms', 'moz', 'webkit', 'o'];
|
||||
|
||||
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
|
||||
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame) {
|
||||
window.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;
|
||||
};
|
||||
}
|
||||
|
||||
if (!window.cancelAnimationFrame) {
|
||||
window.cancelAnimationFrame = function(id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
}
|
||||
|
||||
}());
|
1
sorcery/parallax.min.js
vendored
Normal file
BIN
title9.png
Before Width: | Height: | Size: 9.6 KiB |
BIN
work_samples.png
Before Width: | Height: | Size: 3.7 KiB |