Wrong geometry drag coordinates

237 views Asked by At

I'm trying to drag the gray square inside the white square manteinig the starting point CGPoint(x: 0, y: 0) and respecting the extreme coordinates, see of the image.

The code works but I have two problems:

  • the mouse doesn't match the center of the gray square when it is dragged;
  • I can't subtract the size of the gray rectangle 30x30 (like red rectangle) from the geometry without changing the extreme value of the coordinate.

I tried to solve both problems with

location.x = max (0, min (geometry.size.width - 15, value.location.x) - 15)
location.y = max (0, min (geometry.size.height - 15 , value.location.y) - 15)

but vertices x and y becomes 0.94 instead 1 and 0.06000000000000005 instead 0.

struct ContentView: View {
    @State private var location: CGPoint = CGPoint(x: 0, y: 0)
    
    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            GeometryReader { geometry in
                ZStack(alignment: .topLeading) {
                    Rectangle()
                    .fill(.white)
                    Rectangle()
                    .fill(.gray)
                    .frame(width: 30, height: 30)
                    .offset(x: location.x, y: location.y)
                }
                .gesture(
                    DragGesture(minimumDistance: 0, coordinateSpace: .local)
                    .onChanged { value in
                        location.x = max(0, min(geometry.size.width, value.location.x))
                        location.y = max(0, min(geometry.size.height, value.location.y))

                        print("location",location)
                        print("value location",value.location)

                        let distanceA = distanceA(0, location.x) / geometry.size.width  // < -30
                        let distanceB = distanceB(0, location.y) / geometry.size.height // < -30

                        print(min(distanceA, 1))
                        print(1 - distanceB)
                    }
                )
            }
            .frame(width: 500, height: 500)
        }
    }
    
    func distanceA(_ a: Double, _ b: Double) -> Double {
        let B = b > 0.0 ? b : 0
        let xDist = a - (B)
        return Double(sqrt(pow(xDist, 2)))
    }
    
    func distanceB(_ a: Double, _ b: Double) -> Double {
        let B = b > 0.0 ? b : 0
        let yDist = (B) - a
        return Double(sqrt(pow(yDist, 2)))
    }
}

Wrong geometry drag coordinates

1

There are 1 answers

4
Yrb On

You are attempting to take the small square size into account in the wrong place. The GeometryReader coordinates are the size of the larger square, and that doesn't change. You just need to handle the placement of the smaller square within the larger one. Essentially you need to move it up and left half the size of the square. Commented code:

struct ContentView: View {
    @State private var location: CGPoint = CGPoint(x: 15, y: 15)
    let dragSquareSize: CGFloat = 30
    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            GeometryReader { geometry in
                ZStack(alignment: .topLeading) {
                    Rectangle()
                    .fill(.yellow)
                    Rectangle()
                    .fill(.gray)
                    .frame(width: dragSquareSize, height: dragSquareSize)
                    // subtract half of the dimensions of the smaller square to center the squareon the cursor.
                    .offset(x: location.x - dragSquareSize / 2, y: location.y - dragSquareSize / 2)
                    .gesture(
                        DragGesture(minimumDistance: 0, coordinateSpace: .local)
                        .onChanged { value in
                            // Subtract half of the dimensions of the smaller square from geometry here
                            location.x = max(dragSquareSize / 2, min(geometry.size.width - dragSquareSize / 2, value.location.x))
                            location.y = max(dragSquareSize / 2, min(geometry.size.height - dragSquareSize / 2, value.location.y))

                            print("location",location)
                            print("value location",value.location)

                            let distanceA = distanceA(0, location.x) / geometry.size.width  // < -30
                            let distanceB = distanceB(0, location.y) / geometry.size.height // < -30

                            print(min(distanceA, 1))
                            print(1 - distanceB)
                        }
                    )
                }
            }
            .frame(width: 300, height: 300)
        }
    }
    
    func distanceA(_ a: Double, _ b: Double) -> Double {
        let B = b > 0.0 ? b : 0
        let xDist = a - (B)
        return Double(sqrt(pow(xDist, 2)))
    }
    
    func distanceB(_ a: Double, _ b: Double) -> Double {
        let B = b > 0.0 ? b : 0
        let yDist = (B) - a
        return Double(sqrt(pow(yDist, 2)))
    }
}