Skip to content

Commit

Permalink
Merge pull request #20 from jh3y/develop
Browse files Browse the repository at this point in the history
Resolves #19 and #15 by implementing snap travel and tweaking options
  • Loading branch information
jh3y authored Jun 17, 2016
2 parents 17499f1 + b8b023a commit b673a96
Show file tree
Hide file tree
Showing 13 changed files with 240 additions and 155 deletions.
43 changes: 27 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,44 @@ To create your doormat.

1. Include `doormat{.min}.js` and `doormat{.min}.css` in your page.

2. Create your DOM structure. The structure needs to be a container with the classname `dm`. It then needs to have children with the classname `dm__pnl`. `ol` and `ul` are fitting elements.
2. Create your DOM/Page structure. The structure needs to be a container with the classname `dm`. We are filling the page, so this could be `body`. It then needs to have children with the classname `dm__pnl`. `ol` and `ul` make fitting container elements within the body alternatively.

```html̨
<ol class="dm">
<li class="dm__pnl">Awesome</li>
<li class="dm__pnl">Site</li>
<li class="dm__pnl">Content</li>
</ol>
<body>
<ol class="dm">
<li class="dm__pnl">Awesome</li>
<li class="dm__pnl">Site</li>
<li class="dm__pnl">Content</li>
</ol>
</body>
```

3. Invoke the `Doormat` function passing in desired options(_explained below_) as a parameter;

```javascript
var myDoormat = new Doormat();
var myDoormat = new Doormat({
scrollBuffer : 15,
snapDuration : 250,
snapThreshold: 15
```
```javascript
document.addEventListener('DOMContentLoaded', function() {
var myDoormat = new Doormat({
snapping: {
travel: true,
viewport: false,
threshold: 15,
debounce: 150,
duration: 250
}
});
});
```

