SECRET OF CSS

Build a 3D Bar Chart in SceneKit With SwiftUI | by Mark Lucking | Jun, 2022


Plug in the missing component of the SwiftUI Charts library

An animated GIF of the chart you’ll built with this article

I started this article before the WWDC 2022, an event with a sexy new framework announced by Apple called Charts. I was briefly worried as I heard the announcement in the latest SwiftUI talk that I may have been beaten to the post, but I felt better when I realized the Apple charts framework only does 2D charts.

That said, it’s true I did write a few articles on building 2D pie charts last year, all of which are now definitively dead — but this one lives on. Join me in this paper to use the SceneKit framework I have been talking about this past month or so, not to build a game, but something a little more mundane, a 3D bar chart.

Ok — We will need a SCNScene running within SwiftUI with a Combine publisher linking the two. Within the Scene, I want to draw a line of boxes & labels, boxes I plan to use SCNMorph to change in size over time. I will make it run using a struct much like the one described in the Apple talk on the new Charts framework.

A 3D Chart

Bon — I start by adding these lines to my Scene. They don’t load any data; they just generate some numbers out of thin air and create a super simple 3D bar chart with lines. The first challenge here is that shapes grow from their centres, a status that seems almost impossible to change.

Code that effectively builds us a nice simple 4D chart that looks like this.

1*XG4EXTsjOmhaLFaL w7caA
Snapshot of 3D bar chart [includes a floor, mentioned next]

Animation Techniques

Having drawn it and lined up the bars, I decided to add a SCNFloor to make it look a little more snazzy and added SCNTransation around a SCNMorph to change the bar sizes using animation.

1*XcgKNXlK5
An SCNTransaction managed resizing of our 3D chart

Positioning

I linked this to the SwiftUI interface through the Combine framework using the subscription technique I outlined in this paper in part and using a singleton class with the SceneDelegate.

The code above is contained within the GameScene.swift file, with the Combine-based relating subject trigged through a simple Text object in the SwiftUI interface.

Text("_5yawC")
.onTapGesture {
relocating.send(._5yawClockwise)
}

Code that will let me position my 3D bar chart on the screen for optimal viewing.

Camera View

As I pointed out in this paper, just moving the object is not enough, and I implemented a separate mechanism to move the camera used by the Scene to look at the 3D bar chart. This time I do the job within the SceneDelegate.swift

Common.shared is simply a reference to a shared struct between the SwiftUI interface and the SceneKitDelegate code you see here.

Changing the value of the superSIMDValue.xV results in discrete moves, changing the value of share.superSIMDValue.RX results in continuous movements timed to execute every spawnTime seconds.

Color Palettes

Of course, bar charts need colours, a subject with more to it than you may imagine. I wrote all about color here. Cutting to chase, I decided to add a fixed palette of 12 Colours for now.

1*sNADu T f0uUY92zGZJowg

Text Labels

As the WWDC 2022 talk on this very subject will tell you a chart without labels isn’t very useful, so I added some of these too.

1*aWk6UoOHIWWtbF5Mg2 GA
A 3D bar chart with labels showing the different values

Note I tilted the text using this code to ensure it was readable, before adding it to the bars shown.

let quaternion = simd_quatf(angle: GLKMathDegreesToRadians(-45), axis: simd_float3(1,0,0))
textNodes[k].simdOrientation = quaternion * textNodes[k].simdOrientation
sourceNodes[k].addChildNode(textNodes[k])

Sorting

One of the things to come out of the project that I hadn’t realized is that 3D bar charts only look good when they describe a data set that gets bigger as it goes by, a sorted set. I did this visually; since this was, of course, half the fun.

1*ciADoViTFwuPT2EomZOrVw
A 3D bar chart sorting itself.

Legend

Finally, I added a SwiftUI legend on top of the SceneKit view, with this the net result:

1*8PTEFPRXlCUu3ibZoQ7XSQ

I think a 3D bar chart is quite reasonable; what do you think. I should give a quick nod here to this article on colour too. I used the palettes described in it here.

You could do a few things to make this better, I think.

  • The sorting itself could be more dynamic, happening as you change the values of the bars.
  • The placement of the labels at the top of the bars I think could be better — some fine-tuning.
  • The data could/should be loaded dynamically so a JSON or an XML source perhaps.
  • You could do more with the camera, using some pre-cast routes like circling the chart or flying through it.

All of which brings me to the end of this piece, I hope you enjoyed reading it as much as I did writing it. You can find a bitbucket with all the code shown here on this link.



News Credit

%d bloggers like this: