user2017279 user2017279 - 1 month ago 15
Objective-C Question

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 selected bar data only when user tapped 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?, Please help me

Thanks in advance.

Answer

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...

Comments