2

i am using d3-shape library to build a pie chart in React Native. this is my code:

Slice.js

import React, { Component } from 'react';
import { Path, } from 'react-native-svg';
import * as shape from 'd3-shape';
const d3 = { shape };

export default class Slice extends Component {
    constructor(props) {
        super(props);
        this.arcGenerator = d3.shape.arc()
            .outerRadius(100)
            .padAngle(0)
            .innerRadius(0);
    }

    createPieSlice = (index, endAngle, data) => {

        const arcs = d3.shape.pie()
            .value((item) => item.number)
            .startAngle(0)
            .endAngle(endAngle)
            .centroid()
            (data);

        let arcData = arcs[index];

        return this.arcGenerator(arcData);
    };

    render() {

        const {
            endAngle,
            color,
            index,
            data,
            onPress
        } = this.props;

        return (
            <Path
                onPress={onPress}
                d={this.createPieSlice(index, endAngle, data)}
                fill={color}
            />
        )

    }
}

this class returns every slice of the pie chart. I want to add text to the arcs like this:

enter image description here

I searched a lot and everyone is answering like this:

arcs.append("text")
    .attr("transform", function (d) {
    return "translate(" + newarc.centroid(d) + ")";
})
    .attr("text-anchor", "middle")
    .attr("fill", "white")
    .text(function (d) {
    return d.value + "%";
});

but this is not working in React Native it says:

append is not a function.

and for more information, this is my App.js

import React, { Component } from 'react';
import Svg from 'react-native-svg';
import {
  StyleSheet,
  View,
} from 'react-native';
import Slice from "./Slice";

const demoData = [
  {
    number: 150,
    color: '#28BD8B'
  },
  {
    number: 110,
    color: '#366A6A'
  },
  {
    number: 60,
    color: '#1d2f51'
  },
  {
    number: 40,
    color: '#466B6A'
  },
];


export default class App extends Component {

  constructor(props) {
    super(props);
  }

  render() {
    return (
      <View style={styles.container}>
          <Svg
            width={200}
            style={{
              shadowOffset: {
                width: 0,
                height: 32
              },
              elevation: 12,
              shadowRadius: 12.5,
              shadowOpacity: 1,
            }}
            height={200}
            viewBox={`-100 -100 200 200`}
          >
            {
              demoData.map((item, index) =>
                <Slice
                  index={index}
                  endAngle={Math.PI * 2}
                  color={item.color}
                  data={demoData}
                  key={'pie_shape_' + index}
                />
              )
            }
          </Svg>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

please help me if you know the solution for React Native.

houman.sanati
  • 1,054
  • 3
  • 18
  • 34

1 Answers1

1

React-Native doesn't have css, or selectors, so you can't query for subsets of the DOM that way. Use d3.js for transformation of data and calculating shapes, path data etc., and then render using the declarative React approach.

Using the declarative approach for example, you can add the Text label to the arch by transforming the position using d3.arch.centroid(PathValue) to get the center of the arch. Note that the <Text> is imported from SVG. So Slice return would be something like;

...
return (
         <>
            <Path
                onPress={onPress}
                d={`${value}`}
                fill={color}
            />
           <Text transform={{ translate: d3.arc.centroid(value) }}>
              {value}
           </Text>
        </>
        )
...

Checkout this codepen example.

Waweru Kamau
  • 1,429
  • 14
  • 20