d3#pie TypeScript Examples

The following examples show how to use d3#pie. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: PieChart.ts    From anichart.js with MIT License 6 votes vote down vote up
private getPieData(sec: number) {
    const currentData = [...this.dataScales.values()].map((scale) => {
      return scale(sec);
    });
    const minRadio = this.minRadio / 360;
    const sumValue = sum(currentData, (d) => d[this.valueField]);
    const minValue = sumValue * minRadio;
    const pieGen = pie()
      .padAngle((Math.PI / 180) * this.padAngle)
      .value((d) => max([d[this.valueField], minValue]));

    currentData.sort((a, b) => {
      if (Number.isNaN(b[this.valueField])) {
        return -1;
      } else if (Number.isNaN(a[this.valueField])) {
        return 1;
      } else {
        return b[this.idField] - a[this.idField];
      }
    });
    const pieData = pieGen(currentData);

    return pieData;
  }
Example #2
Source File: PieChart.tsx    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
draw() {
    const { values, pieType, strokeWidth } = this.props;

    if (values.length === 0) {
      return;
    }

    const data = values.map(datapoint => datapoint.numeric);
    const names = values.map(datapoint => formattedValueToString(datapoint));
    const colors = values.map((p, idx) => {
      if (p.color) {
        return p.color;
      }
      return grafana_colors[idx % grafana_colors.length];
    });

    const total = sum(data) || 1;
    const percents = data.map((item: number) => (item / total) * 100);

    const width = this.containerElement.offsetWidth;
    const height = this.containerElement.offsetHeight;
    const radius = Math.min(width, height) / 2;

    const outerRadius = radius - radius / 10;
    const innerRadius = pieType === PieChartType.PIE ? 0 : radius - radius / 3;

    const svg = select(this.svgElement)
      .html('')
      .attr('width', width)
      .attr('height', height)
      .append('g')
      .attr('transform', `translate(${width / 2},${height / 2})`);

    const pieChart = pie();

    const customArc = arc()
      .outerRadius(outerRadius)
      .innerRadius(innerRadius)
      .padAngle(0);

    svg
      .selectAll('path')
      .data(pieChart(data))
      .enter()
      .append('path')
      .attr('d', customArc as any)
      .attr('fill', (d: any, idx: number) => colors[idx])
      .style('fill-opacity', 0.15)
      .style('stroke', (d: any, idx: number) => colors[idx])
      .style('stroke-width', `${strokeWidth}px`)
      .on('mouseover', (d: any, idx: any) => {
        select(this.tooltipElement).style('opacity', 1);
        select(this.tooltipValueElement).text(`${names[idx]} (${percents[idx].toFixed(2)}%)`);
      })
      .on('mousemove', () => {
        select(this.tooltipElement)
          .style('top', `${event.pageY - height / 2}px`)
          .style('left', `${event.pageX}px`);
      })
      .on('mouseout', () => {
        select(this.tooltipElement).style('opacity', 0);
      });
  }
