Reputation: 80
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?
Upvotes: 1
Views: 3064
Reputation: 1
myBarChart.delegate = self
myBarChart.legend.enabled = false
extension StatisticUsageChartView: ChartViewDelegate {
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
let marker: BalloonMarker = BalloonMarker(color: Colors._9e9e9e.color,
font: UIFont.systemFont(ofSize: 10),
textColor: .white,
insets: UIEdgeInsets(top: 5.0, left: 5.0, bottom: 7.0, right: 5.0))
marker.isPercent = self.isPercent
marker.minimumSize = CGSizeMake(50, 35)
chartView.marker = marker
self.myBarChart.centerViewToAnimated(xValue: entry.x,
yValue: entry.y,
axis: self.myBarChart.data![highlight.dataSetIndex].axisDependency,
duration: 0.7)
}
}
Upvotes: 0
Reputation: 188
I converted @rohit Sidpara's answer for 3.2.1 version of Charts
Both functions need to be written at BarHighlighter.swift file
open override func getHighlight(x: CGFloat, y: CGFloat) -> Highlight?
{
guard
let barData = (self.chart as? BarChartDataProvider)?.barData,
let high = super.getHighlight(x: x, y: y)
else { return nil }
let pos = getValsForTouch(x: x, y: y)
if let set = barData.getDataSetByIndex(high.dataSetIndex) as? IBarChartDataSet,
set.isStacked
{
return getStackedHighlight(high: high,
set: set,
xValue: Double(pos.x),
yValue: Double(pos.y))
}
else
{
let set = barData.getDataSetByIndex(high.dataSetIndex) as? IBarChartDataSet
let entry = set?.entryForIndex(Int(high.x)) as! BarChartDataEntry
let rectOfData = getBarBounds(e: entry)
return rectOfData.contains(CGPoint(x: x, y: y)) ? high: nil
}
}
public func getBarBounds(e: BarChartDataEntry) -> CGRect
{
guard
let dataProvider = self.chart as? BarChartDataProvider
else { return CGRect.null }
let barspace = CGFloat((dataProvider.barData?.barWidth)!) / 2.0
let y = CGFloat(e.y)
let x = CGFloat(e.x)
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)
dataProvider.getTransformer(forAxis: YAxis.AxisDependency.left).rectValueToPixel(&bounds)
return bounds
}
Upvotes: 0
Reputation: 1
Maximum hightlightdistance property is available for chartview default is 500 dp. Change it to 10 and check you're view
Upvotes: -1
Reputation: 547
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...
Upvotes: 2
Reputation: 5095
I have a project with the same library and I was able to get the functionality you are asking for by changing the getHighlight function inside the ChartHighlighter.swift file to the following:
/// Returns a Highlight object corresponding to the given x- and y- touch positions in pixels.
/// - parameter x:
/// - parameter y:
/// - returns:
public func getHighlight(x x: CGFloat, y: CGFloat) -> ChartHighlight?
{
print("y: \(y)")
let xIndex = getXIndex(x)
guard let
selectionDetail = getSelectionDetail(xIndex: xIndex, y: y, dataSetIndex: nil)
else { return nil }
print("selectionDetail: \(selectionDetail.y)")
if(y<selectionDetail.y) {
return nil
}
else {
return ChartHighlight(xIndex: xIndex, value: selectionDetail.value, dataIndex: selectionDetail.dataIndex, dataSetIndex: selectionDetail.dataSetIndex, stackIndex: -1)
}
}
Upvotes: 0