【问题标题】:Simple bar progress indicator static or animated简单的条形进度指示器静态或动画
【发布时间】:2017-06-16 16:53:35
【问题描述】:

我需要制作一个简单的条形进度指示器 - 实际上我只需要一个带有绿色部分的条形表示好数量,另一个彩色部分表示不好的数量,以及条中间某处的好百分比。假设栏宽 50 像素,高 15 像素。像下面的例子一样考虑静态进度条。

我在使用 jquery 和一个背景 div 之前已经这样做了,在它的顶部还有 2 个 div 用于显示好坏指标,然后在其上方放置一个 div 来显示文本。

但是我想知道是否有更简单的 HTML5 画布、SVG 或 CSS 解决方案。由于这种时序控制会出现在长表的每一行中,目的是减少对DOM的污染,提高可读性和可重用性。

我知道有些图书馆可以做到这一点,但我想将其用作学习体验。解决方案应该是没有脚本,或者只有JS,或者JS加jquery。

编辑:感谢积极投入的人们。我在下面的答案中提出了我自己的解决方案与工作 sn-p,因为我认为它值得单独投票等。还没有人提出 SVG 解决方案 - 任何接受者?

我的提案图片:

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

编辑 - 已选择答案:为了结束,我已选择并回答以奖励积分。然而,所有提出的答案在不同的情况下似乎都是可行的。出于我的目的,Le Beau 先生基于 SVG 的回答是最佳选择。我的选择参数是我最初在服务器上制作页面标记,因此可以设置所有必要的值以在不执行代码的情况下呈现条形图。后来我允许更改完成百分比,我通过向服务器发送 ajax 帖子和简单的 jquery 来更新文本和条形覆盖率。

我希望 HTML5 进度标签的答案及时让这个问题变得多余,但是到那时我们可能会再次坐在开发人员休息室的甲板上喝鸡尾酒(也许)。

感谢大家的努力。

【问题讨论】:

  • 它是动态的(进度条动画)还是只是一个静态的(“当前进度”)指示器?
  • <progress value="30" max="100" style="background-color:green;">30%</progress> ?
  • @VanquiishedWombat - 没问题,但如果你不希望你的问题被投票给地狱并结束,请显示一些代码,否则这里的人会认为这是公平的游戏;)
  • 我认为 DOM 方式(<div><progress>)是最轻量级的解决方案。无数小画布对性能/内存的影响可能比您预期的要大。
  • @mplungjan 查看我提供的示例代码作为答案。我现在被原谅了吗?

标签: javascript jquery css html svg


【解决方案1】:

这是您提供的 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>

【讨论】:

  • 优秀 - 如果页面是在服务器端构建并设置我猜的宽度和文本,也可能是无脚本版​​本?
  • 是的。如果这对你更好。
【解决方案2】:

你可以只用一个 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 的污染......

【讨论】:

  • 感谢您提供基于 CSS 的简洁解决方案。我喜欢这个,因为它非常精简。
  • 是的 .. 如果您从数据库等动态生成 div,您甚至不需要 Javascript,只需声明 attr 'data-progress' 并完成。
  • 是的,我确实这样做了,所以是一个 nil-script 解决方案。布埃诺。
  • 您能否再看一下 - 文本需要在整个栏中居中,而不仅仅是“好”部分。从你的小提琴中看不清楚,但我怀疑文本会是一个问题,完成 5% 会被截断,也许?
  • 我不知道,我的经验是各个浏览器的进度选项卡非常不同,所以我总是最终创建一个轻量级的自定义选项卡。
【解决方案3】:

你可以使用进度元素:

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

它的样式很难,但易于使用:

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

【讨论】:

  • 谢谢 - 我同意进度元素样式似乎受浏览器的支配。好主意。
  • 我最终选择使用 SVG 答案,因为它与我的用例中的参数相匹配,其中包括我自己的样式,而且我没有太多时间花在检查不同浏览器的外观和样式参数上.我希望您的回答在未来成为事实。
  • @vanquiished wombat:不客气;)。我希望当 IE 真的死了,MS 让 Edge 保持最新时,这将实现......
【解决方案4】:

编辑:添加静态解决方案

我能想到的绝对最小值是这样的:

// 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>

【讨论】:

  • 感谢和 +1 的工作 sn-p。实际上我正在寻找一个静态指示器,所以动画的道具。虽然不是很完美,因为我需要在栏上放置一些居中的文字,说 % green。
【解决方案5】:

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

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

条形背景图像是预先绘制的,高度相同,宽度是条形的两倍,其中两段宽度为 50%,使用表示进度所需的颜色。因此,如果条形图为 50 像素,则背景图像为 100 像素,蓝色为 50 像素,黄色为 50 像素。

在我的示例中,我使用脚本从 div 中读取要显示的值,然后修改 css background-position-x 值以适当地移动图像。将其移至 x=0,条形图一切正常,移至 x= -25,您有 50/50 好/坏等。

如果您知道条的大小并且可以提前制作图像,并且从数据库生成页面时,那么您可以完全跳过脚本并在输出 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>

【讨论】:

    猜你喜欢
    • 2016-10-04
    • 2018-10-19
    • 1970-01-01
    • 2015-09-06
    • 2015-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多