如何修复HTML5画布中模糊的形状边缘? [英] How do I fix blurry shape edges in HTML5 canvas?

查看:264
本文介绍了如何修复HTML5画布中模糊的形状边缘?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用canvas元素制作了一个非常简单的矩形。但是,如果fillRect(x,y,width,height)中x和y的参数是除0和0之外的任何其他任何值,则在放大和/或移动设备上时,所有边看起来完全模糊。如果x和y为0和0,则矩形的顶部和左侧边缘是超级定义的,即使放大,但底部和右侧边缘模糊不清。我使用Chrome浏览器/ Firefox以及750x1334移动屏幕使用Safari将其渲染到1920x1080屏幕。



在桌面上放大到100%时,这不是问题, ,但在移动设备上,它看起来像垃圾。如果您完全放大Chrome和Firefox以及





解决方案

我找出了错在哪里。它是设备的设备像素比率属性。除了 1 的值以外的任何内容都会导致像素化的画布内容。在浏览器中调整缩放比例会改变设备像素比率,并且某些设备具有较高的设备像素比率,例如视网膜显示屏iPhone。

您必须使用Javascript对此进行解释。没有其他办法。 我在博客上更详细地写了这篇文章,并提供了其他一些资源。

您可以在下面看到最终结果。



使用vanilla JavaScript的响应式画布

var aWrapper = document.getElementById(aWrapper); var canvas = document.getElementById(myCanvas); //为我们的canvasdfdfvar访问2D渲染上下文ctx = canvas.getContext(2d); function setCanvasScalingFactor(){return window.devicePixelRatio || 1;} function resizeCanvas(){//获取devicePixelRatio var pixelRatio = setCanvasScalingFactor(); //视口处于纵向模式,因此var width应该基于viewport WIDTH if(window.innerHeight> window.innerWidth){//使画布100%的视口宽度var width = Math.round(1.0 * window.innerWidth); } //视口处于横向模式,因此var width应该基于视口HEIGHT else {//使画布100%的视口高度var width = Math.round(1.0 * window.innerHeight); } //这样做是为了保持1:1的宽高比,根据需要进行调整var height = width; //当devicePixelRatio>>时,这将用于缩放画布元素。 1 aWrapper.style.width = width +px; aWrapper.style.height = height +px; canvas.width = width * pixelRatio; canvas.height = height * pixelRatio;} var cascadeFactor = 255; var cascadeCoefficient = 1; function draw(){//颜色块列数和行数var columns = 5; var rows = 5; //每个square的长度var length = Math.round(canvas.width / columns) - 2; //根据cascadeCoefficient cascadeFactor + = cascadeCoefficient;将cascadeFactor增加或减少1; //确保画布在一帧的开始处是干净的ctx.clearRect(0,0,canvas.width,canvas.height); for(var i = columns; i> = 1; i--){for(var j = rows; j> = 1; j--){//发生颜色魔法的地方ctx.fillStyle =rgba( +(j * i *(cascadeFactor-110))+,+(i * cascadeFactor)+,+(j * cascadeFactor)+,+ 0.6 +); ctx.fillRect((length *(i-1))+((i-1)* 2),(length *(j-1))+((j-1)* 2),length,length) }} if(cascadeFactor> 255 || cas​​cadeFactor< 0){//重置颜色级联cascadeCoefficient = -cascadeCoefficient; } //继续调用draw()直到取消var aRequest = window.requestAnimationFrame(draw);} window.addEventListener(resize,resizeCanvas,false); resizeCanvas(); draw();

< div id = aWrapper > <! - 包含您的用户浏览器不支持canvas的0.00001%机率的一些回退内容 - > < canvas id =myCanvas>后备内容< / canvas>< / div>


I made a very simple rectangle using the canvas element. However, if the arguments for x and y in fillRect(x, y, width, height) are ANYTHING other than 0 and 0, all of the edges look completely blurry when zoomed in and/or on mobile devices. If x and y ARE 0 and 0, the top and left edges of the rectangle are super defined, even if zoomed in, while the bottom and right edges are blurry. I am rendering this on a 1920x1080 screen using Chrome/Firefox as well as a 750x1334 mobile screen using Safari.

This isn't a problem on desktop when zoomed at 100%, but on mobile devices it looks like crap. And you can clearly see the blurry edges if you zoom in fully on Chrome and Firefox as well as JSFiddle. I'm NOT adjusting width and height on the canvas using CSS. It's done using the canvas attributes and/or JS. The HTML I used to test this on browsers is below.