## API options
* `scrollBuffer {number}` - The `scrollBuffer` represents a vertical percentage of `window.innerHeight` to be used as a buffer delay when triggering the next doormat panel to scroll. For example; If my `window` was `1000px` high and I set the `scrollBuffer` as `10`, the scrolling buffer would be `100px`. The reason for percentage is that when the window is resized the delay will remain consistent and proportional to the `window` height.
* `snapThreshold {number}` - The `snapThreshold` works in a similar way to `scrollBuffer` in that it translates to a percentage of `window.innerHeight`. It is used so that the closest panel edge will snap to the viewport when we are scrolling within the defined `snapThreshold`.
* `snapDuration {number}` - The `snapDuration` defines the length of time that are snap functionality is debounced and also the amount of time it will take for our panels to snap to viewport. The `snapDuration` is defined in `ms`. For example; `250`.
* `snapping {object}` - Defines `snapping` behavior for doormat. There are two forms of the `snapping` effect. `travel` and `viewport`.
* `travel {bool, defaults to false}` - enables "snapping" travel. References `threshold`. When scrolling "down", once the threshold is passed, the next slide is snapped into viewport. When scrolling "up" if the user stops scrolling __within__ the threshold, the previous slide snaps into viewport.
* `viewport {bool, defaults to true}` - enables "snap to viewport" behavior. When a user scrolls the page and the current panel is slightly out of viewport by the given threshold, the panel will snap the panel which currently occupies the majority of the viewport into view.
* `threshold {number, defaults to 30}` - defines the "snapping" threshold which is a percentage of the viewport height. For example; if the viewport was `1000px` tall and we set the `threshold` as `10`, then the `threshold` barrier will be the top and bottom `100px` of the panel.
* `debounce {number, defaults to 150}` - we don't want to trigger our snapping behavior on every scroll. The `debounce` option defines a debouncing delay for our snapping behavior to trigger.
* `duration {number, defaults to 250}` - defines the `transition-duration` for a snapping panel.
## How?
The trick is possible by making sections of the page `position: fixed` and then setting a height for the document `body` equal to the combined height of the page sections.
Expand Down Expand Up @@ -75,9 +88,7 @@ __NOTE::__ I would usually use a task runner like `gulp` in my projects. But, wi
npm run
```
### Roll your own
`doormat` development is mainly config driven with `doormat.config.json`. In here you can alter the classnames for elements to your desire. It is __important__ to remember that if you change the classnames in the config though that you will also need to update any reference to them from within the JavaScript.
For example, maybe you're not keen on the classnames being used or want it to support a higher number of panels(_the default is 10_).
`doormat` development is config driven with `doormat.config.json`. In here you can alter the classnames for elements to your desire. It is __important__ to remember that if you change the classnames in the config though that you will also need to update any reference to them from within the JavaScript.

Change the config and then run the build task with `npm run publish`.

Expand Down
41 changes: 5 additions & 36 deletions dist/doormat.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,22 @@
* @author jh3y
* (c) 2016
!*/
body {
-webkit-overflow-scrolling: touch;
}
.dm {
display: block;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
position: relative;
margin: 0;
padding: 0;
}
.dm__pnl {
display: none;
position: absolute;
position: fixed;
top: 0;
right: 0;
left: 0;
}
.dm__pnl:nth-of-type(1) {
z-index: 998;
}
.dm__pnl:nth-of-type(2) {
z-index: 997;
}
.dm__pnl:nth-of-type(3) {
z-index: 996;
}
.dm__pnl:nth-of-type(4) {
z-index: 995;
}
.dm__pnl:nth-of-type(5) {
z-index: 994;
}
.dm__pnl:nth-of-type(6) {
z-index: 993;
}
.dm__pnl:nth-of-type(7) {
z-index: 992;
}
.dm__pnl:nth-of-type(8) {
z-index: 991;
}
.dm__pnl:nth-of-type(9) {
z-index: 990;
}
.dm__pnl:nth-of-type(10) {
z-index: 989;
}
.dm__pnl--crnt,
.dm__pnl--crnt ~ .dm__pnl {
display: block;
Expand Down
120 changes: 78 additions & 42 deletions dist/doormat.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,110 +7,137 @@
*/

(function() {
var Doormat, props;
var Doormat, PROPS;

props = {
PROPS = {
CLASS: 'dm',
CURRENT_CLASS: 'dm__pnl--crnt',
SCROLLBUFFER: 0,
SNAPDURATION: 250,
SNAPTHRESHOLD: 15,
NEXT: 'next',
PREVIOUS: 'previous',
RESET: 'reset'
RESET: 'reset',
snapping: {
travel: false,
viewport: true,
threshold: 30,
debounce: 150,
duration: 250
}
};

Doormat = window.Doormat = function(opts) {
var calibrate, debounce, doormat, el, handleScroll, handleSnap, inSnapRegion, p, prop, setNew;
el = document.querySelector('.' + props.CLASS);
var calibrate, debounce, doormat, el, extend, handleScroll, handleSnap, inSnapRegion, setNew;
el = document.querySelector('.' + PROPS.CLASS);
if (!(this instanceof Doormat)) {
return new Doormat(opts);
}
if (!el) {
throw Error('Doormat: Must pass an element instance');
throw Error('Doormat: Must assign element instance');
}
setNew = function(dir, SNAP) {
setNew = function(dir) {
var cur;
cur = doormat.current;
cur.className = cur.className.replace(props.CURRENT_CLASS, '');
cur.style.top = dir === props.NEXT ? -cur.offsetHeight + 'px' : 0;
doormat.current = dir === props.RESET ? doormat.panels[0] : cur[dir + 'ElementSibling'];
return doormat.current.className += ' ' + props.CURRENT_CLASS;
cur.className = cur.className.replace(PROPS.CURRENT_CLASS, '');
cur.style.top = dir === PROPS.NEXT ? -cur.offsetHeight + 'px' : 0;
doormat.current = dir === PROPS.RESET ? doormat.panels[0] : cur[dir + 'ElementSibling'];
return doormat.current.className += ' ' + PROPS.CURRENT_CLASS;
};
calibrate = function(evt) {
var clientHeight, i, panel, sumHeight;
sumHeight = 0;
i = 0;
clientHeight = el.offsetHeight;
clientHeight = 'onorientationchange' in window ? screen.height : window.innerHeight;
doormat.CLIENT_HEIGHT = clientHeight;
while (i < doormat.panels.length) {
panel = doormat.panels[i];
panel.style.zIndex = 999 - i;
panel.style.display = 'block';
panel.style.minHeight = clientHeight + 'px';
panel.style.top = '0px';
panel.DOORMAT_HEIGHT = panel.offsetHeight;
if ((i + 1) !== doormat.panels.length && props.SCROLLBUFFER !== 0) {
panel.DOORMAT_HEIGHT = panel.DOORMAT_HEIGHT + (clientHeight * (props.SCROLLBUFFER / 100));
}
panel.DOORMAT_POS = sumHeight;
sumHeight = sumHeight + panel.DOORMAT_HEIGHT;
i++;
}
props.SNAPTHRESHOLDSIZE = clientHeight * (props.SNAPTHRESHOLD / 100);
doormat.SNAP_THRESHOLD = clientHeight * (PROPS.SNAPPING.THRESHOLD / 100);
document.body.style.height = sumHeight + 'px';
if (evt) {
window.scrollTo(0, 0);
return setNew(props.RESET);
return setNew(PROPS.RESET);
}
};
debounce = function(func, delay) {
clearTimeout(func.TIMER);
func.TIMER = setTimeout(func, delay);
};
handleSnap = function() {
var cur, reset, scroll;
var cur, reset, scroll, set, snapIn, snapOut;
cur = doormat.current;
scroll = window.scrollY || window.pageYOffset;
snapIn = function() {
return window.scrollTo(0, cur.DOORMAT_POS + (cur.offsetHeight - doormat.CLIENT_HEIGHT));
};
snapOut = function() {
cur.style.top = -cur.offsetHeight + 'px';
setNew(PROPS.NEXT);
return window.scrollTo(0, doormat.current.DOORMAT_POS);
};
if (inSnapRegion() && scroll !== cur.DOORMAT_POS) {
cur.style.transitionProperty = 'top';
cur.style.transitionDuration = props.SNAPTRANSITIONDURATION;
reset = function() {
cur.style.transitionProperty = null;
cur.style.transitionDuration = null;
return cur.removeEventListener('transitionend', reset);
};
cur.addEventListener('transitionend', reset, false);
set = function() {
cur.style.transitionProperty = 'top';
cur.style.transitionDuration = PROPS.SNAPPING.DURATION;
return cur.addEventListener('transitionend', reset, false);
};
if (doormat.SNAP_TOP) {
if (PROPS.SNAPPING.VIEWPORT) {
set();
snapOut();
} else if (PROPS.SNAPPING.TRAVEL && doormat.SCROLL_DIR === 'UP') {
window.scrollTo(0, cur.DOORMAT_POS);
}
}
if (doormat.SNAP_BOTTOM) {
return window.scrollTo(0, cur.DOORMAT_POS + (cur.offsetHeight - el.offsetHeight));
} else {
cur.style.top = -cur.offsetHeight + 'px';
setNew(props.NEXT);
return window.scrollTo(0, doormat.current.DOORMAT_POS - (doormat.current.DOORMAT_HEIGHT - doormat.current.offsetHeight));
set();
if (PROPS.SNAPPING.VIEWPORT) {
return snapIn();
} else if (PROPS.SNAPPING.TRAVEL && doormat.SCROLL_DIR === 'DOWN') {
return snapOut();
}
}
}
};
inSnapRegion = function() {
var cur, scroll;
cur = doormat.current;
scroll = window.scrollY || window.pageYOffset;
doormat.SNAP_TOP = scroll > ((cur.offsetHeight + cur.DOORMAT_POS) - props.SNAPTHRESHOLDSIZE) && scroll < (cur.DOORMAT_POS + cur.offsetHeight);
doormat.SNAP_BOTTOM = scroll > ((cur.DOORMAT_POS + cur.offsetHeight) - el.offsetHeight) && scroll < (((cur.DOORMAT_POS + cur.offsetHeight) - el.offsetHeight) + props.SNAPTHRESHOLDSIZE);
doormat.SNAP_TOP = false;
doormat.SNAP_BOTTOM = false;
doormat.SNAP_TOP = PROPS.SNAPPING.VIEWPORT ? scroll > ((cur.offsetHeight + cur.DOORMAT_POS) - doormat.SNAP_THRESHOLD) && scroll < (cur.DOORMAT_POS + cur.offsetHeight) : scroll > (cur.DOORMAT_POS + (cur.offsetHeight - doormat.SNAP_THRESHOLD)) && scroll < (cur.DOORMAT_POS + cur.offsetHeight);
doormat.SNAP_BOTTOM = PROPS.SNAPPING.VIEWPORT ? scroll > ((cur.DOORMAT_POS + cur.offsetHeight) - doormat.CLIENT_HEIGHT) && scroll < (((cur.DOORMAT_POS + cur.offsetHeight) - doormat.CLIENT_HEIGHT) + doormat.SNAP_THRESHOLD) : scroll > (cur.DOORMAT_POS + (cur.offsetHeight - doormat.CLIENT_HEIGHT)) + doormat.SNAP_THRESHOLD;
return doormat.SNAP_TOP || doormat.SNAP_BOTTOM;
};
handleScroll = function() {
var cur, scroll;
cur = doormat.current;
scroll = window.scrollY || window.pageYOffset;
cur.style.top = -(scroll - cur.DOORMAT_POS) + 'px';
doormat.SCROLL_DIR = scroll > doormat.SCROLL_LAST ? 'DOWN' : 'UP';
doormat.SCROLL_LAST = scroll;
cur.style.top = (cur.DOORMAT_POS - scroll) + 'px';
if (scroll > (cur.DOORMAT_HEIGHT + cur.DOORMAT_POS)) {
if (cur.nextElementSibling) {
return setNew(props.NEXT);
setNew(PROPS.NEXT);
}
} else if (scroll < cur.DOORMAT_POS) {
if (cur.previousElementSibling) {
return setNew(props.PREVIOUS);
setNew(PROPS.PREVIOUS);
}
} else if (inSnapRegion()) {
return debounce(handleSnap, props.SNAPDURATION);
}
if (PROPS.SNAPPING && (PROPS.SNAPPING.VIEWPORT || PROPS.SNAPPING.TRAVEL) && inSnapRegion()) {
return debounce(handleSnap, PROPS.SNAPPING.DEBOUNCE);
}
};
if ('onorientationchange' in window) {
Expand All @@ -122,15 +149,24 @@
doormat = this;
doormat.el = el;
doormat.panels = doormat.el.children;
for (prop in opts) {
p = prop.toUpperCase();
if (props[p] !== undefined) {
props[p] = opts[prop];
extend = function(a, b) {
var prop, result, val;
result = {};
for (prop in a) {
result[prop.toUpperCase()] = a[prop];
if (b.hasOwnProperty(prop)) {
val = b[prop];
result[prop.toUpperCase()] = typeof val === 'object' ? extend(result[prop.toUpperCase()], val) : val;
}
}
props.SNAPTRANSITIONDURATION = (props.SNAPDURATION / 1000) + 's';
return result;
};
PROPS = extend(PROPS, opts);
if (PROPS.SNAPPING) {
PROPS.SNAPPING.DURATION = (PROPS.SNAPPING.DURATION / 1000) + 's';
}
doormat.current = doormat.panels[0];
doormat.current.className += ' ' + props.CURRENT_CLASS;
doormat.current.className += ' ' + PROPS.CURRENT_CLASS;
calibrate();
return doormat;
};
Expand Down
2 changes: 1 addition & 1 deletion dist/doormat.min.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
* @license MIT
* @author jh3y
* (c) 2016
!*/.dm,.dm__pnl{top:0;right:0;left:0}.dm{display:block;position:fixed;bottom:0;margin:0;padding:0}.dm__pnl{display:none;position:absolute}.dm__pnl:nth-of-type(1){z-index:998}.dm__pnl:nth-of-type(2){z-index:997}.dm__pnl:nth-of-type(3){z-index:996}.dm__pnl:nth-of-type(4){z-index:995}.dm__pnl:nth-of-type(5){z-index:994}.dm__pnl:nth-of-type(6){z-index:993}.dm__pnl:nth-of-type(7){z-index:992}.dm__pnl:nth-of-type(8){z-index:991}.dm__pnl:nth-of-type(9){z-index:990}.dm__pnl:nth-of-type(10){z-index:989}.dm__pnl--crnt,.dm__pnl--crnt~.dm__pnl{display:block}
!*/body{-webkit-overflow-scrolling:touch}.dm{display:block;position:relative;margin:0;padding:0}.dm__pnl{display:none;position:fixed;top:0;right:0;left:0}.dm__pnl--crnt,.dm__pnl--crnt~.dm__pnl{display:block}
Loading

0 comments on commit b673a96

Please sign in to comment.