Approaches to creating diagrams for iOS applications

An important component of mobile app development is the creation of informative graphs and charts. Visual representation of data is crucial for conveying complex information to users simply and concisely.

SwiftUI is a framework presented at WWDC19. It allows you to design and develop user interfaces with less code in a declarative way. Unlike the existing, familiar UIKit, which was usually used in combination with storyboards or XIBs, SwiftUI is completely based on program code. However, the syntax of the latter is much easier to understand, which speeds up the implementation of set tasks.

Although SwiftUI provides a powerful set of tools for creating screens and user interfaces, until iOS 16, there was no native framework from Apple for working with graphs. Of course, this didn't mean that there was no way to create apps with graphs and charts. There were two ways to create graphs natively (using struct Shapes) or use third-party frameworks.

Here are some ways to implement charts in iOS 16:

Features and challenges of working with charts in iOS

  1. Developing graphics natively using struct Shapes, or rather struct Path, allows you to create your shapes and objects with any geometric properties, customize the animation of your graphic objects, and divide your UI into many small components, which makes it easier to manage and maintain the code. But this option has the following disadvantages:​
    • сreating complex forms can be cumbersome and require a significant amount of code, potentially making development complex;

    • Path and Shapes may not have all the functionality of standard graphic frameworks, so you'll need to implement some features separately.

  2. Using third-party frameworks saves development time and provides a relatively secure and proven code base (since the code has been used many times in other projects).
    However, even here there are drawbacks:
    • dependence on a third-party framework and its subsequent update after critical bugs are found or with the release of new versions of iOS;

    • dependence of some frameworks on others and their mutual compatibility;

    • a significant increase in the size of the program.

Today we’re going to show you how we at Lampa Software have successfully tested different ways of creating charts for our customers' applications. For example, let's take the format of a regular line chart.

The image below shows a broken-line graph with round points of current values, where the days of the week are marked horizontally, and the mood options (Excellent, Good, Usual, Terrible) are marked vertically by day.

Features and challenges of working with charts in iOS

Line graph of sentiment by day

We needed to develop a line graph using the SwiftUI framework, with support starting from iOS 15. In addition, it was necessary to minimize the use of third-party frameworks. Given that the specialized framework  Swift Charts is available only with iOS 16, our team started with a native way via struct Path.

Method №1: Shapes

SwiftUI provides many powerful tools out of the box, with Shapes being one of them, and Apple's tools include Capsule, Circle, Ellipse, Rectangle, and RoundedRectangle. The Shape protocol conforms to the Animatable and View protocols, which means we can customize their appearance and behavior. But we can also create our shape using the Path structure (the outline of a two-dimensional shape we draw ourselves). The Shape protocol contains an important method func path(in: CGRect) -> Path: after implementing it, we must return a Path describing the structure of the newly created Shape.

Let's start by creating a LineView struct that accepts an array of optional values of type Double? and uses Path to draw a graph from each previous array value to the next.

Shapes

To determine the boundary dimensions of the graph and calculate ratios, we use the GeometryReader, which will allow us to get the height and width values for superview. These values, along with the func ratio(for index: Int) -> Double method, calculate the location of each point on the line by multiplying the height by the ratio of the individual data point to the highest point (func ratio(for index: Int)).

To emulate the input data, we will create an enum MoodCondition that will describe different possible states:

Shapes-1

Using the enum MoodCondition, let's define the variable let selectedWeek, which will store the MoodCondition states for all days of the week:

let selectedWeek: [Double?] = [

 MoodCondition.great.rawValue,

 MoodCondition.soso.rawValue,

 MoodCondition.fine.rawValue,

 MoodCondition.soso.rawValue,

 MoodCondition.fine.rawValue,

 MoodCondition.normal.rawValue, 

MoodCondition.great.rawValue ]

Similar to the struct LineView, we will create a separate struct LineChartCircleView. The specified structure also accepts an array of optional values (let dataPoints), and an additional value let radius. The structure draws separate round points with a radius of radius also through Path.

Shapes-3

We overlay struct LineChartCircleView on struct LineView and get a broken-line graph with points for each value:

Shapes-3

Combining LineChartCircleView and LineView

It is important to display the X and Y coordinate axes along with the curves, so let's start with the implementation of the Y axis, namely, by creating a struct YAxisView:

Shapes-4

The value for the variable scaleFactor will be passed from the parent struct LineChartView, and the offset modifier will list all possible MoodCondition depending on the value of each value and the height of the chart.

To construct the coordinate X, create a struct XAxisView:

Shapes-5

Create an enum WeekDay to display all days of the week on the XaxisView axis:

Shapes-6

To make the graph easier to use, let's add horizontal dashed grid lines for the Y-axis, which will correspond to each MoodCondition. To do this, create a separate struct LinesForYLabel:

Shapes-7

