iosobjective-cbar-chartios-charts

Charts: Get selected bar data only when tapped inside the bar


I used the https://github.com/danielgindi/Charts library in my project. It is working perfectly but I want to select bar data only when user taps inside the bar. Currently it will return bar data on outside the tap also. It is providing the nearest bar data to the tap when user tap outside the bar.

I set up the bar chart like this :

_chartView.delegate = self;

_chartView.drawBarShadowEnabled = NO;
_chartView.drawValueAboveBarEnabled = YES;

_chartView.maxVisibleValueCount = 60;

ChartXAxis *xAxis = _chartView.xAxis;
xAxis.labelPosition = XAxisLabelPositionBottom;
xAxis.labelTextColor = [UIColor whiteColor];
xAxis.labelFont = [UIFont systemFontOfSize:20.f];
xAxis.drawGridLinesEnabled = NO;
xAxis.spaceBetweenLabels = 2.0;
xAxis.labelWidth = 100;

ChartYAxis *leftAxis = _chartView.leftAxis;
leftAxis.labelFont = [UIFont systemFontOfSize:20.f];
leftAxis.labelCount = 5;
leftAxis.labelTextColor = [UIColor whiteColor];
leftAxis.valueFormatter = [[NSNumberFormatter alloc] init];
leftAxis.valueFormatter.maximumFractionDigits = 1;
leftAxis.valueFormatter.negativeSuffix = @"k";
leftAxis.valueFormatter.positiveSuffix = @"k";
leftAxis.valueFormatter.positivePrefix = @"$";
leftAxis.valueFormatter.negativePrefix = @"$";
leftAxis.labelPosition = YAxisLabelPositionOutsideChart;
leftAxis.spaceTop = 0.15;
leftAxis.customAxisMin = 0.0; // this replaces startAtZero = YES


_chartView.legend.position = ChartLegendPositionBelowChartLeft;
_chartView.legend.form = ChartLegendFormSquare;
_chartView.legend.formSize = 20.0;
_chartView.legend.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:20.f];
_chartView.legend.xEntrySpace = 4.0;
_chartView.legend.textColor = [UIColor whiteColor];


NSMutableArray *xVals = [[NSMutableArray alloc] init];

for (int i = 0; i < 12; i++)
{
    [xVals addObject:months[i % 12]];
}

NSMutableArray *yVals = [[NSMutableArray alloc] init];
NSMutableArray *yValsColor = [[NSMutableArray alloc] init];


[yVals addObject:[[BarChartDataEntry alloc] initWithValue:10 xIndex:1]];
[yVals addObject:[[BarChartDataEntry alloc] initWithValue:15 xIndex:2]];
[yVals addObject:[[BarChartDataEntry alloc] initWithValue:20 xIndex:3]];
[yVals addObject:[[BarChartDataEntry alloc] initWithValue:45 xIndex:4]];
[yVals addObject:[[BarChartDataEntry alloc] initWithValue:30 xIndex:5]];
[yVals addObject:[[BarChartDataEntry alloc] initWithValue:5 xIndex:6]];
[yVals addObject:[[BarChartDataEntry alloc] initWithValue:15 xIndex:7]];
[yVals addObject:[[BarChartDataEntry alloc] initWithValue:22 xIndex:8]];
[yVals addObject:[[BarChartDataEntry alloc] initWithValue:32 xIndex:9]];

[yValsColor addObject:[UIColor yellowColor]];

BarChartDataSet *set1 = [[BarChartDataSet alloc] initWithYVals:yVals label:@"Charges"];
set1.barSpace = 0.35;
set1.colors     =  yValsColor;

NSMutableArray *dataSets = [[NSMutableArray alloc] init];
[dataSets addObject:set1];

BarChartData *data = [[BarChartData alloc] initWithXVals:xVals dataSets:dataSets];
[data setValueFont:[UIFont fontWithName:@"HelveticaNeue-Light" size:20.f]];
[data setValueTextColor:[UIColor whiteColor]];

_chartView.data = data;


NSArray *arrLabelData = [NSArray arrayWithObjects:@"All", @"1/1/2016 to 9/29/2016", @"All", @"All", @"Date of Billed",nil];
NSArray *arrLabel     = [NSArray arrayWithObjects:@"Ins:",@" DOS:",@" Location:",@" Provider:",@" Aging Calculation Based On:",nil];


NSMutableAttributedString *strFS = [[NSMutableAttributedString alloc] init];
UIColor *color = [UIColor yellowColor]; // select needed color

NSDictionary *attrs = @{ NSForegroundColorAttributeName : color};
NSDictionary *attrsLab = @{ NSForegroundColorAttributeName : [UIColor whiteColor]};

for(int i = 0; i <arrLabelData.count; i++)
{
    NSString *strLabData = [arrLabelData objectAtIndex:i];
    NSString *strLab     = [arrLabel objectAtIndex:i];
    
    NSAttributedString *attStringLab        = [[NSAttributedString alloc] initWithString:strLab attributes:attrsLab];
    NSAttributedString *attStringLabData    = [[NSAttributedString alloc] initWithString:strLabData attributes:attrs];
    
    [strFS appendAttributedString:attStringLab];
    [strFS appendAttributedString:attStringLabData];
    
}
lblAttributes.attributedText = strFS;

I want to respond the data only when user tapped inside the bar.

Any one have idea?


Solution

  • I have user version 2.2.3 of charts in my App. Try this implementation to resolve your issue

    1) Add function to your ChartHighlighter.swift file.

    public func getBarBounds(e: BarChartDataEntry) -> CGRect
    {
    
        guard let
            set = self.chart?._data?.getDataSetForEntry(e) as? IBarChartDataSet
            else { return CGRectNull }
    
        let barspace = set.barSpace
        let y = CGFloat(e.value)
        let x = CGFloat(e.xIndex)
    
        let barWidth: CGFloat = 0.5
    
        let spaceHalf = barspace / 2.0
        let left = x - barWidth + spaceHalf
        let right = x + barWidth - spaceHalf
        let top = y >= 0.0 ? y : 0.0
        let bottom = y <= 0.0 ? y : 0.0
    
        var bounds = CGRect(x: left, y: top, width: right - left, height: bottom - top)
    
        self.chart?.getTransformer(ChartYAxis.AxisDependency.Left).rectValueToPixel(&bounds)
    
        return bounds
    }
    

    2) Update getHighlight function in ChartHighlighter.swift file.

    public func getHighlight(x x: Double, y: Double) -> ChartHighlight?
    {
        let xIndex = getXIndex(x)
        if (xIndex == -Int.max)
        {
            return nil
        }
    
    
        let dataSetIndex = getDataSetIndex(xIndex: xIndex, x: x, y: y)
        if (dataSetIndex == -Int.max)
        {
            return nil
        }
    
        //Modification for only Bar Selection
        let dataSet = self.chart!.data!.getDataSetByIndex(dataSetIndex)
        let e = dataSet.entryForXIndex(xIndex) as! BarChartDataEntry!
        let rectData = getBarBounds(e)
    
        let point = CGPoint(x: x,y: y)
        let isPointInFrame = CGRectContainsPoint(rectData, point)
        if (!isPointInFrame)
        {
            return nil
        }
        //Modification for only Bar Selection
    
    
        return ChartHighlight(xIndex: xIndex, dataSetIndex: dataSetIndex)
    }
    

    Hope it will help you. Happy Coding...