Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
259 views
in Technique[技术] by (71.8m points)

javascript - Divide semi circle with stroke-dasharray and on active color fill

I'm working on an SVG gauge meter here I want to divide the semi-circle into parts when the range slider move on active stroke fill with gradient color. And want to add one more black color running track when the meter needle moves. I had tried using stroke-dasharray but after adding this all colors are coming at a time meter is not working properly.

  1. I want to divide the semi-circle into parts when the range slider move on active stroke fill with gradient color
  2. And I want to add one more black color running track when the meter needle moves.

My code here

/* 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('#high').setAttribute('stroke-dasharray', semi_cf + ',' + cf);
document.querySelector('#avg').setAttribute('stroke-dasharray', semi_cf_2by3 + ',' + cf);
document.querySelector('#low').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(' + (450 - ((percent * 180) / 100)) + 'deg)';
  lbl.textContent = percent + '%';
}
slider.addEventListener('input', range_change_event);
#wrapper {
  position: relative;
  margin: auto;
}

#meter {
  width: 100%;
  height: 100%;
  transform: rotate(180deg);
}

.circle {
  fill: none;
}

.outline,
#mask {
  stroke: #F1F1F1;
  stroke-width: 65;
}

.range {
  stroke-width: 60;
}

#slider,
#lbl {
  position: absolute;
}

#slider {
  position: absolute;
  transform: rotate(180deg);
  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;
  /*orientation fix*/
  transform: rotate(450deg);
  width: 5px;
  background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<body>
  <div id="wrapper">
    <svg id="meter">
        <circle id="outline_curves" class="circle outline"  cx="50%" cy="50%">
        </circle>
        <circle id="high" 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="low" 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="25" max="100" step="25" value="0" />
    <label id="lbl" id="value" for="">0%</label>
  </div>
  <script src="script.js"></script>
</body>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

My approach here is a pure CSS one ,i didn't use SVG and implementing JS code in this case is lot easier.

Output

enter image description here

var black = document.getElementsByClassName('black')[0];
var gradient = document.getElementsByClassName('gradient')[0]
var tick = document.getElementsByClassName('tick')[0];
var m = document.getElementById('m');
m.addEventListener('input', function() {
  black.style.transform = gradient.style.transform = tick.style.transform = "translate(-50%,-50%)rotateZ(-" + (180 / 100) * m.value + "deg)"
});
* {
  margin: 0px;
  padding: 0px;
  font-family: "arial";
}

.gauge_main,
.white,
.black,
.tick,
.gradient,
.chamber,
.meter {
  position: absolute;
  top: 50%;
  left: 50%;
  height: 280px;
  width: 280px;
  transform: translate(-50%, -50%);
  transition: 0.4s;
}

.meter {
  background-color: white;
  height: 281px;
  width: 281px;
  border-radius: 50%;
  clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0 100%);
  z-index: 1000;
}

.tick,
.chamber {
  width: 160px;
  height: 5px;
  background: linear-gradient(to right, white 50%, black 50%);
  z-index: 110;
  transform-origin: 50%;
}

.tick {
  z-index: 1001;
}

.chamber {
  left: 50%;
  background: white;
  width: 280px;
  height: 5px;
  transform-origin: 50%;
  transform: translate(-50%, -50%)rotateZ(calc(var(--i)*-20deg));
  z-index: 20;
}

.white,
.black,
.gradient {
  position: absolute;
  background-color: black;
  border-radius: 50%;
}

.white {
  height: 180px;
  width: 180px;
  background-color: white;
  z-index: 30;
}

.gradient {
  height: 280px;
  width: 280px;
  background: linear-gradient(0deg, rgba(29, 216, 255, 1) 0%, rgba(4, 106, 255, 1) 50%, rgba(208, 212, 255, 1) 50%);
}

.black {
  height: 200px;
  width: 200px;
  background: linear-gradient(to top, black 50%, rgba(208, 212, 255, 1) 50%);
  box-shadow: 0px 0px 0px 5px white;
  z-index: 25;
}

@keyframes load {
  from {
    transform: translate(-50%, -50%)rotateZ(0deg);
  }
  to {
    transform: translate(-50%, -50%)rotateZ(-180deg);
  }
}

input {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 280px;
  transform: translate(-50%, 50%);
}
<div class="gauge_main">
  <div class="gradient"></div>
  <div class="white"></div>
  <div class="black"></div>
  <div class="tick"></div>
  <div style="--i:1" class="chamber"></div>
  <div style="--i:2" class="chamber"></div>
  <div style="--i:3" class="chamber"></div>
  <div style="--i:4" class="chamber"></div>
  <div style="--i:5" class="chamber"></div>
  <div style="--i:6" class="chamber"></div>
  <div style="--i:7" class="chamber"></div>
  <div style="--i:8" class="chamber"></div>
  <div style="--i:9" class="chamber"></div>
  <div class="meter"></div>

</div>
<input type="range" id="m" name="meter" min="0" max="100" value="0">

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...