Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
027772e364 | ||
|
|
802fa7592c | ||
|
|
f9395c6c27 | ||
|
|
e8b68c246a | ||
|
|
e2a30f53b5 | ||
|
|
c96ff53460 | ||
|
|
9790b42b2e | ||
|
|
b50e688197 |
61
README.md
@@ -1,6 +1,6 @@
|
||||
# lax.js
|
||||
|
||||
Simple & light weight (2kb minified & zipped) vanilla javascript plugin to create *smooth* & beautiful animations when you scrolllll! Harness the power of the most intuitive interaction and make your websites come alive!
|
||||
Simple & light weight (<2kb gzipped) vanilla javascript plugin to create *smooth* & beautiful animations when you scrolllll! Harness the power of the most intuitive interaction and make your websites come alive!
|
||||
|
||||
[>>> DEMO <<<](https://alexfox.dev/laxxx/)
|
||||
|
||||
@@ -28,13 +28,11 @@ import lax from 'lax.js'
|
||||
|
||||
```javascript
|
||||
window.onload = function() {
|
||||
lax.setup({ /* opts */ }) // init
|
||||
lax.setup() // init
|
||||
|
||||
document.addEventListener('scroll', function(e) {
|
||||
lax.update(window.scrollY) // update every scroll
|
||||
}, false)
|
||||
|
||||
lax.update(window.scrollY) // set initial positions
|
||||
}
|
||||
```
|
||||
|
||||
@@ -46,14 +44,19 @@ window.onload = function() {
|
||||
|
||||
4) Scroll and enjoy!
|
||||
|
||||
### Dealing with DOM changes
|
||||
lax builds a list of all elements it needs to control when the page loads so if they are added to the DOM subsequently they won't be updated on page scroll. If you're using a library like React or vue.js, it is likely that not all elements are in the dom on page load. Because of this you will need to call `lax.populateElements()` when you add elements to the DOM that you want to animate.
|
||||
### Usage with React, Vue.js & DOM changes
|
||||
To increase performance lax.js indexes the list of elements to animate when the page loads. If you're using a library like React or vue.js, it is likely that you are adding elements after the initial `window.onload`. Because of this you will need to call `lax.addElement(domElement)` when you add components to the DOM that you want to animate.
|
||||
|
||||
See below for working examples:
|
||||
* [react](https://codepen.io/alexfoxy/pen/PLaKaE)
|
||||
* [vue](https://codepen.io/alexfoxy/pen/ZPRZBq)
|
||||
|
||||
You can also call `lax.removeElement(domElement)` when the component unmounts.
|
||||
|
||||
For example `componentDidMount() // React` or `created() // vue.js`.
|
||||
|
||||
## Presets
|
||||
|
||||
The easiest way to get started is to use the presets via the `data-lax-preset` attribute. You can chain multiple presetes together for e.g. `data-lax-preset="blurOut fadeOut spin"`. Some presets also support an optional strength e.g. `data-lax-preset="blurOut-50"`
|
||||
The easiest way to get started is to use the presets via the `data-lax-preset` attribute. You can chain multiple presets together for e.g. `data-lax-preset="blurOut fadeOut spin"`. Some presets also support an optional strength e.g. `data-lax-preset="blurOut-50"`
|
||||
|
||||
See the list of [Supported Presets](#supported-presets) for details.
|
||||
|
||||
@@ -81,8 +84,8 @@ There are also some shortcuts for useful values:
|
||||
| ------------- | ------------- |
|
||||
| vw | window.innerWidth |
|
||||
| vh | window.innerHeight |
|
||||
| elw | targetElement.clientHeight |
|
||||
| elh | targetElement.clientWidth |
|
||||
| elw | targetElement.clientWidth |
|
||||
| elh | targetElement.clientHeight |
|
||||
|
||||
You can use these instead of integer values for the scrollPos e.g.
|
||||
```html
|
||||
@@ -127,7 +130,8 @@ You can also use vanilla JS within `( )` for calculations and access to more var
|
||||
| zoomInOut | 0.2 |
|
||||
| zoomIn | 0.2 |
|
||||
| zoomOut | 0.2 |
|
||||
|
||||
| swing | 30 |
|
||||
| speedy | 30 |
|
||||
|
||||
## Supported Attribute Keys
|
||||
|
||||
@@ -159,6 +163,15 @@ Filters (note - these may be unperformant on low powered machines)
|
||||
| saturate | data-lax-saturate |
|
||||
| grayscale | data-lax-grayscale |
|
||||
|
||||
Other
|
||||
|
||||
| Filter | Key |
|
||||
| ------------- | ------------- |
|
||||
| background position | data-lax-bg-pos |
|
||||
| background position-x | data-lax-bg-pos-x |
|
||||
| background position-y | data-lax-bg-pos-y |
|
||||
|
||||
|
||||
## Custom Presets
|
||||
To avoid duplicate code you can define your own presets with a list of attributes e.g.
|
||||
```javascript
|
||||
@@ -176,10 +189,15 @@ You can then access this preset like this:
|
||||
</p>
|
||||
```
|
||||
|
||||
## Notes
|
||||
## Performance Tips
|
||||
|
||||
### Performance
|
||||
By default `-webkit-backface-visibility: hidden;` is added to your elements style to encourage the browser to render that object as a layer on the GPU and increase performance. To turn this off add `lax-optimize="false"` to your element.
|
||||
* Avoid nesting lax enabled elements within each other, you'll get better performance using lax with smaller elements in the dom tree.
|
||||
* Avoid transforms on large elements, e.g. full screen backgrounds.
|
||||
* By default elements that have opacity 0 aren't updated. You can either manually set up a `data-lax-opacity` to control this yourself or use `data-lax-optimize` which will set the elements opacity to 0 when it goes off -screen.
|
||||
* By default `-webkit-backface-visibility: hidden;` is added to your elements style to encourage the browser to render that object as a layer on the GPU and increase performance. To turn this off add `data-lax-use-gpu="false"` to your element.
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
### Screen rotating & resizing
|
||||
As some values (vh, vw, elh, elw) are calculated on load, when the screen size changes or rotates you might want to recalculate these. E.g.
|
||||
@@ -191,15 +209,12 @@ window.addEventListener("resize", function() {
|
||||
Be warned, on mobile, a resize event is fired when you scroll and the toolbar is hidden so you might want to check if the width or orientation has changed.
|
||||
|
||||
### Scroll Wheels
|
||||
Scroll wheels only icrement the scroll position in steps which can cause the animations to look janky. You can use the SmoothScroll (http://www.smoothscroll.net/) plugin to smooth this out, however there maybe performance implications that need investigating.
|
||||
Scroll wheels only increment the scroll position in steps which can cause the animations to look janky. You can use the SmoothScroll (http://www.smoothscroll.net/) plugin to smooth this out, however there maybe performance implications that need investigating.
|
||||
|
||||
## To Do / Ideas
|
||||
* Re-calculate values on rotate / change window size
|
||||
* Add debug mode
|
||||
* Elastic bouncing values
|
||||
* Optimise elements that go off screen
|
||||
* Implement a tween for scroll wheels to remove dependency on smoothscroll
|
||||
* Better error reporting
|
||||
* Add "momentum" as option for anchor & presets
|
||||
* Move presets to lax-presets.js to reduce base library size
|
||||
* ~~Re-calculate values on rotate / change window size~~
|
||||
* Elastic bouncing values at edges of screen (if possible)
|
||||
* ~~Optimise: Do not update elements with bounds that are off screen~~
|
||||
* Implement a tween for scroll wheels to remove reliance on smoothscroll
|
||||
* Add "momentum" option
|
||||
|
||||
|
||||
BIN
docs/img/a.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52.22 46.64"><defs><style>.cls-1{fill:#f3f4f5;}</style></defs><title>a</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M1,32.73H6.43C2.55,29.23,0,24.41,0,17.41,0,7.85,5.49,0,15.52,0h.18C26.77,0,31.88,8.42,31.88,20.43a36.09,36.09,0,0,1-2.08,12.4h.85c6,0,9.27-3.69,9.27-10.88A37.31,37.31,0,0,0,37.18,8l11-3.6A44.74,44.74,0,0,1,52.22,24c0,15.7-8.13,22.61-21.85,22.61H1ZM21.38,33a22.24,22.24,0,0,0,1.89-9.18c0-6.15-2.46-9.93-7-9.93h-.19c-3.88,0-6.15,3.21-6.15,7.85,0,6.72,3.69,11.26,8.9,11.26Z"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 615 B |
BIN
docs/img/button-bg.jpg
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
docs/img/l.png
Normal file
|
After Width: | Height: | Size: 237 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 69.06 14.38"><defs><style>.cls-1{fill:#f3f4f5;}</style></defs><title>l</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M0,0H69.06V14.38H0Z"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 264 B |
BIN
docs/img/x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50.71 50.9"><defs><style>.cls-1{fill:#f3f4f5;}</style></defs><title>x</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M0,35.48,15.8,25.26,0,15V0L25.73,17.79,50.71.66V16.08L36,25.54,50.71,35.1v15L26,33,0,50.9Z"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 334 B |
@@ -6,7 +6,7 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,600,800" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
|
||||
|
||||
<script src="./lib/lax.min.js?v=1.0.4"></script>
|
||||
<script src="./lib/lax.min.js"></script>
|
||||
<!-- <script src="../src/lax.js"></script> -->
|
||||
|
||||
<script type="text/javascript">
|
||||
@@ -183,10 +183,12 @@
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 10pt 20pt;
|
||||
background: #35D5E5;
|
||||
padding: 10pt 50pt;
|
||||
background: url(img/button-bg.jpg);
|
||||
background-size: 100pt;
|
||||
border-radius: 10pt;
|
||||
font-weight: 600;
|
||||
color: black !important;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -194,12 +196,12 @@
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: white !important;
|
||||
color: black !important;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background: white;
|
||||
color: #35D5E5 !important;
|
||||
color: black !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -209,15 +211,15 @@
|
||||
|
||||
<body>
|
||||
<div id="main">
|
||||
<div id="header" class="section" data-lax-opacity="0 1, (0.8*vh) 0">
|
||||
<img src="./img/l.svg" style="width: 103pt; margin-left: 26pt; margin-bottom: -4pt;" data-lax-translate-x="0 0, vh 200" />
|
||||
<img src="./img/a.svg" data-lax-translate-x="0 0, vh -200" />
|
||||
<img src="./img/x.svg" />
|
||||
<img src="./img/x.svg" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 200" />
|
||||
<img src="./img/x.svg" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 400" />
|
||||
<img src="./img/x.svg" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 600" />
|
||||
<img src="./img/x.svg" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 800" />
|
||||
<img src="./img/x.svg" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 1000" />
|
||||
<div id="header" class="section">
|
||||
<img src="./img/l.png" style="width: 103pt; margin-left: 26pt; margin-bottom: -4pt;" data-lax-translate-x="0 0, vh 200" data-lax-optimize=true />
|
||||
<img src="./img/a.png" data-lax-translate-x="0 0, vh -200" data-lax-optimize=true />
|
||||
<img src="./img/x.png" data-lax-opacity="0 1, (0.8*vh) 0" />
|
||||
<img src="./img/x.png" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 200" data-lax-opacity="0 1, (0.8*vh) 0" />
|
||||
<img src="./img/x.png" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 400" data-lax-opacity="0 1, (0.8*vh) 0" />
|
||||
<img src="./img/x.png" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 600" data-lax-opacity="0 1, (0.8*vh) 0" />
|
||||
<img src="./img/x.png" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 800" data-lax-opacity="0 1, (0.8*vh) 0" />
|
||||
<img src="./img/x.png" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 1000" data-lax-opacity="0 1, (0.8*vh) 0" />
|
||||
<h2 data-lax-scale="0 1, vh 0.2" data-lax-translate-y="0 0, vh 1200" data-lax-opacity="0 1, (vh*0.5) 0">awesum scroll effects</h2>
|
||||
|
||||
<h4 data-lax-opacity="0 1, (vh*0.05) 0">scroll down</h4>
|
||||
@@ -245,7 +247,7 @@
|
||||
data-lax-preset="lazy-300"
|
||||
></div>
|
||||
|
||||
<h3 data-lax-preset="driftRight" class="chunkyText" style="color: #35D5E5;">oooh!</h3>
|
||||
<h3 data-lax-preset="driftRight" data-lax-optimize=true class="chunkyText" style="color: #35D5E5;">oooh!</h3>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
@@ -263,10 +265,10 @@
|
||||
style="background: #ED2471; margin-left: 20pt; margin-top: 200pt"
|
||||
data-lax-preset="lazy-350"
|
||||
></div>
|
||||
<h3 data-lax-preset="driftLeft" class="chunkyText" style="color: #ED2471; margin-top: 200pt;">aaah!</h3>
|
||||
<h3 data-lax-optimize=true data-lax-preset="driftLeft" class="chunkyText" style="color: #ED2471; margin-top: 200pt;">aaah!</h3>
|
||||
</div>
|
||||
|
||||
<h3 data-lax-preset="crazy zoomInOut" class="crazyText">sooo crazy</h3>
|
||||
<h3 data-lax-preset="crazy zoomInOut" class="crazyText" data-lax-optimize=true>sooo crazy</h3>
|
||||
</div>
|
||||
|
||||
<div id="section2" class="section">
|
||||
@@ -312,7 +314,7 @@
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<h3 data-lax-preset="leftToRight-0.8 fadeInOut" class="chunkyText" style="
|
||||
<h3 data-lax-preset="leftToRight-0.8 speedy" data-lax-optimize=true class="chunkyText" style="
|
||||
color: #white; position: absolute; margin-top: -20pt; margin-left: -100pt">
|
||||
wheee!
|
||||
</h3>
|
||||
@@ -347,10 +349,10 @@
|
||||
</div>
|
||||
|
||||
<div id="section3" class="section">
|
||||
<p data-lax-preset="linger">
|
||||
<p data-lax-preset="linger" data-lax-optimize=true>
|
||||
Harness the power of scrolling and make your websites come alive!
|
||||
</p>
|
||||
<a class="button" data-lax-preset="linger" href="https://github.com/alexfoxy/laxxx">
|
||||
<a class="button" data-lax-preset="linger" data-lax-optimize=true data-lax-bg-pos-x="0 0, 3000 1000" href="https://github.com/alexfoxy/laxxx">
|
||||
Get lax.js
|
||||
</a>
|
||||
</div>
|
||||
|
||||
2
docs/lib/lax.min.js
vendored
230
lib/lax.js
@@ -19,6 +19,7 @@
|
||||
var lax = {
|
||||
elements: []
|
||||
};
|
||||
var lastY = 0;
|
||||
var transforms = {
|
||||
"data-lax-opacity": function dataLaxOpacity(style, v) {
|
||||
style.opacity = v;
|
||||
@@ -73,6 +74,15 @@
|
||||
},
|
||||
"data-lax-grayscale": function dataLaxGrayscale(style, v) {
|
||||
style.filter += " grayscale(".concat(v, "%)");
|
||||
},
|
||||
"data-lax-bg-pos": function dataLaxBgPos(style, v) {
|
||||
style.backgroundPosition = "".concat(v, "px ").concat(v, "px");
|
||||
},
|
||||
"data-lax-bg-pos-x": function dataLaxBgPosX(style, v) {
|
||||
style.backgroundPositionX = "".concat(v, "px");
|
||||
},
|
||||
"data-lax-bg-pos-y": function dataLaxBgPosY(style, v) {
|
||||
style.backgroundPositionY = "".concat(v, "px");
|
||||
}
|
||||
};
|
||||
var _crazy = "";
|
||||
@@ -208,24 +218,36 @@
|
||||
return {
|
||||
"data-lax-scale": "(vh*0.3) 1, -elh ".concat(v)
|
||||
};
|
||||
},
|
||||
speedy: function speedy() {
|
||||
var v = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 30;
|
||||
return {
|
||||
"data-lax-skew-x": "(vh) ".concat(v, ", -elh ").concat(-v)
|
||||
};
|
||||
},
|
||||
swing: function swing() {
|
||||
var v = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 30;
|
||||
return {
|
||||
"data-lax-skew-y": "(vh) ".concat(v, ", -elh ").concat(-v)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
lax.addPreset = function (name, o) {
|
||||
lax.presets[name] = o;
|
||||
lax.addPreset = function (p, o) {
|
||||
lax.presets[p] = o;
|
||||
};
|
||||
|
||||
function intrp(table, v) {
|
||||
function intrp(t, v) {
|
||||
var i = 0;
|
||||
|
||||
while (table[i][0] <= v && table[i + 1] !== undefined) {
|
||||
while (t[i][0] <= v && t[i + 1] !== undefined) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
var x = table[i][0];
|
||||
var prevX = table[i - 1] === undefined ? x : table[i - 1][0];
|
||||
var y = table[i][1];
|
||||
var prevY = table[i - 1] === undefined ? y : table[i - 1][1];
|
||||
var x = t[i][0];
|
||||
var prevX = t[i - 1] === undefined ? x : t[i - 1][0];
|
||||
var y = t[i][1];
|
||||
var prevY = t[i - 1] === undefined ? y : t[i - 1][1];
|
||||
var xPoint = Math.min(Math.max((v - prevX) / (x - prevX), 0), 1);
|
||||
var yPoint = xPoint * (y - prevY) + prevY;
|
||||
return yPoint;
|
||||
@@ -235,102 +257,122 @@
|
||||
lax.populateElements();
|
||||
};
|
||||
|
||||
lax.removeElement = function (el) {
|
||||
var i = this.elements.findIndex(function (o) {
|
||||
return o.el = el;
|
||||
});
|
||||
|
||||
if (i > -1) {
|
||||
this.elements.splice(i, 1);
|
||||
}
|
||||
};
|
||||
|
||||
lax.addElement = function (el) {
|
||||
var o = {
|
||||
el: el,
|
||||
transforms: []
|
||||
};
|
||||
var presetNames = el.attributes["data-lax-preset"] && el.attributes["data-lax-preset"].value;
|
||||
|
||||
if (presetNames) {
|
||||
presetNames.split(" ").forEach(function (p) {
|
||||
var bits = p.split("-");
|
||||
var fn = lax.presets[bits[0]];
|
||||
|
||||
if (!fn) {
|
||||
console.error("preset ".concat(bits[0], " is not defined"));
|
||||
} else {
|
||||
var d = fn(bits[1]);
|
||||
|
||||
for (var k in d) {
|
||||
el.setAttribute(k, d[k]);
|
||||
}
|
||||
}
|
||||
});
|
||||
el.setAttribute("data-lax-anchor", "self");
|
||||
el.attributes.removeNamedItem("data-lax-preset");
|
||||
}
|
||||
|
||||
var useGpu = !(el.attributes["data-lax-use-gpu"] && el.attributes["data-lax-use-gpu"].value === 'false');
|
||||
if (useGpu) el.style["-webkit-backface-visibility"] = "hidden";
|
||||
if (el.attributes["data-lax-use-gpu"]) el.attributes.removeNamedItem("data-lax-use-gpu");
|
||||
o.optimise = false;
|
||||
|
||||
if (el.attributes["data-lax-optimize"] && el.attributes["data-lax-optimize"].value === 'true') {
|
||||
o.optimise = true;
|
||||
var bounds = el.getBoundingClientRect();
|
||||
el.setAttribute("data-lax-opacity", "".concat(-bounds.height - 1, " 0, ").concat(-bounds.height, " 1, ").concat(window.innerHeight, " 1, ").concat(window.innerHeight + 1, " 0"));
|
||||
el.attributes.removeNamedItem("data-lax-optimize");
|
||||
}
|
||||
|
||||
for (var i = 0; i < el.attributes.length; i++) {
|
||||
var a = el.attributes[i];
|
||||
var bits = a.name.split("-");
|
||||
|
||||
if (bits[1] === "lax") {
|
||||
if (a.name === "data-lax-anchor") {
|
||||
o["data-lax-anchor"] = a.value === "self" ? el : document.querySelector(a.value);
|
||||
var rect = o["data-lax-anchor"].getBoundingClientRect();
|
||||
o["data-lax-anchor-top"] = Math.floor(rect.top) + window.scrollY;
|
||||
} else {
|
||||
o.transforms[a.name] = a.value.replace(new RegExp('vw', 'g'), window.innerWidth).replace(new RegExp('vh', 'g'), window.innerHeight).replace(new RegExp('elh', 'g'), el.clientHeight).replace(new RegExp('elw', 'g'), el.clientWidth).replace(new RegExp('-vw', 'g'), -window.innerWidth).replace(new RegExp('-vh', 'g'), -window.innerHeight).replace(new RegExp('-elh', 'g'), -el.clientHeight).replace(new RegExp('-elw', 'g'), -el.clientWidth).replace(/\s+/g, " ").split(",").map(function (x) {
|
||||
return x.trim().split(" ").map(function (y) {
|
||||
if (y[0] === "(") return eval(y);else return parseFloat(y);
|
||||
});
|
||||
}).sort(function (a, b) {
|
||||
return a[0] - b[0];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lax.elements.push(o);
|
||||
lax.updateElement(o);
|
||||
};
|
||||
|
||||
lax.populateElements = function () {
|
||||
lax.elements = [];
|
||||
var selector = Object.keys(transforms).map(function (t) {
|
||||
return "[".concat(t, "]");
|
||||
}).join(",");
|
||||
selector += ",[data-lax-preset]";
|
||||
document.querySelectorAll(selector).forEach(function (el) {
|
||||
var o = {
|
||||
el: el,
|
||||
transforms: []
|
||||
};
|
||||
var presetNames = el.attributes["data-lax-preset"] && el.attributes["data-lax-preset"].value;
|
||||
|
||||
if (presetNames) {
|
||||
presetNames.split(" ").forEach(function (p) {
|
||||
var bits = p.split("-");
|
||||
var fn = lax.presets[bits[0]];
|
||||
|
||||
if (!fn) {
|
||||
console.error("preset #{bits[0]} is not defined");
|
||||
} else {
|
||||
var d = fn(bits[1]);
|
||||
|
||||
for (var k in d) {
|
||||
el.setAttribute(k, d[k]);
|
||||
}
|
||||
}
|
||||
});
|
||||
el.setAttribute("data-lax-anchor", "self");
|
||||
el.attributes.removeNamedItem("data-lax-preset");
|
||||
}
|
||||
|
||||
var optimise = !(el.attributes["data-lax-optimize"] && el.attributes["data-lax-optimize"].value == 'false');
|
||||
if (optimise) el.style["-webkit-backface-visibility"] = "hidden";
|
||||
if (el.attributes["data-lax-optimize"]) el.attributes.removeNamedItem("data-lax-optimize");
|
||||
|
||||
for (var i = 0; i < el.attributes.length; i++) {
|
||||
var a = el.attributes[i];
|
||||
var bits = a.name.split("-");
|
||||
|
||||
if (bits[1] === "lax") {
|
||||
if (a.name === "data-lax-anchor") {
|
||||
o["data-lax-anchor"] = a.value === "self" ? el : document.querySelector(a.value);
|
||||
var rect = o["data-lax-anchor"].getBoundingClientRect();
|
||||
o["data-lax-anchor-top"] = Math.floor(rect.top) + window.scrollY;
|
||||
} else {
|
||||
o.transforms[a.name] = a.value.replace(new RegExp('vw', 'g'), window.innerWidth).replace(new RegExp('vh', 'g'), window.innerHeight).replace(new RegExp('elh', 'g'), el.clientHeight).replace(new RegExp('elw', 'g'), el.clientWidth).replace(new RegExp('-vw', 'g'), -window.innerWidth).replace(new RegExp('-vh', 'g'), -window.innerHeight).replace(new RegExp('-elh', 'g'), -el.clientHeight).replace(new RegExp('-elw', 'g'), -el.clientWidth).replace(/\s+/g, " ").split(",").map(function (x) {
|
||||
return x.trim().split(" ").map(function (y) {
|
||||
if (y[0] === "(") return eval(y);else return parseFloat(y);
|
||||
});
|
||||
}).sort(function (a, b) {
|
||||
return a[0] - b[0];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lax.elements.push(o);
|
||||
});
|
||||
document.querySelectorAll(selector).forEach(this.addElement);
|
||||
};
|
||||
|
||||
var lastScroll = 0;
|
||||
lax.updateElement = function (o) {
|
||||
var y = lastY;
|
||||
var r = o["data-lax-anchor-top"] ? o["data-lax-anchor-top"] - y : y;
|
||||
var style = {
|
||||
transform: "",
|
||||
filter: ""
|
||||
};
|
||||
|
||||
for (var i in o.transforms) {
|
||||
var arr = o.transforms[i];
|
||||
var t = transforms[i];
|
||||
var v = intrp(arr, r);
|
||||
|
||||
if (!t) {
|
||||
console.error("lax: " + i + " is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
t(style, v);
|
||||
}
|
||||
|
||||
for (var k in style) {
|
||||
if (style.opacity === 0) {
|
||||
// if opacity 0 don't update
|
||||
o.el.style.opacity = 0;
|
||||
} else {
|
||||
o.el.style[k] = style[k];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
lax.update = function (y) {
|
||||
var momentum = lastScroll - y;
|
||||
lastScroll = y;
|
||||
lax.elements.forEach(function (o) {
|
||||
var transformString = "";
|
||||
var r = o["data-lax-anchor-top"] ? o["data-lax-anchor-top"] - y : y;
|
||||
var style = {
|
||||
transform: "",
|
||||
filter: ""
|
||||
};
|
||||
|
||||
for (var i in o.transforms) {
|
||||
var arr = o.transforms[i];
|
||||
var t = transforms[i];
|
||||
var v = intrp(arr, r);
|
||||
|
||||
if (!t) {
|
||||
console.error("lax: " + i + " is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
t(style, v);
|
||||
}
|
||||
|
||||
for (var k in style) {
|
||||
if (style.opacity === 0) {
|
||||
// if opacity 0 don't update
|
||||
o.el.style.opacity = 0;
|
||||
} else {
|
||||
o.el.style[k] = style[k];
|
||||
}
|
||||
}
|
||||
});
|
||||
lastY = y;
|
||||
lax.elements.forEach(lax.updateElement);
|
||||
};
|
||||
|
||||
return lax;
|
||||
|
||||
2
lib/lax.min.js
vendored
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "lax.js",
|
||||
"version": "1.0.4",
|
||||
"version": "1.1.0",
|
||||
"scripts": {
|
||||
"build": "babel src -d lib; uglifyjs lib/lax.js -o lib/lax.min.js -c -m; gzip < lib/lax.min.js > lib/lax.min.js.gz"
|
||||
"build": "babel src -d lib; uglifyjs lib/lax.js -o lib/lax.min.js -c -m; gzip < lib/lax.min.js > lib/lax.min.js.gz;"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.2.3",
|
||||
|
||||
235
src/lax.js
@@ -19,6 +19,8 @@
|
||||
elements: []
|
||||
}
|
||||
|
||||
let lastY = 0;
|
||||
|
||||
const transforms = {
|
||||
"data-lax-opacity": function(style, v) { style.opacity = v },
|
||||
"data-lax-translate": function(style, v) { style.transform += ` translate(${v}px, ${v}px)` },
|
||||
@@ -31,7 +33,6 @@
|
||||
"data-lax-skew-x": function(style, v) { style.transform += ` skewX(${v}deg)` },
|
||||
"data-lax-skew-y": function(style, v) { style.transform += ` skewY(${v}deg)` },
|
||||
"data-lax-rotate": function(style, v) { style.transform += ` rotate(${v}deg)` },
|
||||
|
||||
"data-lax-brightness": function(style, v) { style.filter += ` brightness(${v}%)` },
|
||||
"data-lax-contrast": function(style, v) { style.filter += ` contrast(${v}%)` },
|
||||
"data-lax-hue-rotate": function(style, v) { style.filter += ` hue-rotate(${v}deg)` },
|
||||
@@ -39,6 +40,9 @@
|
||||
"data-lax-invert": function(style, v) { style.filter += ` invert(${v}%)` },
|
||||
"data-lax-saturate": function(style, v) { style.filter += ` saturate(${v}%)` },
|
||||
"data-lax-grayscale": function(style, v) { style.filter += ` grayscale(${v}%)` },
|
||||
"data-lax-bg-pos": function(style, v) { style.backgroundPosition = `${v}px ${v}px` },
|
||||
"data-lax-bg-pos-x": function(style, v) { style.backgroundPositionX = `${v}px` },
|
||||
"data-lax-bg-pos-y": function(style, v) { style.backgroundPositionY = `${v}px` }
|
||||
}
|
||||
|
||||
let crazy = ""
|
||||
@@ -114,24 +118,30 @@
|
||||
zoomOut: (v=0.2) => {
|
||||
return { "data-lax-scale": `(vh*0.3) 1, -elh ${v}` }
|
||||
},
|
||||
speedy: (v=30) => {
|
||||
return { "data-lax-skew-x": `(vh) ${v}, -elh ${-v}` }
|
||||
},
|
||||
swing: (v=30) => {
|
||||
return { "data-lax-skew-y": `(vh) ${v}, -elh ${-v}` }
|
||||
}
|
||||
}
|
||||
|
||||
lax.addPreset = (name, o) => {
|
||||
lax.presets[name] = o
|
||||
lax.addPreset = (p, o) => {
|
||||
lax.presets[p] = o
|
||||
}
|
||||
|
||||
function intrp(table, v) {
|
||||
function intrp(t, v) {
|
||||
var i = 0
|
||||
|
||||
while(table[i][0] <= v && table[i+1] !== undefined) {
|
||||
while(t[i][0] <= v && t[i+1] !== undefined) {
|
||||
i+=1
|
||||
}
|
||||
|
||||
var x = table[i][0]
|
||||
var prevX = table[i-1] === undefined ? x : table[i-1][0]
|
||||
var x = t[i][0]
|
||||
var prevX = t[i-1] === undefined ? x : t[i-1][0]
|
||||
|
||||
var y = table[i][1]
|
||||
var prevY = table[i-1] === undefined ? y : table[i-1][1]
|
||||
var y = t[i][1]
|
||||
var prevY = t[i-1] === undefined ? y : t[i-1][1]
|
||||
|
||||
var xPoint = Math.min(Math.max((v-prevX)/(x-prevX),0),1)
|
||||
var yPoint = (xPoint*(y-prevY)) + prevY
|
||||
@@ -143,112 +153,127 @@
|
||||
lax.populateElements()
|
||||
}
|
||||
|
||||
lax.removeElement = function(el) {
|
||||
const i = this.elements.findIndex(o => o.el = el)
|
||||
if(i > -1) {
|
||||
this.elements.splice(i, 1)
|
||||
}
|
||||
}
|
||||
|
||||
lax.addElement = function(el) {
|
||||
var o = {
|
||||
el: el,
|
||||
transforms: []
|
||||
}
|
||||
|
||||
var presetNames = el.attributes["data-lax-preset"] && el.attributes["data-lax-preset"].value
|
||||
if(presetNames) {
|
||||
presetNames.split(" ").forEach((p) => {
|
||||
const bits = p.split("-")
|
||||
const fn = lax.presets[bits[0]]
|
||||
if(!fn) {
|
||||
console.error(`preset ${bits[0]} is not defined`)
|
||||
} else {
|
||||
const d = fn(bits[1])
|
||||
for(var k in d) {
|
||||
el.setAttribute(k, d[k])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
el.setAttribute("data-lax-anchor", "self")
|
||||
el.attributes.removeNamedItem("data-lax-preset")
|
||||
}
|
||||
|
||||
const useGpu = !(el.attributes["data-lax-use-gpu"] && el.attributes["data-lax-use-gpu"].value === 'false')
|
||||
if(useGpu) el.style["-webkit-backface-visibility"] = "hidden"
|
||||
if(el.attributes["data-lax-use-gpu"]) el.attributes.removeNamedItem("data-lax-use-gpu")
|
||||
|
||||
o.optimise = false
|
||||
if(el.attributes["data-lax-optimize"] && el.attributes["data-lax-optimize"].value === 'true') {
|
||||
o.optimise = true
|
||||
const bounds = el.getBoundingClientRect()
|
||||
el.setAttribute("data-lax-opacity", `${-bounds.height-1} 0, ${-bounds.height} 1, ${window.innerHeight} 1, ${window.innerHeight+1} 0`)
|
||||
el.attributes.removeNamedItem("data-lax-optimize")
|
||||
}
|
||||
|
||||
for(var i=0; i<el.attributes.length; i++) {
|
||||
var a = el.attributes[i]
|
||||
var bits = a.name.split("-")
|
||||
if(bits[1] === "lax") {
|
||||
if(a.name === "data-lax-anchor") {
|
||||
o["data-lax-anchor"] = a.value === "self" ? el : document.querySelector(a.value)
|
||||
const rect = o["data-lax-anchor"].getBoundingClientRect()
|
||||
o["data-lax-anchor-top"] = Math.floor(rect.top) + window.scrollY
|
||||
} else {
|
||||
o.transforms[a.name] = a.value
|
||||
.replace(new RegExp('vw', 'g'), window.innerWidth)
|
||||
.replace(new RegExp('vh', 'g'), window.innerHeight)
|
||||
.replace(new RegExp('elh', 'g'), el.clientHeight)
|
||||
.replace(new RegExp('elw', 'g'), el.clientWidth)
|
||||
.replace(new RegExp('-vw', 'g'), -window.innerWidth)
|
||||
.replace(new RegExp('-vh', 'g'), -window.innerHeight)
|
||||
.replace(new RegExp('-elh', 'g'), -el.clientHeight)
|
||||
.replace(new RegExp('-elw', 'g'), -el.clientWidth).replace(/\s+/g," ")
|
||||
.split(",").map((x) => {
|
||||
return x.trim().split(" ").map(y => {
|
||||
if(y[0] === "(") return eval(y)
|
||||
else return parseFloat(y)
|
||||
})
|
||||
}).sort((a,b) => {
|
||||
return a[0] - b[0]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lax.elements.push(o)
|
||||
lax.updateElement(o)
|
||||
}
|
||||
|
||||
lax.populateElements = function() {
|
||||
lax.elements = []
|
||||
|
||||
|
||||
var selector = Object.keys(transforms).map(t => `[${t}]`).join(",")
|
||||
selector += ",[data-lax-preset]"
|
||||
|
||||
document.querySelectorAll(selector).forEach(function(el) {
|
||||
var o = {
|
||||
el: el,
|
||||
transforms: []
|
||||
}
|
||||
|
||||
var presetNames = el.attributes["data-lax-preset"] && el.attributes["data-lax-preset"].value
|
||||
if(presetNames) {
|
||||
presetNames.split(" ").forEach((p) => {
|
||||
const bits = p.split("-")
|
||||
const fn = lax.presets[bits[0]]
|
||||
if(!fn) {
|
||||
console.error(`preset #{bits[0]} is not defined`)
|
||||
} else {
|
||||
const d = fn(bits[1])
|
||||
for(var k in d) {
|
||||
el.setAttribute(k, d[k])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
el.setAttribute("data-lax-anchor", "self")
|
||||
el.attributes.removeNamedItem("data-lax-preset")
|
||||
}
|
||||
|
||||
const optimise = !(el.attributes["data-lax-optimize"] && el.attributes["data-lax-optimize"].value == 'false')
|
||||
if(optimise) el.style["-webkit-backface-visibility"] = "hidden"
|
||||
if(el.attributes["data-lax-optimize"]) el.attributes.removeNamedItem("data-lax-optimize")
|
||||
|
||||
for(var i=0; i<el.attributes.length; i++) {
|
||||
var a = el.attributes[i]
|
||||
var bits = a.name.split("-")
|
||||
if(bits[1] === "lax") {
|
||||
if(a.name === "data-lax-anchor") {
|
||||
o["data-lax-anchor"] = a.value === "self" ? el : document.querySelector(a.value)
|
||||
const rect = o["data-lax-anchor"].getBoundingClientRect()
|
||||
o["data-lax-anchor-top"] = Math.floor(rect.top) + window.scrollY
|
||||
} else {
|
||||
o.transforms[a.name] = a.value
|
||||
.replace(new RegExp('vw', 'g'), window.innerWidth)
|
||||
.replace(new RegExp('vh', 'g'), window.innerHeight)
|
||||
.replace(new RegExp('elh', 'g'), el.clientHeight)
|
||||
.replace(new RegExp('elw', 'g'), el.clientWidth)
|
||||
.replace(new RegExp('-vw', 'g'), -window.innerWidth)
|
||||
.replace(new RegExp('-vh', 'g'), -window.innerHeight)
|
||||
.replace(new RegExp('-elh', 'g'), -el.clientHeight)
|
||||
.replace(new RegExp('-elw', 'g'), -el.clientWidth).replace(/\s+/g," ")
|
||||
.split(",").map((x) => {
|
||||
return x.trim().split(" ").map(y => {
|
||||
if(y[0] === "(") return eval(y)
|
||||
else return parseFloat(y)
|
||||
})
|
||||
}).sort((a,b) => {
|
||||
return a[0] - b[0]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lax.elements.push(o)
|
||||
})
|
||||
document.querySelectorAll(selector).forEach(this.addElement)
|
||||
}
|
||||
|
||||
var lastScroll = 0
|
||||
lax.updateElement = function(o) {
|
||||
const y = lastY
|
||||
var r = o["data-lax-anchor-top"] ? o["data-lax-anchor-top"]-y : y
|
||||
|
||||
var style = {
|
||||
transform: "",
|
||||
filter: ""
|
||||
}
|
||||
|
||||
for(var i in o.transforms) {
|
||||
var arr = o.transforms[i]
|
||||
var t = transforms[i]
|
||||
var v = intrp(arr, r)
|
||||
|
||||
if(!t) {
|
||||
console.error("lax: " + i + " is not supported")
|
||||
return
|
||||
}
|
||||
|
||||
t(style, v)
|
||||
}
|
||||
|
||||
for(let k in style) {
|
||||
if(style.opacity === 0) { // if opacity 0 don't update
|
||||
o.el.style.opacity = 0
|
||||
} else {
|
||||
o.el.style[k] = style[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lax.update = function(y) {
|
||||
var momentum = lastScroll-y
|
||||
lastScroll = y
|
||||
|
||||
lax.elements.forEach(function(o) {
|
||||
var transformString = ""
|
||||
var r = o["data-lax-anchor-top"] ? o["data-lax-anchor-top"]-y : y
|
||||
|
||||
var style = {
|
||||
transform: "",
|
||||
filter: ""
|
||||
}
|
||||
|
||||
for(var i in o.transforms) {
|
||||
var arr = o.transforms[i]
|
||||
var t = transforms[i]
|
||||
var v = intrp(arr, r)
|
||||
|
||||
if(!t) {
|
||||
console.error("lax: " + i + " is not supported")
|
||||
return
|
||||
}
|
||||
|
||||
t(style, v)
|
||||
}
|
||||
|
||||
for(let k in style) {
|
||||
if(style.opacity === 0) { // if opacity 0 don't update
|
||||
o.el.style.opacity = 0
|
||||
} else {
|
||||
o.el.style[k] = style[k]
|
||||
}
|
||||
}
|
||||
})
|
||||
lastY = y
|
||||
lax.elements.forEach(lax.updateElement)
|
||||
}
|
||||
|
||||
return lax;
|
||||
|
||||