Home > Blockchain >  Add filled circles (markers) at SwiftUI path points
Add filled circles (markers) at SwiftUI path points

Time:02-14

I'm trying to draw a line with markers at each point by using a Shape view in SwiftUI. I want the line to have a filled circle at each CGPoint on the line. The closest to this that I've gotten is by adding an arc at each point. Instead of using the arc, how can I add a Circle() shape at each point? I'm open to other approaches to accomplish this. My only requirements are to use SwiftUI and have the ability to interact with the markers.

line plot

import SwiftUI

struct LineShape: Shape {
    
    let values: [Double]
    
    func path(in rect: CGRect) -> Path {
        let xStep = rect.width / CGFloat(values.count - 1)
        
        var path = Path()
        path.move(to: CGPoint(x: 0.0, y: (1 - values[0]) * Double(rect.height)))
        
        for i in 1..<values.count {
            let pt = CGPoint(x: Double(i) * Double(xStep), y: (1 - values[i]) * Double(rect.height))
            path.addLine(to: pt)
            path.addArc(center: pt, radius: 8, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 360), clockwise: false)
        }
        
        return path
    }
}

struct ContentView: View {
    var body: some View {
        LineShape(values: [0.2, 0.4, 0.3, 0.8, 0.5])
            .stroke(.red, lineWidth: 2.0)
            .padding()
            .frame(width: 400, height: 300)
    }
}

CodePudding user response:

You can make two different shapes, one for the line and one for the markers, and overlay them. Then you can also control their coloring individually:

enter image description here

struct LineShape: Shape {
    
    let values: [Double]
    
    func path(in rect: CGRect) -> Path {
        let xStep = rect.width / CGFloat(values.count - 1)
        
        var path = Path()
        path.move(to: CGPoint(x: 0.0, y: (1 - values[0]) * Double(rect.height)))
        
        for i in 1..<values.count {
            let pt = CGPoint(x: Double(i) * Double(xStep), y: (1 - values[i]) * Double(rect.height))
            path.addLine(to: pt)
        }
        
        return path
    }
}

struct MarkersShape: Shape {
    
    let values: [Double]
    
    func path(in rect: CGRect) -> Path {
        let xStep = rect.width / CGFloat(values.count - 1)
        
        var path = Path()
        
        for i in 1..<values.count {
            let pt = CGPoint(x: Double(i) * Double(xStep), y: (1 - values[i]) * Double(rect.height))
            path.addEllipse(in: CGRect(x: pt.x - 8, y: pt.y - 8, width: 16, height: 16))
        }
        
        return path
    }
}

struct ContentView: View {
    var body: some View {
        
        LineShape(values: [0.2, 0.4, 0.3, 0.8, 0.5])
            .stroke(.red, lineWidth: 2.0)
            .overlay(
                MarkersShape(values: [0.2, 0.4, 0.3, 0.8, 0.5])
                    .fill(.blue)
            )
            .frame(width: 350, height: 300)
    }
}
  • Related