diff --git a/.eslintrc.json b/.eslintrc.json
index fea36d9..0fa8526 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -230,7 +230,7 @@
],
"linebreak-style": [
2,
- "windows"
+ "unix"
],
"max-nested-callbacks": [
2,
@@ -367,4 +367,4 @@
"prefer-template": 2,
"require-yield": 2
}
-}
\ No newline at end of file
+}
diff --git a/README.md b/README.md
index 6b38c32..bbb2211 100644
--- a/README.md
+++ b/README.md
@@ -9,16 +9,20 @@ A module for testing if a DOM element is visible in the viewport, then triggers
Using ES6:
- import Scrollmap from 'scrollmap';
+```javascript
+import Scrollmap from 'scrollmap';
+```
Using a CDN via jsDelivr:
-
-
+```html
+
+
+```
********************************************
-##Method - trigger(options, callback)
+## Method - trigger(options, callback)
**Description:**
A method for adding triggers when element is visible in the viewport.
@@ -36,24 +40,29 @@ as long as the scroll event is happening.
**alwaysRunOnTrigger (boolean)**: by default the triggered element callback will only be executed one time. Setting to true will re-trigger the callback everytime the element has been in and out of the viewport.
+**treshold (number)**: add this much pixels to calculation to the visibility check (useful if you want to execute code just before the element becomes visible)
+
**callback (object)**:
This is the function which will be exectued when the element is detected in the viewport. To reference the node, pass it
into the callback as an argument.
**EXAMPLE**
- Scrollmap.trigger({
- target: '.collection-list .items',
- surfaceVisible: 0.5,
- runOnScroll: true,
- alwaysRunOnTrigger: true
- }, (element) => {
- $(element).addClass("visible");
- });
+```javascript
+Scrollmap.trigger({
+ target: '.collection-list .items',
+ surfaceVisible: 0.5,
+ runOnScroll: true,
+ alwaysRunOnTrigger: true,
+ treshold: 200
+}, (element) => {
+ $(element).addClass("visible");
+});
+```
********************************************
-##Method - sequence(options, callback)
+## Method - sequence(options, callback)
**Description:**
A method for staggering an array of triggers.
@@ -71,52 +80,55 @@ can get the item and index of the array as arguments
**EXAMPLE**
- Scrollmap.trigger({
- target: ".boxes",
- surfaceVisible: 0.2
- }, (element) => {
+```javascript
+Scrollmap.trigger({
+ target: ".boxes",
+ surfaceVisible: 0.2
+}, (element) => {
- //define the array of the elements to sequence
+ //define the array of the elements to sequence
- const array = element.querySelectorAll(".box");
+ const array = element.querySelectorAll(".box");
- //use the sequence method to define, interval and callback
- //function.
+ //use the sequence method to define, interval and callback
+ //function.
- Scrollmap.sequence(array, {
- interval: 5,
- order: "random"
- }, (item) => {
+ Scrollmap.sequence(array, {
+ interval: 5,
+ order: "random"
+ }, (item) => {
- //add any code to be triggered when
- //the element is in the viewport
+ //add any code to be triggered when
+ //the element is in the viewport
- item.classList.add("color-change");
+ item.classList.add("color-change");
- });
- });
+ });
+});
+```
********************************************
-##Method - out(function)
+## Method - out(function)
When the trigger is has been executed and the element is no longer in the viewport, the out method
can be chained to the trigger to execute the specified function.
**EXAMPLE**
- Scrollmap.trigger({
- target: ".boxes",
- surfaceVisible: 0.2
- }, (element) => {
- element.classList.add("foo");
- }).out((element) => {
- element.classList.add("bar");
- });
-
+```javascript
+Scrollmap.trigger({
+ target: ".boxes",
+ surfaceVisible: 0.2
+}, (element) => {
+ element.classList.add("foo");
+}).out((element) => {
+ element.classList.add("bar");
+});
+```
********************************************
-##Hooks
+## Hooks
**data-scrollmap-loaded (boolean):**
Once the element is initialized.
diff --git a/dist/scrollmap.js b/dist/scrollmap.js
index 94ef103..2709694 100644
--- a/dist/scrollmap.js
+++ b/dist/scrollmap.js
@@ -20,7 +20,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
* @namespace scrollMap
* @description store element points and check if
* elements are visible
-*/
+ */
var Scroll_Event_Trigger = function () {
function Scroll_Event_Trigger() {
@@ -157,7 +157,7 @@ var Scroll_Event_Trigger = function () {
}
}, {
key: "elementInViewport",
- value: function elementInViewport(el, percetageOfElement) {
+ value: function elementInViewport(el, percetageOfElement, treshold) {
/*
* @desc check if element is in viewport
@@ -173,7 +173,7 @@ var Scroll_Event_Trigger = function () {
var rect = el.getBoundingClientRect();
var stats = {
- top: rect.top - window.innerHeight,
+ top: rect.top - window.innerHeight + treshold,
bottom: rect.bottom + rect.height,
height: rect.height
};
@@ -188,7 +188,7 @@ var Scroll_Event_Trigger = function () {
}, {
key: "checkVisible",
value: function checkVisible(point) {
- var viewport = this.elementInViewport(point.element, point.surfaceVisible);
+ var viewport = this.elementInViewport(point.element, point.surfaceVisible, point.treshold);
if (viewport) {
this.setTriggerIn(point);
@@ -234,8 +234,20 @@ var Scroll_Event_Trigger = function () {
value: function events() {
var _this2 = this;
+ var supportsPassive = false;
+
+ try {
+ var opts = Object.defineProperty({}, "passive", {
+ get: function get() {
+ supportsPassive = true;
+ }
+ });
+
+ window.addEventListener("test", null, opts);
+ } catch (e) {} // eslint-disable-line no-empty
+
// initial check on page load to see if elements are visible
- window.addEventListener('load', function () {
+ window.addEventListener("load", function () {
_this2.points.forEach(function (point) {
_this2.checkVisible(point);
});
@@ -247,15 +259,13 @@ var Scroll_Event_Trigger = function () {
_this2.points.forEach(function (point) {
_this2.checkVisible(point);
});
- });
+ }, supportsPassive ? { passive: true } : false);
}
}]);
return Scroll_Event_Trigger;
}();
-;
-
var Scrollmap = new Scroll_Event_Trigger();
window.Scrollmap = Scrollmap;
diff --git a/dist/trigger.js b/dist/trigger.js
index b2bc96b..d142927 100644
--- a/dist/trigger.js
+++ b/dist/trigger.js
@@ -1,7 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
- value: true
+ value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
@@ -9,36 +9,36 @@ var _createClass = function () { function defineProperties(target, props) { for
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Trigger = function () {
- function Trigger(element, options, callback) {
- _classCallCheck(this, Trigger);
-
- this.element = element;
- this.surfaceVisible = 0.5;
- this.callback = callback;
- this.triggeredIn = false;
- this.triggeredOut = false;
- this.runOnScroll = false;
- this.alwaysRunOnTrigger = false;
- if (options) {
- Object.assign(this, options);
- }
- }
-
- _createClass(Trigger, [{
- key: "onTriggerIn",
- value: function onTriggerIn() {
- this.callback(this.element);
- return this;
- }
- }, {
- key: "destroy",
- value: function destroy() {
- this.element = null;
- this.isDestroyed = true;
- }
- }]);
-
- return Trigger;
+ function Trigger(element, options, callback) {
+ _classCallCheck(this, Trigger);
+
+ this.element = element;
+ this.surfaceVisible = 0.5;
+ this.treshold = 0;
+ this.callback = callback;
+ this.triggeredIn = false;
+ this.triggeredOut = false;
+ this.runOnScroll = false;
+ this.alwaysRunOnTrigger = false;
+ if (options) {
+ Object.assign(this, options);
+ }
+ }
+
+ _createClass(Trigger, [{
+ key: "onTriggerIn",
+ value: function onTriggerIn() {
+ this.callback(this.element);
+ return this;
+ }
+ }, {
+ key: "destroy",
+ value: function destroy() {
+ this.element = null;
+ }
+ }]);
+
+ return Trigger;
}();
exports.default = Trigger;
\ No newline at end of file
diff --git a/package.json b/package.json
index 25d2949..f9263d5 100644
--- a/package.json
+++ b/package.json
@@ -4,11 +4,11 @@
"description": "A module for testing if an element is visible in the viewport, then triggers callbacks on execution.",
"main": "./dist/scrollmap.js",
"scripts": {
- "start": "set PROD_ENV=false&&webpack --progress --colors --watch",
+ "start": "PROD_ENV=false webpack --progress --colors --watch",
"watch": "./node_modules/.bin/webpack -d --watch --colors",
- "build": "set PROD_ENV=true&&babel src -d dist",
- "dev": "set PROD_ENV=false&&webpack-dev-server ./src/scrollmap.js --hot --watch --colors",
- "cdn" : "set PROD_ENV=false&&webpack&&set PROD_ENV=true&&webpack -p",
+ "build": "PROD_ENV=true babel src -d dist",
+ "dev": "PROD_ENV=false webpack-dev-server ./src/scrollmap.js --hot --watch --colors",
+ "cdn": "PROD_ENV=false webpack && PROD_ENV=true webpack -p",
"lint": "eslint src"
},
"repository": {
@@ -47,7 +47,9 @@
"webpack-dev-server": "^2.4.2"
},
"babel": {
- "presets": ["latest"]
+ "presets": [
+ "latest"
+ ]
},
"keywords": [
"element",
diff --git a/src/scrollmap.js b/src/scrollmap.js
index 0bb387c..e9a1aec 100644
--- a/src/scrollmap.js
+++ b/src/scrollmap.js
@@ -1,10 +1,10 @@
import Trigger from "./trigger";
- /**
- * @namespace scrollMap
- * @description store element points and check if
- * elements are visible
- */
+/**
+ * @namespace scrollMap
+ * @description store element points and check if
+ * elements are visible
+ */
class Scroll_Event_Trigger {
constructor () {
@@ -12,92 +12,98 @@ class Scroll_Event_Trigger {
this.points = [];
this.events();
}
+
out (args) {
this.onTriggerOut = args;
return this;
}
+
sequence (array, options, func) {
- /*
- * @desc run through an array of elements and apply a
- * staggered sequence delay
- */
- array = Array.prototype.slice.call(array);
+ /*
+ * @desc run through an array of elements and apply a
+ * staggered sequence delay
+ */
+ array = Array.prototype.slice.call(array);
- let delay = 0;
+ let delay = 0;
- if (options.order) {
- this.sequenceOrder(array, options.order);
- }
+ if (options.order) {
+ this.sequenceOrder(array, options.order);
+ }
- if (options.delay) {
- delay = options.delay;
- }
+ if (options.delay) {
+ delay = options.delay;
+ }
- const run = array.forEach((item, i) => {
- setTimeout(() => {
- func(array[ i ], i);
- }, options.interval * i);
- });
+ const run = array.forEach((item, i) => {
+ setTimeout(() => {
+ func(array[ i ], i);
+ }, options.interval * i);
+ });
- setTimeout(run, delay);
+ setTimeout(run, delay);
- return this;
+ return this;
}
+
sequenceOrder (array, order) {
- /*
- * @desc randomize an array for a trigger sequence
- */
+ /*
+ * @desc randomize an array for a trigger sequence
+ */
- switch (order) {
- case "random" :
- array = array.sort(() => {
- return 0.5 - Math.random();
- });
- break;
- case "reverse" :
- array = array.reverse();
- break;
- default :
-
- }
- return array;
+ switch (order) {
+ case "random" :
+ array = array.sort(() => {
+ return 0.5 - Math.random();
+ });
+ break;
+ case "reverse" :
+ array = array.reverse();
+ break;
+ default :
+
+ }
+ return array;
}
+
trigger (args, callback) {
- /*
- * @desc add classname indicating element is intialized
- */
-
- let el = args.target;
-
- switch (typeof el) {
- case "string":
- el = document.querySelectorAll(el);
- break;
- case "object":
- el = [el];
- break;
- default:
- el = document.querySelectorAll(el);
- }
-
- el = this.toArray(el);
-
- el.forEach((node) => {
- node.setAttribute("data-scrollmap-loaded", true);
- node.setAttribute("data-scrollmap-triggered-in", false);
- node.setAttribute("data-scrollmap-triggered-out", false);
- const point = new Trigger(node, args, callback);
-
- this.points.push(point);
- });
- return this;
+ /*
+ * @desc add classname indicating element is intialized
+ */
+
+ let el = args.target;
+
+ switch (typeof el) {
+ case "string":
+ el = document.querySelectorAll(el);
+ break;
+ case "object":
+ el = [el];
+ break;
+ default:
+ el = document.querySelectorAll(el);
+ }
+
+ el = this.toArray(el);
+
+ el.forEach((node) => {
+ node.setAttribute("data-scrollmap-loaded", true);
+ node.setAttribute("data-scrollmap-triggered-in", false);
+ node.setAttribute("data-scrollmap-triggered-out", false);
+ const point = new Trigger(node, args, callback);
+
+ this.points.push(point);
+ });
+ return this;
}
+
toArray (collection) {
return Array.prototype.slice.call(collection);
}
+
setTriggerIn (point) {
point.element.setAttribute("data-scrollmap-is-visible", true);
point.element.setAttribute("data-scrollmap-triggered-in", true);
@@ -109,6 +115,7 @@ class Scroll_Event_Trigger {
}
}
}
+
setTriggerOut (point) {
point.element.setAttribute("data-scrollmap-is-visible", false);
point.element.setAttribute("data-scrollmap-triggered-out", true);
@@ -121,43 +128,46 @@ class Scroll_Event_Trigger {
point.triggeredOut = true;
}
}
- elementInViewport (el, percetageOfElement) {
- /*
- * @desc check if element is in viewport
- */
+ elementInViewport (el, percetageOfElement, treshold) {
+
+ /*
+ * @desc check if element is in viewport
+ */
- /*
- * look for direction of scroll and base element visible
- * percentage off of either top bottom when scrolling
- * down, or the top when scrolling up. This may not be
- * the perfect method but is cross browser compatible.
- */
+ /*
+ * look for direction of scroll and base element visible
+ * percentage off of either top bottom when scrolling
+ * down, or the top when scrolling up. This may not be
+ * the perfect method but is cross browser compatible.
+ */
- const rect = el.getBoundingClientRect();
+ const rect = el.getBoundingClientRect();
- const stats = {
- top: rect.top - window.innerHeight,
- bottom: rect.bottom + rect.height,
- height: rect.height
- };
+ const stats = {
+ top: rect.top - window.innerHeight + treshold,
+ bottom: rect.bottom + rect.height,
+ height: rect.height
+ };
- const amount = stats.height * percetageOfElement;
+ const amount = stats.height * percetageOfElement;
- if ( (stats.bottom - amount > stats.height) && (stats.top + amount < 0)) {
- return true;
- }
- return false;
+ if ((stats.bottom - amount > stats.height) && (stats.top + amount < 0)) {
+ return true;
+ }
+ return false;
}
+
checkVisible (point) {
- const viewport = this.elementInViewport(point.element, point.surfaceVisible);
+ const viewport = this.elementInViewport(point.element, point.surfaceVisible, point.treshold);
- if (viewport) {
- this.setTriggerIn(point);
- } else {
- this.setTriggerOut(point);
- }
+ if (viewport) {
+ this.setTriggerIn(point);
+ } else {
+ this.setTriggerOut(point);
+ }
}
+
on (string, callback) {
/*
* methods for creating various listeners
@@ -172,6 +182,7 @@ class Scroll_Event_Trigger {
}
return this;
}
+
scrollDirection () {
/*
* return the scroll direction via a string value
@@ -179,34 +190,47 @@ class Scroll_Event_Trigger {
let direction = "";
const st = window.pageYOffset || document.documentElement.scrollTop;
- if (st > this.lastScrollTop) {
- direction = "Down";
- } else {
- direction = "Up";
- }
- this.lastScrollTop = st;
- return direction;
+ if (st > this.lastScrollTop) {
+ direction = "Down";
+ } else {
+ direction = "Up";
+ }
+ this.lastScrollTop = st;
+ return direction;
}
+
events () {
- // initial check on page load to see if elements are visible
- window.addEventListener('load', () => {
- this.points.forEach((point) => {
- this.checkVisible(point);
- });
- }, false);
+ let supportsPassive = false;
- // check for visible elements on scroll
- window.addEventListener("scroll", () => {
- this.scrollOrient = this.scrollDirection();
- this.points.forEach((point) => {
- this.checkVisible(point);
- });
- });
+ try {
+ const opts = Object.defineProperty({}, "passive", {
+ get () {
+ supportsPassive = true;
+ }
+ });
+
+ window.addEventListener("test", null, opts);
+ } catch (e) {} // eslint-disable-line no-empty
+
+ // initial check on page load to see if elements are visible
+ window.addEventListener("load", () => {
+ this.points.forEach((point) => {
+ this.checkVisible(point);
+ });
+ }, false);
+
+ // check for visible elements on scroll
+ window.addEventListener("scroll", () => {
+ this.scrollOrient = this.scrollDirection();
+ this.points.forEach((point) => {
+ this.checkVisible(point);
+ });
+ }, supportsPassive ? { passive: true } : false);
}
-};
+}
const Scrollmap = new Scroll_Event_Trigger();
window.Scrollmap = Scrollmap;
-export default Scrollmap;
\ No newline at end of file
+export default Scrollmap;
diff --git a/src/trigger.js b/src/trigger.js
index e643aae..c0ecb6c 100644
--- a/src/trigger.js
+++ b/src/trigger.js
@@ -1,24 +1,26 @@
class Trigger {
- constructor (element, options, callback) {
- this.element = element;
- this.surfaceVisible = 0.5;
- this.callback = callback;
- this.triggeredIn = false;
- this.triggeredOut = false;
- this.runOnScroll = false;
- this.alwaysRunOnTrigger = false;
- if (options) {
- Object.assign(this, options);
- }
- }
- onTriggerIn () {
- this.callback(this.element);
- return this;
- }
- destroy () {
- this.element = null;
- this.isDestroyed = true;
- }
+ constructor (element, options, callback) {
+ this.element = element;
+ this.surfaceVisible = 0.5;
+ this.treshold = 0;
+ this.callback = callback;
+ this.triggeredIn = false;
+ this.triggeredOut = false;
+ this.runOnScroll = false;
+ this.alwaysRunOnTrigger = false;
+ if (options) {
+ Object.assign(this, options);
+ }
+ }
+
+ onTriggerIn () {
+ this.callback(this.element);
+ return this;
+ }
+
+ destroy () {
+ this.element = null;
+ }
}
-export default Trigger;
\ No newline at end of file
+export default Trigger;