SteelKiwi Inc. develops mobile applications for iOS and Android apart from web sites development on Python/Django. Mobile department received a project connected with schedules drawing. Nothing difficult — an ordinary linear schedule. However, it was narrowly specialized and absolutely unported, which resulted in its time-consuming changing to a new data format.

It was decided to outline a small class for linear schedules drawing. The used classes have been taken out to the test project and are available for everyone under the following link. Code comments are available.

CLASSES:

  • SKChartView — canvas itself and display logic.
  • SKChartViewDataSource — the protocol for data source.
  • SKChartPopupView — UIView appearing at user’s request.

SKCHARTVIEW

SKChartView is a successor of standard UIView. Type of schedules is linear. Drawing is carried out with the use of standard CoreGraphics. @IBInspectable and @IBDesignable are used for convenience of main features’ customization via InterfaceBuilder:

A brief digest of property class:

  • dataSourceObject — object — source of data for our schedule. It is made by analogy with UITableViewDataSource for dynamic data loading. Some problems appeared with it: we wanted to create a correct object binding via @IBOutlet, but due to the bug in XCode, which did not allow to bind the given outlet with the class that realized a necessary protocol, it was of AnyObject type. The problem of type compatibility was solved by a wrapper via private variable:
private var dataSource: SKChartViewDataSource? { 
return dataSourceObject as? SKChartViewDataSource
}
  • defaultLineColor, gridColor — default color for schedule’s and grid’s lines correspondingly;
  • showLeftLabels — whether to reflect or not text for grid horizontal lines;
  • showVerticalGrid, gridXOffset — whether to reflect or not the vertical grid (InterfaceBuilder for now does not allow to establish boundary values, therefore in code a minimal indent which equals 3 is defined). There are similar features for horizontal lines;
  • showValues, showDots — whether to reflect or not values and dots on the lines;
  • showPopupOnTouch, popupBackground — whether to reflect or not a pop-up window at request and its background color installation.

Initially, for every feature which influences the schedule (lines’ color, grid, etc.) the didSet with call for drawing was installed, but later it was decided to shift responsibilities for updates on a programmer, and correct the code at the same time, as the repeating block under every feature lowered readability.

Algorithm for drawing is the following:

  1. Getting/Receiving the quantity of lines, values for them and color from dataSource. The received data is stored in the internal valuables of a class. Most people may ask “why?”. It was made in order not to address the delegate every time when any value is needed (and such requests happen several times within one iteration). At the beginning of iteration data is rubbed out;
  2. If text on the left from the grid is required — calculation of a frame for it and its reflection;
  3. Grid drawing;
  4. In case if a call is made from InterfaceBuilder (TARGET_INTERFACE_BUILDER checkbox/flag for record) a test line is drawn;
  5. Lines drawing itself with the use of UIBeziePath on the basis of the obtained data from dataSource.

SKCHARTVIEWDATASOURCE

SKChartViewDataSource — a protocol, which contains three methods obligatory for realization:

  • chartViewNumberOfLines — the number of lines in schedule is set;
  • valuesForLine — CGFloat array of values is transferred. No restrictions for values or quantity. Schedule dynamically adapts to the transferred values;
  • colorForLine — color for lines. In case of nil transfer the default value will be used.

SKCHARTPOPUPVIEW

SKChartPopupView — a pop-up window at request. It has dynamic sizes, which are calculated on the basis of lines’ values.

In our opinion only calculation of pop-up’s position is worth attention:

  1. Touch coordinates are calculated (restricted by schedules’ frame):
let x = touchPoint.x < chartFrame.origin.x ? 
chartFrame.origin.x :
(touchPoint.x > frame.width ?
frame.width :
touchPoint.x)

let y = touchPoint.y < 0 ?
0 :
(touchPoint.y > frame.height ?
frame.height :
touchPoint.y)

2. Pop-up’s starting point position is defined:

let x = touchPoint.x + popupView!.size.width > frame.width ? 
frame.width - popupView!.size.width :
touchPoint.x
let y = touchPoint.y + popupView!.size.height > frame.height ?
frame.height - popupView!.size.height :
touchPoint.y

Screenshots:

That is probably all. Thank you for your time and, we hope, you will find something useful in our Blog :)

--

--

Globaldev Group

#Web and #mobile development for b2b and b2c sectors, including secure enterprise solutions and #MVP-development for #startups. Website: https://globaldev.tech/