[Swift Charts] custom LineMark symbol is transparent

I have the following Chart and I can't figure out why the AreaMark's are transparent.

The area marks are opaque when I move the .symbol view modifier to the AreaMark, but then the gradient doesn't work anymore

Any ideas on how to solve this?

struct Ranking: Identifiable {
    let name: String
    let steps: Int
    var id: String { name }
}

let rankings: [Ranking] = [
    .init(name: "Tom", steps: 200),
    .init(name: "Joseph", steps: 850),
    .init(name: "Emil", steps: 700),
    .init(name: "Sandra", steps: 100),
    .init(name: "Annie", steps: 400),
    .init(name: "Teo", steps: 700),
    .init(name: "Pär", steps: 400)
]

struct ContentView: View {

    let curGradient = LinearGradient(
        gradient: Gradient (
            colors: [
                Color(.blue).opacity(0.1),
                Color(.blue).opacity(0.0)
            ]
        ),
        startPoint: .top,
        endPoint: .bottom
    )

    var body: some View {
        VStack() {
            Text("Ranking")

            Chart {
                ForEach(rankings) { element in
                    LineMark(
                        x: .value("Name", element.name),
                        y: .value("Steps", element.steps)
                    )
                    .interpolationMethod(.catmullRom)
                    .foregroundStyle(.blue)
                    .symbol {
                        Circle()
                            .fill(.white)
                            .frame(width: 20)
                            .shadow(radius: 2)
                    }

                    AreaMark(
                        x: .value("Name", element.name),
                        y: .value("Steps", element.steps)
                    )
                    .interpolationMethod(.catmullRom)
                    .foregroundStyle(curGradient)
                }
            }
            .chartYAxis(.hidden)
            .chartXAxis {
                AxisMarks(position: .top) { value in
                    AxisValueLabel(verticalSpacing: 20)
                }
            }
            .frame(height: 200)

            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {

    static var previews: some View {
        ContentView()
    }
}
Answered by Jeria in 734491022

Ok, I need to add a post-it note to my monitor "in SwiftUI- order matters".

It will work as expected if the order of LineMark and AreaMark is swapped.

Chart {
    ForEach(rankings) { element in
        AreaMark(...)
        LineMark(...)
    }
}

I hope I've understood this right, here goes...

Change the .symbol's Circle colour to .blue and turn off the symbol's shadow (just comment the line out for now).

Notice how the blue circles are partially transparent? There is no setting you've applied in your code that makes them transparent, so this has to be a built-in behaviour of the Chart.

Even if you add an .opacity(1.0) to the .symbol that's just going to apply 100% of the current opacity value, so if the Chart is setting it to, say, 0.8, then 1.0 * 0.8 is still 0.8.

If you change the new opacity value for the Circle to 0.1, your blue line is still displayed.

Change the colour to red, and change the opacity to 0.1, 0.2, 0.3 etc.

0.1:

0.3:

0.5:

0.9:

In every case, the line remains drawn, but if you zoom in on the line under the circle when your opacity is 0.9 you can see that the blue line is half-disappearing.

1.0:

At 1.0 the line has disappeared but the circle is still partially transparent.

What I think is happening is that your use of white with a shadow and no explicit opacity is hiding the built-in effects of the Chart. I'd suggest playing around with the colours and opacities and find something that works for you.

If you use blue, you're applying a blue circle over the top of a blue line so the line is going to be more visible. Personally, I've just tried a bunch of settings and blue with 0.5 opactity looks good to me:

Thank for looking into this darkpaw.

The final design will include a number inside the circle, and the default opacity would make the text more difficult to read.

I will continue to play around with this and hopefully I will find a solution- I will post it here if I find something. Thanks again for the help.

Accepted Answer

Ok, I need to add a post-it note to my monitor "in SwiftUI- order matters".

It will work as expected if the order of LineMark and AreaMark is swapped.

Chart {
    ForEach(rankings) { element in
        AreaMark(...)
        LineMark(...)
    }
}
[Swift Charts] custom LineMark symbol is transparent
 
 
Q