jsでピンチ操作(touchmoveでrotateとかスケーリング)
コロナの影響もあってか
公開の延期とかペンディング
なんかがチラホラある今日このごろです。
結構急ぎの対応になる予定だったのだけども
延期になってちょっと時間ができたので
実装進行中のjsで画像の拡大とかスケーリングする
仕組み的な物記事にしてみます。
gesturechange
gesturechangeに対応してればscaleとかrotateって簡単にとれますが
iOS以外はサポートしてない?ような覚えがあるので
アンドロイドとかそのあたり実装の参考になりましたら幸いです。
とりあえずこんなの
実際案件として作ってるのは移動したりレイヤー複数だったりするのですが
あまり色々書くとわかりづらくなると思うのでPC省きでスマホ動作の拡縮と回転のみです。
あとReactとtypescript使ってますが、特に別でmoduleとか使ってないので
各処理は素のjsとかでも読み変えてもらえると思います。
See the Pen touchmoveでrotation by admin@nocebo.jp (@nocebojp) on CodePen.
あとはちょい説明
Pointクラス
class Point {
x: number;
y: number;
constructor(x: number = 0, y: number = 0) {
this.x = x || 0;
this.y = y || 0;
}
static distance(a: Point, b: Point) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
}
static interpolate(p1: Point, p2: Point, t: number) {
let x = p1.x * (1 - t) + p2.x * t;
let y = p1.y * (1 - t) + p2.y * t;
return new Point(x, y);
}
add(p: Point) {
this.x += p.x;
this.y += p.y;
return this;
}
subtract(p: Point) {
this.x -= p.x;
this.y -= p.y;
return this;
}
}
distanceはそのまま距離求める関数です。
指2本間の距離
三平方の定理のハズ。
interpolateもそのままですが2点間の補間点です。
今回は指2本の中間点とるのに使ってます。
touch系の処理
disableTouch
useEffectで使ってます。
userscalableオフにするやつ
passive: falseっていれないと
最近のiOSでは効かない。
touchPosition
タッチしてる指の本数分(e.touches)を配列で返します。
Object.entriesでmapってのを使ってみた。
touchDeg
角度求めるヤツです。
上で出たinterpolate使って
指2本の補間点(中心)と
逆正接関数(Math.atan2)ってのを使って指1との角度を求める。
というつもり。であってるハズ。
Math.atanってのもあるので注意です。こんなの学校でならったかしら
コンポーネント
あとはコンポーネントで色々ハンドラとか書く。
自己流ReactなのでuseCallbackとかuseMemoとかのメモ化なんか
特に雰囲気で使ってるけどあってるかな?あってるといいな。
焼き肉が食べたいな。
一応回転とスケーリングの処理だけ補足。
rotate
回転
const currentPoints = touchPosision(e);
// それぞれの指の位置取得
const currentDeg = touchDeg(currentPoints);
// 指1と指2から角度取得
const diffDeg = currentDeg - startDeg;
// touchstart時の角度とmove時の角度の差を取得
const result = tempRotate + diffDeg;
// 要素自体のtouchstart時のrotate+差分
です。
scale
拡縮
const startDistance = Point.distance(startPoints[0], startPoints[1]);
// スタート時の指2本の距離
const currentDistance = Point.distance(currentPoints[0], currentPoints[1]);
// move時の指2本の距離
let scale = (currentDistance / startDistance) * tempScale;
// 現在距離/スタート時の距離 * 拡縮要素タッチ時の元のスケール
scale = Number.isNaN(scale) ? 1.0 : scale;
// ここは保険
scale = Math.max(scale, 0.5);
scale = Math.min(scale, 4.0);
// 最小スケールと最大スケール
です。
その他の処理
あと多分拡縮・回転だけってのは実案件だとそんなにないと思うので
移動だったりPCも対応もしたいって場合は
過去記事の下記なんか参考になるかもです。
参考になりましたら幸いでございます。
ディスカッション
コメント一覧
まだ、コメントがありません