How to draw a circle with n slices
Asked Answered
T

2

5

I am using react-native-svg module and I want to draw a circle divided to n slices. My circle radius is 41 and the center of it is (50, 50) for example for n=6 I want to draw something like this:

circle with 5 slics

Truculent answered 14/12, 2019 at 19:35 Comment(0)
B
6

I've worked hard to find a solution for you

But I learned a lot of things along the way

Based on this article

import Svg, {Path} from 'react-native-svg';

import React from 'react';
import {View, StyleSheet} from 'react-native';

export default class SvgExample extends React.Component {
  slice() {
    let slices = [];

  //option 1  Equal size pieces
    slices.push({percent: 0.25, color: 'blue'});
    slices.push({percent: 0.10, color: 'red'});
    slices.push({percent: 0.28, color: 'green'});
    slices.push({percent: 0.19, color: 'yellow'});


    //option 2  Different size pieces
    // const numberOfSlice = 6; //number for slice

    // const colorArr = ['red', 'green', 'yellow', 'blue']; //color the slice
    // for (let i = 0; i < numberOfSlice; i++) {
    //   slices.push({percent: 1 / numberOfSlice, color: colorArr[i] || 'gray'});
    // }

    let cumulativePercent = 0;

    function getCoordinatesForPercent(percent) {
      const x = Math.cos(2 * Math.PI * percent);
      const y = Math.sin(2 * Math.PI * percent);
      return [x, y];
    }

    let arr = [];
    arr = slices.map(slice => {
      const [startX, startY] = getCoordinatesForPercent(cumulativePercent);
      cumulativePercent += slice.percent;
      const [endX, endY] = getCoordinatesForPercent(cumulativePercent);
      const largeArcFlag = slice.percent > 0.5 ? 1 : 0;
      const pathData = [
        `M ${startX} ${startY}`, // Move
        `A 1 1 0 ${largeArcFlag} 1 ${endX} ${endY}`, // Arc
        'L 0 0', // Line
      ].join(' ');
      return <Path d={pathData} fill={slice.color} key={pathData} />;
    });
    return arr;
  }

  render() {
    return (
      <View
        style={[
          StyleSheet.absoluteFill,
          {alignItems: 'center', justifyContent: 'center'},
        ]}>
        <Svg
          height="100"
          width="100"
          viewBox="-1 -1 2 2"
          style={{transform: [{rotate: '-90deg'}]}}>
          {this.slice()}
        </Svg>
      </View>
    );
  }
}

expo codesandbox

option 1 option 2

Buss answered 14/12, 2019 at 23:25 Comment(2)
Yes! Thank you so much, works just the way I expected.Truculent
Hi @Yoel, how to use this code inside a g tag of SVG. here is 'M0 250 L125 34 C87 12 44 0 0 0 v250 z' my path for 12 slices circle. i need to make n slices (2-15 for example). but i can not achieve that!Nerva
C
1

Following @Yoel answer, more updated version on functional React-Native.

import React from "react";
import { Path, Svg } from "react-native-svg";
import {View} from "react-native";

export type PieCircleProps = {
    slices: Slice[];
}

export type Slice = {
    percentage: number;
    color: string;
}

export const PieCircle: React.FunctionComponent<PieCircleProps> = (
    {
        slices
    }
) => {
    let totalPercentage = 0;
    
    const getCoordinatesForPercent = () => {
        const x = Math.cos(2 * Math.PI * totalPercentage);
        const y = Math.sin(2 * Math.PI * totalPercentage);
        return [x, y];
    }
    
    const _renderSlice = (
        {
            percentage,
            color
        }: Slice
    ) => {
        const [startX, startY] = getCoordinatesForPercent();
        totalPercentage += percentage;
        const [endX, endY] = getCoordinatesForPercent();
        
        const largeArcFlag = percentage > 0.5 ? 1 : 0;
        const pathData = [
            `M ${startX} ${startY}`, // Move
            `A 1 1 0 ${largeArcFlag} 1 ${endX} ${endY}`, // Arc
            'L 0 0', // Line
        ].join(' ');
        
        return <Path
            d={pathData}
            fill={color}
            key={pathData}
        />;
    }
    
    return (
        <View
            style={[
                {alignItems: 'center', justifyContent: 'center'},
            ]}>
            <Svg
                height="100"
                width="100"
                viewBox="-1 -1 2 2"
                style={{transform: [{rotate: '-90deg'}]}}
            >
                {
                    slices.map(slice => _renderSlice(slice))
                }
            </Svg>
        </View>
    )
}
Cons answered 29/12, 2021 at 14:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.