在我们开始画图之前,我们需要了解一下画布栅格(canvas grid)以及坐标空间。canvas 的栅格的起点为左上角(坐标为 (0, 0))。
index.html 文件:
DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Cartesian coordinate systemtitle>
<link href="css/main.css" rel="stylesheet">
head>
<body>
<canvas id="ccs">canvas>
<script src="js/main.js">script>
body>
html>
main.css 文件:
#ccs {
box-shadow: 0px 0px 2px 1px rgba(0, 0, 0, 0.4);
}
main.js 文件:
window.onload = (event) => {
// console.log(event);
main();
}
function main() {
const ccs = document.querySelector("#ccs");
// 设置画布的宽高
ccs.width = 400;
ccs.height = 400;
// console.dir(ccs);
const ccsContext = ccs.getContext("2d");
// 画直线
ccsContext.beginPath();
ccsContext.moveTo(0, 0); // 画笔的起点
ccsContext.lineTo(100, 100); // 画笔的终点,第一个参数表示向左移动 100 像素,,第二个参数表示向下移动 100 像素
ccsContext.stroke();
}
画布的起点默认在左上角(坐标为 (0, 0)),我们可以使用 CanvasRenderingContext2D.translate()
方法平移画布的起点,使其在画布居中,这样比较符合直角坐标系的风格,但还是有点区别。
编辑 main.js 文件:
window.onload = (event) => {
// console.log(event);
main();
}
function main() {
const ccs = document.querySelector("#ccs");
// 设置画布的宽高
ccs.width = 400;
ccs.height = 400;
// console.dir(ccs);
const ccsContext = ccs.getContext("2d");
// 使画布的起点向左移动 ccs.width / 2 像素,向下移动 ccs.height / 2 像素,使其起点位于画布中心
ccsContext.translate(ccs.width / 2, ccs.height / 2);
// 画直线
ccsContext.beginPath();
ccsContext.moveTo(0, 0); // 画笔的起点
ccsContext.lineTo(100, 100); // 画笔的终点,第一个参数表示向左移动 100 像素,,第二个参数表示向下移动 100 像素
ccsContext.stroke();
}
编辑 main.js 文件:
window.onload = (event) => {
// console.log(event);
main();
}
function main() {
const ccs = document.querySelector("#ccs");
// 设置画布的宽高
ccs.width = 400;
ccs.height = 400;
// console.dir(ccs);
const ccsContext = ccs.getContext("2d");
// 使画布的起点向左移动 ccs.width / 2 像素,向下移动 ccs.height / 2 像素,使其起点位于画布中心
ccsContext.translate(ccs.width / 2, ccs.height / 2);
// 画空心三角形
ccsContext.beginPath();
ccsContext.moveTo(0, 0); // 画笔的起点
ccsContext.lineTo(50, 50); // 第二个点
ccsContext.lineTo(0, 100); // 第三个点
ccsContext.closePath(); // 闭合路径。你可以注释它,看看变化
ccsContext.stroke();
}
编辑 main.js 文件:
注意:当你调用
fill()
函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用closePath()
函数。但是调用stroke()
时不会自动闭合。
window.onload = (event) => {
// console.log(event);
main();
}
function main() {
const ccs = document.querySelector("#ccs");
// 设置画布的宽高
ccs.width = 400;
ccs.height = 400;
// console.dir(ccs);
const ccsContext = ccs.getContext("2d");
// 使画布的起点向左移动 ccs.width / 2 像素,向下移动 ccs.height / 2 像素,使其起点位于画布中心
ccsContext.translate(ccs.width / 2, ccs.height / 2);
// 画实心三角形
ccsContext.beginPath();
ccsContext.moveTo(0, 0); // 画笔的起点
ccsContext.lineTo(50, 50); // 第二个点
ccsContext.lineTo(0, 100); // 第三个点
ccsContext.fill();
}
学会怎么画直线和三角形之后,我们就可以开始画直角坐标系!
编辑 main.js 文件:
window.onload = (event) => {
// console.log(event);
main();
}
function main() {
const ccs = document.querySelector("#ccs");
// 设置画布的宽高
ccs.width = 400;
ccs.height = 400;
// console.dir(ccs);
const ccsContext = ccs.getContext("2d");
// 使画布的起点向左移动 ccs.width / 2 像素,向下移动 ccs.height / 2 像素,使其起点位于画布中心
ccsContext.translate(ccs.width / 2, ccs.height / 2);
// 画 x 正半轴
drawLine(ccsContext, 0, 0, ccs.width / 2, 0);
// 画 x 正半轴上的刻度
const offset = 20;
for (let i = 0; i < ccs.width / 2 / offset; i++) {
drawLine(ccsContext, offset * i, 0, offset * i, 5);
}
// 画 x 正半轴的箭头
strokeTriangle(ccsContext, ccs.width / 2 - 10, 5, ccs.width / 2, 0, ccs.width / 2 - 10, -5);
// 画 x 负半轴
drawLine(ccsContext, 0, 0, -ccs.width / 2, 0);
// 画 x 负半轴上的刻度
for (let i = 0; i < ccs.width / 2 / offset; i++) {
drawLine(ccsContext, -offset * i, 0, -offset * i, 5);
}
// 画 y 正半轴
drawLine(ccsContext, 0, 0, 0, ccs.height / 2);
// 画 y 正半轴上的刻度
for (let i = 0; i < ccs.height / 2 / offset; i++) {
drawLine(ccsContext, 0, offset * i, 5, offset * i);
}
// 画 y 正半轴的箭头
fillTriangle(ccsContext, 5, ccs.height / 2 - 10, 0, ccs.height / 2, -5, ccs.height / 2 - 10);
// 画 y 负半轴
drawLine(ccsContext, 0, 0, 0, -ccs.height / 2);
// 画 y 负半轴上的刻度
for (let i = 0; i < ccs.height / 2 / offset; i++) {
drawLine(ccsContext, 0, -offset * i, 5, -offset * i);
}
}
function drawLine(canvasContext, x0, y0, x1, y1) {
canvasContext.beginPath();
canvasContext.moveTo(x0, -y0);
canvasContext.lineTo(x1, -y1);
canvasContext.stroke();
}
function fillTriangle(canvasContext, x0, y0, x1, y1, x2, y2) {
canvasContext.beginPath();
canvasContext.moveTo(x0, -y0);
canvasContext.lineTo(x1, -y1);
canvasContext.lineTo(x2, -y2);
canvasContext.closePath();
canvasContext.fill();
}
function strokeTriangle(canvasContext, x0, y0, x1, y1, x2, y2) {
canvasContext.beginPath();
canvasContext.moveTo(x0, -y0);
canvasContext.lineTo(x1, -y1);
canvasContext.lineTo(x2, -y2);
canvasContext.closePath();
canvasContext.stroke();
}
编辑 main.js 文件,显示鼠标在画布中的坐标(见第 58 ~ 89 行):
window.onload = (event) => {
// console.log(event);
main();
}
function main() {
const ccs = document.querySelector("#ccs");
// 设置画布的宽高
ccs.width = 400;
ccs.height = 400;
// console.dir(ccs);
const ccsContext = ccs.getContext("2d");
// 使画布的起点向左移动 ccs.width / 2 像素,向下移动 ccs.height / 2 像素,使其起点位于画布中心
ccsContext.translate(ccs.width / 2, ccs.height / 2);
// 画 x 正半轴
drawLine(ccsContext, 0, 0, ccs.width / 2, 0);
// 画 x 正半轴上的刻度
const offset = 20;
for (let i = 0; i < ccs.width / 2 / offset; i++) {
drawLine(ccsContext, offset * i, 0, offset * i, 5);
}
// 画 x 正半轴的箭头
strokeTriangle(ccsContext, ccs.width / 2 - 10, 5, ccs.width / 2, 0, ccs.width / 2 - 10, -5);
// 画 x 负半轴
drawLine(ccsContext, 0, 0, -ccs.width / 2, 0);
// 画 x 负半轴上的刻度
for (let i = 0; i < ccs.width / 2 / offset; i++) {
drawLine(ccsContext, -offset * i, 0, -offset * i, 5);
}
// 画 y 正半轴
drawLine(ccsContext, 0, 0, 0, ccs.height / 2);
// 画 y 正半轴上的刻度
for (let i = 0; i < ccs.height / 2 / offset; i++) {
drawLine(ccsContext, 0, offset * i, 5, offset * i);
}
// 画 y 正半轴的箭头
fillTriangle(ccsContext, 5, ccs.height / 2 - 10, 0, ccs.height / 2, -5, ccs.height / 2 - 10);
// 画 y 负半轴
drawLine(ccsContext, 0, 0, 0, -ccs.height / 2);
// 画 y 负半轴上的刻度
for (let i = 0; i < ccs.height / 2 / offset; i++) {
drawLine(ccsContext, 0, -offset * i, 5, -offset * i);
}
// 创建一个元素,用于显示鼠标在画布中的坐标
const span = document.createElement("span");
span.innerText = new Date().toString();
span.style.setProperty("display", "none");
span.style.setProperty("box-shadow", "0px 0px 2px 1px rgba(0, 0, 0, 0.4)");
span.style.setProperty("padding", "0px 5px");
span.style.setProperty("position", "fixed");
document.body.appendChild(span);
// 添加鼠标在画布中移动的监听事件
ccs.addEventListener("mousemove", (event) => {
// console.log(event);
console.log(event.layerX, event.layerY);
// console.dir(span);
span.innerText = event.layerX + ", " + event.layerY; // 鼠标在画布中的坐标
span.style.setProperty("display", "inline");
});
// 添加鼠标在 document 中移动的监听事件
document.onmousemove = (event) => {
console.log(event);
console.log(event.clientX, event.clientY);
if (event.toElement !== ccs) {
span.style.setProperty("display", "none");
} else {
span.style.setProperty("top", (event.clientY + 10) + "px");
span.style.setProperty("left", (event.clientX + 10) + "px");
}
}
}
function drawLine(canvasContext, x0, y0, x1, y1) {
canvasContext.beginPath();
canvasContext.moveTo(x0, -y0);
canvasContext.lineTo(x1, -y1);
canvasContext.stroke();
}
function fillTriangle(canvasContext, x0, y0, x1, y1, x2, y2) {
canvasContext.beginPath();
canvasContext.moveTo(x0, -y0);
canvasContext.lineTo(x1, -y1);
canvasContext.lineTo(x2, -y2);
canvasContext.closePath();
canvasContext.fill();
}
function strokeTriangle(canvasContext, x0, y0, x1, y1, x2, y2) {
canvasContext.beginPath();
canvasContext.moveTo(x0, -y0);
canvasContext.lineTo(x1, -y1);
canvasContext.lineTo(x2, -y2);
canvasContext.closePath();
canvasContext.stroke();
}
从以上效果可以看到,显示的坐标是鼠标在画布中的坐标,而不是鼠标在直角坐标系中的坐标:
编辑 main.js 文件,显示鼠标在直角坐标系中的坐标(见第 16 行):
window.onload = (event) => {
// console.log(event);
main();
}
function main() {
// 其他保持不变...
// 添加鼠标在画布中移动的监听事件
ccs.addEventListener("mousemove", (event) => {
// console.log(event);
console.log(event.layerX, event.layerY);
// console.dir(span);
// span.innerText = event.layerX + ", " + event.layerY; // 鼠标在画布中的坐标
span.innerText = `${event.layerX - ccs.width / 2}, ${-(event.layerY - ccs.height / 2)}`; // 鼠标在直角坐标系中的坐标
span.style.setProperty("display", "inline");
});
// 其他保持不变...
}
// 其他保持不变...
Web technology for developers > Web APIs > Canvas API > Canvas tutorial > Drawing shapes with canvas
Web technology for developers > Web APIs > CanvasRenderingContext2D > CanvasRenderingContext2D.translate()