Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

canvas绘制圆环进度条出现模糊效果解决方案 #204

Open
confidence68 opened this issue Jun 14, 2016 · 1 comment
Open

canvas绘制圆环进度条出现模糊效果解决方案 #204

confidence68 opened this issue Jun 14, 2016 · 1 comment

Comments

@confidence68
Copy link
Owner

问题

近期用canvas绘制了圆环进度条,但是进度条出现周围模糊的现象,针对这种现象,网上搜了搜,有人提问,但是貌似没有很好的解决方案,针对这种情况,提出几种解决方案,仅供参考!
模糊效果如下:

<iframe style="width: 100%; height: 250px" src="http://sandbox.runjs.cn/show/moptpafm" allowfullscreen="allowfullscreen" frameborder="0"></iframe>

解决方案

针对这种情况,我提出几种解决思路。

一、运用hidpi-canvas-polyfill 的js进行解决

HiDPI Canvas Polyfill 是针对设备提出的canvas高清解决方案,首先引入hidpi-canvas.js。

这个js会自动识别你的canvas,会把你的canvas变小,虽然不模糊了,但是不是我们想要的效果。(可以结合后面的方法进行改进)

关于hidpi-canvas-polyfill 地址:https://github.com/jondavidjohn/hidpi-canvas-polyfill

具体使用方法大家可以看他的描述。在这里就不展开讲解了。

缺点: 这种方式虽然可以解决,但是感觉毕竟要引入一些js还有,进行自动化识别中,canvas可能会变小,还有,他会自动给canvas加了一个宽高,这些在一定情况下不是我们想要的。

二、指定默认宽高法

这种方式在一定程度上,可以解决我说的模糊问题。将上面模糊的代码进行如下改进。

<canvas id="pczren" data-process="70" width="250" height="250"></canvas>

canvas指定一个宽高,然后半径只要小于250/2就可以。中心点坐标直接是canvas的宽高除以2。

代码如下:

var pczren = document.getElementById('pczren');
var mprocess = pczren.getAttribute('data-process');
var mctx = pczren.getContext('2d');
var Wc = pczren.width;
var Hc = pczren.height;

