🐈‍⬛

GitHubの画像diffはどのように実装されているのか

2023/05/04に公開

GitHubの画像diffって便利だし何だか面白いですよね。

ところで、このSwipe Diff機能がどのように実現されているか、皆様はパッとわかるでしょうか?



私は20秒ほど考えてわからなかったので、DevToolsから仕組みを調べてみました。

実装方法

わかってしまえば非常にシンプルで、

  1. 2枚の画像を重ねる
  2. 上層の画像のWrapper幅を、スライダーの位置と連動させる

という発想でできていました。

上層のWrapper幅が小さくなると、下に隠されていた画像が覗いて、あたかも連続的に変化しているように見えるという寸法ですね。

実装

Reactで簡易的に実装したコードです。マウスホバー/スワイプで境界を動かせます。
(スマホからだとスワイプが少し難しいためPCで開いたほうがわかりやすいです)

要点のみ解説すると、

  • onPointerMoveイベントでポインタのX座標を取得し、上層画像のWrapperのwidthと連動させる
  • Wrapperにoverflow-x: hiddenを付け、幅が狭まったときに下の画像が見えるようにする

といった感じです。

Onion Skin diffの作り方

もう一つのモードであるOnion Skin Diffの作り方も見ていきましょう。

Onion Skin diffは、スライダーの位置に応じて新しい画像が浮かび上がったり消えたりするモードです。

実装方法

先ほどの応用で、Wrapper幅と連動させる代わりにopacityと連動させるだけですね。

実装

今回は面倒なのでスライダーは実装していません。画像領域内を横にホバー/スワイプしてみてください。

Swipe diffコンポーネントとの差分は実質的にはこの1行のみです。

style={{
- width: `${xPosRatio * 100}%`
+ opacity: xPosRatio
}}

Differenceモードの作り方

今は無くなってしまいましたが、以前は新旧画像で変化した箇所だけ浮かび上がらせる Difference というモードもあったようです。

せっかくなので最後にこちらを実装してみましょう。


追加された眼鏡の部分だけが浮かび上がっている

実装方法

以前はPhotoshopのblend modeを模倣したOSSを使って実装していたとのことなので、現代ではCSSのmix-blend-modeプロパティを使えば同じものが実装できそうです。

新旧画像を重ねて同じ色の箇所を打ち消しあうようにすれば、変更された箇所だけ浮かび上がるはずなので、mix-blend-mode: differenceを使っていきます。

実装

ポインタ連動機能を削除してmix-blend-mode: differenceを加えただけで、全く同じものができました。

+.deleted-image {
+  mix-blend-mode: difference;
+}

Discussion