JSFiddle - React, Tailwind, and code Playground

by Ajith S Punalur

HTML

<body>
    <div id="wrapper">
	<svg id="meter">
	    <circle id="outline_curves" class="circle outline"  cx="50%" cy="50%">
	    </circle>
	    <circle id="low" class="circle range" cx="50%" cy="50%" stroke="#FDE47F">
	    </circle>
	    <circle id="avg" class="circle range" cx="50%" cy="50%" stroke="#7CCCE5">
	    </circle>
	    <circle id="high" class="circle range" cx="50%" cy="50%" stroke="#E04644">
	    </circle>
	    <circle id="mask" class="circle" cx="50%" cy="50%" >
	    </circle>
	    <circle id="outline_ends" class="circle outline" cx="50%" cy="50%">
	    </circle>
	</svg>
<svg version="1.1" id="meter_needle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	 width="16.721px" height="93.834px" viewBox="0 0 16.721 93.834" enable-background="new 0 0 16.721 93.834" xml:space="preserve">
			<path fill="#464646" d="M13.886,84.243L2.83,83.875c0,0,3.648-70.77,3.956-74.981C7.104,4.562,7.832,0,8.528,0
				c0.695,0,1.752,4.268,2.053,8.894C10.883,13.521,13.886,84.243,13.886,84.243z"/>
			<path fill="#464646" d="M16.721,85.475c0,4.615-3.743,8.359-8.36,8.359S0,90.09,0,85.475c0-4.62,3.743-8.363,8.36-8.363
				S16.721,80.855,16.721,85.475z"/>
			<circle fill="#EEEEEE" cx="8.426" cy="85.471" r="2.691"/>
</svg>
	<input id="slider" type="range" min="0" max="100" value="0" /> 
	<label id="lbl" id="value" for="">0%</label>
	</div>
    <script src="script.js"></script>
</body>

CSS

#wrapper {position: relative;  margin: auto;}
		#meter {
		    width: 100%; height: 100%;
		    transform: rotateX(180deg);
		}
		.circle {fill: none;}
		.outline, #mask {
		    stroke: #F1F1F1; 
		    stroke-width: 65;
		}
		.range { stroke-width: 60; }
		#slider, #lbl {
		    position: absolute;
		}
		#slider {
		    cursor: pointer;
		    left: 0;
		    margin: auto;
		    right: 0;
		    top: 58%;
		    width: 94%;
		}
		#lbl {
		    background-color: #4B4C51; 
		    border-radius: 2px;
		    color: white;   
		    font-family: 'courier new';
		    font-size: 15pt;
		    font-weight: bold;
		    padding: 4px 4px 2px 4px;
		    right: -48px;
		    top: 57%;
		}
		#meter_needle {
		    height: 40%;
		    left: 0;
		    margin: auto;
		    position: absolute;
		    right: 0;
		    top: 10%;
		    transform-origin: bottom center;
		    transform: rotate(270deg);
		}
        
        input[type=range] {
            -webkit-appearance: none;
        }
        
        input[type=range]:focus {
            outline: none;
        }
        
        input[type=range]::-webkit-slider-runnable-track {
            width: 100%;
            height: 12px;
            cursor: pointer;
            background: #F6F6F6;
            border-radius: 25px;
            box-shadow: 0 0 0 1px #f6f6f6;
        }
        
        input[type=range]::-webkit-slider-thumb {
            box-shadow: 0 0 2px #B2B2B2;
            border-radius: 50%;
            height: 30px;
            width: 30px;
            background: #fff;
            cursor: pointer;
            -webkit-appearance: none;
            margin-top: -9px;
        }
        
        input[type=range]:focus::-webkit-slider-runnable-track {
            background: #F6F6F6;

        }
        
        input[type=range]::-moz-range-track {
            width: 100%;
            height: 12.8px;
            cursor: pointer;
            background: #F6F6F6;
            border-radius: 25px;
        }
        
       ...

JavaScript

/* set radius for all circles */
		var r = 400;
		var circles = document.querySelectorAll('.circle');
		var total_circles = circles.length;
		for (var i = 0; i < total_circles; i++) {
		    circles[i].setAttribute('r', r);
		}
		/* set meter's wrapper dimension */
		var meter_dimension = (r * 2) + 100;
		var wrapper = document.querySelector('#wrapper');
		wrapper.style.width = meter_dimension + 'px';
		wrapper.style.height = meter_dimension + 'px';
		/* add strokes to circles  */
		var cf = 2 * Math.PI * r;
		var semi_cf = cf / 2;
		var semi_cf_1by3 = semi_cf / 3;
		var semi_cf_2by3 = semi_cf_1by3 * 2;
		document.querySelector('#outline_curves')
		    .setAttribute('stroke-dasharray', semi_cf + ',' + cf);
		document.querySelector('#low')
		    .setAttribute('stroke-dasharray', semi_cf + ',' + cf);
		document.querySelector('#avg')
		    .setAttribute('stroke-dasharray', semi_cf_2by3 + ',' + cf);
		document.querySelector('#high')
		    .setAttribute('stroke-dasharray', semi_cf_1by3 + ',' + cf);
		document.querySelector('#outline_ends')
		    .setAttribute('stroke-dasharray', 2 + ',' + (semi_cf - 2));
		document.querySelector('#mask')
		    .setAttribute('stroke-dasharray', semi_cf + ',' + cf);
		/*bind range slider event*/
		var slider = document.querySelector('#slider');
		var lbl = document.querySelector("#lbl");
		var mask = document.querySelector('#mask');
		var meter_needle =  document.querySelector('#meter_needle');
		function range_change_event() {
		    var percent = slider.value;
		    var meter_value = semi_cf - ((percent * semi_cf) / 100);
		    mask.setAttribute('stroke-dasharray', meter_value + ',' + cf);
		    meter_needle.style.transform = 'rotate(' + (270 + ((percent * 180) / 100)) + 'deg)';
		    lbl.textContent = percent + '%';
		}
		slider.addEventListener('input', range_change_event);