首页 文章

简单的条形进度指示器静态或动画

提问于
浏览
2

我需要制作一个简单的条形进度指示器 - 实际上我只需要一个条形图,其中绿色部分表示良好的数量,另一个颜色部分表示不良金额和百分比在条形图中间的某处 . 假设条宽50px,高15px . 想想静态进度条,如下例所示 .

enter image description here

在使用jquery和背景div之前我已经完成了这个操作,其中有两个位于其上方的div,用于好的和坏的指示符,然后是一个位于其上方的div来显示文本 .

但是我想知道是否有更简单的HTML5画布,SVG或CSS解决方案 . 由于这个timy控件将出现在长表的每一行中,目的是减少对DOM的污染并提高可读性和可重用性 .

我知道有些图书馆可以做到这一点,但我想用它作为学习经验 . 解决方案应该是无脚本,或者只有JS,或者是带有jquery的JS .

编辑:感谢积极的输入人员 . 我在下面的答案中提出了我自己的解决方案和工作片段,因为我认为值得单独参加投票等 . 没有人提出了SVG解决方案 - 任何接受者?

我的道具形象:

enter image description here

到目前为止编辑2:3优秀的解决方案(加上我的) . 事实证明这是一个非常有趣的周末挑战 . 还有吗?

编辑 - 答案选择:为了结束,我选择并回答了奖励积分 . 但是,所有提出的答案在不同情况下似乎都是可行的 . 就我而言,Le Beau先生基于SVG的答案是最佳的 . 我选择的参数是我最初在服务器上制作页面标记,因此可以设置渲染条形所需的所有值而无需执行代码 . 后来我允许更改完成百分比,我用ajax发布到服务器和简单的jquery来更新文本和条形覆盖 .

我希望HTML5进度标记的回答能够让这个问题变得多余,但是我们可能会再次坐在开发人员的家里,在那里喝着鸡尾酒(也许) .

谢谢大家的努力 .

