我在开发中使用canvas的机会不是很多,但是第一次实际使用中就遇到了问题,“很久很久以前,我自己画了一个雷达图,线宽都是1像素,但是显示效果不如期望,这才发现canvas中的画线还是有坑的”,对比一下两个图,可以发现下图比较清晰。

我们先画一个线宽为1像素的线,代码和显示效果如下:

  const ctx = document.getElementById(canvas).getContext("2d");
ctx.strokeStyle = "red";
ctx.lineWidth =1;
ctx.moveTo(50, 10);
ctx.lineTo(200, 10);
ctx.stroke();

不对呀,这条线咋这么模糊,而且宽度貌似也不是1px

为了画这条线,浏览器首先到达初始起点(50,10)。这条线宽1px,所以两边各留0.5px。所以基本上初始起点是从(50,9.5)延伸到(50,10.5)。现在浏览器不能在屏幕上显示0.5像素——最小阈值是1像素。浏览器别无选择,只能将起点的边界延伸到屏幕上的实际像素边界。它会在两边再加0.5倍的“垃圾”。所以现在,最初的起点是从(50,9)扩展到(50,11),所以看起来有2px宽。情况如下:

下面是真实的2px宽的线,作为对照,可以发现,上面的线宽确实占据了2px,只是边缘显示非常模糊

那如何绘制1像素的线呢?本文总结了三种方法。

  • 将划线起始点移动到x.5的位置

既然1px宽的线是向两边各延伸0.5px,那如果我们的起点直接放在x.5的位置,向左右扩展则刚好占据1px,如下图所示:

修改代码

  ctx.moveTo(50, 10.5);
ctx.lineTo(200, 10.5);


上面的方法有个坏处是我们要修改现有的计算逻辑,时刻留意要多出0.5px

  • 绘制上下文整体移动x.5
    这个方法的好处是不扰乱我们的设计尺寸和计算逻辑,操作也很简单,只需要正常画好线后,上下文整体移动。
ctx.translate(0, 0.5);
  • 控制canvas元素大小与绘制上下文大小的比率

canvas有两个尺寸,一个是元素本身的css尺寸,一个是绘上下文的尺寸(画布的尺寸),默认情况下,canvas的画布尺寸和元素尺寸都是300*150.比率为1.画布尺寸是通过直接在元素上添加widthheight属性设置的,css尺寸则是通过css样式属性设置的,需要注意的是:

1.如果仅在元素上添加widthheight属性来设置画布尺寸,实际表现则同时设置了画布尺寸和css尺寸为相同的大小;
2.如果仅设置了css尺寸,则画布尺寸还是默认的300*150,并不会改变;
3.如果同时设置了画布尺寸和css尺寸,浏览器会缩放画布尺寸来适应css尺寸;

上面的第三条规则给我们画1px线宽提供了另一种方法,具体方法是设置canvas的画布尺寸是css尺寸的两倍,这样我们只需要按照两倍的设计尺寸(2px)来画线,这样就不会存在占用半个像素导致模糊的问题,浏览器会自动压缩画布到它的一半大小,原来2px的线宽会压缩显示成1px。

<canvas id="canvas5" width="600" height="300"> </canvas>
<canvas id="canvas6" width="600" height="300"> </canvas>
#canvas5 {
width: 300px;
height: 150px;
}
#canvas6 {
transform-origin: top left;
transform: scale(0.5);
}

如果想画出真实的物理1px的线,可以将画布尺寸继续放大widow.devicePixelRatio

参考
How to Draw 1px Crisp Lines in HTML5 Canvas

