我需要制作一个简单的条形进度指示器 - 实际上我只需要一个条形图,其中绿色部分表示良好的数量,而另一个颜色部分表示不良金额和百分比良好的位置在条形图中间。假设条宽50px,高15px。想想静态进度条,如下例所示。
我在使用jquery和背景div之前已经完成了这个操作,其中2个div位于其上方,用于好的和坏的指示符,然后是位于其上方的div以显示文本。
但是我想知道是否有更简单的HTML5画布,SVG或CSS解决方案。由于这个timy控件将出现在长表的每一行中,目的是减少对DOM的污染,并提高可读性和可重用性。
我知道有些图书馆会这样做,但我想用它作为学习经验。解决方案应该是无脚本,或者只有JS,或者是带有jquery的JS。
编辑:感谢积极的投入人士。我在下面的答案中提出了我自己的解决方案和工作片段,因为我认为值得单独参加投票等等。没有人提出过SVG解决方案 - 任何接受者?我的道具形象:
编辑2:3到目前为止优秀的解决方案(加上我的)。事实证明这是一个非常有趣的周末挑战。还有吗?
编辑 - 选择的答案:为了结束,我选择并回答了奖励积分。但是,所有提出的答案在不同情况下似乎都是可行的。就我的目的而言,Le Beau先生基于SVG的答案是最佳的。我选择的参数是我最初在服务器上进行页面标记,因此可以设置渲染条形所需的所有值而无需执行代码。后来我允许更改完成百分比,我用ajax发布到服务器和简单的jquery来更新文本和栏覆盖。
我希望HTML5进度标记的回答能够让这个问题变得多余,但是我们可能会再次坐在开发人员家的甲板上,然后喝着鸡尾酒(也许)。
谢谢大家的努力。
答案 0 :(得分:3)
这是与您的产品相当的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>
&#13;
答案 1 :(得分:2)
编辑:添加了静态解决方案
我能想出的最低限度是:
// 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 :(得分:2)
您可以使用progress元素:
<progress max="100" value="0" />
难以造型,但易于使用:
var i=0;
setInterval(function(){
document.getElementsByTagName("progress")[0].value=++i;
},100);
答案 3 :(得分: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,那么这只是一个非常简单的例子......
答案 4 :(得分:0)
这是我自己的产品。请注意,脚本的很大一部分是从画布生成透明背景图像,您可能不需要这样做。
该技术使用每个条形的单个div,一些用于样式的标准CSS和单个图像。
条形背景图像以相同的高度和条形宽度的两倍预先绘制,两个线条宽度的50%使用表示进度所需的颜色。因此,如果条形图为50像素,则背景图像为100像素,例如50像素蓝色和50像素黄色。
在我的例子中,我使用脚本来读取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.
}
&#13;
.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;
}
&#13;
<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>
&#13;