image.png
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="myCanvas" width="1080" height="630"></canvas>
</body>
</html>
<script>
class MyRect {
constructor(x, y, width, height) { // 相對(duì)坐標(biāo)拥娄,指相對(duì)于pageSlicePos的坐標(biāo)
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
draw(ctx, x, y, width, height) { // 真正繪制用像素坐標(biāo)
ctx.save();
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + width, y);
ctx.lineTo(x + width, y + height);
ctx.lineTo(x, y + height);
ctx.closePath();
ctx.fillStyle = "#000";
ctx.fill();
ctx.restore();
}
}
// 當(dāng)前 canvas 的 0 0 坐標(biāo)最仑,我們?cè)O(shè)置 canvas 左上角頂點(diǎn)為 0 0窟勃,向右??和向下??是 X Y 軸正方向,0,0 為 pageSlicePos 初始值
const pageSlicePos = {
x: 0,
y: 0,
};
var scale = 10; // 縮放比例
const solidColor = '#999'; // 實(shí)線(xiàn)顏色
const dashedColor = '#ccc'; // 虛線(xiàn)顏色
const zeroColor = '#358bf3'; // 0 點(diǎn)坐標(biāo)系顏色
const myCanvas = document.querySelector('#myCanvas');
const GRIDSIZE = 5; // 一個(gè)正方形網(wǎng)格的寬高大小, 一個(gè)GRIDSIZE視為一個(gè)單位
const ctx = myCanvas.getContext('2d');
myCanvas.addEventListener("mousedown", mouseDown);
myCanvas.addEventListener("mousewheel", mouseWheel);
let features = [
new MyRect(50, 50, 10, 10),
];
setInterval(() => {
drawLineGrid();
drawFeature();
}, 0);
/**
* 繪制網(wǎng)格
* @param scaleVal 縮放倍數(shù)
*/
var drawLineGrid = (scaleVal = scale) => {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
/*獲取繪圖工具*/
// 設(shè)置網(wǎng)格大小
var girdSize = getPixelSize(GRIDSIZE);
// 獲取Canvas的width之剧、height
var CanvasWidth = ctx.canvas.width;
var CanvasHeight = ctx.canvas.height;
// 在 pageSlicePos 的 x够吩,y 點(diǎn)位畫(huà)一個(gè) 10 * 10 的紅色標(biāo)記用來(lái)表示當(dāng)前頁(yè)面的 0 0 坐標(biāo)
ctx.fillRect(pageSlicePos.x, pageSlicePos.y, 10, 10); // 效果圖紅色小方塊
ctx.fillStyle = 'red';
const canvasXHeight = CanvasHeight - pageSlicePos.y;
const canvasYWidth = CanvasWidth - pageSlicePos.x;
// 從 pageSlicePos.y 處開(kāi)始往 Y 軸正方向畫(huà) X 軸網(wǎng)格
const xPageSliceTotal = Math.ceil(canvasXHeight / girdSize);
for (let i = 0; i < xPageSliceTotal; i++) {
ctx.beginPath(); // 開(kāi)啟路徑,設(shè)置不同的樣式
ctx.moveTo(0, pageSlicePos.y + girdSize * i);
ctx.lineTo(CanvasWidth, pageSlicePos.y + girdSize * i);
ctx.strokeStyle = i === 0 ? zeroColor : (i % 5 === 0 ? solidColor : dashedColor); // 如果為 0 則用藍(lán)色標(biāo)記囤攀,取余 5 為實(shí)線(xiàn)软免,其余為比較淡的線(xiàn)
ctx.stroke();
}
// 從 pageSlicePos.y 處開(kāi)始往 Y 軸負(fù)方向畫(huà) X 軸網(wǎng)格
const xRemaining = pageSlicePos.y;
const xRemainingTotal = Math.ceil(xRemaining / girdSize);
for (let i = 0; i < xRemainingTotal; i++) {
if (i === 0) continue;
ctx.beginPath(); // 開(kāi)啟路徑,設(shè)置不同的樣式
ctx.moveTo(0, pageSlicePos.y - girdSize * i); // -0.5是為了解決像素模糊問(wèn)題
ctx.lineTo(CanvasWidth, pageSlicePos.y - girdSize * i);
ctx.strokeStyle = i === 0 ? zeroColor : (i % 5 === 0 ? solidColor : dashedColor);// 如果為 0 則用藍(lán)色標(biāo)記焚挠,取余 5 為實(shí)線(xiàn)膏萧,其余為比較淡的線(xiàn)
ctx.stroke();
}
// 從 pageSlicePos.x 處開(kāi)始往 X 軸正方向畫(huà) Y 軸網(wǎng)格
const yPageSliceTotal = Math.ceil(canvasYWidth / girdSize); // 計(jì)算需要繪畫(huà)y軸的條數(shù)
for (let j = 0; j < yPageSliceTotal; j++) {
ctx.beginPath(); // 開(kāi)啟路徑,設(shè)置不同的樣式
ctx.moveTo(pageSlicePos.x + girdSize * j, 0);
ctx.lineTo(pageSlicePos.x + girdSize * j, CanvasHeight);
ctx.strokeStyle = j === 0 ? zeroColor : (j % 5 === 0 ? solidColor : dashedColor);// 如果為 0 則用藍(lán)色標(biāo)記蝌衔,取余 5 為實(shí)線(xiàn)榛泛,其余為比較淡的線(xiàn)
ctx.stroke();
}
// 從 pageSlicePos.x 處開(kāi)始往 X 軸負(fù)方向畫(huà) Y 軸網(wǎng)格
const yRemaining = pageSlicePos.x;
const yRemainingTotal = Math.ceil(yRemaining / girdSize);
for (let j = 0; j < yRemainingTotal; j++) {
if (j === 0) continue;
ctx.beginPath(); // 開(kāi)啟路徑,設(shè)置不同的樣式
ctx.moveTo(pageSlicePos.x - girdSize * j, 0);
ctx.lineTo(pageSlicePos.x - girdSize * j, CanvasHeight);
ctx.strokeStyle = j === 0 ? zeroColor : (j % 5 === 0 ? solidColor : dashedColor);// 如果為 0 則用藍(lán)色標(biāo)記噩斟,取余 5 為實(shí)線(xiàn)曹锨,其余為比較淡的線(xiàn)
ctx.stroke();
}
};
/**
* 滾輪縮放倍數(shù)
*/
function mouseWheel(e) {
if (e.wheelDelta > 0) {
if (scale < 10) {
scale++;
}
} else {
if (scale > 1) {
scale--;
}
}
}
/**
* 拖動(dòng) canvas 動(dòng)態(tài)渲染,拖動(dòng)時(shí)剃允,動(dòng)態(tài)設(shè)置 pageSlicePos 的值
* @param e Event
*/
function mouseDown(e) {
const downX = e.clientX;
const downY = e.clientY;
const { x, y } = pageSlicePos;
myCanvas.onmousemove = (ev) => {
const moveX = ev.clientX;
const moveY = ev.clientY;
pageSlicePos.x = x + (moveX - downX);
pageSlicePos.y = y + (moveY - downY);
myCanvas.onmouseup = (en) => {
myCanvas.onmousemove = null;
myCanvas.onmouseup = null;
};
}
myCanvas.onmouseup = (en) => {
myCanvas.onmousemove = null;
myCanvas.onmouseup = null;
};
}
function getPixelPos(block) { // 獲取實(shí)際像素坐標(biāo)
return {
x: pageSlicePos.x + (block.x / GRIDSIZE) * scale, // block.x:起點(diǎn)x沛简, block.x / GRIDSIZE 表示多少個(gè)單位長(zhǎng)度, (block.x / GRIDSIZE) * scale 表示實(shí)際像素寬度斥废;pageSlicePos.x + (block.x / GRIDSIZE) * scale 表示距原點(diǎn)x方向多少距離開(kāi)始繪制
y: pageSlicePos.y + (block.y / GRIDSIZE) * scale, // 同上
};
}
// function getRelativePos(block) { // 獲取相對(duì)的坐標(biāo)椒楣,同理反推
// return {
// x: ((block.x - pageSlicePos.x) / scale) * GRIDSIZE,
// y: ((block.y - pageSlicePos.y) / scale) * GRIDSIZE,
// };
// }
function getPixelSize(size) { // 獲取實(shí)際像素大小
return size * scale;
}
// function getRelativeSize(size) { // 獲取相對(duì)大小
// return size / scale;
// }
function getPixelPosAndWH(block) { // 元素的像素坐標(biāo)和大小
let { x, y } = getPixelPos(block);
var width = getPixelSize(block.width);
var height = getPixelSize(block.height);
return { x, y, width, height, }
}
// function getRelativePosAndWH(x1, y1, width1, height1, block) { // 元素的絕對(duì)坐標(biāo)和大小
// let { x, y } = getRelativePos(
// { x: x1, y: y1 }, block
// );
// let width = getRelativeSize(width1, block)
// let height = getRelativeSize(height1, block)
// return { x, y, width, height }
// }
function drawFeature() {
features.forEach(f => {
let { x, y, width, height } = getPixelPosAndWH(f); // 獲取實(shí)際像素坐標(biāo)和大小, 真正繪制肯定是以實(shí)際像素繪制
f.draw(ctx, x, y, width, height)
})
}
drawLineGrid();
</script>
學(xué)習(xí)更多canvas高級(jí)技巧,可以訪(fǎng)問(wèn)我的課堂: https://www.bilibili.com/cheese/play/ss19337