5 回答

  • 2

    这是我自己的产品 . 请注意,脚本的很大一部分是从画布生成透明度的背景图像,您可能不需要这样做 .

    该技术使用每个条形的单个div,一些用于样式的标准CSS和单个图像 .

    条形背景图像以相同的高度和条形宽度的两倍预先绘制,两个区段的宽度为宽度的50%,使用表示进度所需的颜色 . 因此,如果条形图为50px,则背景图像为100px,例如50px蓝色和50px黄色 .

    enter image description here

    在我的例子中,我使用脚本来读取div中显示的值,然后修改css background-position-x值以适当地移动图像 . 将它移动到x = 0并且条形图都很好,移动到x = -25并且你有50/50好/坏等 .

    如果您知道条形大小并且可以提前生成图像,并且在从DB生成页面时,则可以完全跳过脚本,并在输出html时在div上设置必要的元素css .

    const barW = 50; // display width of bar element on page. Note green-red bg image width must be 2 x barW
    
    /*
    This is where we apply the image to the bars. Because I create the image from a canvas, this is called as a callback from the image create process. If your image is just a plain web image and you know dimensions you could run this function in your document.ready() event.
    */
    function makeBars(img) {
    
      // apply the bar background to each tiny bar class (tbc)
      $('.tbc').each(function() {
    
        var num = parseFloat($(this).html(), 10) / 100; // I stored the % in the element html - read that.
    
        var xPos = Math.round(-(barW * (1 - num))); // offset x by minus the bad proportion. 
    
        $(this).css({
          backgroundImage: 'url(' + img.src + ')',
          backgroundPositionX: xPos
        }); // apply to element.
    
      })
    }
    
    
    
    
    
    /*
    Everything from here is optional - it generates an image via a canvas 
    */
    makeImg(makeBars); // call for the background image to be made
    
    // this is all to generate an image - made from a canvas.
    function makeImg(cbf) {
    
      // add a stage
      var s = new Konva.Stage({
        container: 'container',
        width: 800,
        height: 200
      });
    
      // add a layer        
      var l = new Konva.Layer();
      s.add(l);
    
      // Add a good rect to the LAYER just to show the good amount.
      var green = new Konva.Rect({
        fill: 'blue',
        width: 50,
        height: 15,
        x: 0,
        y: 0,
        opacity: 0.5
      });
      l.add(green);
      
      // Add a bad rect to the LAYER just to show the good amount.
      var red = new Konva.Rect({
        fill: 'gold',
        width: 50,
        height: 15,
        x: 50,
        y: 0,
        opacity: 0.5
      });
      l.add(red);
    
      var bg;
      var catchImg = function(img) {
        cbf(img); // callback passing the new img
      }
      l.draw();
      s.toImage({
        callback: catchImg,
        x: 0,
        y: 0,
        width: 100,
        height: 15
      })
      
      $('#container').remove(); // now we have an image - trash the canvas.
    
    
    }
    
    .tbc {
      display: inline-block;
      width: 50px;
      height: 15px;
      line-height: 15px;
      border: 1px solid #ccc;
      text-align: center;
      font-size: 8pt;
      font-family: Calibri, sans-serif;
      font-weight: bold;
      color: blue;
      
    }
    
    .country {
      display: inline-block;
      width: 200px;
    }
    
    .info {
      margin-top: 20;
      font-size: 10px;
    }
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.rawgit.com/konvajs/konva/1.6.3/konva.min.js"></script>
    <h1>Urban population rate by country </h1>
    
    <div>
      <div class='country'>China</div>
      <div class='tbc'>57.6%</div>
    </div>
    
    <div>
      <div class='country'>India</div>
      <div class='tbc'>32%</div>
    </div>
    
    <div>
      <div class='country'>U.S.</div>
      <div class='tbc'>82.1%</div>
    </div>
    
    <div>
      <div class='country'>Russia</div>
      <div class='tbc'>73.2%</div>
    </div>
    
    <div>
      <div class='country'>UK</div>
      <div class='tbc'>81.2%</div>
    </div>
    
    <div>
      <div class='country'>Burundi</div>
      <div class='tbc'>11.5%</div>
    </div>
    
    <div class='info'><a href='http://www.worldometers.info/world-population/population-by-country/' target=''>Source: www.worldometers.info/</a>
    
    
      <div id='container'>Temp: Used to contain canvas</div>
    
  • 3

    EDIT: 添加了静态解决方案

    我能想到的最低限度是:

    // p must be an INTEGER from 0 to 100
    function bar(n, p)
    {
      document.getElementById("bar-" + n)
        .firstChild.style.width = (p * 2) + "px";
    }
    
    var bars = [ 0, 0 ];
    
    setInterval(function () {
      var i;
    
      for (i = 0; i < bars.length; i++)
      {
        bar(i, bars[i]);
        
        if (bars[i] < 100)
        {
          bars[i] += i + 1;
        }
      }
    
    }, 100);
    
    div.bar
    {
      width: 200px;
      height: 15px;
      margin: 4px;
    
      background-color: #ffffc0;
      border: 1px solid #000000;
      border-radius: 3px;
    }
    
    div.bar div
    {
      height: 15px;
      background-color: #408040;
    }
    
    <div id="bar-0" class="bar"><div></div></div>
    <div id="bar-1" class="bar"><div></div></div>
    

    这里是静态解决方案:

    (function () {
      $("[data-bar]").each(function () {
        var p;
        
        p = parseInt($(this).data("bar"), 10);
        $(this)
          .append($("<div>").addClass("p").text(p + "%"))
          .append($("<div>").addClass("q").css("width", (2 * p) + "px"));
      });
    }());
    
    div.bar
    {
      position: relative;
      
      width: 200px;
      height: 15px;
      margin: 4px;
    
      background-color: #ffffc0;
      border: 1px solid #000000;
      border-radius: 3px;
      
      text-align: center;
    }
    
    div.bar div.p
    {
      position: absolute;
      width: 100%;
      margin-top: 1px;
      
      font-size: 11px;
      font-weight: bold;
      font-family: monospace;
    }
    
    div.bar div.q
    {
      height: 15px;
      background-color: #408040;
    }
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <div class="bar" data-bar="32"></div>
    <div class="bar" data-bar="78"></div>
    
  • 2

    您可以使用progress元素:

    <progress max="100" value="0" />
    

    它很难造型,但易于使用:

    var i=0;
    setInterval(function(){
     document.getElementsByTagName("progress")[0].value=++i;
    },100);
    
  • 2

    这是与您的产品相当的SVG .

    $("svg.tbc").each(function(i, item) {
      var $item = $(item);
      var rate = $item.parent().find(".country").attr("rate");
      $item.find(".bar").attr("width", rate);
      $item.find("text").text(rate);
    });
    
    .tbc {
      width: 50px;
      height: 15px;
    }
    
    .tbc .bg {
      fill: gold;  
      fill-opacity: 0.5;
    }
    
    .tbc .bar {
      fill: blue;
      fill-opacity: 0.5;
    }
    
    .tbc text {
      font-size: 8pt;
      font-family: Calibri, sans-serif;
      font-weight: bold;
      fill: blue;
    }
    
    .country {
      display: inline-block;
      width: 200px;
    }
    
    .info {
      margin-top: 20;
      font-size: 10px;
    }
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <h1>Urban population rate by country </h1>
    
    <div>
      <div class="country" rate="57.6%">China</div>
      <svg class="tbc"><rect class="bg" width="100%" height="100%"/><rect class="bar" width="0%" height="100%"/><text x="50%" y="70%" text-anchor="middle">0%</text></svg>
    </div>
    
    <div>
      <div class="country" rate="32%">India</div>
      <svg class="tbc"><rect class="bg" width="100%" height="100%"/><rect class="bar" width="0%" height="100%"/><text x="50%" y="70%" text-anchor="middle">0%</text></svg>
    </div>
    
    <div>
      <div class="country" rate="82.1%">U.S.</div>
      <svg class="tbc"><rect class="bg" width="100%" height="100%"/><rect class="bar" width="0%" height="100%"/><text x="50%" y="70%" text-anchor="middle">0%</text></svg>
    </div>
    
    <div>
      <div class="country" rate="73.2%">Russia</div>
      <svg class="tbc"><rect class="bg" width="100%" height="100%"/><rect class="bar" width="0%" height="100%"/><text x="50%" y="70%" text-anchor="middle">0%</text></svg>
    </div>
    
    <div>
      <div class="country" rate="81.2%">UK</div>
      <svg class="tbc"><rect class="bg" width="100%" height="100%"/><rect class="bar" width="0%" height="100%"/><text x="50%" y="70%" text-anchor="middle">0%</text></svg>
    </div>
    
    <div>
      <div class="country" rate="11.5%">Burundi</div>
      <svg class="tbc"><rect class="bg" width="100%" height="100%"/><rect class="bar" width="0%" height="100%"/><text x="50%" y="70%" text-anchor="middle">0%</text></svg>
    </div>
    
    <div class="info"><a href="http://www.worldometers.info/world-population/population-by-country/" target="">Source: www.worldometers.info/</a>
    
  • 0

    你只需要一个DIV和伪 :before:after ,一个用于背景,一个用于文本,就像这里https://jsfiddle.net/3keey3t6/2/

    .progress::before {
        position: absolute;
        top: 0;
        left: 0;
        width: 100px;
        bottom: 0;
        background: #eee;
        content: "";
        z-index: -1;
    }
    
    .progress {
        position:relative;
        width:75px;
        height:35px;
        background:green;
    }
    
    .progress:after {
        position: absolute;
        content: attr(data-progress) '%';
        width: 100%;
        line-height: 35px;
        text-align: center;
        color: white;
        text-shadow:1px 0 0 black, 0 1px 0 black, -1px 0 0 black, 0 -1px 0 black;
    }
    

    然后

    <div id="pbar" class="progress" data-progress="20"/>
    

    function setProgress(p) {
        var prg = document.getElementById("pbar");
        prg.style.width = p+"px";
        prg.setAttribute("data-progress", p);
    }
    
    setProgress(10);
    

    只是一个非常简单的例子,如果目标是尽可能少地污染DOM ......

相关问题