Как выровнять текст по центру среза круговой диаграммы? - PullRequest
0 голосов
/ 04 мая 2018

enter image description here

Я хочу добавить текст в Piechart.

UIGraphicsPushContext(context);
CGContextMoveToPoint(context, newCenterX, newCenterY);
CGContextAddArc(context, newCenterX, newCenterY, radius,arcOffset-(myAngle/2),arcOffset+(myAngle/2), 0);
UIColor *color = [PIECHART_COLORS objectAtIndex:i%6];
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextClosePath(context);
CGContextFillPath(context);
CGMutablePathRef arcPath = CGPathCreateMutable();
CGPathAddArc(arcPath, NULL, self.frame.size.width/2, self.frame.size.height/2, radius, arcOffset-(myAngle/2), arcOffset+(myAngle/2),0);
CGRect rect =CGPathGetBoundingBox(arcPath);

rect = CGRectMake(rect.origin.x+rect.size.width/2, rect.origin.y+rect.size.height/2, 80, 20);

// For InnerCircle Empty

CGContextMoveToPoint(context, newCenterX, newCenterY);
float innercircleRadius = IS_IPAD ? 70 : 40;
CGContextAddArc(context, newCenterX, newCenterY, radius-innercircleRadius,arcOffset-(myAngle/2),arcOffset+(myAngle/2), 0);
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
CGContextClosePath(context);
CGContextFillPath(context);

Сверху я смогу нарисовать круговую диаграмму с пробелом во внутренней части, но я не могу добавить текст в определенный фрагмент круговой диаграммы. Кто-нибудь может помочь с хорошим примером?

Моя круговая диаграмма отображается отлично, но выравнивание текста происходит неправильно.

// Для текста я попробую этот код

NSString *text = [NSString stringWithFormat:@"%.2f %%",[[[myArray objectAtIndex:i] objectForKey:@"Count"] floatValue]];
[text drawInRect: rect withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16], NSForegroundColorAttributeName:[UIColor redColor]} ];

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

Предполагается, что вы пытаетесь соответствовать примеру, и если вы пытаетесь выровнять текстовые фреймы, которые читают «Firefox», «IE7», «IE6» и т. Д. *

Центры каждого текстового поля вокруг вашей круговой диаграммы находятся на другом невидимом круге, который окружает вашу круговую диаграмму. Вы можете представить линию, которая указывает от центра, через центральную точку каждой дуги, к теоретическому кругу, на котором будут располагаться ваши текстовые рамки.

Как только вы вычислите точку на этом невидимом внешнем круге, у вас будет центральная точка, в которую можно поместить UILabel (для простоты).

Если вы обращаетесь к метке центра, а она не отображается, то, скорее всего, у вас проблема порядка прорисовки. В этом случае поверх текста рисуется белый круг. В контексте CGGraphics все рисуется в методе живописца, что означает, что все, что вы рисуете, будет нарисовано «поверх» предыдущей работы. В таком случае текст должен быть последним, что вы рисуете (или, по крайней мере, он должен быть нарисован ПОСЛЕ белого кружка в центре)

0 голосов
/ 09 мая 2018

Хотя ваш вопрос совершенно неясен, как именно вы хотите отцентрировать label до pie slice. Я пытался с тем, что я понимаю из вопроса, который вы опубликовали выше.

Прежде всего используйте UIBezierPath вместо CGContext. Я использовал Параметрическое уравнение круга , чтобы вычислить граничные точки моего круга.

CGPoint newPoints = CGPointMake(a + r * cos(theta), b + r * sin(theta));
// theta = angle
// r = radius
// a = centerX
// b = centerY

Это даст вам очки, где вам нужно показать свой лейбл. Теперь вам просто нужно рассчитать правильный угол (центр среза) для достижения вашей цели.

UIBezierPath имеет метод [bezierPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];, который создает дугу.

Теперь я собираюсь поделиться кодом шаг за шагом:

Два макроса:

#define TO_DEGREE(x) (x * 180.0)/M_PI
#define TO_RADIAN(x) (x * M_PI)/180.0

viewDidLoad: метод инициализации фиктивных данных для моего графика.

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    chartView.backgroundColor = [UIColor clearColor];

    /// Assuming dummy data for our chartView
    NSArray *gendersData = @[@{@"color": [UIColor redColor], @"title": @"Boys", @"percentage": @40},
                         @{@"color": [UIColor greenColor], @"title": @"Girls", @"percentage": @45},
                         @{@"color": [UIColor purpleColor], @"title": @"Unknown", @"percentage": @15}];

    [self preparePieChartForData:gendersData];

}

preparePieChartForData: метод