function draw(ctx, process, colors, fco) {
    // 画灰色的圆
    ctx.beginPath();
    ctx.arc(Wc/2, Hc/2,100, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fillStyle = fco;
    ctx.fill();
    // 画进度环
    ctx.beginPath();
    ctx.moveTo(Wc/2, Hc/2);
    ctx.arc(Wc/2, Hc/2, 100, Math.PI * 2.5, Math.PI * (2.5 + 2 * process / 100));
    ctx.closePath();
    ctx.fillStyle = colors;
    ctx.fill();
    // 画内填充圆
    ctx.beginPath();
    ctx.arc(Wc/2, Hc/2, 80, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fillStyle = '#fff';
    ctx.fill();
}
draw(mctx, mprocess, '#53b48d', '#edecec');

效果图如下:

<iframe style="width: 100%; height: 250px" src="http://sandbox.runjs.cn/show/vjmsqz7e" allowfullscreen="allowfullscreen" frameborder="0"></iframe>

三、canvas替代法

当然,这种方法不是我们想要的,在没有办法的情况下,我们可以选择替代方案来解决这个问题,我们可以想象,除了用canvas绘制圆环进度条之外,我们有没有其他方式呢?例如css3+jquery方案,css3方案等等。

3.1css3+jquery方案

html如下:

<div class="circle" style="left:220px">
    <div class="pie_left"><div class="left"></div></div>
    <div class="pie_right"><div class="right"></div></div>
    <div class="mask"><span>15</span>%</div>
</div>

css如下:

body {
            font-family: "微软雅黑";
        }
        .circle {
            width: 200px;
            height: 200px;
            position: absolute;
            border-radius: 50%;
            background: #0cc;
        }
        .pie_left, .pie_right {
            width:200px; 
            height:200px;
            position: absolute;
            top: 0;left: 0;
        }
        .left, .right {
            width:200px; 
            height:200px;
            background:#00aacc;
            border-radius: 50%;
            position: absolute;
            top: 0;
            left: 0;
        }
        .pie_right, .right {
            clip:rect(0,auto,auto,100px);
        }
        .pie_left, .left {
            clip:rect(0,100px,auto,0);
        }
        .mask {
            width: 150px;
            height: 150px;
            border-radius: 50%;
            left: 25px;
            top: 25px;
            background: #FFF;
            position: absolute;
            text-align: center;
            line-height: 150px;
            font-size: 20px;
            font-weight: bold;
            color: #00aacc;
        }

jquery如下:

$(function() {
            $('.circle').each(function(index, el) {
                var num = $(this).find('span').text() * 3.6;
                if (num<=180) {
                    $(this).find('.right').css('transform', "rotate(" + num + "deg)");
                } else {
                    $(this).find('.right').css('transform', "rotate(180deg)");
                    $(this).find('.left').css('transform', "rotate(" + (num - 180) + "deg)");
                };
            });

        });

上述代码可以实现圆环进度条!

3.2 css方案

**方法一:**用图片方式,n张图片,不停的background-position位置变化,模拟1%到100%的情况!

方法二:

圆环css写法如下:

.circleprogress{
    width: 160px;
    height: 160px;
    border:20px solid red;
    border-radius: 50%;
}

不完整的圆如下写法:

.circleprogress{
  width: 160px;
  height: 160px;
  border:20px solid red;
  border-left:20px solid transparent;
  border-bottom:20px solid transparent;
  border-radius: 50%;
}

但是不是45度角的倍数怎么办呢?如下代码可以用css动画实现进度条效果!

  .circleProgress_wrapper{
  width: 200px;
  height: 200px;
  margin: 50px auto;
  position: relative;
  border:1px solid #ddd;
}
.wrapper{
  width: 100px;
  height: 200px;
  position: absolute;
  top:0;
  overflow: hidden;
}
.right{
  right:0;
}
.left{
  left:0;
}
.circleProgress{
  width: 160px;
  height: 160px;
  border:20px solid rgb(232, 232, 12);
  border-radius: 50%;
  position: absolute;
  top:0;
  -webkit-transform: rotate(45deg);
}
.rightcircle{
  border-top:20px solid green;
  border-right:20px solid green;
  right:0;
  -webkit-animation: circleProgressLoad_right 5s linear infinite;
}
.leftcircle{
  border-bottom:20px solid green;
  border-left:20px solid green;
  left:0;
  -webkit-animation: circleProgressLoad_left 5s linear infinite;
}
@-webkit-keyframes circleProgressLoad_right{
  0%{
    border-top:20px solid #ED1A1A;
    border-right:20px solid #ED1A1A;
    -webkit-transform: rotate(45deg);
  }
  50%{
    border-top:20px solid rgb(232, 232, 12);
    border-right:20px solid rgb(232, 232, 12);
    border-left:20px solid rgb(81, 197, 81);
    border-bottom:20px solid rgb(81, 197, 81);
    -webkit-transform: rotate(225deg);
  }
  100%{
    border-left:20px solid green;
    border-bottom:20px solid green;
    -webkit-transform: rotate(225deg);
  }
}
@-webkit-keyframes circleProgressLoad_left{
  0%{
    border-bottom:20px solid #ED1A1A;
    border-left:20px solid #ED1A1A;
    -webkit-transform: rotate(45deg);
  }
  50%{
    border-bottom:20px solid rgb(232, 232, 12);
    border-left:20px solid rgb(232, 232, 12);
    border-top:20px solid rgb(81, 197, 81);
    border-right:20px solid rgb(81, 197, 81);
    -webkit-transform: rotate(45deg);
  }
  100%{
    border-top:20px solid green;
    border-right:20px solid green;
    border-bottom:20px solid green;
    border-left:20px solid green;
    -webkit-transform: rotate(225deg);
  }
}

实现效果如下:

<iframe style="width: 100%; height: 250px" src="http://sandbox.runjs.cn/show/ur8yrqge" allowfullscreen="allowfullscreen" frameborder="0"></iframe>

小结

上面提出了几种解决canvas绘制圆环出现模糊效果的解决方案,大家有什么其他更好的办法可以留言提出,相互交流。文章原创,转载务必联系注明!

@saury
Copy link

saury commented Jun 30, 2016

如果不考虑ie,可以使用svg通过stroke-dasharray配合css来绘制,这是目前我个人使用下来最好的方法。
另外css+jquery的方案存在不少问题,在页面存在多个环或其他动画同时进行时,会有卡顿甚至是左右环没有平滑衔接上的问题,这应该是客户端性能的问题;而在非retina屏的情况下,进度环的动画在某些情况下,比如stroke的值比较小(可能是因为值存在半像素可能性的缘故)时,rotate并没有严格按照圆心来运动(此时设置transform-original为center也无济于事),甚至会有溢出容器现象(明明设置了overflow hidden,但并没有什么用),尽管除了性能问题,我都做了相应的work round尽可能解决了这些问题,但还是不太推荐使用。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants