Line Graph

This is a custom line graph written in Objective-C using a standard UIView as a base class. The Graph is rendered inside an overloaded drawRect function using CGContext to render the graph and all it’s components.

Features:
• Positive Graph Rendering.
• Positive / Negative Graph Rendering.
• Basic line rendering.
• Background Image support.
• Font selection.
• Label support.
• Title support.
• Hide / Show Scale.

linegraph

Improvements and Additions:
• The drawRect function needs to be tidied up, but it’s fine if you just want to use the class.
• The graph code needs to be improved to support totally negative graph values.
• I would like to extend the line rendering to be a bit more flexibility.
• Support for key graph points would be nice addition.

Warning’s :
• Watch the length of your string’s and font size’s as the current implementation does not re-size fonts and these may overlap.
• I don’t recommend this implementation if you wish to animate the graph, I’ve found that causing the view to redraw is expensive.

Source:

//
//  LineGraph.h
//
//  Created by Robert on 04/10/2009.
//

#import <UIKit/UIKit.h>

typedef enum
{
LineGraphOrientationUnknown,
LineGraphOrientationPortrait,            // Device oriented vertically, home button on the bottom
LineGraphOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
LineGraphOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
LineGraphOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
} LineGraphOrientation;

// --------------------------------------------------------
// The Line Object
// --------------------------------------------------------
@interface Line : NSObject
{
@private
NSString *			name;
NSMutableArray *	values;
UIColor *			color;
float				width;
Boolean				dashed;
}

@property (nonatomic, readonly) NSString *			name;
@property (nonatomic, readonly) NSMutableArray *	values;
@property (nonatomic, retain)   UIColor *			color;
@property (nonatomic)			float				width;
@property (nonatomic)			Boolean				dashed;

- (id) initWithName:(NSString*)_name AndColor:(UIColor*)_color AndWidth:(float)_width;
- (id) initWithName:(NSString*)_name AndColor:(UIColor*)_color AndWidth:(float)_width SetDashed:(Boolean)_dashed;

- (void) add:(float)_value;
- (void) clear;

@end

@interface LineGraph : UIView
{
@private

// --------------------------------
// Background Image :
// will be rendered if not nil.
// --------------------------------
UIImage *		 backgroundImage;
// --------------------------------

// --------------------------------
// Work out the Graph Values
// --------------------------------
NSInteger		 minNumEntries;
NSInteger		 peakEntries;
float			 maxValue;
float			 minValue;
NSInteger		 totalEntries;
float			 totalValue;
// --------------------------------

// --------------------------------
// Data Array :
// Contains the bar objects.
// --------------------------------
NSMutableArray * values;

NSString *		 title;
NSString *		 verticalAxisName;
NSString *		 horizontalAxisName;

LineGraphOrientation orientation;
// --------------------------------

// --------------------------------
// Graph Indent :
// How much away from the edges
// does the graph get rendered.
// --------------------------------
CGSize			indent;
UIFont *		font;
UIFont *		fontSmall;
UIColor	*		fontColor;
// --------------------------------

// --------------------------------
// line settings :
// --------------------------------
NSInteger		lineWidth;
UIColor *		lineColor;
// --------------------------------

// --------------------------------
// grid data
// --------------------------------
NSInteger		gridLineWidth;
UIColor *		gridLineColor;
// --------------------------------

// --------------------------------
// Fill data
// --------------------------------
UIColor *		fillColor;
// --------------------------------

// --------------------------------
// line values
// --------------------------------
float			lineHighlightPercentage;
UIColor *		lineHighlightColor;

CGPoint			lineShadowOffset;
UIColor *		lineShadowColor;
// --------------------------------

// --------------------------------
// Render Flags :
// Indicate the parts of the line
// to render.
// --------------------------------
Boolean			drawGrid;
Boolean			drawEdge;
Boolean			drawLine;
Boolean			drawFill;
Boolean			drawScale;
Boolean			drawKey;
// -------------------------------

}
@property (nonatomic, readonly)	NSInteger count;

@property (nonatomic, retain)	UIImage * backgroundImage;
@property (nonatomic, copy)		NSString * title;
@property (nonatomic, copy)		NSString * verticalAxisName;
@property (nonatomic, copy)		NSString * horizontalAxisName;
@property (nonatomic) LineGraphOrientation orientation;

