##はじめに
React+Reduxで写真コントロールUIを作成しました。
具体的には、
- マウスホイールを使ってズーム
- マウスでスクロールして見る位置を変更
できる機能を目指した。
Reactでこういう機能を実現したライブラリでは、react-image-lightboxがあったのですが、既存のライブラリを使うとなかなか思い通りにカスタマイズできないという悩みにぶつかり、これを参考にしつつ実装してみることに。
今回、特にこのマウスホイールのズーム操作に苦戦したので、そのとき気づいたことをまとめます。
##transformプロパティで画像をコントロール
画像を拡大、縮小させることでズームイン、ズームアウトを実現しました。
これだけなら、スタイルのwidthプロパティを変更すればできるが、マウスコントロールで画像の位置を変えられるようにするために、transformプロパティを使用。
transform: `translate3d(${offset.x}px,${offset.y}px,0) scale3d(${zoomRatio},${zoomRatio},1)`
上記のように、translate3dとscale3dをスペース区切りで指定すれば、ズームと移動を同時にできる。
##はまったポイント
- translate()では動かない
最初、画像を移動させる際には、translate()関数を指定したが、機能せず。
translate3d()を使ったら上手く動作しました。
- transformOriginを使ってはいけない!!
マウスポインタの位置を中心としてズームさせるために、transformOriginプロパティを使って、ズームの中心をマウスのホイールイベントごとに設定するようにしました。
transformOrigin: `${event.clientX}px ${event.clientY}px`
しかし、この時ズームの中心となるのは、画像の最初の位置に対するマウスポインタの座標。
一度、マウスホイールでズームした後、マウスを動かして別の位置でズームしようとすると、当然マウスポインタが指す画像上の画素は、元のサイズの時とは位置がずれているので、画像が大きくずれる羽目に!
- transitionで指定した変化時間でパラメータが上書きされる
先に書いたように、ズームの倍率が変わると、ズームの中心以外の位置の画素は、最初の位置からズレてしまう。
そのため、ズームと同時にズームによって生じたズレ分だけ反対方向に画像をずらして、見かけ上ズレが起きてないように見せなければならない。
しかし、transitionでアニメーションの変化時間を持たせると、その間にパラメータは更新されたが、画像のレンダリングの更新が終わらないという状態ができてしまった。
結果、連続的にマウスホイールを回すと、画像のレンダリングがパラメータの更新に追いつかず、画像が徐々にずれるようになった。
##解決策
解決策は
ズームの中心は変えずに、ズームに合わせて画像を動かして、マウスポインタの位置が動いていないように見せる。
transformOriginを使わなければ、常に対象レイヤーの中心を軸にしたズームになります。
対象レイヤーの中心はgetBoundingClientRect()を使えば求められるので、あとはズームの際の、マウスポインタが指す画素の移動距離を計算して補正をかければいい。
##課題
これで一通り期待通りのUIを作成できたが、やはりズームやスクロールに伴うアニメーションをスムーズにしたい。
今のところ、一回のズームの倍率を適当な値に設定してごまかしていますが、良い方法を模索したいと思います。