Canvas中如何画一条清晰的线宽为奇数(如1px逻辑像素)的线?的更多相关文章

  1. 有趣html5(两)----使用canvas结合剧本画在画布上的简单图(html5另一个强大)

    请珍惜劳动小编成果,这篇文章是原来小编,转载请注明出处. 于html5中能够使用canvas标签在画布上绘图,先直接上代码,这篇文章先简介一下canvas的用法.简单画几个圆,矩形,三角形,写字. 在 ...

  2. 根据多个点使用canvas贝赛尔曲线画一条平滑的曲线

    众所周知想用canvas画一条曲线我们可以使用这些函数: 二次曲线:quadraticCurveTo(cp1x, cp1y, x, y) 贝塞尔曲线:bezierCurveTo(cp1x, cp1y, ...

  3. HTML5在canvas中绘制复杂形状附效果截图

    HTML5在canvas中绘制复杂形状附效果截图 一.绘制复杂形状或路径 在简单的矩形不能满足需求的情况下,绘图环境提供了如下方法来绘制复杂的形状或路径. beginPath() : 开始绘制一个新路 ...

  4. Html5新特性 &lt;canvas&gt;画板画直线

     以下样例为用canvas标签画多条直线 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" & ...

  5. <canvas>中isPointInPath()方法在不同绘制内容中的效果

    <canvas>是HTML5中新增加的一个元素,我们可以使用脚本(通常使用JavaScript)在上面绘制图形,就像个画布一样.我们可以用它来绘制图表.制作一些动画.默认大小为300px ...

  6. HTML5 在canvas中绘制复杂形状

    作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/32942667 一.绘制复杂形状或路径 在简单的矩形不能满足需求的情况下,画图环 ...

  7. Canvas中的save方法和restore方法

    初学者也许会误认为canvas中save方法是用来保存绘图状态的图形,而restore方法是用来还原之前保存的绘图状态的图形,其实不然. save():保存当前的绘图状态. restore():恢复之 ...

  8. 浅谈HTML5中canvas中的beginPath()和closePath()的重要性

    beginPath的作用很简单,就是开始一段新的路径,但在使用canvas绘图的过程中却非常重要 先来看一小段代码: var ctx=document.getElementById("can ...

  9. Canvas中的非零围绕规则原理

    非零围绕规则:对于路径中指定范围区域,从该区域内部画一条足够长的线段.使此线段的全然落在路径范围之外. 非零围绕规则计数器:然后,将计数器初始化为0,每当这个线段与路径上的直线或曲线相交时,就改变计数 ...

随机推荐

  1. Codeforces 1092C Prefixes and Suffixes(思维)

    题目链接:Prefixes and Suffixes 题意:给定未知字符串长度n,给出2n-2个字符串,其中n-1个为未知字符串的前缀(n-1个字符串长度从1到n-1),另外n-1个为未知字符串的后缀 ...

  2. 【php】php7新特性及其优化原理

    php7.x版本系列相比之前的php的版本提交性能提高了不少,这里面其中的一些主要改变是性能提高的关键,主要有以下内容. 1.zval使用栈内存   在zend引擎和扩展中,经常要创建php变量,其底 ...

  3. (转)学习HTML5 Canvas这一篇文章就够了

    作者:做人要厚道2013 原文:https://blog.csdn.net/u012468376/article/details/73350998

  4. 编写高质量的Python代码系列(七)之协作开发

    如果多个人要开发同一个Python程序,那就得仔细商量代码的写法了.即使你是一个人开发,也需要理解其他人所写的模块.本节讲解多人协作开发Python程序时所用的标准工具及最佳做法. 第四十九条:为每个 ...

  5. Maven 学习总结 (六) 之 版本

    版本管理 版本管理是指项目整体版本的演变过程管理.版本控制是指借助版本控制工具(如Subversion)追踪代码的每一个变更. 为了方便团队合作,项目开发过程中,大家应该使用快照版本,快照版本机制促进 ...

  6. C#之C#、.NET Framework、CLR的关系

    转自 https://www.cnblogs.com/cocoon/p/4997005.html 补补基础: 很多人没有将C#..NET Framework(.NET框架).CLR(Common La ...

  7. 移动开发day2_css预处理器_flex布局

    css预处理器 一种技术,可以提高编写css代码的技术而已. 有3种预处理器常见 less sass stylues less使用流程 编写符合less语法的less文件 使用工具 将less编译成 ...

  8. trackerClient.getConnection()为null

    如题,整了个fastDFS文件服务器.但是集成项目spring boot时上传文件失败! Debug到trackerClient.getConnection()时为null.于是看了服务器上track ...

  9. webpack-dev-server live reloading 技术实现

    webpack-dev-server  live reloading https://github.com/webpack/webpack-dev-server Use webpack with a ...

  10. PHP带参数传值调用python脚本

    PHP主要用在服务器端做网站后台开发,有些功能用PHP来实现有点费劲或者无法实现,现在在学习python,同样是脚本语言,感觉python能做的事情PHP不一定能胜任.但是现在大部分的网站后台也是用P ...