2

I'm working with React and ChartJS to draw a doughnut chart with a 3*Pi/2 circumference and rounded corner.

I saw these two posts where they explain how to round corners for data sets and it is working as expected with a complete circle and with half a circle:

ChartJs - Round borders on a doughnut chart with multiple datasets

Chartjs doughnut chart rounded corners for half doghnut

One answer on this post is to change "y" or "x" translation by factor of n, for example 2 in the following case: ctx.translate(arc.round.x, arc.round.y*2);

With this in mind I started to change values for x and y but have not yet reach the correct set of values that will make it work.

For example I tried to use a factor of 3/2 on the translation of y and this is what I get.

ctx.translate(arc.round.x, (arc.round.y * 3) / 2);

enter image description here

with no factor I get the following:

ctx.translate(arc.round.x, arc.round.y);

enter image description here

The code to round the end corner is exactly the same as in the posts I refer. But here it is just in case:

let roundedEnd = {
    // @ts-ignore
    afterUpdate: function (chart) {
      var a = chart.config.data.datasets.length - 1;
      for (let i in chart.config.data.datasets) {
        for (
          var j = chart.config.data.datasets[i].data.length - 1;
          j >= 0;
          --j
        ) {
          if (Number(j) == chart.config.data.datasets[i].data.length - 1)
            continue;
          var arc = chart.getDatasetMeta(i).data[j];
          arc.round = {
            x: (chart.chartArea.left + chart.chartArea.right) / 2,
            y: (chart.chartArea.top + chart.chartArea.bottom) / 2,
            radius:
              chart.innerRadius +
              chart.radiusLength / 2 +
              a * chart.radiusLength,
            thickness: (chart.radiusLength / 2 - 1) * 2.5,
            backgroundColor: arc._model.backgroundColor,
          };
        }
        a--;
      }
    },
    // @ts-ignore
    afterDraw: function (chart) {
      var ctx = chart.chart.ctx;
      for (let i in chart.config.data.datasets) {
        for (
          var j = chart.config.data.datasets[i].data.length - 1;
          j >= 0;
          --j
        ) {
          if (Number(j) == chart.config.data.datasets[i].data.length - 1)
            continue;
          var arc = chart.getDatasetMeta(i).data[j];
          var startAngle = Math.PI / 2 - arc._view.startAngle;
          var endAngle = Math.PI / 2 - arc._view.endAngle;

          ctx.save();
          ctx.translate(arc.round.x, arc.round.y);
          console.log(arc.round.startAngle);
          ctx.fillStyle = arc.round.backgroundColor;
          ctx.beginPath();
          //ctx.arc(arc.round.radius * Math.sin(startAngle), arc.round.radius * Math.cos(startAngle), arc.round.thickness, 0, 2 * Math.PI);
          ctx.arc(
            arc.round.radius * Math.sin(endAngle),
            arc.round.radius * Math.cos(endAngle),
            arc.round.thickness,
            0,
            2 * Math.PI
          );
          ctx.closePath();
          ctx.fill();
          ctx.restore();
        }
      }
    },   };

These are the options to configure the chart:

const chartJsOptions = useMemo<chartjs.ChartOptions>(() => {
    if (data) {
      return {
        elements: {
          center: {
            text: `${data.impact > 0 ? "%"}`,
            color: isDarkTheme ? darkText : greyAxis, // Default is #000000
            fontStyle: "Open Sans Hebrew, sans-serif",
            sidePadding: 20, // Default is 20 (as a percentage)
            minFontSize: 15, // Default is 20 (in px), set to false and text will not wrap.
            lineHeight: 20, // Default is 25 (in px), used for when text wraps
          },
        },
        legend: {
          display: false,
        },
        // rotation: Math.PI / 2,
        rotation: (3 * Math.PI) / 4,
        circumference: (3 * Math.PI) / 2,
        maintainAspectRatio: false,
        animation: {
          duration: ANIMATION_DURATION,
        },
        plugins: {
          datalabels: false,
          labels: false,
        },
        cutoutPercentage: 90,
        tooltips: {
          enabled: false,
          rtl: true,
        },
      };
    } else {
      return {};
    }   }, [data, isDarkTheme]);

Here is where I call the react component for the chart:

 <Doughnut 
        data={chartJsData} 
        options={chartJsOptions} 
        plugins={[roundedEnd]} />

How can I correctly calculate the rounded edges on a 3*Pi/2 circumference or any other circumference between complete and half?

This issue may be more of a math than programing and my geometrical math is also a bit rusty.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
edumarg
  • 78
  • 1
  • 2
  • 10
  • What is exactly the problem, the rotated amount, or that the radius of the rounded corner does not fit in the circumference? – rustyBucketBay Aug 22 '21 at 10:10
  • if the radius is the problem, seems to me that it should not depend on the dataset length, as it does in your settings (`a * chart.radiusLength`) – rustyBucketBay Aug 22 '21 at 10:15
  • I think the issue is the rotated amount, as mention the logic works with a complete circle and for half a circle when adjusting the factor of the translate of y by 2: ctx.translate(arc.round.x, arc.round.y *2 ); – edumarg Aug 22 '21 at 11:06

0 Answers0