Example #3
Source File: pie.ts    From obsidian-tracker with MIT License 4 votes vote down vote up
function renderPie(
    canvas: HTMLElement,
    chartElements: ChartElements,
    renderInfo: RenderInfo,
    pieInfo: PieInfo
) {
    // console.log("renderPie");
    // console.log(renderInfo);
    let errorMessage = "";

    let radius = renderInfo.dataAreaSize.width * 0.5;
    let outterRadius = radius * 0.7;
    let innerRadius = outterRadius * pieInfo.ratioInnerRadius;

    // values
    let values: Array<number> = [];
    for (let strExpr of pieInfo.data) {
        let retValue = expr.resolveValue(strExpr, renderInfo);
        if (typeof retValue === "string") {
            errorMessage = retValue;
            break;
        } else if (typeof retValue === "number") {
            values.push(retValue);
        }
    }
    if (errorMessage !== "") {
        return errorMessage;
    }
    // console.log(values);

    // labels
    let labels: Array<string> = [];
    for (let strExpr of pieInfo.label) {
        let retLabel = expr.resolveTemplate(strExpr, renderInfo);
        // console.log(retLabel);
        if (retLabel.startsWith("Error")) {
            errorMessage = retLabel;
            break;
        }
        labels.push(retLabel);
    }
    if (errorMessage !== "") {
        return errorMessage;
    }
    // console.log(labels);

    // hideLabelLessThan
    let hideLabelLessThan = pieInfo.hideLabelLessThan;

    // label sizes
    let labelSizes = labels.map(function (n) {
        return helper.measureTextSize(n, "tracker-tick-label");
    });

    // extLabel
    let extLabels: Array<string> = [];
    for (let strExpr of pieInfo.extLabel) {
        let retExtLabel = expr.resolveTemplate(strExpr, renderInfo);
        if (retExtLabel.startsWith("Error")) {
            errorMessage = retExtLabel;
            break;
        }
        extLabels.push(retExtLabel);
    }
    if (errorMessage !== "") {
        return errorMessage;
    }
    // console.log(extLabels);

    // extLabel sizes
    let extLabelSizes = extLabels.map(function (n) {
        return helper.measureTextSize(n, "tracker-pie-label");
    });
    // console.log(extLabelSizes);

    let showExtLabelOnlyIfNoLabel = pieInfo.showExtLabelOnlyIfNoLabel;

    // scale
    let colorScale = d3.scaleOrdinal().range(pieInfo.dataColor);

    let sectorsGroup = chartElements.dataArea.append("g");
    sectorsGroup.attr("transform", function () {
        let strTranslate =
            "translate(" +
            renderInfo.dataAreaSize.width * 0.5 +
            "," +
            renderInfo.dataAreaSize.height * 0.5 +
            ")";

        return strTranslate;
    });

    let pie = d3.pie();
    let pieValues = pie(values);

    let sectors = sectorsGroup
        .selectAll("sector")
        .data(pieValues)
        .enter()
        .append("g")
        .attr("class", "sector");

    let arc = d3.arc().innerRadius(innerRadius).outerRadius(outterRadius);

    var hiddenArc = d3
        .arc()
        .innerRadius(radius * 0.9)
        .outerRadius(radius * 0.9);

    let sectorPaths = sectors
        .append("path")
        .attr("fill", function (d: any, i: number) {
            return colorScale(i.toString());
        })
        .attr("d", arc);

    function isLabelHidden(arcObj: any) {
        // console.log(`start/end: ${arcObj.startAngle}/${arcObj.endAngle}`);
        let fraction = (arcObj.endAngle - arcObj.startAngle) / (2.0 * Math.PI);
        if (fraction < hideLabelLessThan) {
            return true;
        }
        return false;
    }

    // label elements
    let labelElements = sectorsGroup
        .selectAll("label")
        .data(pie(values))
        .enter()
        .append("text")
        .text(function (arcObj: any, i: number) {
            if (isLabelHidden(arcObj)) {
                return "";
            }
            return labels[i];
        })
        .attr("transform", function (d: any) {
            return (
                "translate(" +
                arc.centroid(d)[0] +
                "," +
                arc.centroid(d)[1] +
                ")"
            );
        })
        .style("text-anchor", "middle")
        .attr("class", "tracker-pie-label");

    function getMidAngle(arcObj: any) {
        return arcObj.startAngle + (arcObj.endAngle - arcObj.startAngle) / 2;
    }

    // external label elements
    let extLabelElements = sectorsGroup
        .selectAll("extLabel")
        .data(pieValues)
        .enter()
        .append("text")
        .text(function (arcObj: any, i: number) {
            if (showExtLabelOnlyIfNoLabel) {
                if (labels[i] === "" || isLabelHidden(arcObj)) {
                    return extLabels[i];
                }
                return "";
            } else {
                return extLabels[i];
            }
        })
        .attr("transform", function (arcObj: any, i: number) {
            let posLabel = hiddenArc.centroid(arcObj);
            let midAngle = getMidAngle(arcObj);

            posLabel[0] =
                (radius * 0.99 - extLabelSizes[i].width) *
                (midAngle < Math.PI ? 1 : -1);
            return "translate(" + posLabel[0] + "," + posLabel[1] + ")";
        })
        .style("text-anchor", function (arcObj: any) {
            let midAngle = getMidAngle(arcObj);
            return midAngle < Math.PI ? "start" : "end";
        })
        .attr("class", "tracker-pie-label");

    function getPointsForConnectionLines(arcObj: any, i: number) {
        let labelWidth = labelSizes[i].width;
        let extLabelWidth = extLabelSizes[i].width;
        let labelHidden = isLabelHidden(arcObj);
        let midAngle = getMidAngle(arcObj);

        let posLabel = arc.centroid(arcObj); // line insertion in the slice
        let posMiddle = hiddenArc.centroid(arcObj); // line break: we use the other arc generator that has been built only for that
        let posExtLabel = hiddenArc.centroid(arcObj); // Label position = almost the same as posB
        // console.log(labels[i]);
        // console.log(`label/middle/extLabel: ${posLabel}/${posMiddle}/${posExtLabel}`);

        let distMiddleToLabel = Math.sqrt(
            (posMiddle[0] - posLabel[0]) ** 2 +
                (posMiddle[1] - posLabel[1]) ** 2
        );

        if (labels[i] !== "") {
            // shift posLabel, toward the middle point
            posLabel[0] =
                posLabel[0] +
                ((posMiddle[0] - posLabel[0]) * labelWidth) / distMiddleToLabel;
            posLabel[1] =
                posLabel[1] +
                ((posMiddle[1] - posLabel[1]) * labelWidth) / distMiddleToLabel;

            // shift posExtLabel
            posExtLabel[0] =
                (radius * 0.99 - extLabelWidth - 3) *
                (midAngle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
        }

        distMiddleToLabel = Math.sqrt(
            (posMiddle[0] - posLabel[0]) ** 2 +
                (posMiddle[1] - posLabel[1]) ** 2
        );

        let distExtLabelToLabel = Math.sqrt(
            (posExtLabel[0] - posLabel[0]) ** 2 +
                (posExtLabel[1] - posLabel[1]) ** 2
        );

        if (distMiddleToLabel > distExtLabelToLabel) {
            // console.log("two points");
            return [posLabel, posExtLabel];
        }
        return [posLabel, posMiddle, posExtLabel];
    }

    // Add lines between sectors and external labels
    let lines = sectorsGroup
        .selectAll("line")
        .data(pieValues)
        .enter()
        .append("polyline")
        .attr("stroke", "black")
        .style("fill", "none")
        .attr("stroke-width", 1)
        .attr("points", function (arcObj: any, i: number) {
            if (showExtLabelOnlyIfNoLabel) {
                if (labels[i] === "" || isLabelHidden(arcObj)) {
                    if (extLabels[i] !== "") {
                        return getPointsForConnectionLines(arcObj, i);
                    }
                }
            } else {
                if (extLabels[i] !== "") {
                    return getPointsForConnectionLines(arcObj, i);
                }
            }
        })
        .attr("class", "tracker-axis");
}