I have a view that draws some lines and filled circles. But to know the position of these lines I need to dynamically calculate them as they are being drawn.
I have two issues.
The first is that for some reason, the view code runs twice on the first load messing up the array lastYPos; but if I resize the window, the code runs once and it works fine.
The second is that I use “let _ = ” to change the value of variables, and I believe that this is a bad practice, but I cannot think of a better way to do it.
`struct StoryArcLinesView: View {
@Environment(.modelContext) private var modelContext
var t: Timeline?
var xStep: CGFloat
var yStep: CGFloat
var body: some View {
if let t {
let es = [someClass]
let ar = [someClass]
var ls: [Line] = []
var lastYPos: [CGFloat] = []
ZStack{
ForEach(es) { e in
let xPos = xStep * CGFloat(e.position)
ForEach(ar.indices, id: .self) { aIndex in
let arc = ar[aIndex]
let yPos = yStep * CGFloat(arcIndex + 1)
if !lastYPos.indices.contains(aIndex) {
let _ = lastYPos.insert(yPos, at: aIndex)
}
if e.position > 1 {
if e.position == 2 {
let yStart = yStep * CGFloat(isPrevShared.1 + 1)
drawJoiningLine(arc: arc, xPos: xPos, xStep: xStep, yStart: yStart, yEnd: yPos, lines: &ls, position: e.position)
let _ = setVariables(xStart: xPos - xStep, yStart: yStart, xEnd: xPos, yEnd: yPos, arcIndex: arcIndex, lines: &ls, arcYPos: &lastYPos)
} else {
drawJoiningLine(arc: arc, xPos: xPos, xStep: xStep, yStart: lastYPos[aIndex], yEnd: yPos, lines: &ls, position: e.position)
let _ = setVariables(xStart: xPos - xStep, yStart: lastYPos[aIndex], xEnd: xPos, yEnd: yPos, arcIndex: aIndex, lines: &ls, arcYPos: &lastYPos)
}
}
}
}
}
}
}
func drawJoiningLine(a: SomeClass, xPos: CGFloat, xStep: CGFloat, yStart: CGFloat, yEnd: CGFloat, lines: inout [Line], position: Int) -> some View {
print("Drawing Line for arc:(a.name), event position:(position)")
let overlappingLines = lines.filter {
($0.start == CGPoint(x: xPos - xStep, y: yStart) && $0.end == CGPoint(x: xPos, y: yEnd)) ||
($0.start == CGPoint(x: xPos, y: yEnd) && $0.end == CGPoint(x: xPos - xStep, y: yStart))
}.count
let width = 40
let lineWidth = yStart == yEnd ? CGFloat(width) / CGFloat(overlappingLines + 1) : CGFloat(width) / CGFloat(overlappingLines + 2)
let newColor = Color(NSColor(hex: a.color))
return Canvas(rendersAsynchronously: false) { contex, size in
if yStart != yEnd || position == 2 {
let xStart = xPos - xStep
contex.fill(
Path(ellipseIn: CGRect(origin: CGPoint(x: xStart - (lineWidth/2), y: yStart - (lineWidth/2)), size: CGSize(width: lineWidth, height: lineWidth)))
, with: .color(newColor))
}
contex.fill(
Path(ellipseIn: CGRect(origin: CGPoint(x: xPos - (lineWidth/2), y: yEnd - (lineWidth/2)), size: CGSize(width: lineWidth, height: lineWidth)))
, with: .color(newColor))
contex.stroke(Path{ path in
path.move(to: CGPoint(x: xPos - xStep, y: yStart))
path.addLine(to: CGPoint(x: xPos, y: yEnd))
}, with: .color(newColor), lineWidth: lineWidth)
}
}
func setVariables(xStart: CGFloat, yStart: CGFloat, xEnd: CGFloat, yEnd: CGFloat, arcIndex: Int, lines: inout [Line], lastYPos: inout [CGFloat]) {
let line = Line(start: CGPoint(x: xStart, y: yStart), end: CGPoint(x: xEnd, y: yEnd))
lines.append(line)
lastYPos[arcIndex] = yEnd
}
}`