SVG路径半圆中的圆角

Rounded corners in SVG path semi circle

我有一条半圆的路径。如何使角变圆?我不想使用 stroke-linecap: round 因为我需要它只在这些角上被舍入:

<svg>
  <g>
    <!--background -->
    <path fill="none" stroke-dasharray="" stroke-width="16" stroke="#607985" d="M30 100 A 40 40 0 0 1 170 100"></path>
    <!-- strokes -->
    <path id="meter-back" fill="none" stroke-width="15" stroke="white" d="M30 100 A 40 40 0 0 1 170 100"></path>
    <!--progress -->
    <path id="meter-fill" fill="none" stroke-dashoffset="219.942" stroke-dasharray="109.971, 109.971" stroke="rgba(96,121,133,0.7)" stroke-width="15" d="M30 100 A 40 40 0 0 1 170 100" stroke="#607985"></path>

  </g>
</svg>

使用getPath例程计算所需路径 (半圆圆心的0,0点):

const getPath = (outerRadius, innerRadius, cornerRadius) => {
  return `M ${-outerRadius},0 
    A ${outerRadius},${outerRadius} 1 1 1 ${outerRadius},0
    Q ${outerRadius},${cornerRadius} 
    ${outerRadius-cornerRadius},${cornerRadius} 
    H ${innerRadius+cornerRadius}
    Q ${innerRadius},${cornerRadius} 
    ${innerRadius},0 
    A ${innerRadius},${innerRadius} 0 0 0 
    ${-innerRadius},0       
    Q ${-innerRadius},${cornerRadius} 
    ${-innerRadius-cornerRadius},${cornerRadius} 
    H ${-outerRadius+cornerRadius}
    Q ${-outerRadius},${cornerRadius} 
    ${-outerRadius},0 
  Z`;
};

d3.select('path').attr('d', getPath(120, 90, 12));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg width='300' height='200'>
  <g transform='translate(150,150)'>
    <path stroke='red' fill='none'/>
    <circle fill='red' r='5' cx='0' cy='0'/>
  </g>
</svg>

这是一个固定的解决方案。 dividerPos 可以在 0 到 1 的范围内:

const getPath = (outerRadius, innerRadius, cornerRadius, dividerPos) => {
  const angle = Math.PI * (1 - dividerPos);
  const outerPointX = outerRadius * Math.cos(angle);
  const outerPointY = outerRadius * -Math.sin(angle);
  const innerPointX = innerRadius * Math.cos(angle);
  const innerPointY = innerRadius * -Math.sin(angle);

  const left = `M ${-outerRadius},0 
    A ${outerRadius},${outerRadius} 0 0 1 
    ${outerPointX},${outerPointY}
    L ${innerPointX},${innerPointY}
    A ${innerRadius},${innerRadius} 0 0 0 ${-innerRadius},0       
    Q ${-innerRadius},${cornerRadius} 
    ${-innerRadius-cornerRadius},${cornerRadius} 
    H ${-outerRadius+cornerRadius}
    Q ${-outerRadius},${cornerRadius} 
    ${-outerRadius},0 
  Z`;
  
  const right = `M ${outerPointX},${outerPointY}
    A ${outerRadius},${outerRadius} 0 0 1 
    ${outerRadius},0
    Q ${outerRadius},${cornerRadius} 
    ${outerRadius-cornerRadius},${cornerRadius} 
    H ${innerRadius+cornerRadius}
    Q ${innerRadius},${cornerRadius} 
    ${innerRadius},0 
    A ${innerRadius},${innerRadius} 0 0 0 
    ${innerPointX},${innerPointY}       
  Z`;

  return {left, right};
};

const {left, right} = getPath(120, 90, 15, 0.5);
d3.select('.left').attr('d', left);
d3.select('.right').attr('d', right);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width='300' height='200'>
  <g transform='translate(150,150)'>
    <path stroke='grey' fill='grey' class='left'/>
    <path stroke='grey' fill='none' class='right'/>
  </g>
</svg>