render()

in src/PieChart.js [265:399]


  render() {
    const {
      marginLeft,
      marginRight,
      marginTop,
      marginBottom,
      holeRadius,
    } = this.props;

    // sizes fallback based on provided info: given dimension -> radius + margin -> other dimension -> default
    const width =
      this.props.width ||
      (this.props.radius
        ? this.props.radius * 2 + marginLeft + marginRight
        : this.props.height) ||
      DEFAULT_SIZE;
    const height =
      this.props.height ||
      (this.props.radius
        ? this.props.radius * 2 + marginTop + marginBottom
        : this.props.width) ||
      DEFAULT_SIZE;
    const radius =
      this.props.radius ||
      Math.min(
        (width - (marginLeft + marginRight)) / 2,
        (height - (marginTop + marginBottom)) / 2,
      );
    const center = { x: marginLeft + radius, y: marginTop + radius };

    const {
      data,
      total,
      centerLabel,
      getPieSliceLabel,
      markerLineValue,
      markerLineOverhangInner,
      markerLineOverhangOuter,
      pieSliceClassName,
    } = this.props;

    const valueAccessor = makeAccessor(this.props.slice);
    const sum = sumBy(data, valueAccessor);
    const newTotal = total || sum;
    const markerLinePercent = isFinite(markerLineValue)
      ? markerLineValue / newTotal
      : null;

    let startPercent = 0;
    const slices = data.map(d => {
      const slicePercent = valueAccessor(d) / newTotal;
      const slice = {
        start: startPercent,
        end: startPercent + slicePercent,
      };
      startPercent += slicePercent;

      return slice;
    });

    return (
      <svg className="rct-pie-chart" {...{ width, height }}>
        {data.map((d, i) => {
          const [onMouseEnter, onMouseMove, onMouseLeave, onClick] = [
            'onMouseEnterSlice',
            'onMouseMoveSlice',
            'onMouseLeaveSlice',
            'onClick',
          ].map(eventName => {
            // partially apply this slice's data point as 2nd callback argument
            const callback = methodIfFuncProp(eventName, this.props, this);
            return isFunction(callback) ? bindTrailingArgs(callback, d) : null;
          });

          const className = `rct-pie-slice rct-pie-slice-${i} ${getValue(
            pieSliceClassName,
            d,
            i,
          ) || ''}`;
          const slice = slices[i];
          const pathStr = pieSlicePath(
            slice.start,
            slice.end,
            center,
            radius,
            holeRadius,
          );
          const key = `pie-slice-${i}`;

          return (
            <path
              {...{
                className,
                d: pathStr,
                onMouseEnter,
                onMouseMove,
                onMouseLeave,
                onClick,
                key,
                style: getValue(this.props.pieSliceStyle, d, i),
              }}
            />
          );
        })}

        {sum < newTotal ? ( // draw empty slice if the sum of slices is less than expected total
          <path
            className="rct-pie-slice rct-pie-slice-empty"
            d={pieSlicePath(startPercent, 1, center, radius, holeRadius)}
            key="pie-slice-empty"
          />
        ) : null}

        {markerLinePercent !== null && isFinite(markerLinePercent)
          ? this.renderMarkerLine(
              markerLine(
                markerLinePercent,
                center,
                radius,
                holeRadius,
                markerLineOverhangOuter,
                markerLineOverhangInner,
              ),
            )
          : null}

        {centerLabel ? this.renderCenterLabel(center) : null}
        {getPieSliceLabel
          ? data.map((d, i) =>
              this.renderSliceLabel(d, slices[i], center, radius, i),
            )
          : null}
      </svg>
    );
  }