It is important to combine all the Views into one single struct LineChartView, where they will be contained simultaneously:

  • X and Y axes;

  • broken-line graph;

  • intersection points;

  • horizontal dashed lines for the Y-axis.

Shapes-8

Using init(), we initialize the struct LineChartView with the input data for the dataPoints property through MoodCondition for all days of the week. The calculation of axisWidth and scaleFactor values is based on the ratio of values along the Y-axis and the size of the chart and may vary depending on the design. The structures LinesForYLabel(), LineView(dataPoints: dataPoints), LineChartCircleView(dataPoints: dataPoints, radius: 4.0) are superimposed on each other and placed in the ZStack. Then they are combined with YAxisView(scaleFactor: Double(scaleFactor)) and XAxisView() in HStack/VStack, respectively.

This way, you can develop any variants and combinations of charts. However, there is an interdependence of each component of the View, for example, the amount of code and the complexity of maintaining and expanding the existing functionality.

Method №2: SwiftUICharts

Another option for building a similar chart is to use a third-party framework, such as SwiftUICharts.

It's what they do:

  • Pie charts, line charts, bar charts, and histograms.

  • Various coordinate grids.

  • Interactive labels to show the current value of the chart, etc. 

The library is available with iOS 13 and Xcode 11 and can be installed via Swift Package Manager or CocoaPods. After adding SwiftUICharts to your project, you need to import the framework using import SwiftUICharts:

SwiftUICharts

First, we initialize the let dataSet model with input data based on values from enum MoodCondition and enum WeekDay. Immediately, we configure the point markers with pointStyle and the model to control the style of the lines with style. We use GridStyle to configure the grid view for the chart and LineChartStyle to add the main chart settings.

The configuration returns a LineChartData object with all the necessary settings. This allows you to specify the required array of input values and customize the chart display according to the specified design.

SwiftUICharts-1

Method №3: Swift Charts

The last option for building a chart is the Swift Charts framework.

It creates various types of charts, including line, dot, and bar charts. Scales and axes that correspond to the input data are automatically generated for them.

We import the framework using import Charts, then create a struct Day function that will correspond to a specific day WeekDay and MoodCondition:

Swift-Charts

Based on the struct Day, we will create a let currentWeeks variable that will correspond to the given week with the corresponding Day:

Swift-Charts-1

To build the required graph, we use structures:

  • LineMark, which visualizes data using a sequence of connected segments.

  • PointMark, which displays data using dots.

Swift-Charts-2

Using ForEach, we run through all the input data currentWeeks and set x, y values to LineMark and PointMark, respectively.

In the .chartXAxis modifier, set up the axis:

  • Positioning.

  • Color.

  • Scale for the X-axis.

The same applies to chartYAxis, but we also configure the Y-axis grid.

The peculiarity of using Swift Charts is that, with the help of various modifiers, we can quickly create many different types of charts without much effort. The framework is easy to use, supports animation, has a wide range of functions for creating and editing charts/diagrams, and also contains a lot of material on how to work with it.

Let's compare the options for building charts using ShapesSwiftUIChartsLIbrary, and Swift Charts for a comparative analysis:

Swift-Charts-3

The result was as follows:

Swift Charts-4

Create diagrams using Shapes, SwiftUIChartsLibrary, Swift Charts

So, we have tested 3 different options for building diagrams in the SwiftUI environment. Let's compare them.

Criterion

Shapes

SwiftUIChartsLibrary

Swift Charts

Approach to construction

Manual creation of a chart

Using the library

Using the framework

Time

Takes a long time

Less time (when customizing the chart)

Less time (declarative approach)

Reliability

Reliable, native

Library dependency

Framework dependency, native

Support for different versions of iOS

iOS 13 and above

iOS 13 and above

iOS 16 and above

Ease of use (intuitiveness)

Not difficult, but requires some experience

Relatively easy to use

Intuitive and easy to use

Scope of work (program code)

Big

Little

Little

Customization options

Great customization options

Extensive graphics editing functionality, but limited by the library

Intuitive customization, but limited by the framework

Availability of optimization in the future

Yes

Yes, subject to third-party support

Yes

The number of possible diagrams to implement

There are practically no restrictions

Wide functionality, but limited by the library

Wide functionality, but limited by the framework

Swift-Charts-5

We have created a primitive chart, but even such a simple design allows you to understand all the difficulties that may arise in the future for iOS developers when building charts using the SwiftUI framework.

Need professional assistance gathering all the required artifacts to build a mobile app? Order product ideation services from Lampa!

Subscribe via email and know it all first!

Explore the Latest Blogs on Trends and Technology.

We use cookies on our website

We use cookies to personalise content and ads, to provide social media features and to analyse our traffic. We also share information about your use of our site with our social media, advertising and analytics partners who may combine it with other information that you’ve provided to them or that they’ve collected from your use of their services. You consent to our cookies if you continue to use our website.