Kevin

Merge pull request #176 from sanandrea/master

Interactive Pie
... ... @@ -27,4 +27,7 @@
*/
- (void)userClickedOnBarAtIndex:(NSInteger)barIndex;
- (void)userClickedOnPieIndexItem:(NSInteger)pieIndex;
- (void)didUnselectPieItem;
@end
... ...
... ... @@ -25,6 +25,7 @@ typedef NS_ENUM(NSUInteger, PNLegendItemStyle) {
@property (assign, nonatomic) BOOL hasLegend;
@property (assign, nonatomic) PNLegendPosition legendPosition;
@property (assign, nonatomic) PNLegendItemStyle legendStyle;
@property (assign, nonatomic) NSUInteger labelRowsInSerialMode;
@property (assign, nonatomic) CGFloat legendFontSize;
/**
... ... @@ -37,4 +38,6 @@ typedef NS_ENUM(NSUInteger, PNLegendItemStyle) {
*/
- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth;
- (void) setupDefaultValues;
@end
... ...
... ... @@ -24,37 +24,11 @@
}
*/
- (UIView*) drawLegend{
return nil;
}
- (id)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self setupDefaultValues];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupDefaultValues];
}
return self;
}
- (void) setupDefaultValues{
self.hasLegend = YES;
self.legendPosition = PNLegendPositionBottom;
self.legendStyle = PNLegendItemStyleStacked;
self.labelRowsInSerialMode = 1;
}
... ... @@ -67,6 +41,13 @@
return nil;
}
- (void) setLabelRowsInSerialMode:(NSUInteger)num{
if (self.legendStyle == PNLegendItemStyleSerial) {
_labelRowsInSerialMode = num;
}else{
_labelRowsInSerialMode = 1;
}
}
@end
... ...
... ... @@ -66,7 +66,6 @@
_yChartLabels = [NSMutableArray new];
}
#warning modify origin
if (yStep == 0.0) {
PNChartLabel *minLabel = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, (NSInteger)_chartCavanHeight, (NSInteger)_chartMargin, (NSInteger)_yLabelHeight)];
minLabel.text = [NSString stringWithFormat:yLabelFormat, 0.0];
... ... @@ -197,7 +196,6 @@
for (int index = 0; index < xLabels.count; index++) {
labelText = xLabels[index];
#warning modify origin
NSInteger x = 2 * _chartMargin + (index * _xLabelWidth) - (_xLabelWidth / 2);
NSInteger y = _chartMargin + _chartCavanHeight;
... ... @@ -403,7 +401,6 @@
CGFloat offSetX = (_chartCavanWidth) / (chartData.itemCount);
#warning modify chart path
int x = 2 * _chartMargin + (i * offSetX);
int y = _chartCavanHeight - (innerGrade * _chartCavanHeight) + (_yLabelHeight / 2);
... ... @@ -652,7 +649,6 @@
- (void)drawRect:(CGRect)rect
{
if (self.isShowCoordinateAxis) {
#warning modify
CGFloat yAxisOffset = 10.f;
CGContextRef ctx = UIGraphicsGetCurrentContext();
... ... @@ -726,6 +722,7 @@
- (void)setupDefaultValues
{
[super setupDefaultValues];
// Initialization code
self.backgroundColor = [UIColor whiteColor];
self.clipsToBounds = YES;
... ... @@ -807,15 +804,15 @@
CGFloat x = 0;
CGFloat y = 0;
/* accumulated width and height */
CGFloat totalWidth = 0;
/* accumulated height */
CGFloat totalHeight = 0;
NSMutableArray *legendViews = [[NSMutableArray alloc] init];
NSUInteger numLabelsPerRow = ceil((float)[self.chartData count] / self.labelRowsInSerialMode);
/* Determine the max width of each legend item */
CGFloat maxLabelWidth = self.legendStyle == PNLegendItemStyleStacked ? (mWidth - legendLineWidth) : (mWidth / [self.chartData count] - legendLineWidth);
CGFloat maxLabelWidth = self.legendStyle == PNLegendItemStyleStacked ? (mWidth - legendLineWidth) : (mWidth / numLabelsPerRow - legendLineWidth);
/* this is used when labels wrap text and the line
* should be in the middle of the first row */
... ... @@ -823,6 +820,9 @@
withWidth:MAXFLOAT
font:[UIFont systemFontOfSize:self.legendFontSize]].height;
NSUInteger counter = 0;
NSUInteger rowMaxHeight = 0;
for (PNLineChartData *pdata in self.chartData) {
/* Expected label size*/
CGSize labelsize = [PNLineChart sizeOfString:pdata.dataTitle
... ... @@ -831,6 +831,11 @@
/* draw lines */
if (counter != 0 && counter % numLabelsPerRow == 0) {
x = 0;
y += rowMaxHeight;
rowMaxHeight = 0;
}
/* If there is inflection decorator, the line is composed of two lines
* and this is the space that separates two lines in order to put inflection
... ... @@ -872,16 +877,18 @@
label.font = [UIFont systemFontOfSize:self.legendFontSize];
label.lineBreakMode = NSLineBreakByWordWrapping;
label.numberOfLines = 0;
rowMaxHeight = fmaxf(rowMaxHeight, labelsize.height);
x += self.legendStyle == PNLegendItemStyleStacked ? 0 : labelsize.width + legendLineWidth;
y += self.legendStyle == PNLegendItemStyleStacked ? labelsize.height : 0;
totalWidth = self.legendStyle == PNLegendItemStyleStacked ? fmaxf(totalWidth, labelsize.width + legendLineWidth) : totalWidth + labelsize.width + legendLineWidth;
totalHeight = self.legendStyle == PNLegendItemStyleStacked ? fmaxf(totalHeight, labelsize.height) : totalHeight + labelsize.height;
[legendViews addObject:label];
totalHeight = self.legendStyle == PNLegendItemStyleStacked ? fmaxf(totalHeight, rowMaxHeight + y) : totalHeight + labelsize.height;
[legendViews addObject:label];
counter++;
}
UIView *legend = [[UIView alloc] initWithFrame:CGRectMake(0, 0, totalWidth, totalHeight)];
UIView *legend = [[UIView alloc] initWithFrame:CGRectMake(0, 0, mWidth, totalHeight)];
for (UIView* v in legendViews) {
[legend addSubview:v];
... ...
... ... @@ -9,6 +9,7 @@
#import <UIKit/UIKit.h>
#import "PNPieChartDataItem.h"
#import "PNGenericChart.h"
#import "PNChartDelegate.h"
@interface PNPieChart : PNGenericChart
... ... @@ -34,10 +35,11 @@
/** Show only values, this is useful when legend is present */
@property (nonatomic) BOOL showOnlyValues;
/** Show absolute values not relative i.e. percentages */
@property (nonatomic) BOOL showAbsoluteValues;
@property (nonatomic, weak) id<PNChartDelegate> delegate;
- (void)strokeChart;
@end
... ...
... ... @@ -21,7 +21,7 @@
@property (nonatomic) UIView *contentView;
@property (nonatomic) CAShapeLayer *pieLayer;
@property (nonatomic) NSMutableArray *descriptionLabels;
@property (strong, nonatomic) CAShapeLayer *sectorHighlight;
- (void)loadDefault;
... ... @@ -57,6 +57,7 @@
_descriptionTextShadowOffset = CGSizeMake(0, 1);
_duration = 1.0;
[super setupDefaultValues];
[self loadDefault];
}
... ... @@ -101,6 +102,7 @@
CGFloat radius = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius) / 2;
CGFloat borderWidth = _outerCircleRadius - _innerCircleRadius;
CAShapeLayer *currentPieLayer = [self newCircleLayerWithRadius:radius
borderWidth:borderWidth
fillColor:[UIColor clearColor]
... ... @@ -251,13 +253,78 @@
}];
}
- (void)didTouchAt:(CGPoint)touchLocation
{
CGPoint circleCenter = CGPointMake(_contentView.bounds.size.width/2, _contentView.bounds.size.height/2);
CGFloat distanceFromCenter = sqrtf(powf((touchLocation.y - circleCenter.y),2) + powf((touchLocation.x - circleCenter.x),2));
if (distanceFromCenter < _innerCircleRadius) {
if ([self.delegate respondsToSelector:@selector(didUnselectPieItem)]) {
[self.delegate didUnselectPieItem];
}
[self.sectorHighlight removeFromSuperlayer];
return;
}
CGFloat percentage = [self findPercentageOfAngleInCircle:circleCenter fromPoint:touchLocation];
int index = 0;
while (percentage > [self endPercentageForItemAtIndex:index]) {
index ++;
}
if ([self.delegate respondsToSelector:@selector(userClickedOnPieIndexItem:)]) {
[self.delegate userClickedOnPieIndexItem:index];
}
if (self.sectorHighlight) {
[self.sectorHighlight removeFromSuperlayer];
}
PNPieChartDataItem *currentItem = [self dataItemForIndex:index];
CGFloat red,green,blue,alpha;
UIColor *old = currentItem.color;
[old getRed:&red green:&green blue:&blue alpha:&alpha];
alpha /= 2;
UIColor *newColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
CGFloat startPercnetage = [self startPercentageForItemAtIndex:index];
CGFloat endPercentage = [self endPercentageForItemAtIndex:index];
self.sectorHighlight = [self newCircleLayerWithRadius:_outerCircleRadius + 5
borderWidth:10
fillColor:[UIColor clearColor]
borderColor:newColor
startPercentage:startPercnetage
endPercentage:endPercentage];
[_contentView.layer addSublayer:self.sectorHighlight];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInView:_contentView];
[self didTouchAt:touchLocation];
}
}
- (CGFloat) findPercentageOfAngleInCircle:(CGPoint)center fromPoint:(CGPoint)reference{
//Find angle of line Passing In Reference And Center
CGFloat angleOfLine = atanf((reference.y - center.y) / (reference.x - center.x));
CGFloat percentage = (angleOfLine + M_PI/2)/(2 * M_PI);
return (reference.x - center.x) > 0 ? percentage : percentage + .5;
}
- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth{
if ([self.items count] < 1) {
return nil;
}
/* This is a small circle that refers to the chart data */
CGFloat legendCircle = 10;
CGFloat legendCircle = 16;
CGFloat hSpacing = 0;
CGFloat beforeLabel = legendCircle + hSpacing;
/* x and y are the coordinates of the starting point of each legend item */
CGFloat x = 0;
... ... @@ -269,9 +336,13 @@
NSMutableArray *legendViews = [[NSMutableArray alloc] init];
/* Determine the max width of each legend item */
CGFloat maxLabelWidth = self.legendStyle == PNLegendItemStyleStacked ? (mWidth - legendCircle) : (mWidth / [self.items count] - legendCircle);
CGFloat maxLabelWidth;
if (self.legendStyle == PNLegendItemStyleStacked) {
maxLabelWidth = mWidth - beforeLabel;
}else{
maxLabelWidth = MAXFLOAT;
}
/* this is used when labels wrap text and the line
* should be in the middle of the first row */
... ... @@ -279,29 +350,45 @@
withWidth:MAXFLOAT
font:[UIFont systemFontOfSize:self.legendFontSize]].height;
NSUInteger counter = 0;
NSUInteger rowWidth = 0;
NSUInteger rowMaxHeight = 0;
for (PNPieChartDataItem *pdata in self.items) {
/* Expected label size*/
CGSize labelsize = [PNLineChart sizeOfString:pdata.textDescription
withWidth:maxLabelWidth
font:[UIFont systemFontOfSize:self.legendFontSize]];
if ((rowWidth + labelsize.width + beforeLabel > mWidth)&&(self.legendStyle == PNLegendItemStyleSerial)) {
rowWidth = 0;
x = 0;
y += rowMaxHeight;
rowMaxHeight = 0;
}
rowWidth += labelsize.width + beforeLabel;
totalWidth = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(rowWidth, totalWidth) : fmaxf(totalWidth, labelsize.width + beforeLabel);
// Add inflexion type
[legendViews addObject:[self drawInflexion:legendCircle * .8
[legendViews addObject:[self drawInflexion:legendCircle * .6
center:CGPointMake(x + legendCircle / 2, y + singleRowHeight / 2)
andColor:pdata.color]];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x + legendCircle, y, maxLabelWidth, labelsize.height)];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x + beforeLabel, y, labelsize.width, labelsize.height)];
label.text = pdata.textDescription;
label.font = [UIFont systemFontOfSize:self.legendFontSize];
label.lineBreakMode = NSLineBreakByWordWrapping;
label.numberOfLines = 0;
x += self.legendStyle == PNLegendItemStyleStacked ? 0 : labelsize.width + legendCircle;
rowMaxHeight = fmaxf(rowMaxHeight, labelsize.height);
x += self.legendStyle == PNLegendItemStyleStacked ? 0 : labelsize.width + beforeLabel;
y += self.legendStyle == PNLegendItemStyleStacked ? labelsize.height : 0;
totalWidth = self.legendStyle == PNLegendItemStyleStacked ? fmaxf(totalWidth, labelsize.width + legendCircle) : totalWidth + labelsize.width + legendCircle;
totalHeight = self.legendStyle == PNLegendItemStyleStacked ? fmaxf(totalHeight, labelsize.height) : totalHeight + labelsize.height;
totalHeight = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(totalHeight, rowMaxHeight + y) : totalHeight + labelsize.height;
[legendViews addObject:label];
counter ++;
}
UIView *legend = [[UIView alloc] initWithFrame:CGRectMake(0, 0, totalWidth, totalHeight)];
... ...
... ... @@ -20,6 +20,7 @@
self.rightSwitch.hidden = YES;
self.leftLabel.hidden = YES;
self.rightLabel.hidden = YES;
self.changeValueButton.hidden = YES;
if ([self.title isEqualToString:@"Line Chart"]) {
... ... @@ -67,7 +68,7 @@
data02.color = PNTwitterColor;
data02.alpha = 0.5f;
data02.itemCount = data02Array.count;
data02.inflexionPointStyle = PNLineChartPointStyleNone;
data02.inflexionPointStyle = PNLineChartPointStyleCircle;
data02.getData = ^(NSUInteger index) {
CGFloat yValue = [data02Array[index] floatValue];
return [PNLineChartDataItem dataItemWithY:yValue];
... ... @@ -79,11 +80,11 @@
[self.view addSubview:self.lineChart];
self.lineChart.legendStyle = PNLegendItemStyleStacked;
self.lineChart.legendStyle = PNLegendItemStyleSerial;
self.lineChart.legendFontSize = 12.0;
UIView *legend = [self.lineChart getLegendWithMaxWidth:200];
[legend setFrame:CGRectMake(100, 400, legend.frame.size.width, legend.frame.size.width)];
UIView *legend = [self.lineChart getLegendWithMaxWidth:320];
[legend setFrame:CGRectMake(30, 340, legend.frame.size.width, legend.frame.size.width)];
[self.view addSubview:legend];
}
else if ([self.title isEqualToString:@"Bar Chart"])
... ... @@ -156,7 +157,7 @@
self.pieChart.legendFontSize = 12.0;
UIView *legend = [self.pieChart getLegendWithMaxWidth:200];
[legend setFrame:CGRectMake(100, 400, legend.frame.size.width, legend.frame.size.width)];
[legend setFrame:CGRectMake(130, 350, legend.frame.size.width, legend.frame.size.height)];
[self.view addSubview:legend];
[self.view addSubview:self.pieChart];
... ...