画像比較がドラッグでできるjsを作りました。

画像比較がドラッグでできるjsを作りました。

改良版を作りました。ほとんど変わっていませんが、スマホで使いやすいように改良しています。使用する際は改良版をお使いくださいませ。

ファイルはこちら

先日、2枚の画像を比較するためにWordpressプラグイン「Twenty20 Image Before-After」と同じ挙動のjsを作成しました。
(作成後に「Twenty20 Image Before-After」の存在を知り、初めから知っておけばもっと楽に作れたんじゃないかと思った。。)

とりあえず完成品をご覧ください。真ん中の白い丸を動かすと画像の見える範囲が変わります。
scssが見にくい人は「VIEW COMPILED」とボタンを押すとcssで表示されます。

See the Pen view.comparison by blanks (@blanks-site) on CodePen.

どうでしょうか?加工前と加工後の写真比較が簡単にできて、なんだかいい感じですよね!
どんな言葉で検索すれば、プラグイン等を見つけることができるかよく分からなかったので、自分で作成しよう!と思って作成しました。

ちなみにこれは以下のような特長があります。

  1. jQueryプラグインなしで動く!
  2. スマホも対応!
  3. 同一ページに複数設置可能!

ダウンロードはgithubからできます。自由に使ってください!

ここからは使い方などを説明していきます。


使い方

必要ファイルとマークアップ

githubからダウンロードした「view.comparison.js」と「view.comparison.css」を読み込ませれば使うことができます。

マークアップは以下のとおりです

マークアップ

コードをクリップボードにコピー
<div class="comparison-block">
  <span class="comparison-arrow"></span>
  <div class="comparison-before-img"><img src="左側の画像パス" alt="左側の写真"></div>
  <div class="comparison-after-img"><img src="右側の画像" alt="右側の写真"></div>
</div>

「.comparison-arrow」が境界線の要素です。
「.comparison-before-img」が左側に表示される画像を囲む要素です。
「.comparison-after-img」が右側に表示される画像を囲む要素です。
以上3つを囲む全体の要素が「.comparison-block」です。

これらのタグにクラスを追加したり、要素の順番を入れ替えたりしても正常に動きます。

タグ名を変更したい人もいると思いますので、必要なスタイルやjsファイルで書き換える場所を次から説明していきます。


マークアップを変更したい時

次のスタイルは必要なので、自分がマークアップしたクラス名に合わせて必ず記述してください。

コードをクリップボードにコピー
/* 全体を囲む要素 */
.comparison-block {
  width: 100%;
  max-width: 640px;  /* 画像の最大幅です。適宜変更してください */
  position: relative;
}

/* 左側の画像を囲む要素 */
.comparison-before-img {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  z-index: 5; /* 「右側の画像を囲む要素」のz-inexより大きければ問題ないです。 */
}

/* 右側の画像を囲む要素 */
.comparison-after-img {
  position: relative;
  z-index: 1;
}

/* 右側の画像 */
.comparison-after-img img {
  width: 100%;
}

/* 境界線 */
.comparison-arrow{
  background-color: #fff;  /* 境界線の色です。 */
  position: absolute;
  z-index: 10; /* 「左側の画像を囲む要素」のz-inexより大きければ問題ないです。 */
  top: 0;
  width: 2px;  /* 境界線の太さ */
  height: 100%;
  left: 50%;
  cursor: pointer;
}

次はできるだけ書いておいたほうがいいスタイルです。以下を書かないと、ドラッグしたときに画像が選択状態になるときがあり、画像に色が付いてしまいます。

コードをクリップボードにコピー
/* 全体を囲む要素と全体を囲む要素の子要素全て、選択時の背景色を透明にする */
.comparison-block::selection {
  background-color: transparent;
}
.comparison-block::-moz-selection {
  background-color: transparent;
}
.comparison-block *::selection {
  background-color: transparent;
}
.comparison-block *::-moz-selection {
  background-color:transparent;
}

次はjsの変更箇所です。1行目〜3行目の次箇所を自分のマークアップに合わせて変更してください。

コードをクリップボードにコピー
const blockElements = document.getElementsByClassName("comparison-block"); //arrow,before-img,after-imgを囲むクラス名
const elements = document.getElementsByClassName("comparison-arrow"); //境界線のクラス名
const beforeImages = document.getElementsByClassName("comparison-before-img"); //右側の画像を囲む要素のクラス名

