enter image description here

Quiero agregar texto en 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);

Desde arriba, podré dibujar un gráfico circular con espacio interior en la parte interna, pero no puedo agregar texto en un segmento de gráfico circular en particular. ¿Alguien puede ayudar con algún buen ejemplo?

Mi gráfico circular se muestra perfectamente, pero la alineación del texto no se realiza correctamente.

// Para texto probaré este código

NSString *text = [NSString stringWithFormat:@"%.2f %%",[[[myArray objectAtIndex:i] objectForKey:@"Count"] floatValue]];
[text drawInRect: rect withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16], NSForegroundColorAttributeName:[UIColor redColor]} ];
0
Dinesh 4 may. 2018 a las 09:02

3 respuestas

La mejor respuesta

Aunque su pregunta no es clara, ¿cómo exactamente quiere centrar el label en pie slice. Intenté con lo que entiendo de la pregunta que publicaste anteriormente.

Lo primero es usar UIBezierPath en lugar de CGContext. Utilicé Ecuación paramétrica del círculo para calcular los puntos límite de mi círculo.

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

Le dará los puntos donde necesita mostrar su etiqueta. Ahora solo necesita calcular el ángulo correcto (centro de corte) para lograr su objetivo.

UIBezierPath tiene un método [bezierPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; que crea un arco.

Ahora voy a compartir el código paso a paso:

Dos macros:

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

viewDidLoad: método para inicializar los datos ficticios para mi gráfico.

- (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: método

- (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;
    }
}

Cómo hacer un método de corte de tarta

- (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 es un UIView agregado en self.view en el guión gráfico. Su tamaño es (300.0, 300.0) y se coloca en el centro de la pantalla. A continuación se muestra la salida:

enter image description here

Traté de cubrir todo en mi respuesta si aún algo no está claro, por favor siéntase libre de comentar. También adjunto mi proyecto de muestra para ahorrar tiempo.

¡Espero que ayude!

2
TheTiger 10 may. 2018 a las 04:37

Asumiendo que está tratando de coincidir con el ejemplo, y asumiendo que está tratando de alinear los marcos de texto que dicen "Firefox", "IE7", "IE6", etc.

Los centros de cada cuadro de texto alrededor de su gráfico circular existen en otro círculo invisible que rodea su gráfico circular. Puede imaginar una línea que apunte desde el centro, a través del punto central de cada arco, hasta el círculo teórico sobre el cual se ubicarían sus marcos de texto.

Una vez que calcule el punto en ese círculo exterior invisible, tendría un punto central en el que colocar un UILabel (por simplicidad).

Si te estás refiriendo a la etiqueta central y no se muestra, entonces es probable que tengas un problema de orden de dibujo. El círculo blanco se dibuja sobre el texto, en tal caso. En un contexto CGGraphics, todo se dibuja en el método del pintor, lo que significa que todo lo que dibuje se dibujará "encima" del trabajo anterior. En tal caso, el texto debe ser lo último que dibuje (o, al menos, debe dibujarse DESPUÉS del círculo central blanco)

0
christopherdrum 9 may. 2018 a las 07:42

No necesita dibujar un círculo interno, solo dibuje los cortes usando la ruta de Bezier.

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. Primera línea de dibujo (rx + offset, ry + offset) a (rx + offset + 10, ry + offset + 10) [aPath addLineToPoint:]
  2. dibujar arco exterior [aPath addarc:]
  3. dibujar línea (rx + offset + 10, ry + offset + 10) a (rx + offset, ry + offset) [aPath addLineToPoint:]
  4. dibujar arco interno [aPath addarc:]
  5. camino cerrado

O simplemente establezca el ancho de línea de la ruta bezier y dibuje la ruta bezier con un arco. [UIBezierPath bezierPathWithArcCenter:]

Luego puede agregar texto dentro de la ruta bezier directamente. Escribir texto dentro de UIBezierPath

0
Satyam Raikar 4 may. 2018 a las 09:31