iOS图表:如何在数据输入图标/圆点下绘制值?

时间:2019-03-05 17:52:49

标签: swift ios-charts

如果LineChartDataSet()的{​​{1}}设置为true,是否可以在条目下绘制该值,而不是在标签上方绘制该值的默认位置?

enter image description here

我还没有立即在API中找到任何有帮助的东西。

谢谢!

2 个答案:

答案 0 :(得分:0)

当前,没有选项可以轻松更改LineChartDataSet标签的位置,但是建议使用以下功能:
[Feature Request] Make it easier to change the position of the labels drawn above the circles in a LineChartView #2581

可悲的是...此功能请求已经开放很长时间了,因此不确定是否有人对实现它感兴趣。
但是...如果绝对必要,则可以在LineChartRenderer.drawValues(context:)中进行更改。

在这里,它调用ChartUtils.drawText(context:text:point:align:attributes:),并传递CGPoint值确定该位置的y

您可以通过更改以下行来在y位置添加一些点:

pt.y - CGFloat(valOffset) - valueFont.lineHeight

收件人:

pt.y - CGFloat(valOffset) - valueFont.lineHeight + 100

我希望这会有所帮助,但是请注意,所有更改都将在您的项目中进行,并且如果您/其他人更新了组件,则这些更改将丢失。

答案 1 :(得分:0)

我已经实现了一些解决定位标签问题的方法。我的目标是排除重叠的标签和图形线。主要思想是在值字符串中添加换行符和空格,以使其正确定位。

不幸的是,源代码在Objective-C中,但是可以轻松地被Swift所采用

LineChartValueFormatter.h 文件:

#import <Foundation/Foundation.h>

@interface LineChartValueFormatter : NSObject

- (instancetype)initWithChartData:(NSArray<NSNumber *> *)chartData;
- (NSString *)formattedValueStringAtIndex:(NSUInteger)index;

@end

LineChartValueFormatter.m 文件:

#import "LineChartValueFormatter.h"

typedef enum : NSUInteger {
    ChartValueDirectionTop,
    ChartValueDirectionTopLeft,
    ChartValueDirectionTopRight,
    ChartValueDirectionBottom,
    ChartValueDirectionBottomLeft,
    ChartValueDirectionBottomRight,
} ChartValueDirection;

BOOL chartValueDirectionIsBottom(ChartValueDirection direction) {
    return (direction == ChartValueDirectionBottom || direction == ChartValueDirectionBottomLeft  || direction == ChartValueDirectionBottomRight);
}

BOOL chartValueDirectionIsTop(ChartValueDirection direction) {
    return (direction == ChartValueDirectionTop|| direction == ChartValueDirectionTopLeft  || direction == ChartValueDirectionTopRight);
}


@interface LineChartValueFormatter ()

@property (nonatomic, strong) NSArray<NSNumber *> * chartData;
@property (nonatomic, strong) NSMutableArray<NSNumber *> * directions;

@end

@implementation LineChartValueFormatter

- (instancetype)initWithChartData:(NSArray<NSNumber *> *)chartData {
    self = [super init];
    if (self) {
        self.chartData = chartData;
        self.directions = [NSMutableArray arrayWithCapacity:chartData.count];
        [self.directions addObject:@([self firstValueDirection])];
        for (NSInteger i = 1; i < self.chartData.count - 1; ++i) {
            [self.directions addObject:@([self commonValueDirectionAtIndex:i])];
        }
        [self.directions addObject:@([self lastValueDirection])];
    }
    return self;
}

- (NSString *)formattedValueStringAtIndex:(NSUInteger)index {
    if (!self.directions || !self.directions.count) {
        return valueString;
    }
    ChartValueDirection direction = [self.directions[index] integerValue];
    NSString * newlineString = @"\n";
    NSString * valueString = [self.chartData[index] stringValue];
    NSUInteger numberOfSpaces = valueString.length;
    // There is U+2007 space used (“Tabular width”, the width of digits), not usual space
    NSString * spaceString = [@"" stringByPaddingToLength:numberOfSpaces
                                               withString:@" "
                                          startingAtIndex:0];
    switch (direction) {
        case ChartValueDirectionTopLeft:
            return [NSString stringWithFormat:@"%@%@", valueString, spaceString];
        case ChartValueDirectionTopRight:
            return [NSString stringWithFormat:@"%@%@", spaceString, valueString];
        case ChartValueDirectionBottom:
            return [NSString stringWithFormat:@"%@%@", newlineString, valueString];
        case ChartValueDirectionBottomLeft:
            return [NSString stringWithFormat:@"%@%@%@", newlineString, valueString, spaceString];
        case ChartValueDirectionBottomRight:
            return [NSString stringWithFormat:@"%@%@%@", newlineString, spaceString, valueString];
        default:
            return valueString;
    }
}

- (ChartValueDirection)firstValueDirection {
    double rate = [self.chartData[0] doubleValue];
    double nextRate = [self.chartData[1] doubleValue];
    if (nextRate > rate) {
        return ChartValueDirectionBottomRight;
    }
    return ChartValueDirectionTopRight;
}

- (ChartValueDirection)lastValueDirection {
    NSUInteger count = self.chartData.count;
    double rate = [self.chartData[count - 1] doubleValue];
    double previousRate = [self.chartData[count - 2] doubleValue];
    if (previousRate > rate) {
        return ChartValueDirectionBottomLeft;
    }
    return ChartValueDirectionTopLeft;
}

- (ChartValueDirection)commonValueDirectionAtIndex:(NSUInteger)index {
    double rate = [self.chartData[index] doubleValue];
    double previousRate = [self.chartData[index - 1] doubleValue];
    double nextRate = [self.chartData[index + 1] doubleValue];
    if (previousRate > rate && rate > nextRate) {
        return ChartValueDirectionBottomLeft;
    }
    if (previousRate >= rate && rate <= nextRate) {
        return ChartValueDirectionBottom;
    }
    if (previousRate < rate && rate < nextRate) {
        return ChartValueDirectionTopLeft;
    }
    if (previousRate <= rate && rate >= nextRate) {
        return ChartValueDirectionTop;
    }
    return ChartValueDirectionTop;
}

@end

用法示例:

// Here is your code for configuring charts ...
// chartData is your array of y values of type NSArray<NSNumber *> * defined and filled somewhere above
// lineChartDataSet is your dataset for graph drawing defined and initialized somewhere above

LineChartValueFormatter * formatter = [[LineChartValueFormatter alloc] initWithChartData:chartData];
lineChartDataSet.valueFormatter = [ChartDefaultValueFormatter withBlock:^NSString * _Nonnull(double value, ChartDataEntry * _Nonnull entry, NSInteger dataSetIndex, ChartViewPortHandler * _Nullable viewPortHandler) {
            return [formatter formattedValueStringAtIndex:entry.x];
        }];

Example of how does it looks like after formatting

这并不是一个很好的解决方案,但是它可以解决问题而无需更改Charts源代码,这对我来说至关重要。希望对别人有帮助