Blog

Back to Blog

The making of a legend

Posted on 10 Sep 2012 Written by Stuart Grey

A legend on a chart can be pretty handy for letting users know what’s going on – and we think our ShinobiCharts legend does a good job of this. But we’re all about interaction here at ShinobiHQ and we think you can be too. Here’s our quick guide to adding interaction to your legend.

I’ll build this example on the PieChart sample app that comes with our zipped bundles. 

Adding series selection via the legend

The following code will detect a tap on a legend item and highlight it – it will also select the corresponding slice in the pie chart. 

First off, we need to make sure we have a legend showing and can detect tap gestures on it. Add the following to the very end of the viewDidLoad method: 

pieChart.legend.hidden = NO;
    
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(legendClick:)];
[pieChart.legend addGestureRecognizer:tap];
[tap release];

 

Now that we’re recongizing tap gestures, we’d better add a method to receive them. The first part of this method is concerned with detecting which slice was selected. Each slice is represented by a label and a symbol. We check each for the target of the click:

- (void)legendClick:(UITapGestureRecognizer*)sender {
    
    CGPoint tapPoint = [sender locationInView:pieChart.legend];

    SChartPieSeries *series = (SChartPieSeries*)[[pieChart allChartSeries] objectAtIndex:0];
    
    int selectedIndex = -1;
    
    //find the item (if any) that we hit in the legend click
    for (int i=0; i < pieChart.legend.symbols.count; i++) {
        
        CGRect symbolFrame = [[pieChart.legend.symbols objectAtIndex:i] frame];
        CGRect legendFrame = [[pieChart.legend.labels objectAtIndex:i] frame];
        
        if (CGRectContainsPoint(symbolFrame , tapPoint) || CGRectContainsPoint(legendFrame, tapPoint)) {
            
            selectedIndex = i;
            break;
        }
    }

Now that we know if our user tapped a slice and, if so, which slice it was –  we can begin to deal with it and provide some sort of repsonse. We deliberatly step through each slice on the pie to restore the original formatting to all but the newly selected item. 

if (selectedIndex != -1) {
        //now we alter our slices for our needs
        int sliceCount = series.dataSeries.dataPoints.count;
        
        for (int j=0; j < sliceCount; j++) {
            
            SChartLegendSymbol *clickedSymbol = [pieChart.legend.symbols objectAtIndex:j];
            UILabel *clickedLabel = [pieChart.legend.labels objectAtIndex:j];                       
            
            if (j == selectedIndex) {
                [series setSlice:j asSelected:YES];
                [clickedLabel setTextColor:[series.style.flavourColors objectAtIndex:j]];
            } else {
                [series setSlice:j asSelected:NO];
                [clickedLabel setTextColor:[UIColor lightGrayColor]];
            }
         }
        [pieChart redrawChart];
    }
}

 

That’s our legend interaction done – you can now respond to clicks on your legend and use them to trigger the chart into action.

legend_interaction_blog

But we’re not stopping there – what if you want to add the reciprocal action: select a pie slice to highlight the legend item….

Slices return the favour…

We want the reverse process to now work – where we tap on a slice in the pie and the legend item also highlights. Since we know that the pie chart series conforms to SChartLegendItem, we can create our own subclass of the pie series and add a custom implementation of - (UIColor*)textColorForSeriesTitleInLegend

#import <ShinobiCharts/ShinobiChart.h>

@interface MyPieSeries : SChartPieSeries {
    int i;
}

@end
#import "MyPieSeries.h"

@implementation MyPieSeries



- (id) init {
    self = [super init];
    if (self) {
        i = 0;
    }
    return self;
}


- (UIColor*)textColorForSeriesTitleInLegend {
    
    int index = i%self.dataSeries.dataPoints.count;
       
    SChartRadialDataPoint *rdp = (SChartRadialDataPoint*)[self.dataSeries.dataPoints objectAtIndex:index];
    i++;
    
    return rdp.selected ? [self.style.flavourColors objectAtIndex:index] : [UIColor lightTextColor];
    
         
}

@end

 

 And that’s it, if you use this series class instead of SChartPieSeries, our slices now return the favour and highlight our legend items when they’re selected. 

Summing it up

Hopefully, you’re a much more creative bunch than I am and you should find it easy to customise the styling options to meet your needs. The main thing is we want our legends to get interactive! Download the updated sample here and get started!

Back to Blog