Chartjs-How to make Dashed and Solid Line Donut Chart.js

1👍

Two ideas that don’t require any frameworks:

1. CSS Conic gradients

I wonder if you could pull this off using CSS conic gradients. You could use a repeating conic gradient for the dashes, and a regular conic gradient for the filled value.

Note: This approach won’t work in IE because IE doesn’t have conic-gradient support.

Proof of concept:

body {
  /*
  Set up a couple custom properties to specify the colors.
  You could hard-code them if you prefer, but this avoids
  having to repeat the same color in various places and makes
  it easier to change later
  */
  --fgcolor: #346b79;
  --bgcolor: #04151f;

  /* set the background color for the page */
  background: var(--bgcolor);
}

.demo {
  /* make the div a circle. 400px is arbitrary. */
  width: 400px;
  height: 400px;
  border-radius: 50%;
  
  /*
  Here's the magic part. one conic gradient to fill the "value" area
  and a second, repeating conic gradient, to make the dashes. The dashes
  go all the way around but get covered by the fill.
  */
  background-image:
    conic-gradient(var(--fgcolor) 0deg, var(--fgcolor) 204deg, transparent 204deg),
    repeating-conic-gradient(var(--fgcolor) 0deg 0.5deg, var(--bgcolor) 0.5deg 2deg);
  
  /* center the contents on both axes */
  display: flex;
  justify-content: center;
  align-items: center;
  
  /* just gives it some room on the page, centers it. */
  margin: 1rem auto;
}

.demo > span {
  /* The "value" element */
  /* Sets the size of the inner circle.*/
  width: 70%;
  height: 70%;
  
  /* fill the center with the background color */
  background: var(--bgcolor);
  
  /* make it a circle */
  border-radius: 50%;
  
  /* center the value on both axes */
  display: flex;
  justify-content: center;
  align-items: center;

  /* text treatment */
  color: white;
  font-size: 5rem;
  font-family: sans-serif;
  font-weight: bold;
}
<div class="demo">
  <span>64%</span>
</div>

2. SVG stroke-dasharray

Creating an SVG that does this is pretty straightforward. You’d create a circle and an arc, each with a stroke. The circle would use stroke-dasharray to create the dashes, and the arc would fill in the "value" area.

Proof of concept:

body {
  --fgcolor: #346b79;
  --bgcolor: #04151f;

  background: var(--bgcolor);
}

svg {
  width: 300px;
  height: 300px;
  stroke: var(--fgcolor);
}

.dashes {
  stroke-width: 15;
  stroke-dasharray: 0.5px 2px;
}

.value {
  stroke-width: 15;
}

text {
  font-family: sans-serif;
  font-weight: bold;
  text-anchor: middle;
}
<svg viewBox="0 0 100 100">
  <circle class="dashes" r="40" cx="50" cy="50" fill="none" />
  <path class="value" d="M 50 10 A 40 40 0 1 1 24.50304 80.820529" fill="none" />
  <text x=50 y=55 fill="white" stroke="none">64%</text>
</svg>

The path/arc part can seem a bit intimidating, but here’s what it does:

d="M 50 10 A 40 40 0 1 1 24.50304 80.820529"

M 50 50 Moves to (50, 50) to start drawing from there.

A 40 40 0 1 1 24.50304 80.820529 Draws an arc with a radius of 40 on both axes with its endpoint at (24.50304, 80.820529). The middle three arguments can be confusing and I don’t think I can explain them any better than MDN does so I’d point you there for details.

Calculating those endpoints isn’t particularly hard.

You take the sine and cosine (for x and y respectively) of the ending angle, multiply it by the radius of the circle, and add the circle’s center coordinate.

// for a value of 64%, a radius of 40, and center at [50,50]
const value = 0.64;
const radius = 40;
const cx = 50;
const cy = 50;

const endAngleDegrees = 360 * value;
const endAngleRadians = endAngleDegrees / (180/Math.PI);
const x = Math.sin(endAngleRadians) * radius + cx;
const y = Math.cos(endAngleRadians) * radius + cy;

Leave a comment