javascript - 如何将多维数组映射到html画布中的矩形网格?
问题描述
有一个大小为 12 x 12 的矩形网格,其中每个角都可以点击,即 12*12 网格的每个角有 6*3 个单元格(单击任何 4 个角应选择 6*3 个单元格)。
我创建了一个大小为 12*12 的多维数组,它将由 0 表示。根据角落用户选择相应的 6*3 单元格将变为 1。如何通过 html 画布显示这个概念?那是如何以网格的形式表示这个数组,我也希望选择网格的角,即那些变成 1 的单元格以不同的颜色表示。
addBed = (x,y) => {let test = Array(12).fill(0).map(x => Array(12).fill(0));
let bedX = 3, bedY = 6; // BED AREA = 6*3
let dx = 1, dy = 1;
let endX = bedX, endY = bedY;
const roomX = 11, roomY = 11
if(x === roomX) {
dx = -1
endX = roomX-bedX
}
if (y === roomY) {
dy = -1
endY = roomY-bedY
}
for(let i = x; dx === 1 ? i < endX : i > endX; i += dx) {
for(let j = y; dy === 1 ? j < endY: j > endY; j += dy) {
test[i][j] = 1;
}
}
console.log(test)
// this.setState({ testMap: test });
}
addBed(0,0); // this will make the first corner to be turned to 1
解决方案
这就是我的做法:我会使用一维单元格数组。
我还将创建可单击单元格的数组,其中包含单元格数组中的索引以及单击时要绘制的相应扩展矩形。
请阅读我的代码中的注释。
let ctx = room.getContext("2d");
let cw = room.width = 300;//the width of the canvas
let ch = room.height = 300;//the height of the canvas
let size = 25;//the size of every cell
let rows = 12;//number of rows
let cols = 12;//number of columns
// initiate the cells array
let cells = new Array(cols*rows);
// the clickable cells: the index in the cells array and the extended rect position (x,y) and size (w,h)
let clickble = [
{index:0, rect:{x:0,y:0,w:size*3,h:size*6}},
{index:11, rect:{x:300-size*3,y:0,w:size*3,h:size*6}},
{index:12*11, rect:{x:0,y:300-size*6,w:size*3,h:size*6}},
{index:12*12-1, rect:{x:300-size*3,y:300-size*6,w:size*3,h:size*6}}
]
// fill the cells array with values
for (y = 0; y <= rows; y++) {
for (x = 0; x < cols; x++) {
let index = x + y * cols;
let cell = {}
cell.x = x*size;
cell.y = y*size;
cells[index] = cell;
}
}
//draw every cell in the grid of cells
cells.forEach((c,i)=>{
ctx.beginPath();
ctx.strokeRect(c.x,c.y,size,size);
})
// mark the cells clickble
clickble.forEach(c=>{ctx.fillRect(cells[c.index].x,cells[c.index].y,size,size);})
// when clicking on the canvas
room.addEventListener("click",(evt)=>{
//get the mouse position
let m = oMousePos(room, evt);
for(let i = 0; i < clickble.length; i++ ){
let cell = cells[clickble[i].index];
ctx.beginPath();
//get the extended rect
ctx.rect(cell.x,cell.y,size,size);
// if the click happened inside one of the clickable cells
if (ctx.isPointInPath(m.x, m.y)){
let rect = clickble[i].rect;
// draw the extended rect
ctx.beginPath();
ctx.fillStyle = "red";
ctx.fillRect(rect.x,rect.y,rect.w,rect.h);
//breack the loop. No need to search further
break;}
}
})
// a function to detect the mouse position on the canvas
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return {
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
<canvas id="room"></canvas>
更新
OP正在评论:
我需要所有 4 个角,但是这取决于用户选择要单击哪个角,单击一个角后,他将无法单击另一个角。
在这种情况下,我在前面的代码中添加了一个全局变量let clicked = false;
:还没有点击任何角落。
当用户单击一个角clicked = true;
而不能单击其他角时。
if (ctx.isPointInPath(m.x, m.y)){
clicked = true;
................
因为点击时只会发生if(!clicked)
room.addEventListener("click",(evt)=>{
if(!clicked){...........}
let ctx = room.getContext("2d");
let cw = room.width = 300;
let ch = room.height = 300;
let size = 25;
let rows = 12;
let cols = 12;
let clicked = false;
let cells = new Array(cols*rows)
// the clickables cells: the index in the cells array and the extended rect position (x,y) and size (w,h)
let clickbles = [
{index:0, rect:{x:0,y:0,w:size*3,h:size*6}},
{index:11,rect:{x:300-size*3,y:0,w:size*3,h:size*6}},
{index:12*11,rect:{x:0,y:300-size*6,w:size*3,h:size*6}},
{index:12*12-1,rect:{x:300-size*3,y:300-size*6,w:size*3,h:size*6}}
]
//draw the grid of cells
for (y = 0; y <= rows; y++) {
for (x = 0; x < cols; x++) {
let index = x + y * cols;
let cell = {}
cell.x = x*size;
cell.y = y*size;
cells[index] = cell;
}
}
cells.forEach((c,i)=>{
ctx.beginPath();
ctx.strokeRect(c.x,c.y,size,size);
})
// mark the cells clickbles
clickbles.forEach(c=>{ctx.fillRect(cells[c.index].x,cells[c.index].y,size,size);})
// when clicking on the canvas
room.addEventListener("click",(evt)=>{
if(!clicked){
//get the mouse position
let m = oMousePos(room, evt);
for(let i = 0; i < clickbles.length; i++ ){
let cell = cells[clickbles[i].index];
let rect = clickbles[i].rect;
ctx.beginPath();
ctx.rect(cell.x,cell.y,size,size);
// if the click happened inside one of the clickables cells
if (ctx.isPointInPath(m.x, m.y)){
clicked = true;
// draw the extended rect
ctx.beginPath();
ctx.fillStyle = "red";
ctx.fillRect(rect.x,rect.y,rect.w,rect.h);
//breack the loop. No need to search further
break;}
}
}
})
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return {
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
<canvas id="room"></canvas>
我希望这是你要问的
推荐阅读
- excel - Power Query:如何将查询与为返回的每一行运行一个查询连接
- sqlite - 随机排序
- php - 基于对缓存对象的引用查询文档
- typeorm - 基于图信息的动态关系
- visual-studio-code - 如何配置 vscode 以便它识别我的构建导入?
- android - 如何从firebase中的嵌套节点检索数据
- excel - 使用任务计划程序运行 VBS 文件以启动 Excel VBA 宏
- gridview - 在 GridView 列中显示来自不同对象的值
- angular - 如何防止 Observable 错误传播?
- mysql - Mysql 多对多关系。过滤完全匹配