tsonobe1 / imonit

0 stars 0 forks source link

TaskBoxをDragGestureで移動する際、Timelineの拡大率に応じた特定の倍数で区切る #47

Closed tsonobe1 closed 1 year ago

tsonobe1 commented 2 years ago

以下のように、DragでTaskの開始時刻や、終了時刻、時刻自体を変更する時、座標(CGFloat)とTimlineの時刻の比を整理して、座標の値と見た目場の値を合わせないといけない。 Simulator Screen Shot - iPhone 12 - 2022-10-13 at 22 31 37

tsonobe1 commented 2 years ago

例えば、Timelineの拡大率が5のときは、画面上で60分移動すると、DragGestureのvalue.translation.heightは150移動する。 value.translation.heightは、移動する前の場所から移動後までの移動量

スクリーンショット 2022-10-13 22 47 34

各拡大率時の比を表にすると以下の通り

Timelineの拡大率 1

画面上のX分 座標の移動量(CGFloat)
60 30.0
1 0.5

Timelineの拡大率 2

画面上のX分 座標の移動量(CGFloat)
60 60.0
1 1

Timelineの拡大率 5

画面上のX分 座標の移動量(CGFloat)
60 150.0
1 2.5

Timelineの拡大率 10

画面上のX分 座標の移動量(CGFloat)
60 300.0
1 5

Timelineの拡大率 30

画面上のX分 座標の移動量(CGFloat)
60 900.0
1 15
tsonobe1 commented 2 years ago

value.translation.heightをTaskBoxの上辺・下辺と、時間表示にそのまま代入すると、上表のような比の差異があるので、調整する必要がある。 また、CGFloatは小数点も含むので、5分刻み、15分きざみなどで移動させることができない。 拡大率によっては使いづらいので、好みの倍数で切り捨てたほうがよい

例えば、拡大率が5で、画面上で5分ずつキリよく移動させたい場合は、上表に当てはめて考えてみる。

Timelineの拡大率 5 画面上のX分 座標の移動量(CGFloat)
60 150.0
1 2.5
5 12.5

5分の移動のときは、座標を12.5移動させると良いということがわかる なので、value.translation.heightを12.5ごとに切り捨てればよい。 ExcelのFloor()関数だと、丸められる値(number)と、丸めたい倍数(Multiple)を指定すれば、numberをMultipleごとに区切ることができる。

swiftのfloor()関数ではMultipleがないので、独自に実装すればよい。

let x = value.translation.height / 12.5
let y = floor(x) // 切り捨てる
let z = y * 12.5

これで、12.4なら0になり、12.6なら12.5になり、24.9なら25.0になり、27なら25.0になり...と、12.5ずつ区切られる。 こんな感じで、Timelineの拡大率と、各拡大率の画面上のX分と座標の移動量の比と、区切りたい分数を整理して、それぞれの拡大率に応じて使い回せるようにしたのが以下の関数

func floorWithMultiple(_ movePosition: CGFloat, _ positionsMultiple: CGFloat, _ datesMultiple: Double) -> (movedPosition: CGFloat, movedMinute: Int) {
        let x = movePosition / positionsMultiple // 
        let y = floor(x)
        let a = y * positionsMultiple
        let b = Int(y * datesMultiple)
        return (a, b)
    }

使う時はこう

DragGesture()
    .onChanged { value in
        // ドラッグ中の処理
        var floored = floorWithMultiple(value.translation.height, 7.5, 15)
        switch magnifyBy 
        case 1.0: floored = floorWithMultiple(value.translation.height, 7.5, 15) // 拡大率 = 1, 15分区切りで移動
        case 2.0: floored = floorWithMultiple(value.translation.height, 15, 15) // 拡大率 = 2, 15分区切りで移動
        case 5.0: floored = floorWithMultiple(value.translation.height, 12.5, 5) // 拡大率 = 5, 5分区切りで移動
        case 10.0: floored = floorWithMultiple(value.translation.height, 5, 1) // 拡大率 = 10, 1分区切りで移動
        case 30.0: floored = floorWithMultiple(value.translation.height, 15, 1) // 拡大率 = 30, 1分区切りで移動
        default:
            print("What?")
        }
        changedPosition = floored.movedPosition
        changedDate = floored.movedMinute
    }