爱生活,爱编程,学习使我快乐
【出现条件】:这种情况一般是垂直或者水平的线,且坐标为整数,宽度不是偶数。
【解决方法】:坐标偏移0.5像素。
下面我们看个例子
var dom = document.querySelector("#canvas1");
var ctx = dom.getContext('2d');
ctx.strokeStyle = '#000';
// 正常画线(坐标为整数,线宽为1px),1像素画出的效果像2像素。
ctx.lineWidth = 1;
ctx.moveTo(30, 50);
ctx.lineTo(30, 200);
ctx.stroke();
// 处理之后(坐标偏移0.5像素),线条宽度正常。
ctx.lineWidth = 1;
ctx.moveTo(50.5, 50);
ctx.lineTo(50.5, 200);
ctx.stroke();
效果如下图(在PS中放大后效果)
【实例解析】
1. 指定坐标为30px时,实际是以30px为中心向两边各画一半(0.5px),会画在30px前后的两个像素格子中。又因为像素是最小单位,所以30px前后的两个像素都被画了1px的线,但是颜色要比实际的谈一些。
如上图所示,从左到右宽分别是1.3px、0.8px、0.5px、0.1px。上面4条以整数为坐标的线宽度其实是2px,下面4条X坐标都偏移了0.5px。效果更接近预期的宽度。
以上所说的偏移0.5px,其实并不准确。因为上面例子中,坐标都是整数。
更准确的说法应该是: 当线宽为偶数时,坐标应指定为整数。否则坐标应指定为整数+0.5px。
这里以竖线为例,横线同理
// 封装一个画线的方法
function drawLine (ctx, x, y1, y2, width) {
// 当线宽为偶数时,坐标应指定为整数。否则坐标应指定为整数+0.5px。
let newx = width % 2 === 0 ? Math.floor(x) : Math.floor(x) + 0.5;
ctx.lineWidth = width;
ctx.moveTo(newx, y1);
ctx.lineTo(newx, y2);
}
ctx.beginPath();
ctx.strokeStyle = '#000';
drawLine (ctx, 350, 250, 380, 1);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = '#000';
drawLine (ctx, 360, 250, 380, 2);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = '#000';
drawLine (ctx, 370.4, 250, 380, 1.3);
ctx.stroke();
具体效果请看canvas画线条源码中,右下角的三根线。
想了解更多canvas画线问题的解析,请稳步到 canvas中画线条,线条效果比预期宽1像素且模糊问题分析及解决方案
语法:context.rect(x,y,width,height)
参数 | 描述 |
---|---|
x | 矩形左上角的 x 坐标。 |
y | 矩形左上角的 y 坐标。 |
width | 矩形的宽度,以像素计。 |
height | 矩形的高度,以像素计。 |
语法:context.arc(x,y,r,sAngle,eAngle,counterclockwise)
参数 | 描述 |
---|---|
x | 圆的中心的 x 坐标。 |
y | 圆的中心的 y 坐标。 |
r | 圆的半径。 |
sAngle | 起始角,以弧度计(弧的圆形的三点钟位置是 0 度)。 |
eAngle | 结束角,以弧度计。 |
counterclockwise | 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。 |
语法:context.moveTo(x,y)
参数 | 描述 |
---|---|
x | 路径的目标位置的 x 坐标。 |
y | 路径的目标位置的 y 坐标。 |
语法:context.lineTo(x,y)
参数 | 描述 |
---|---|
x | 路径的目标位置的 x 坐标。 |
y | 路径的目标位置的 y 坐标。 |
语法:context.arcTo(x1,y1,x2,y2,r)
参数 | 描述 |
---|---|
x1 | 两切线交点的横坐标。 |
y1 | 两切线交点的纵坐标。 |
x2 | 第二条切线上一点的横坐标。 |
y2 | 第二条切线上一点的纵坐标。 |
r | 弧的半径。 |
【分析方案】
方案1:圆弧(arc)+ 线(moveTo+lineTo)画矩形。
分析:可以实现画圆角矩形,不过需要反复多次调用以上API(要画8条线),性能略差。
方案2:使用两个切线之间的弧(arcTo)结合moveTo画矩形。
分析:可以实现画圆角矩形,并且调用API较少(只画4条线)。【推荐】
更详细的分析说明请移步到 在Canvas中绘制圆角矩形及逐步分析过程
// 入参说明:上下文、左上角X坐标,左上角Y坐标,宽,高,圆角的半径
function arcRect (ctx, x, y, w, h, r) {
// 右上角弧线
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + r, r);
// 右下角弧线
ctx.moveTo(x + w, y + r);
ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
// 左下角弧线
ctx.moveTo(x + w - r, y + h);
ctx.arcTo(x, y + h, x, y + h - r, r);
// 左上角弧线
ctx.moveTo(x, y + h - r);
ctx.arcTo(x, y, x + r, y, r);
}
该代码实现的效果如下图
圆角矩形画好后,具体是要路径(外框),还是要填充。只需要分别使用
stroke()
和fill()
方法实现即可。
1.1、阴影相关属性如下:
属性 | 描述 |
---|---|
shadowColor | 设置或返回用于阴影的颜色。 |
shadowBlur | 设置或返回用于阴影的模糊级别。 |
shadowOffsetX | 设置或返回阴影与形状的水平距离。 |
shadowOffsetY | 设置或返回阴影与形状的垂直距离 |
1.2、clip()方法
clip()方法从原始画布中剪切任意形状和尺寸。
提示:一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内(不能访问画布上的其他区域)。您也可以在使用 clip() 方法前通过使用 save() 方法对当前画布区域进行保存,并在以后的任意时间对其进行恢复(通过 restore() 方法)。
给闭合线(如:矩形、圆等)设置阴影,然后把线以及线外部的阴影裁切掉,只留线内部的阴影。从而达到内阴影效果。
1、shadowBlur值越大,范围变大,但阴影也更模糊。
2、线越宽,阴影越清晰。
3、所有这两个属性相结合一起控制【内阴影】的大小。
ctx.strokeStyle = '#f00';
ctx.lineWidth = 7;
// 单独内阴影
rectInnerShadow(ctx, 80, 40, 200, 120);
// 矩形框和内阴影一起时,要先画内阴影
rectInnerShadow(ctx, 20, 230, 150, 120);
ctx.strokeRect(20, 230, 150, 120);
// 否则会有重叠(因为线是向两侧画的)
ctx.strokeRect(220, 230, 150, 120);
rectInnerShadow(ctx, 220, 230, 150, 120);
// 【矩形内阴影(边框+阴影,再把边框和外阴影裁剪掉)】
// 参数说明:ctx上下文内容,x,y,w,h同rect的入参,shadowColor阴影颜色,shadowBlur和lineWidth一同控制阴影大小。
function rectInnerShadow (ctx, x, y, w, h, shadowColor, shadowBlur, lineWidth) {
var shadowColor = shadowColor || '#00f'; // 阴影颜色
var lineWidth = lineWidth || 20; // 边框越大,阴影越清晰
var shadowBlur = shadowBlur || 30; // 模糊级别,越大越模糊,阴影范围也越大。
ctx.save();
ctx.beginPath();
// 裁剪区(只保留内部阴影部分)
ctx.rect(x, y, w, h);
ctx.clip();
// 边框+阴影
ctx.beginPath();
ctx.lineWidth = lineWidth;
ctx.shadowColor = shadowColor;
ctx.shadowBlur = shadowBlur;
// 因线是由坐标位置向两则画的,所以要移动起点坐标位置,和加大矩形。
ctx.strokeRect(x - lineWidth/2, y - lineWidth/2 , w + lineWidth, h + lineWidth);
// 取消阴影
ctx.shadowBlur = 0;
ctx.restore();
}
效果如下图(点击查看源代码)
更多内阴影相关内容,请稳步到 在Canvas中实现内阴影效果