@property (nonatomic)			CGSize indent;
@property (nonatomic, retain)	UIFont * font;
@property (nonatomic, retain)	UIFont * fontSmall;
@property (nonatomic, retain)	UIColor	* fontColor;
@property (nonatomic)			NSInteger lineWidth;
@property (nonatomic, retain)	UIColor * lineColor;
@property (nonatomic)			NSInteger gridLineWidth;
@property (nonatomic, retain)	UIColor * gridLineColor;
@property (nonatomic, retain)	UIColor * fillColor;
@property (nonatomic)			float lineHighlightPercentage; // 0 - 1 value;
@property (nonatomic, retain)	UIColor * lineHighlightColor;
@property (nonatomic)			CGPoint lineShadowOffset;
@property (nonatomic, retain)	UIColor * lineShadowColor;

@property (nonatomic)			Boolean drawGrid;
@property (nonatomic)			Boolean drawEdge;
@property (nonatomic)			Boolean drawLine;
@property (nonatomic)			Boolean	drawFill;
@property (nonatomic)			Boolean drawScale;
@property (nonatomic)			Boolean drawKey;

// remove all the current lines
- (void) removeAllLines;
- (void) removeLineAtIndex:(NSInteger)_index;
- (void) removeLineWithName:(NSString*)_name;
- (void) removeLine:(Line*)_line;

// add a line
- (Line*) addLineWithName:(NSString*)_name WithColor:(UIColor*)_color AndWidth:(float)_width;
- (Line*) addLineWithName:(NSString*)_name WithColor:(UIColor*)_color AndWidth:(float)_width SetDashed:(Boolean)_dashed;

// retrieve the line
- (Line*) lineAtIndex:(NSInteger)_index;
- (Line*) lineWithName:(NSString*)_name;

@end

The code is provided as is, use at your own risk.

Source Code : LineGraph.h, LineGraph.m