<!DOCTYPE html>
<html>
    <head>
         <meta charset="utf-8">
         <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    </head>

    <body>
         <canvas id="gameCanvas" width="150" height="150">A game.</canvas>

         <script>
             var canvas = document.getElementById("gameCanvas");
             var ctx = canvas.getContext("2d");

             ctx.fillRect(0, 0, 100, 100);
         </script>
    </body>
</html>

Edit: I'm NOT trying to draw a 1 pixel line. I tried experimenting with half pixel values as well but it made the blurry edges alot worse.

The first two screenshots are from an iPhone 7 screen on Safari, non-zoomed and zoomed, respectively. The last screenshot is on a 1920x1080 laptop screen, zoomed in on Chrome.

解决方案

I figured out what was wrong. It was the device-pixel-ratio property of the device. Anything other than a value of 1 would result in pixelated canvas content. Adjusting the zoom in a browser alters device-pixel-ratio, and some devices come with a high device-pixel-ratio such as retina display iPhones.

You have to account for this using Javascript. There is no other way. I wrote about this in more detail on my blog, and provide some other sources as well.

You can see the final result below.

Responsive canvas using vanilla JavaScript:

var aWrapper = document.getElementById("aWrapper");
var canvas = document.getElementById("myCanvas");

//Accesses the 2D rendering context for our canvasdfdf
var ctx = canvas.getContext("2d");

function setCanvasScalingFactor() {
   return window.devicePixelRatio || 1;
}

function resizeCanvas() {
    //Gets the devicePixelRatio
    var pixelRatio = setCanvasScalingFactor();

    //The viewport is in portrait mode, so var width should be based off viewport WIDTH
    if (window.innerHeight > window.innerWidth) {
        //Makes the canvas 100% of the viewport width
        var width = Math.round(1.0 * window.innerWidth);
    }
  //The viewport is in landscape mode, so var width should be based off viewport HEIGHT
    else {
        //Makes the canvas 100% of the viewport height
        var width = Math.round(1.0 * window.innerHeight);
    }

    //This is done in order to maintain the 1:1 aspect ratio, adjust as needed
    var height = width;

    //This will be used to downscale the canvas element when devicePixelRatio > 1
    aWrapper.style.width = width + "px";
    aWrapper.style.height = height + "px";

    canvas.width = width * pixelRatio;
    canvas.height = height * pixelRatio;
}

var cascadeFactor = 255;
var cascadeCoefficient = 1;

function draw() {
  //The number of color block columns and rows
  var columns = 5;
  var rows = 5;
  //The length of each square
  var length = Math.round(canvas.width/columns) - 2;
  
  //Increments or decrements cascadeFactor by 1, based on cascadeCoefficient
  cascadeFactor += cascadeCoefficient;

  //Makes sure the canvas is clean at the beginning of a frame
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  for (var i = columns; i >= 1; i--) {  
    for (var j = rows; j >= 1; j--) {
      //Where the color magic happens
      ctx.fillStyle = "rgba(" + (j*i*(cascadeFactor-110)) + "," + (i*cascadeFactor) + "," + (j*cascadeFactor) + "," + 0.6 + ")";
        
      ctx.fillRect((length*(i-1)) + ((i-1)*2), (length*(j-1)) + ((j-1)*2), length, length);
    }
  }
  
  if (cascadeFactor > 255 || cascadeFactor < 0) {
    //Resets the color cascade
    cascadeCoefficient = -cascadeCoefficient;
  }
  //Continuously calls draw() again until cancelled
  var aRequest = window.requestAnimationFrame(draw);
}

window.addEventListener("resize", resizeCanvas, false);

resizeCanvas();
draw();

#aWrapper {
    /*Horizontally centers the canvas*/
    margin: 0 auto;
}

#myCanvas {
    /*This eliminates inconsistent rendering across browsers, canvas is supposed to be a block-level element across all browsers anyway*/
    display: block;

    /*myCanvas will inherit its CSS width and style property values from aWrapper*/
    width: 100%;
    height: 100%;
}
asdfasdf

<div id="aWrapper">
    <!--Include some fallback content on the 0.00001% chance your user's browser doesn't support canvas -->
    <canvas id="myCanvas">Fallback content</canvas>
</div> 

这篇关于如何修复HTML5画布中模糊的形状边缘?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