Skip to content

Instantly share code, notes, and snippets.

@sounisi5011
Last active March 16, 2018 22:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sounisi5011/5c3b5c914d8663111b6a0d8f30bb1bf7 to your computer and use it in GitHub Desktop.
Save sounisi5011/5c3b5c914d8663111b6a0d8f30bb1bf7 to your computer and use it in GitHub Desktop.
端までスクロールしたらコンソールに出力するテストコード
<!doctype html>
<meta charset=utf-8>
<meta name=viewport content="width=device-width,initial-scale=1">
<meta name=format-detection content="telephone=no,email=no,address=no">
<title>端までスクロールしたらコンソールに出力するテストコード</title>
<link href="main.css" rel=stylesheet>
<h1>端までスクロールしたらコンソールに出力するテストコード</h1>
<h2>Gist</h2>
<p><a href="https://gist.github.com/sounisi5011/5c3b5c914d8663111b6a0d8f30bb1bf7">https://gist.github.com/sounisi5011/5c3b5c914d8663111b6a0d8f30bb1bf7</a>
<script src="https://cdn.rawgit.com/sounisi5011/6d0be09d2f2a2853974bfe9a20d229bc/raw/constants.min.js"></script>
<script src="main.js"></script>
html {
width: 200%;
height: 200%;
}
/**
* @see https://www.w3.org/TR/cssom-view-1/#extensions-to-the-window-interface
* @see https://www.w3.org/TR/cssom-view-1/#extensions-to-the-document-interface
* @see https://www.w3.org/TR/cssom-view-1/#extension-to-the-element-interface
*/
/**
* ウィンドウのスクロール量を取得する
* @see https://dev.opera.com/articles/fixing-the-scrolltop-bug/
* @see https://qiita.com/rryu/items/c83e54cff15755b37426
*/
class ScrollData {
/**
* @param {!Window} targetWindow ウィンドウに対応するwindowオブジェクト
*/
constructor(targetWindow = window) {
const targetDocument = targetWindow.document;
const scrollingElem = targetDocument.scrollingElement || (
targetWindow.navigator.userAgent.includes('WebKit') ?
targetDocument.body :
targetDocument.documentElement
);
/** @type {number} */
this.x;
/** @type {number} */
this.y;
/** @type {number} */
this.maxX;
/** @type {number} */
this.maxY;
Object.defineProperties(this, {
x: {
value: (
//targetWindow.scrollX
scrollingElem.scrollLeft
),
enumerable: true,
},
y: {
value: (
//targetWindow.scrollY
scrollingElem.scrollTop
),
enumerable: true,
},
maxX: {
value: (
//scrollingElem.scrollWidth + (targetWindow.innerWidth - scrollingElem.clientWidth) - targetWindow.innerWidth
scrollingElem.scrollWidth - scrollingElem.clientWidth
),
enumerable: true,
},
maxY: {
value: (
//scrollingElem.scrollHeight + (targetWindow.innerHeight - scrollingElem.clientHeight) - targetWindow.innerHeight
scrollingElem.scrollHeight - scrollingElem.clientHeight
),
enumerable: true,
},
});
}
}
/**
* いずれかの修飾キーが押下されているか判定する
* @param {!KeyboardEvent} keyEvent
* @return {boolean}
*/
function isActivatedAnyModifierKey(keyEvent) {
if (keyEvent.ctrlKey || keyEvent.altKey || keyEvent.shiftKey || keyEvent.metaKey) {
return true;
}
if (typeof keyEvent.getModifierState === 'function') {
for (const key of MODIFIER_KEYS_SET) {
if (keyEvent.getModifierState(key)) {
return true;
}
}
}
return false;
}
const topWallElem = document.createElement('div');
topWallElem.style.position = 'fixed';
const leftWallElem = topWallElem.cloneNode(false);
topWallElem.style.cssText += 'left: 0px; right: 0px; height: 2em;';
leftWallElem.style.cssText += 'top: 0px; bottom: 0px; width: 2em;';
const bottomWallElem = topWallElem.cloneNode(false);
const rightWallElem = leftWallElem.cloneNode(false);
topWallElem.style.cssText += 'top: 0px; background-image: linear-gradient(red, transparent);';
bottomWallElem.style.cssText += 'bottom: 0px; background-image: linear-gradient(transparent, red);';
leftWallElem.style.cssText += 'left: 0px; background-image: linear-gradient(90deg, red, transparent);';
rightWallElem.style.cssText += 'right: 0px; background-image: linear-gradient(90deg, transparent, red);';
/**
* @type {!WeakMap.<Element, number>}
*/
const timeoutIdMap = new WeakMap;
function showWallElem(targetWallElem) {
if (!targetWallElem.parentNode) {
document.body.appendChild(targetWallElem);
}
if (timeoutIdMap.has(targetWallElem)) {
clearTimeout(timeoutIdMap.get(targetWallElem));
}
timeoutIdMap.set(
targetWallElem,
setTimeout(() => {
const parentElem = targetWallElem.parentNode;
if (parentElem) {
parentElem.removeChild(targetWallElem);
}
}, 500)
);
}
/**
* @type {!Map.<string, ScrollData>}
*/
const keyMap = new Map;
const keyListener = e => {
const key = e.key;
/*
* 矢印キーのイベントであれば、以降の処理を実行する
*/
if (/^Arrow/.test(key)) {
/*
* 修飾キーが押下されていなければ、以降の処理を実行する
*/
if (!isActivatedAnyModifierKey(e)) {
const type = e.type;
const scroll = new ScrollData;
if (type === 'keydown') {
if (!keyMap.has(key)) {
keyMap.set(key, scroll);
}
} else if (type === 'keyup') {
if (keyMap.has(key)) {
const prevScroll = keyMap.get(key);
if (/^Arrow(?:Left|Right)$/.test(key) && prevScroll.x === scroll.x) {
if (0 < scroll.x) {
showWallElem(rightWallElem);
console.log(`Max scroll X`);
} else {
showWallElem(leftWallElem);
console.log(`Min scroll X`);
}
console.log(key, prevScroll, scroll);
}
if (/^Arrow(?:Up|Down)$/.test(key) && prevScroll.y === scroll.y) {
if (0 < scroll.y) {
showWallElem(bottomWallElem);
console.log(`Max scroll Y`);
} else {
showWallElem(topWallElem);
console.log(`Min scroll Y`);
}
console.log(key, prevScroll, scroll);
}
keyMap.delete(key);
}
}
}
}
};
window.addEventListener('keydown', keyListener, {passive: true});
window.addEventListener('keyup', keyListener, {passive: true});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment