2

I have to draw charts as displayed in following image for an iPad app. is there any free native chart api available for it?

Or any help to draw it...

enter image description here

enter image description here

enter image description here

Any help would be appreciable.

vikingosegundo
  • 52,040
  • 14
  • 137
  • 178
iCreative
  • 1,499
  • 1
  • 9
  • 22
  • 1
    you might be intrested in watching the wwdc2011 video [Session 129 - Practical Drawing for iOS Developers](https://deimos.apple.com/WebObjects/Core.woa/BrowsePrivately/adc.apple.com.8270634034.08270634040.8367260941?i=1990915091). and it's [sample code](http://developer.apple.com/library/ios/samplecode/SimpleStocks/Introduction/Intro.html). – vikingosegundo Oct 10 '12 at 15:48

7 Answers7

8

I would like to go with Quartz 2D. I dont think so any library will do your deal. You need to create your own. Here are my ideas.

For one kind of charts, you can take idea how speedometer works. Eeww, I didnt searched links for that, hope idea will do. You can calculate angle for your percentage and draw arc accordingly. This wont be too hard.

For droplets, oops that will be bit busy. But here is some logic for that:

I guess you will have percentage for each segment in your droplet like chart. You can calculate radius for them ! Hope image below will better explain your idea. I am just trying to share logic and not code, since SO is not about give me code kinda stuff :)

Hope this helps

enter image description here

DivineDesert
  • 6,924
  • 1
  • 29
  • 61
  • +1 for the afford you put into the answer. However in this particular case not much logic is needed, as UIBezierPath is providing some handy methods. See my answer. – vikingosegundo Oct 12 '12 at 13:53
4

I have a working project on GitHub.

#import "PlectrumView.h"

@implementation PlectrumView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
    }
    return self;
}


-(void) drawPlectrumWithPercentage:(CGFloat) percentage color:(UIColor *)color
{
    CGFloat factor = self.frame.size.width ;
    percentage*=factor;
    UIBezierPath* plectrum = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(0, factor - percentage, percentage,percentage)
                                                   byRoundingCorners: UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomRight
                                                         cornerRadii: CGSizeMake(percentage/2, percentage/2)];
    [color setFill];
    [plectrum fill];
}


- (void)drawRect:(CGRect)rect
{
    [self drawPlectrumWithPercentage:1.0 color:[UIColor colorWithWhite:.9 alpha:1]];
    [self drawPlectrumWithPercentage:.75 color:[UIColor colorWithRed:245.0/255.0 green:134.0/255.0 blue:122.0/255.0 alpha:1]];
    [self drawPlectrumWithPercentage:.61 color:[UIColor colorWithRed:171.0/255.0 green:212.0/255.0 blue:105.0/255.0 alpha:1]];
}

@end

Results in

enter image description here


I change the plectrum code in a way that it's area will represent the percentage instead of it's width. It feels more natural.

plectrum new

-(void) drawPlectrumWithPercentage:(CGFloat) percentage color:(UIColor *)color
{
    static CGFloat pi = 3.141592653589793;
    static CGFloat radius100percent = 50.0;

    static CGFloat area100percent;
    static CGFloat threeFouthPiPlusOne;
    area100percent= radius100percent * radius100percent * pi *3/4 + radius100percent*radius100percent;
    threeFouthPiPlusOne = (1 + (pi*(3.0/4.0)));
    CGFloat area = area100percent * percentage;

    CGFloat newRadius = sqrt(area / threeFouthPiPlusOne);
    percentage = newRadius/ 50.0;
    CGFloat factor = self.frame.size.width ;
    percentage*=factor;
    UIBezierPath* plectrum = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(0, factor - percentage, percentage,percentage)
                                                   byRoundingCorners: UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomRight
                                                         cornerRadii: CGSizeMake(percentage/2, percentage/2)];
    [color setFill];
    [plectrum fill];
}
Zoe
  • 27,060
  • 21
  • 118
  • 148
vikingosegundo
  • 52,040
  • 14
  • 137
  • 178
  • Can you please help me in drawing the next graph too? In that i have to show the arrows too. – iCreative Oct 26 '12 at 09:36
  • 1
    As i understand, the solutions and projects shown and linked in this thread, cover all the example you've shown. So I am not sure, how I can help u. – vikingosegundo Oct 26 '12 at 12:57
2

There are a lot of "chart" libraries:

Check out on Cocoa Controls

or this one:

MeterView

Janak Nirmal
  • 22,706
  • 18
  • 63
  • 99
Max B.
  • 881
  • 10
  • 21
2

Your example pictures are actually quite easy to draw using Quartz 2D. If you are not concerned with exactly how your charts look, I would suggest looking into what is already out there. If you need the charts to look exactly as you show (for example because they should look similar to a web app), I suggest you draw them yourself. It is not that hard, to draw the kind of simple charts you show:

  • Use UILabels for the text
  • Create layers with a CGPath for the droplet shape.
  • Move and scale the layers with the value for each chart. They can even be animated smoothly with just a few lines of code.

Let me know if you want to try and need any more details.

Community
  • 1
  • 1
Krumelur
  • 31,081
  • 7
  • 77
  • 119
2

If you use SVG, you can easily create the shapes with a function like:

/**
 * @param {SVGPathElement} aShape a SVG path element
 * @param {number} radius the radius of the plectrum's arc
 * @param {string} fillColor color in "#rrggbb" format
 */
function drawPlectrum(aShape, radius, fillColor) {

    // Creating a string which defines a path in SVG
    // M = moveto, A = line to, etc. See http://www.w3.org/TR/SVG/paths.html
    var ss="M "+parseInt(0)+" "+parseInt(0)+" ";         // moveto 0, 0
    ss+="L "+parseInt(0)+" "+parseInt(radius)+" ";       // lineto 0, R                
    ss+="A "+parseInt(radius)+" "+parseInt(radius)+" 0 0 0 "+parseInt(radius)+" "+parseInt(2*radius)+" ";// elliptic curve to R, 2*R
    ss+="A "+parseInt(radius)+" "+parseInt(radius)+" 0 0 0 "+parseInt(2*radius)+" "+parseInt(radius)+" ";// elliptic curve to 2*R, R
    ss+="A "+parseInt(radius)+" "+parseInt(radius)+" 0 0 0 "+parseInt(radius)+" "+parseInt(0)+" ";       // elliptic curve to R, 0
    ss+="Z";                                             // closepath

    // The d attribute of the path element holds the line information
    // In XML the element will essentially be <path d="*the created string*">
    aShape.setAttribute("d", ss);

    // Give the color                
    aShape.setAttribute("fill", fillColor);                
}

Successive drawings looks something like this:

    // Note that 3 different path elements are used to overlap the plectrums
    drawPlectrum(node, 100, "#aaaaaa");
    drawPlectrum(node2, 75, "#33dd33");            
    drawPlectrum(node3, 50, "#3333dd");

Edit 1: Added more comments in the code for better understandibility

plectrum

tinkerbeast
  • 1,707
  • 1
  • 20
  • 42
  • I Need some clarification on SVG. Can you provide me best link to understand it for my example?? – iCreative Oct 11 '12 at 13:17
  • 1
    This seems to be java code, `parseInt` @tinkerbeast can you please elaborate. Also if you can draw the way you showed, can you tell how SVG is involved ? I am curious – DivineDesert Oct 11 '12 at 18:51
  • SVG is an XML format to describe vector images. In my example I'm just creating a Path element (http://www.w3.org/TR/SVG/paths.html or easier http://www.w3schools.com/svg/svg_path.asp). The code is actually JavaScript code. I assumed a web-solution. – tinkerbeast Oct 12 '12 at 12:59
  • If you're going to build a native IOS app Quartz 2D is the best solution. However Quartz 2D does not support SVG by default. I haven't worked with Quartz 2D, but it's not that hard to draw this thing. I can easily provide you with C(graphics.h) or Java(Java2d) which does the same thing. – tinkerbeast Oct 12 '12 at 13:11
  • 1
    This http://stackoverflow.com/a/12852256/1224075 gives you the implementation in Objective-C. Give him the bounty :). – tinkerbeast Oct 12 '12 at 13:34
1

Download this project and use this but they are using ARC for that. Hope it will help you!

Janak Nirmal
  • 22,706
  • 18
  • 63
  • 99
amit soni
  • 2,183
  • 1
  • 14
  • 17
1

I think all of the above could probably be done using transparent images with an underlying shape that increases in size/diameter using mathematical code.

With the Arc Percentages you could have the dial (available area / 100) * Amount of Progress and then have the image rotate by the amount to get the dial in place and an underlying coloured square fill by the same amount from left to right? this will save a lot on drawing code.

Sean Lintern
  • 3,103
  • 22
  • 28