Using the SwiftUI Canvas

Hello,

I was following a tutorial on how to use the SwiftUI Canvas and I can't seem to get it to work. Below is the code that I have.

struct Line {
    var points: [CGPoint]
    var color: Color
}

struct CanvasView: View {
    @State var lines: [Line] = []
    @State var selectedColor: Color = Color.black
    
    var body: some View {
        ScrollView([.horizontal, .vertical]) {
            Canvas { ctx, size in
                for line in lines {
                    var path = Path()
                    path.addLines(line.points)
                    
                    ctx.stroke(path, with: .color(line.color), style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))
                }
            }.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
                .onChanged({ value in
                    let position = value.location
                    
                    if value.translation == .zero {
                        lines.append(Line(points: [position], color: selectedColor))
                    } else {
                        guard let lastIndex = lines.indices.last else {
                            return
                        }
                        
                        lines[lastIndex].points.append(position)
                    }
                })
              )
        }
    }
}

I'm pretty sure I followed the tutorial exactly so I'm not sure why it isn't drawing. Any help would be greatly appreciated. Thank you.

Hi! I tried your code! For me, no line was drawn with the ScrollView, so I tried replacing the ScrollView([.horizontal, .vertical]) with a VStack and then you could draw! The code that worked:

struct Line {
   var points: [CGPoint]
    var color: Color
}

struct ContentView: View {
    @State var lines: [Line] = []
    @State var selectedColor: Color = Color.black
    
    var body: some View {
        VStack {
            Canvas { ctx, size in
                for line in lines {
                    var path = Path()
                    path.addLines(line.points)
                        
                    ctx.stroke(path, with: .color(line.color), style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))
                }
            }.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
                .onChanged({ value in
                    let position = value.location
                    
                    if value.translation == .zero {
                        lines.append(Line(points: [position], color: selectedColor))
                    } else {
                        guard let lastIndex = lines.indices.last else {
                            return
                        }
                        
                        lines[lastIndex].points.append(position)
                    }
                })
            )
        }
    }
}

However, I am uncertain why the scrollview didn't work.

Have a great day!

I have two follow up questions. Any help would be greatly appreciated.

  1. How can I implement a scroll feature with the Canvas so that the Canvas itself would be larger than the screen?

  2. How can I draw on the canvas upon loading the canvas? For example, if I pass data stored as a Line variable to the view that the Canvas is on, how can I draw onto the canvas upon loading based off of that data?

Thank you.

Hi! Did you solve it?

Question number 1: I have unfortunately no idea how to do that, I think you need to play around with PencilKit from UIKit and then implementing custom drag gestures for Swift to determine that you want to scroll or paint. However, this should be possible because Apple's own Freeform app can do such.

Question number 2: Did you mean something like this? (before you draw this will have drawn some line on the screen, because you pass lines as a parameter to the draw view)

ContentView(lines: [
            Line(points: [
                CGPoint(x: 12, y: 426),
                CGPoint(x: 12, y: 65)
            ], color: .black),
            Line(points: [
                CGPoint(x: 122, y: 412),
                CGPoint(x: 425, y: 212)
            ], color: .black),
            Line(points: [
                CGPoint(x: 553, y: 2),
                CGPoint(x: 1, y: 23)
            ], color: .black)
        ], selectedColor: .black) 
Using the SwiftUI Canvas
 
 
Q