Sample Project : LineGraphSample

  1. lunS
    May 29th, 2010 at 10:51 | #1

    Hi Bert. I am trying to test your code but without luky. Can you give a steps for test in the xcode?..I mean impor the class and create a object, add to a view …..please. I know it is a stupid question but i am a litle bit rookie with the objective C. Thanks in advance.

  2. May 29th, 2010 at 13:35 | #2

    Hi there I’ll try and get an example xcode project together for you.

    Cheers for getting in touch,
    Bert

  3. lunS
    May 29th, 2010 at 13:47 | #3

    @Bert
    Thanks. I will be waiting for it. Nice help.

  4. May 30th, 2010 at 14:59 | #4

    @lunS
    Hi,
    I’ve added a very basic sample project to the post, I added the line graph to a view via Interface Builder. This is then linked to the view controller via an IBObject and when the view controller loads the view I setup the graph object and add a line to the graph.
    Hope this helps and if you have any problems let me know,
    Sorry for the delay on getting this up
    Cheers,
    Bert

  5. lunS
    May 31st, 2010 at 08:27 | #5

    THANKS. You are great. Thanks. Great tutorial and great help.

  6. lunS
    May 31st, 2010 at 08:51 | #6

    Hi Bert. I was testing your sample and is great. I have one question: Can I put a label for each point of the graph in the horizontal axis?… I dont know if the question is clear.
    (Example) I have some data and this data is related with a day, can i put the days in the horizontal axis? Thanks again.

  7. May 31st, 2010 at 09:21 | #7

    Hi,

    The current code does not support this, though you could extend the render code to draw an array of strings along the bottom, if you take a look at how I render the scale you might be able to add this feature.

    Have you done any custom draw code before?

    Cheers,
    Bert

  8. lunS
    May 31st, 2010 at 11:00 | #8

    No. I am new at Objective C. But I will try it.

  9. May 31st, 2010 at 17:38 | #9

    @lunS
    Cool, there are lot’s of good tutorials about online about rendering to the context.

    If you have done any graphics programming before then this should be fairly easy, the Quartz 2D code has a C API (Apple Docs) it’s fairly simple to use.

    If you do run into any problems let me know and I’ll try to help you out.

    Good luck,
    Bert

  10. lunS
    June 3rd, 2010 at 23:34 | #10

    @Bert
    Hi. I have tried the array of string issue without any luck. Besides, i have noticed that when i add a line and try to draw a point (only one) the program doesnt draw anything. Do you have the same problem or not?

  11. June 4th, 2010 at 14:15 | #11

    @lunS
    Yep missed that one, silly bugs :) I wrote the code a while ago for an application feature that we dropped so it’s not been through the wash much. Though i’ve fixed the sample so it now renders a single point. Thanks for letting me know.

    Sorry to here your having trouble with adding an array of names below the graph :(
    I’ll give it a go on this end and see if I can get it working for you.

    Cheers,
    Bert

  12. June 4th, 2010 at 15:14 | #12

    @lunS
    Ok here is a very rough and ready version with labels across the bottom, it still need a bit of work but it should get you started.

    LineGraphSampleTwo

    Let me know if you have any problems.

    Cheers,
    Bert

  13. lunS
    June 5th, 2010 at 15:09 | #13

    Thanks. The arrays were making me crazy. I thank you.

  14. June 7th, 2010 at 09:11 | #14

    @lunS
    No Problem, I’m glad the code sample helped :)

  15. srinivas
    June 16th, 2010 at 09:56 | #15

    can u help for rendering bar and line(compound chart) in same page.

  16. June 17th, 2010 at 11:54 | #16

    @srinivas
    The best way to do that would combine parts of the draw code from both the bar graph and line graph. The DrawRect function starts off by building the graph background and the last part then renders the lines, the code is fairly well commented and you should hopefully be able to pick it apart so you can create a hybrid graph from these samples.

    Bert

  17. srinivas
    June 22nd, 2010 at 08:25 | #17

    i cant understand this. can u explain clearly,
    what to do in the coding for bar and line(compound) graph.

  18. June 22nd, 2010 at 11:11 | #18

    @srinivas
    There is no simple way to combine the line graph and bar graph, you will need to dig into both drawRect functions and pull together the bits that you require. Both the line graph and bar graph drawRect’s follow a similar structure, check the comments.

    The basic idea was as each outer / edge element of the graph is rendered (name, titles, etc) I reduce the internal rect until I end up with an area that will just be used to draw the graph contents. At the final point I draw the graphs contents (bars, lines).

    Hope this helps.
    Bert

  19. srinivas
    June 25th, 2010 at 07:39 | #19

    @Hello Bert
    i want zooming options for this graphs. can u help in this .

  20. srinivas
    June 25th, 2010 at 10:53 | #20

    i want zooming options in onload image draw. for example graphs, webview loadings,etc.,
    i want to zoom the above things in iphone api. the above code is for an image zooming only.can u help in this. its very urgent.

    for ref: sites.
    1)http://developer.apple.com/iphone/library/documentation/WindowsViews/Conceptual/UIScrollView_pg/ZoomZoom/ZoomZoom.html#//apple_ref/doc/uid/TP40008179-CH102-SW1
    2)http://www.iphonesdkarticles.com/2008/09/multi-touch-tutorial-part-2.html
    3)http://blog.timeister.com/2009/09/02/objective-c-zoom-image/comment-page-1/#comment-5048

  21. June 25th, 2010 at 17:56 | #21

    You could just add the graph as a subview in the UIScroll view and then enable the zoom feature described in the articles.

  22. srinivas
    July 7th, 2010 at 14:20 | #22

    Hello@Bert
    still iam not getting the line and bar(compound graph).
    once i have attached both draw rect function it will displayed only one graph line or bar.

    one is hidden or overwritten.
    can u help in this.

  23. Deepan
    July 15th, 2010 at 12:27 | #23

    hello
    still iam not getting the line and bar(compound graph).
    once i have attached both draw rect function it will displayed only one graph line or bar.
    one is hidden or overwritten.
    can u help in this.

  24. July 15th, 2010 at 12:53 | #24

    Hi@srinivas

    Sorry I’ve been really busy, I presume at the moment that you are creating two separate graphs on each with it’s own View? Then placing them one on Top of the other, therefore one is covering up the other?

    Correct me if I’m wrong.

    What you will need to do to create a combined bar / line graph is combine parts of the line graph class with the Bar Graph code.

    The draw code should follow these simple steps:
    • Render the Graph Background and Text
    • Render the Graphs Bars
    • Render the Graphs lines over the bars

    By doing it this way all the objects are rendered onto the same context permitting both the bar and lines to be seen.

    Please find the developer documentation on rendering into the context here:
    http://developer.apple.com/mac/library/documentation/GraphicsImaging/Reference/CGContext/Reference/reference.html

    Sorry I can’t be of much more help at the moment, if do eventually build a combined Bar / Line graph I will post it though I currently have no need for one.

    Good Luck,
    Bert

  1. November 17th, 2009 at 23:59 | #1