Swift advanced charts from scratch
By: Alexey Kolchedantsev
Tags: From Scratch, Bar Chart, Swift, Charts, Animation

Simple chart

I will skip the part this creating and setting up the project — we all know how to do that.

Create a subclass of UIView and name it BarChart.

Inside the class we create 2 enums:

PeriodType: We going to use this to manage different types of input data. This enum has spacing value, this will be used to space our bars from each other so it looks good. ChartType: This one I created because my class handles different chart types with different UI, in this article we gonna focus only on multiColor. But anyway it’s always good to have some place for customization and extension.

Also we add setup function, we will use this function to create out chart, and change it if needed. And again, you can see that there is to different options for the chart, but forget about doubleColor for now.

Then we extend our class with some more futures:

Color: This enum will be used to paint our chart, I use here my custom colors. You can use yours, or take this ones from github project. DataPoint: That’s a model that will contain needed data and values

DataPoint:

Label: X value label that you want to show under the bar Value: actual value of the bar Color: contains color for the bar, so each bar can actually be different color ComplexValues: this is important one. It’s a variable for our future, advanced chart. It contains additional values for the bar, those which we will be showing on top of main bar. It’s a array of tuple (CGFloat, Color). I picked this types, so I can easily customize each single bar how I want. And it’s also sorted by colors, so no matter each values are passed in — color ordered always the same.

Okay, finally our main function

In first 4 lines we simply get values and calculate spacing and width for our bars. Then let’s take a look a some lines in the loop:

Get the percent from maximum value from the array. This is done, so biggest value always will have highest bar. Here we calculate line height for the current bar. There is tricky condition: (percent > 0 ? percent : 2 ). I did this, so if value is 0, bar will still be visible, otherwise it will look like a gap. Calculate X for the value depending on it’s index. And finally create rect for our bar with values we’ve calculated earlier. Then create Path from this rect with rounded corners. I called variable endPath and not just path for a reason, will get back to it latter. At the end we just create layer and set path to it. And add our new bar layer to main layer of our view.

Now, let’s setup our view controller to check out we achieved so far. I add BarChart in storyboard and Segmented control as well. You can do it programmatically with you want, doesn’t matter. Here is how my VC looks:

So few things about ViewController:

Take a look at segmentAction function: depending on selected segment, it calls setup function of barChart with needed count of DataPoints. This function uses randomDataPoints function, I created it to simply get needed amount of dataPoints for my chart.

And here is what we got so far:

Not bad! Let’s add some more colors now!

But before we jump back to code again, let’ me explain the idea behind my implementation. This is actually quite important!

Let’s take for example a bar that holds value of 100. Now we don’t care about it’s height inside a view bound! We just have a bar with value of 100, and height X. Now we want to add one more color on top of it and we want it to represent 25% of total value. Then we have to pass value of 25 to it. Makes sense right? All idea of this chart, is that main bar(blue) — is 100 % of all values inside the bar. Additional colors just represent some percent of total value. So all values of additional colors combined can not be more then value of main(blue) bar. I hope is more less clear with my amazing English :)

Now let’s continue

Bar with multiple colors

Now we add this peace of code inside for loop in scheduleMultiColor function:

Create variable that will hold Y axes offset, so we don’t lay our new layers on top of each other. Calculate line height. As I sad, values for extra layer are just a percent of total value. So we calculate it’s height with this idea. There is also min() function, just to make sure there is no way our extra layer will be higher then main one. Calculate Y position. Since we want our sublayers to lay from top of the bar, we need to subtract it’s value from height of main bar. And then we add the Y offset.

Then we do the same we did before. Create path, add to layer and add this layer as sublayer to our bar layer. Don’t forget to increase Y position offset.

Now let’s add this functionality to ViewController:

We need to change randomDataPoints function a little bit, so it provides additional values to the chart. This is how function looks now:

Just in case you need some clearance, here is what we do:

Now we generate and store total value for the bar inside randomValue variable. Then we fill complexValues with array of 3 tuples. First one will represent 1/4 of the total value, second — 1/6 and third — 1/8. So together they suppose to be half of total value.

Let’s see what we got:

Nice! Now let’s add animations that we all love !

Animation

Before we start to add animations right to our chart, let’ create some helpers for it.

Here is a helping struct for animations. It also contains some functions we are not going to use. But I decided maybe it will be useful to you anyway.

And extension for CALayer:

This extension uses previously created Animation struct.

Now we just need to add couple lines of code to make our chart alive.

Remember that I was naming our rects and paths with prefix End ? Here is why! To animate path, first we need to create bar with path which has height equal to 0. And then change this path to final one with animation.

So after little refactoring of function for this purpose it looks like this:

Now you see, firstly we create 0 height bar, and then we animate it just with one line of code ! Also, take a look at how we animate extra layer, to make our multiple layers animate one after another, we need to add this peace of code: delay: 0.5 + (0.3 * Double(index)). Like this each layer will start to animate right after previous one.

And here is the result:

Full code you can find in my gitHub repo here: https://github.com/Kolch/Charts

I hope your really enjoined it and found it useful for yourself!

Today I just showed you one of many charts I did from scratch! If you liked it and if you want me to show some more, let me know in the comments.

And if you leave with some claps I’ll really appreciate it! :)