Canvas 03
颜色
在前面的章节例子中,我们都是使用默认的线条和填充样式。
- fillStyle = color 设置图形填充颜色。
- strokeStyle = color 设置图形轮廓颜色。
color可以是css的颜色值,渐变对象和图案对象。 fillStyle属性例子
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 6; j++) {
ctx.fillStyle = `rgb(${Math.floor(255 - 42.5 * i)} ${Math.floor(
255 - 42.5 * j,
)} 0)`;
ctx.fillRect(j * 25, i * 25, 25, 25);
}
}
}
strokeStyle例子
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 6; j++) {
ctx.strokeStyle = `rgb(0 ${Math.floor(255 - 42.5 * i)} ${Math.floor(
255 - 42.5 * j,
)})`;
ctx.beginPath();
ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, 2 * Math.PI, true);
ctx.stroke();
}
}
}
透明度
- 通过设置globalAlpha属性控制绘制图形透明度。globalAlpha = transparencyValue
- 当然我们也可以通过设置fillStyle和strokeStyle的对应颜色值透明度效果。
ctx.strokeStyle = "rgb(255 0 0 / 50%)";
ctx.fillStyle = "rgb(255 0 0 / 50%)";
globalAlpha 示例 通过透明圆不断叠加,原先的源泉透明度会降低很多
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
// 画背景
ctx.fillStyle = "#FD0";
ctx.fillRect(0, 0, 75, 75);
ctx.fillStyle = "#6C0";
ctx.fillRect(75, 0, 75, 75);
ctx.fillStyle = "#09F";
ctx.fillRect(0, 75, 75, 75);
ctx.fillStyle = "#F30";
ctx.fillRect(75, 75, 75, 75);
ctx.fillStyle = "#FFF";
// 设置透明度值
ctx.globalAlpha = 0.2;
// 画半透明圆
for (let i = 0; i < 7; i++) {
ctx.beginPath();
ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true);
ctx.fill();
}
}
rgba()示例
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
// 画背景
ctx.fillStyle = "rgb(255 221 0)";
ctx.fillRect(0, 0, 150, 37.5);
ctx.fillStyle = "rgb(102 204 0)";
ctx.fillRect(0, 37.5, 150, 37.5);
ctx.fillStyle = "rgb(0 153 255)";
ctx.fillRect(0, 75, 150, 37.5);
ctx.fillStyle = "rgb(255 51 0)";
ctx.fillRect(0, 112.5, 150, 37.5);
// 画半透明矩形
for (let i = 0; i < 10; i++) {
ctx.fillStyle = `rgb(255 255 255 / ${(i + 1) / 10})`;
for (let j = 0; j < 4; j++) {
ctx.fillRect(5 + i * 14, 5 + j * 37.5, 14, 27.5);
}
}
}
线型
- lineWidth = value 设置线条宽度
- lineCap = type 设置线条末端样式 butt round square
- lineJoin = type 设置线条连接处样式 round bevel(三角) miter
- getLineDash() 返回一个包含当前虚线样式,长度为非负偶数的数组。
- lineDashOffset = value 设置虚线样式的起始偏移量。
lineWidth 属性的示例
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
for (let i = 0; i < 10; i++) {
ctx.lineWidth = 1 + i;
ctx.beginPath();
ctx.moveTo(5 + i * 14, 5);
ctx.lineTo(5 + i * 14, 140);
ctx.stroke();
}
}
我们会发现所有宽度为奇数的线条并没有精确的呈现,因为路径定位问题导致。 如果线条或者图形刚好落在画布的边界时,图像就会有清晰的边缘。 假设我们要绘制一条3,1到3,5的宽度为1.0的线条,实际canvas绘制的时候填充沿着中心线两边延伸一半。另外半个像素会以近似的方式进行渲染,意味这些像素只是部分着色,导致宽度为1.0的线条不准确的原因。 我们可以在宽1的线条,设置3.5,1和3.5,5两个连接点绘制线条,使其边缘正好落在像素边界上,保证填充准确的宽为1.0的线条。 像素网格和路径的位置关系,可以确保我们在缩放和变形时图像效果保持一致。 lineCap属性示例 默认butt
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
// 创建路径
ctx.strokeStyle = "#09f";
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(140, 10);
ctx.moveTo(10, 140);
ctx.lineTo(140, 140);
ctx.stroke();
// 画线条
ctx.strokeStyle = "black";
["butt", "round", "square"].forEach((lineCap, i) => {
ctx.lineWidth = 15;
ctx.lineCap = lineCap;
ctx.beginPath();
ctx.moveTo(25 + i * 50, 10);
ctx.lineTo(25 + i * 50, 140);
ctx.stroke();
});
}
lineJoin 属性的示例 默认是miter
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
ctx.lineWidth = 10;
["round", "bevel", "miter"].forEach((lineJoin, i) => {
ctx.lineJoin = lineJoin;
ctx.beginPath();
ctx.moveTo(-5, 5 + i * 40);
ctx.lineTo(35, 45 + i * 40);
ctx.lineTo(75, 5 + i * 40);
ctx.lineTo(115, 45 + i * 40);
ctx.lineTo(155, 5 + i * 40);
ctx.stroke();
});
}
miter会在两个线段连接处进行延伸至相交,效果收到miterLimit限制 miterLimit 属性示例 设置外延交点和连接点的最大距离,如果距离大于设置值,连接效果就会变成bevel。
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
// 清空画布
ctx.clearRect(0, 0, 150, 150);
// 绘制参考线
ctx.strokeStyle = "#09f";
ctx.lineWidth = 2;
ctx.strokeRect(-5, 50, 160, 50);
// 设置线条样式
ctx.strokeStyle = "#000";
ctx.lineWidth = 10;
// 检查输入
if (document.getElementById("miterLimit").checkValidity()) {
ctx.miterLimit = parseFloat(document.getElementById("miterLimit").value);
}
// 绘制线条
ctx.beginPath();
ctx.moveTo(0, 100);
for (let i = 0; i < 24; i++) {
const dy = i % 2 === 0 ? 25 : -25;
ctx.lineTo(Math.pow(i, 1.5) * 2, 75 + dy);
}
ctx.stroke();
return false;
}
虚线使用
使用setLineDash方法和lineDashOffset属性来控制我们绘制虚线的样式。 例子
const ctx = document.getElementById("canvas").getContext("2d");
let offset = 0;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setLineDash([4, 2]);
ctx.lineDashOffset = -offset;
ctx.strokeRect(10, 10, 100, 100);
}
function march() {
offset++;
if (offset > 5) {
offset = 0;
}
draw();
setTimeout(march, 20);
}
march();
渐变
我们可以使用线性或径向渐变效果来填充或描边我们的图像。 通过方式新建一个canvasGradient对象,然后赋值给图形的fillStyle或strokeStyle. createLinearGradient(x1, y1, x2, y2) createRadialGradient(x1, y1, r1, x2, y2, r2) 初始化出我们的canvasGradient对象后可以使用方法gradient.addColorStop(position, color)进行渐变上色。
var lineargradient = ctx.createLinearGradient(0, 0, 150, 150);
lineargradient.addColorStop(0, "white");
lineargradient.addColorStop(1, "black");
createLinearGradient示例
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
// 创建渐变
const linGrad = ctx.createLinearGradient(0, 0, 0, 150);
linGrad.addColorStop(0, "#00ABEB");
linGrad.addColorStop(0.5, "#fff");
linGrad.addColorStop(0.5, "#26C000");
linGrad.addColorStop(1, "#fff");
const linGrad2 = ctx.createLinearGradient(0, 50, 0, 95);
linGrad2.addColorStop(0.5, "#000");
linGrad2.addColorStop(1, "rgb(0 0 0 / 0%)");
// assign gradients to fill and stroke styles
ctx.fillStyle = linGrad;
ctx.strokeStyle = linGrad2;
// 画图形
ctx.fillRect(10, 10, 130, 130);
ctx.strokeRect(50, 50, 50, 50);
}
createRadialGradient示例
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
// 创建渐变
var radgrad = ctx.createRadialGradient(45, 45, 10, 52, 50, 30);
radgrad.addColorStop(0, "#A7D30C");
radgrad.addColorStop(0.9, "#019F62");
radgrad.addColorStop(1, "rgba(1,159,98,0)");
var radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50);
radgrad2.addColorStop(0, "#FF5F98");
radgrad2.addColorStop(0.75, "#FF0188");
radgrad2.addColorStop(1, "rgba(255,1,136,0)");
var radgrad3 = ctx.createRadialGradient(95, 15, 15, 102, 20, 40);
radgrad3.addColorStop(0, "#00C9FF");
radgrad3.addColorStop(0.8, "#00B5E2");
radgrad3.addColorStop(1, "rgba(0,201,255,0)");
var radgrad4 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90);
radgrad4.addColorStop(0, "#F4F201");
radgrad4.addColorStop(0.8, "#E4C700");
radgrad4.addColorStop(1, "rgba(228,199,0,0)");
// 画图形
ctx.fillStyle = radgrad4;
ctx.fillRect(0, 0, 150, 150);
ctx.fillStyle = radgrad3;
ctx.fillRect(0, 0, 150, 150);
ctx.fillStyle = radgrad2;
ctx.fillRect(0, 0, 150, 150);
ctx.fillStyle = radgrad;
ctx.fillRect(0, 0, 150, 150);
}
图案样式
createPattern(image, type) image表示Image对象的引用或者canvas对象,部分浏览器存在兼容问题可能不支持canva对象。 type的可选值 repeat repeat-x repeat-y no-repeat
我们在设置图案样式前,需要确保图像已经加载完成后再使用。 createPattern示例
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
// 创建新 image 对象,用作图案
const img = new Image();
img.src = "canvas_create_pattern.png";
img.onload = () => {
// 创建图案
const pattern = ctx.createPattern(img, "repeat");
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, 150, 150);
};
}
阴影
- shadowOffsetX = float 正值阴影向右延伸
- shadowOffsetY = float 正值阴影向下延伸
- shadowBlur = float 阴影的模糊程度
- shadowColor = color
文字阴影示例
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 2;
ctx.shadowColor = "rgb(0 0 0 / 50%)";
ctx.font = "20px Times New Roman";
ctx.fillStyle = "Black";
ctx.fillText("Sample String", 5, 30);
}
canvas填充规则
你可以选择一个填充规则,从而根据某个路径与某个路径里面或外面是否被填充,这对于自己与自己路径相交或者路径被嵌套时使用。 例如同心圆的绘制。 可选的两个值 nonzero (默认)、evenodd(奇偶环绕规则) 示例(中间镂空的同心圆)
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
ctx.beginPath();
ctx.arc(50, 50, 30, 0, Math.PI * 2, true);
ctx.arc(50, 50, 15, 0, Math.PI * 2, true);
ctx.fill("evenodd");
}
写在最后
未完待续… 希望大家好好生活,健康快乐。