マークアップを変更した場合は、以上のような点に気をつけて書き換えてください。


javascriptコードの説明

javascriptのコードこちらです。
これを見ながら、次からの説明は読んでください。


1〜10行目

この関数で使う定数・変数を定義しています。


12〜17行目

UAによりデバイス判定を行い、変数「device」に結果を格納しています。


19〜30行目

「device」によりイベントハンドラの種類をそれぞれ変数に格納しています。
ここでイベントハンドラを変数に格納して、デバイスにより変数の中身を変えることで、スマホでのタッチイベントに対応させることができています。


32〜64行目

マウスを押した時または、タッチをした時に実行させる「dragStart」関数についての記述です。

34〜39行目

タッチイベントでは複数の指によるタッチイベントも取得可能です。そこでタッチイベントで座標を取得する際は「event.changedTouches[0].pageX」といった形で取得する必要があります。
座標を取得する度に「event.pageX」と「event.changedTouches[0].pageX」を書き分けるの面倒なので、スマホ時は「event = event.changedTouches[0]」にしています。

41〜43行目

ここで「move_flg」をtrueにします。これでdragMove関数が動くようになります。

45〜61行目

スマホユーザーのユーザビリティを向上ために、スマホ時は境界線をタッチするのでなく、全体を囲んでいる要素「comparison-block」をタッチしてスライドさせれば、境界線が動くようになっています。ですので、境界線要素(arrow要素)の取得方法がPC/スマホで異なります。そのためif文により振り分けています。

62〜63行目

dragStart関数が発火した全体を囲む要素(comparison-block ※以下「COMPARISON_BLOCK要素」)をdragMove関数に渡す必要があります。この要素を渡すことでイベントが発火した要素を確定でき、同一ページに複数されても独立して動くようになります。
また、一度dragMove関数をグローバル変数のdragMoveFuncに格納することで、dragMove関数を解除できるようにして、かつ、dragMove関数に変数を渡せるようにしています。
これに関しては、addEventListenerで関数に引数を渡すを参考にさせていただきました。


66〜105行目

今回のとなるdragMove関数についての記述です。

68〜73行目

「34〜39行目」と同じです。

75行目

「41〜43行目」で説明した「move_flg」がtrueの場合のみ、境界線を動かします。

80〜90行目

COMPARISON_BLOCK要素の子要素の「.comparison-before-img」要素(※以下「BEFORE_IMG要素」)を取得しています。

91〜92行目

「X」は境界線のx座標から、COMPARISON_BLOCK要素のx座標を引いた値です。
「maxX」は境界線のx座標の移動値の最大値です。「maxX」はCOMPARISON_BLOCK要素の幅を取得しています。

93〜103行目

境界線がCOMPARISON_BLOCK要素を出ないように、境界線のx座標に下限、上限を決めています。
また画像の表示に関しては、「.comparison-after-img」要素(※以下「AFTER_IMG要素」)の上にposition:absolute;でBEFORE_IMG要素を乗せていて、overfloe:hidden;を設定しているBEFORE_IMG要素の幅を境界線の相対的なx値に合わせることで、下のAFTER_IMG要素が見えるようにしています。
以下にイメージを添付していますので、参考にしてみてください。

構造イメージ
構造のイメージ

107〜112行目

dragEnd関数の記述です。「move_flg」をfalseにして、「dragMoveFunc」を解除しています。
これにより、COMPARISON_BLOCK要素以外の場所でマウスムーブや、タッチムーブをしても境界線要素は動きません。


114〜123行目

ロード時の関数の記述です。BEFORE_IMG要素のwidthをCOMPARISON_BLOCK要素のwidthの半分にして、BEFORE_IMG要素の画像はCOMPARISON_BLOCK要素のwidthに合わせています。


125〜136行目

リサイズ時の関数の記述です。リサイズすると、ロード時の関数と同じ処理+境界線要素(arrow要素)をCOMPARISON_BLOCK要素の真ん中に持ってくる処理も行っています。


139〜152行目

関数の実行です。「45〜61行目」の時に説明したように、デバイスによりdragStart関数が発火する要素が違います。


使う機会があれば是非、使ってみてくださいませ〜。

arrow_circle_up