- (void)preparePieChartForData:(NSArray *)data {

    /// We will use Parametric equaction of circle to get the boundary of circle
    /*
     * Parametric equation of circle
     * x = a + r cos t
     * y = b + r sin ⁡t
     * a, b are center of circle
     * t (theta) is angle
     * x and y will be points which are on circumference of circle
     *
               270
                |
            _   |   _
                |
     180 -------o------- 360
                |
            +   |   +
                |
                90
     *
     */

    /// Thats why starting from 270.0
    CGFloat lastAngle = 270.0;
    for (NSDictionary *genderData in data) {

        /// Getting data from dictionary
        CGFloat percentage = [genderData[@"percentage"] floatValue];
        UIColor *color = genderData[@"color"];
        NSString *title = genderData[@"title"];

        /// Calculating the angle from percentage, 360 is full circle.
        CGFloat angle = lastAngle + (360 * percentage)/100.0;
        [self makeSliceStartFrom:lastAngle endAt:angle radius:80.0 color: color title:title];

        /// Updating lastAngle so that next angle can start just after this
        lastAngle = angle;
    }
}

Метод приготовления кусочков пирога

- (void)makeSliceStartFrom:(CGFloat)startAngle
                     endAt:(CGFloat)endAngle
                    radius:(CGFloat)radius
                     color:(UIColor *)color
                     title:(NSString *)title {

    /// Converting degree to radians as bezierPath accept angle in radians
    CGFloat endAngleInRadians   = TO_RADIAN(endAngle);
    CGFloat startAngleInRadians = TO_RADIAN(startAngle);
    if (endAngle >= -180.0 && endAngle < -90.0) {
        /// This is because of above diagram
        startAngleInRadians = TO_RADIAN(-90);
    }

    /// This is the center of chartView
    CGPoint center = CGPointMake(chartView.bounds.size.width/2.0, chartView.bounds.size.height/2.0);

    /// Initializing Bezeir path
    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
    [bezierPath addArcWithCenter:center radius:radius startAngle:startAngleInRadians endAngle:endAngleInRadians clockwise:YES];

    /// Line width of pie chart
    CGFloat lineWidth = 30.0;
    CGPathRef slicePath = bezierPath.CGPath;

    /// Making shape layer from the path
    CAShapeLayer *sliceLayer = [CAShapeLayer layer];
    sliceLayer.path = slicePath;
    sliceLayer.strokeColor = color.CGColor;
    sliceLayer.lineWidth = lineWidth;
    sliceLayer.fillColor = [UIColor clearColor].CGColor;
    [chartView.layer addSublayer:sliceLayer];

    /*
     * ------------- LABEL PART -------------
     * Adding label at center of the slice
     */

    /// Creating an empty label
    UILabel *lbl = [[UILabel alloc] init];
    lbl.font = [UIFont systemFontOfSize:10.0];
    lbl.text = title;
    [lbl sizeToFit];

    /// theta is the center (middle) angle of this slice
    CGFloat theta = startAngleInRadians + (endAngleInRadians - startAngleInRadians)/2.0;

    /// Adding lineWith and 10.0 extra in radius so that label can visible outside of the circle
    CGFloat r = radius + lineWidth + 10.0;
    CGFloat a = center.x;
    CGFloat b = center.y;

    /// Calculating points from theta and angle by using parametric equation of cricle
    CGPoint newPoints = CGPointMake(a + r * cos(theta), b + r * sin(theta));
    CGRect  frame = lbl.frame;

    /// Recalculating the origin so that label can be exact center of slice. newPoints are (0, 0) position of label.
    frame.origin = CGPointMake(newPoints.x - frame.size.width/2.0, newPoints.y - frame.size.height/2.0);
    lbl.frame = frame;
    [chartView addSubview:lbl];
}

chartView - это UIView добавление self.view в раскадровку. Его размер (300,0, 300,0) расположен в центре экрана. Ниже вывод:

enter image description here

Я постарался охватить все в своем ответе, если все еще что-то неясно, пожалуйста, не стесняйтесь комментировать. Я также прилагаю свой пример проекта для экономии времени.

Надеюсь, это поможет!

0 голосов
/ 04 мая 2018

Вам не нужно рисовать внутренний круг, просто нарисуйте кусочки, используя путь Безье.

https://developer.apple.com/documentation/uikit/uibezierpath https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/BezierPaths/BezierPaths.html#//apple_ref/doc/uid/TP40010156-CH11-SW1

UIBezierPath *aPath = [UIBezierPath bezierPath];
  1. Первая линия рисования (rx + смещение, ry + смещение) в (rx + смещение + 10, ry + смещение + 10) [aPath addLineToPoint:]
  2. нарисовать внешнюю дугу [aPath addarc:]
  3. рисовать линию (rx + смещение + 10, ry + смещение + 10) в (rx + смещение, ry + смещение) [aPath addLineToPoint:]
  4. нарисовать внутреннюю дугу [aPath addarc:]
  5. closepath

или просто установите ширину линии пути Безье и нарисуйте путь Безье с помощью дуги. [UIBezierPath bezierPathWithArcCenter:]

Затем вы можете добавить текст внутри пути Безье напрямую. Ввод текста внутри UIBezierPath

...