Swift3で12時を起点に時計をドラッグで回転させる
以前、僕はSwift3で9時を起点に時計をドラッグで回転させるという記事を書きました。文字通り、9時を起点に時計をドラッグで回転させるというものです。なぜ9時なのか、起点を別の位置に変える方法がわかりかねたからです。実装では回転の起点をちょうど12時の場所に持って来なきゃいけなくて、僕の数学の知識がウスラトンカチだったのでかなり悩みました。
おかしくなる原因
おかしくなる原因はatan2で割り出した回転軸xとyの軸が現実世界だと中心から始まるのに対して、ウェブのの世界では左上から始まるからです。
考え方
考え方として、時計の針の起点が9時の部分にあったとして、それを12時の部分に持ってきたいのだから-90
すればいいんじゃないかと思った訳ですが、単純に90引き算してもおかしな挙動をします。atan2で求めた角度は度数法ではなくラジアンなので、90を引くのにもラジアンで引かなければいけないってことでした。頭が悪いと苦労します…orz
ポイント
atan2で求めたangleが「ビューの中心からみたpositionの方向」であり、方向はX軸の正の方向(左上を軸とした起点)を0として左回りにラジアンで求めています。
let angle = atan2f(Float(target.y-position.y), Float(target.x-position.x))
この実装に度数法ではなくアラジンで-90を引き算します。M_PI2
というのは円周360なので、その半分でM_PI
180を2引き算します。
- Float(M_PI) / Float(2)
全実装
import UIKit
class ViewController: UIViewController {
var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
myView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 100))
myView.center = self.view.center
myView.backgroundColor = UIColor.red;
self.view.addSubview(myView)
myView.layer.anchorPoint = CGPoint(x: 0.5, y: 1.0)
let box = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
box.backgroundColor = UIColor.blue
myView.addSubview(box)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent!) {
let touch = touches.first!
if touch.view === myView.subviews[0] {
let position = touch.location(in: self.view)
let target = myView.center
let angle = atan2f(Float(target.y-position.y), Float(target.x-position.x)) - Float(M_PI) / Float(2)
myView.transform = CGAffineTransform(rotationAngle: CGFloat(angle))
}
}
}
参考
Swift3でタップした位置が何故か左になる
binary operator ‘/’ cannot be applied to two ‘Double’ operands
Swift3で9時を起点に時計をドラッグで回転させる