TAGJavaScript
ドラッグで左右の画像比較する方法:javascript

ドラッグで左右の画像比較ができるjavascriptをご紹介します。
WordPressのプラグインでいうと「Twenty20 Image Before-After」のような動きをjsのみで実装する方法です。
ビフォーアフター画像の紹介等におすすめです。
HTML
<div class="bfafimg-block"> <span class="bfafimg-arrow"></span> <div class="bfafimg-before"><img src="ここに左側に使用する画像" alt="左側の写真"></div> <div class="bfafimg-after"><img src="ここに右側に使用する画像" alt="右側の写真"></div> </div>
CSS
.bfafimg-block {
width: 50%;
position: relative;
margin: 0 auto;
}
.bfafimg-block::selection {
background-color: transparent;
}
.bfafimg-block::-moz-selection {
background-color: transparent;
}
.bfafimg-block *::selection {
background-color: transparent;
}
.bfafimg-block *::-moz-selection {
background-color: transparent;
}
.bfafimg-before {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
z-index: 5;
}
.bfafimg-before img {
width: 100%;
}
.bfafimg-after {
position: relative;
z-index: 1;
}
.bfafimg-after img {
width: 100%;
}
.bfafimg-arrow {
background-color: #fff;
position: absolute;
z-index: 10;
top: 0;
width: 2px;
height: 100%;
left: 50%;
cursor: pointer;
}
.bfafimg-arrow:after {
content: "";
display: block;
background: url(ここにドラッグ用の画像URL) no-repeat center center;
background-size: contain;
width: 4em;
height: 4em;
position:absolute;
top: 50%;
margin-top: -1.5em;
left: -1.8em;
}
javascript
const blockElements = document.getElementsByClassName("bfafimg-block"); //全体を囲む要素
const elements = document.getElementsByClassName("bfafimg-arrow"); //境界線の要素
const beforeImages = document.getElementsByClassName("bfafimg-before"); //左側の画像を囲む要素
let device = ""; // デバイス
let move_start_x = 0; // 境界線のX線上の初期値
let move_flg = false; // マウスダウンをしているかどうかのbool値
let dragMoveFunc = ""; // mouseDrag関数を格納するための変数
let startEvent = ""; // ドラッグ開始イベント
let moveEvent = ""; // ドラッグ中のイベント
let endEvent = ""; // ドラッグ終了のイベント
//UAによるデバイス判定
if (
navigator.userAgent.indexOf("iPhone") > 0 ||
navigator.userAgent.indexOf("iPod") > 0 ||
navigator.userAgent.indexOf("Windows Phone") > 0 ||
navigator.userAgent.indexOf("iPad") > 0 ||
navigator.userAgent.indexOf("Android") > 0
) {
device = "smt";
} else {
device = "pc";
}
//イベントの種類を設定
if (device == "smt") {
//スマホ時のイベントの種類
startEvent = "touchstart";
moveEvent = "touchmove";
endEvent = "touchend";
} else {
//パソコン時のイベントの種類
startEvent = "mousedown";
moveEvent = "mousemove";
endEvent = "mouseup";
}
//マウスダウン、タッチスタート時の関数
function dragStart(e) {
let event = "";
if (device === "smt") {
event = e.changedTouches[0];
} else {
event = e;
}
move_flg = true;
let for_flag = false;
let targetElement = ""; //arrow要素
//PCとスマホでは「startEvent」の対象要素が違うため、arrow要素を取得するためにそれぞれ違う処理を行う
if (device == "smt") {
for (let childEle of this.children) {
for (let childEleClass of childEle.classList) {
if (childEleClass == "comparison-arrow") {
move_start_x = event.pageX - childEle.offsetLeft;
targetElement = childEle;
break;
for_flag = true;
}
}
if (for_flag) {
break;
}
}
} else {
move_start_x = event.pageX - this.offsetLeft;
targetElement = this;
}
dragMoveFunc = function (e) {
dragMove(e, targetElement);
}; //イベントの解除を有効にするためにdragMoveを一度dragMoveFuncに格納
document.body.addEventListener(moveEvent, dragMoveFunc, false); //dragMoveFuncを実行
}
//マウスムーブ、タッチムーブ時の関数
function dragMove(e, ele) {
let event = "";
if (device === "smt") {
event = e.changedTouches[0];
} else {
event = e;
}
// move_flgは mouseDownを通るとtrueになり、mouseUpを通るとfalseになる
if (move_flg) {
let arrowElement = ele;
let blockElement = ele.parentNode;
let for_flag = false;
let beforeImgElement = "";
// イベントが発火した blockElements の子要素の「.bfafimg-before」を取得
for (let childEle of blockElement.children) {
for (let childEleClass of childEle.classList) {
if (childEleClass == "bfafimg-before") {
beforeImgElement = childEle;
break;
for_flag = true;
}
}
if (for_flag) {
break;
}
}
let X = event.clientX - move_start_x;
let maxX = blockElement.clientWidth;
// arrow要素が全体を囲んでいる要素からはみ出さないように移動の下限、上限を設定
if (X < 0) {
arrowElement.style.left = "0px"; //arrow要素のx値
beforeImgElement.style.width = "0px"; //beforeのwidth
} else if (X > maxX) {
arrowElement.style.left = `${maxX}px`; //arrow要素のx値
beforeImgElement.style.width = `${maxX}px`; //beforeのwidth
} else {
arrowElement.style.left = `${X}px`; //arrow要素のx値
beforeImgElement.style.width = `${X}px`; //beforeのwidth
}
}
}
//マウスアップ、タッチエンド時の関数
function dragEnd() {
move_flg = false;
// dragMoveFuncを解除する
document.body.removeEventListener(moveEvent, dragMoveFunc, false);
}
//ロード時の関数
function loadFunc() {
for (let i = 0; i < elements.length; i++) {
let w = blockElements[i].clientWidth;
// 「.before-img」のwidthを親要素の半分にする
beforeImages[i].style.width = `${w / 2}px`;
// 「.before-img」の子要素の画像サイズを変換
beforeImages[i].children[0].style.width = `${w}px`;
}
}
//リサイズ時の関数
function resizeFunc() {
for (let i = 0; i < elements.length; i++) {
let w = blockElements[i].clientWidth;
// arrow要素を全体の真ん中の位置に移動させる
elements[i].style.left = `${w / 2}px`;
// 「.before-img」のwidthを親要素の半分にする
beforeImages[i].style.width = `${w / 2}px`;
// 「.before-img」の子要素の画像サイズを変換
beforeImages[i].children[0].style.width = `${w}px`;
}
}
//関数の実行
if (device == "smt") {
for (let i = 0; i < elements.length; i++) {
//スマホ時はユーザビリティ向上の為、イベント発火の対象はarrow部分でなく、画像を囲む要素
blockElements[i].addEventListener(startEvent, dragStart, false);
}
} else {
for (let i = 0; i < elements.length; i++) {
elements[i].addEventListener(startEvent, dragStart, false);
}
}
document.body.addEventListener(endEvent, dragEnd, false);
window.addEventListener("load", loadFunc, false);
window.addEventListener("resize", resizeFunc, false);
スマホにも対応しており、jQueryに依存することなく実装可能です。
同じページに複数設置にも対応しています。

