Search code examples
iosswiftswiftui

Draw straight lines on canvas SwiftUI


I am trying to draw straight lines using canvas and the detectDragGestures method, but so far I have only achieved chaotic behavior without any fixations. I am seeking a solution to ensure that my lines are always straight.

import SwiftUI

struct GraphicDictView: View {

@State private var lines: [CGPoint] = []
@State private var circleToDraw = CGPoint()

var body: some View {
    Canvas { context, _ in
        
        context.fill(
            Path(ellipseIn: CGRect(
                x: circleToDraw.x - 7,
                y: circleToDraw.y - 7,
                width: 14,
                height: 14
            )),
            with: .color(Color.blue)
        )
        
        var path = Path()
        
        for line in lines {
            path.addLine(to: line)
        }
        context.stroke(path, with: .color(Color.blue), lineWidth: 2)
    }
    .gesture(
        DragGesture()
            .onChanged { value in
                circleToDraw = value.location
                lines.append(value.location)
            }
    )
  }
}

Right now my code has this behavior:

enter image description here

The behavior I need to achieve: enter image description here


Solution

  • You can set a start point and end point and add them to the lines array

    //
    //  GraphicDictView.swift
    //  Meyollo
    //
    //  Created by Hezy Ziv on 28/09/2024.
    //
    import SwiftUI
    
    struct GraphicDictView: View {
        @State private var startPoint: CGPoint?
        @State private var endPoint: CGPoint?
        @State private var lines: [(start: CGPoint, end: CGPoint)] = []
    
        var body: some View {
            Canvas { context, size in
                for line in lines {
                    var path = Path()
                    path.move(to: line.start)
                    path.addLine(to: line.end)
                    context.stroke(path, with: .color(Color.blue), lineWidth: 2)
                }
    
                if let start = startPoint, let end = endPoint {
                    var path = Path()
                    path.move(to: start)
                    path.addLine(to: end)
                    context.stroke(path, with: .color(Color.blue), lineWidth: 2)
                }
            }
            .gesture(
                DragGesture()
                    .onChanged { value in
                        if startPoint == nil {
                            startPoint = value.location
                        }
                        endPoint = value.location
                    }
                    .onEnded { value in
                        if let start = startPoint {
                            lines.append((start: start, end: value.location))
                        }
                        startPoint = nil
                        endPoint = nil
                    }
            )
        }
    }
    
    #Preview {
        GraphicDictView()
    }