Home > Software design >  Rotation to closest value label
Rotation to closest value label

Time:02-23

import SwiftUI

struct ContentView: View {
    
    private let letters: [String] = ["A", "B", "C"]
    private let numbers: [Int] = [
        4, 5, 21,     // A, B, C
        23, 27, 36,   // A, B, C
        37, 52, 59    // A, B, C
    ]
    
    @State private var randomNumber: Int = 0
    @State private var rotation: CGFloat = 0.0
    @State private var started: Bool = false
    
    var body: some View {
        VStack {
            ZStack {
                ZStack {
                    Circle()
                        .foregroundColor(.blue)
                    ForEach(letters.indices) { i in
                        Text(letters[i])
                            .foregroundColor(.white)
                            .offset(x: 0, y: -110)
                            .rotationEffect(.degrees(Double(i * (360 / letters.count))))
                    }
                }
                .frame(width: 250, height: 250, alignment: .center)
                .rotationEffect(.degrees(rotation))
                
                VStack {
                    Text("Rotation: \(rotation, specifier: "%.2f")")
                    Text("Number: \(randomNumber)")
                    Text("Closest: \(closest(to: randomNumber))")
                }
            }
            
            Spacer()
                .frame(height: 50)
            Button(started ? "Stop" : "Start", action: started ? stop : start)
                .buttonStyle(.borderedProminent)
                .tint(started ? .red : .blue)
        }
    }
    
    private func start() {
        started = true
        loop()
    }
    
    private func stop() {
        started = false
    }
    
    private func loop() {
        if !started { return }
        
        randomNumber = .random(in: numbers.min()!...numbers.max()!)
        withAnimation { 
            rotation = CGFloat(0)
        }
        
        DispatchQueue.main.asyncAfter(deadline: .now()   1, execute: loop)
    }
    
    private func closest(to x: Int) -> Int {
        return numbers.enumerated().min(by: { abs($0.1 - x) < abs($1.1 - x)})!.element
    }
}

Hello, I want to rotate the zstack according to randomNumber value to match the letter number in array for example if randomNumber = 30 closest number = 27 which is labeled B in the circle I want to rotate the zstack so the letter B point to north but a little offset because the number is 30 not 27 exactly

The code above is example the calculation happens in loop function inside withAnimation brackets

Thank you

CodePudding user response:

Here is a proposal for your loop, so the rotation picks the closest number in the array:

            randomNumber = .random(in: numbers.min()!...numbers.max()!)
            let differences = numbers.compactMap { abs($0 - randomNumber) }.sorted { $0 < $1 }
            let closest = randomNumber - (differences.first ?? 0)
                
            withAnimation {
            if numbers.contains(closest) {
                    rotation = closest
                } else {
                    rotation = randomNumber   (differences.first ?? 0)
                }
            }

Just remember to use the proper types (Int, CGFloat…).

  • Related