I am trying to plot y-values against x-values, which are 0, 1, .., y.count-1. Users can choose to zoom in or out by specifying different ymin and ymax values. Here is the simplified code:
import SwiftUI
struct LineGraph: Shape {
let y: [Double]
let ymin: Double
let ymax: Double
func path(in rect: CGRect) -> Path {
// for simplicity x-axis has values 0, 1, .., y.count-1
let dx = rect.width / CGFloat(y.count-1)
// ycur is the current y point.
let yrange = ymax - ymin
let dy = rect.height / yrange
let ycur = dy * (y[0]-ymin)
var path = Path()
path.move(to: CGPoint(x: 0, y: rect.height - ycur))
for k in 1..<y.count {
path.addLine(to: CGPoint(x: dx * CGFloat(k),
y: rect.height - dy * (y[k]-ymin)))
}
return path
}
}
struct ContentView: View {
var body: some View {
VStack {
LineGraph(y: [8.0, 5.0, -2.0, -2.0, 3.0, 1.0],
ymin: -2.0,
ymax: 8.0)
.stroke(.black)
}
.frame(width: 200, height: 300)
.border(.red, width: 3)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Initiating the LineGraph with the y's min and max values, which are -2 and 8, yields an expected result. However, if I initiate it with ymin:0 and ymax: 5, then I get the right side plot below:
My question is how can the child view LineGraph be contained within the border of its parent view VStack (within the red frame)? I tried .mask() with a clear rectangle and also overlaying this graph on a rectangle but couldn't get the result that I wanted. One solution is to find intersection points of the graph with the lines y=ymax and y=ymin, but I wonder if there is another way such as masking.
CodePudding user response:
I assume you wanted clipping, like
VStack {
LineGraph(y: [8.0, 5.0, -2.0, -2.0, 3.0, 1.0],
ymin: -2.0,
ymax: 8.0)
.stroke(.black)
}
.frame(width: 200, height: 300)
.border(.red, width: 3)
.clipped() // << here !!