Самый простой способ, чтобы заполнить фоновый прямоугольник ширины выбранной области и высоту максимальной высоты вашей фигуры, затем используйте операции компоновки, чтобы сохранить только ту часть, где ваша фигура перекрывается, и, наконец, нарисовать штрих.
slider.oninput = drawGauge;
function drawGauge(evt){
// first convert the value to our pixel system
var value = (width/100) * evt.target.value;
// clear the previous frame
ctx.clearRect(0,0,canvas.width, canvas.height);
// draw the filled rect the width of our value
ctx.fillRect(marginLeft, marginTop, value, circleRad*2);
// change the gCO so we keep only the pixels where our shape and the filled rect overlap
ctx.globalCompositeOperation = 'destination-in';
drawShape();
ctx.fill(); // this will make the compositing
// reset the gCO so we can draw the stroke
ctx.globalCompositeOperation = 'source-over';
ctx.stroke();
}
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'lightblue';
ctx.strokeStyle = 'lightgray';
// the positions of our shapes
var marginLeft = 5,
marginTop = 5,
width = 280,
circleRad = 30,
circleCenter = width - circleRad,
rectHeight = 30,
rectTop = marginTop + (circleRad - rectHeight/2),
rectWidth = width - circleRad * 1.82;
// you may have a better version of it ;-)
function drawShape(){
ctx.beginPath();
ctx.moveTo(marginLeft, rectTop);
ctx.lineTo(rectWidth, rectTop);
ctx.arc(circleCenter+1, rectTop + rectHeight /2, circleRad, -Math.PI*.8, Math.PI*.8);
ctx.lineTo(marginLeft, rectTop+ rectHeight);
ctx.closePath();
}
drawGauge({target:{value:50}});
<input type="range" id="slider" from="0" to="100" value="50"/><br>
<canvas id="canvas"></canvas>