<div id="app">
  <input type="range" v-model="show" min="1" :max="chartData.length">
  <div>{{show}}</div>
  <input type="range" v-model="gap" min="0" max="10">
  
  <svg viewBox="-100 -100 200 200" width="200" xmlns="http://www.w3.org/2000/svg" overflow="visible">
    <g v-for="(path, index) in paths" :key="index" class="pie">
      <path :d="path.d"></path>
      <text :x="path.cx" :y="path.cy" text-anchor="middle" dominant-baseline="middle">{{chartData[index].text}}</text>
    </g>
  </svg>
</div>
body {
  color: #fff;
  background-color: #222;
  font-family: monospace;
}

svg, input {
  display: block;
}

.pie path {
  fill: #2d2d2d;
  stroke: #f8e5ad;
}

.pie text {
  fill: #fff;
}

.pie:hover path {
  fill: #f8e5ad;
  stroke: #f8e5ad;
}

.pie:hover text {
  fill: #2d2d2d;
}
new Vue({
  el: '#app',
  data: {
    show: 5,
    gap: 5,
    from: -Math.PI / 2,
    outerRadius: 100,
    innerRadius: 30,
    chartData: [
      { text: 'text_1' },
      { text: 'text_2' },
      { text: 'text_3' },
      { text: 'text_4' },
      { text: 'text_5' },
      { text: 'text_6' },
      { text: 'text_7' },
      { text: 'text_8' },
    ],
  },

  computed: {
    paths() {
      const from = this.from;
      const n = this.show;
      const step = 2 * Math.PI / n;
      return this.chartData.slice(0, n).map((_, i) => {
        return pie(from + step * i, step, this.outerRadius, this.innerRadius, this.gap);
      });
    }
  }
})


function pie(from, angle, outerRadius, innerRadius, gap = 0) {
  const or = outerRadius;
  const ir = innerRadius;
  let d;

  if (angle > Math.PI) {
    const x0 = or * Math.cos(from);
    const y0 = or * Math.sin(from);
    d = `M ${x0} ${y0} `;
    
    const x1 = or * Math.cos(from + Math.PI);
    const y1 = or * Math.sin(from + Math.PI);
    d += `A ${or} ${or} 0 0 1 ${x1} ${y1} `;
    d += `A ${or} ${or} 0 0 1 ${x0} ${y0} `;

    const x2 = ir * Math.cos(from);
    const y2 = ir * Math.sin(from);
    d += `M ${x2} ${y2} `;

    const x4 = ir * Math.cos(from + Math.PI);
    const y4 = ir * Math.sin(from + Math.PI);
    d += `A ${ir} ${ir} 0 0 0 ${x4} ${y4} `;

    d += `A ${ir} ${ir} 0 0 0 ${x2} ${y2} Z`;
  } 
  else {
    const og = Math.asin(gap / 2 / outerRadius);
    const ig = Math.asin(gap / 2 / innerRadius);
    
    const x0 = or * Math.cos(from + og);
    const y0 = or * Math.sin(from + og);
    d = `M ${x0} ${y0} `;
    
    const x2 = or * Math.cos(from + angle - og);
    const y2 = or * Math.sin(from + angle - og);
    d += `A ${or} ${or} 0 0 1 ${x2} ${y2} `;

    const x3 = ir * Math.cos(from + angle - ig);
    const y3 = ir * Math.sin(from + angle - ig);
    d += `L ${x3} ${y3} `;

    const x4 = ir * Math.cos(from + ig);
    const y4 = ir * Math.sin(from + ig);
    d += `A ${ir} ${ir} 0 0 0 ${x4} ${y4} `;
    d += `L ${x0} ${y0} Z`;
  }

  const mid = from + angle / 2;
  return {
    d,
    cx: (or + ir) * 0.5 * Math.cos(mid),
    cy: (or + ir) * 0.5 * Math.sin(mid),
  };
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js