简体   繁体   English

绘制 100 万个正方形的可点击网格

[英]Draw clickable grid of 1 million squares

I need to find a way to draw a 1000x1000 squares grid, each square is clickable and they must be independently color changeable.我需要找到一种方法来绘制一个 1000x1000 的正方形网格,每个正方形都是可点击的,并且它们必须可以独立地改变颜色。 Like mines game.像地雷游戏。 I can use HTML (pure or using Canvas or SVG), CSS and JavaScript for this.为此,我可以使用 HTML(纯或使用 Canvas 或 SVG)、CSS 和 JavaScript。

I know how to create one grid with these characteristics with JavaScript and CSS, it does well with 10x10 squares, with 100x100 the squares will turn into tall rectangles and 1000x1000 it loads, but the "squares" are soo much compressed that borders meet each other and renders a full gray page.我知道如何使用 JavaScript 和 CSS 创建一个具有这些特征的网格,它适用于 10x10 正方形,使用 100x100 正方形将变成高矩形并加载 1000x1000,但是“正方形”被压缩太多以至于边界彼此相遇并呈现一个完整的灰色页面。

I tried using HTML and JavaScript to draw SVG squares, the squares' size problem solves, but I don't know how to make they change color when clicked and when I set to load 1000x1000 squares it will freeze the browse and eventually crash the tab.我尝试使用 HTML 和 JavaScript 绘制 SVG 方块,方块的大小问题解决了,但我不知道如何让它们在单击时改变颜色,当我设置加载 1000x1000 方块时,它会冻结浏览并最终使选项卡崩溃.

Is this feasible in any way?这在任何方面都可行吗?

EDIT编辑

Sorry if I wasn't clear, but yes, I need scroll bars in that.对不起,如果我不清楚,但是是的,我需要滚动条。 They are no problem for me.他们对我来说没问题。

You can see the two trials I described here:你可以看到我在这里描述的两个试验:

JavaScript and CSS JavaScript 和 CSS

 var lastClicked; var grid = clickableGrid(100,100,function(el,row,col,i){ console.log("You clicked on element:",el); console.log("You clicked on row:",row); console.log("You clicked on col:",col); console.log("You clicked on item #:",i); el.className='clicked'; if (lastClicked) lastClicked.className=''; lastClicked = el; }); document.body.appendChild(grid); function clickableGrid( rows, cols, callback ){ var i=0; var grid = document.createElement('table'); grid.className = 'grid'; for (var r=0;r<rows;++r){ var tr = grid.appendChild(document.createElement('tr')); for (var c=0;c<cols;++c){ var cell = tr.appendChild(document.createElement('td')); ++i; cell.addEventListener('click',(function(el,r,c,i){ return function(){ callback(el,r,c,i); } })(cell,r,c,i),false); } } return grid; }
 .grid { margin:1em auto; border-collapse:collapse }.grid td { cursor:pointer; width:30px; height:30px; border:1px solid #ccc; }.grid td.clicked { background-color:gray; }

JavaScript and HTML JavaScript 和 HTML

 document.createSvg = function(tagName) { var svgNS = "http://www.w3.org/2000/svg"; return this.createElementNS(svgNS, tagName); }; var numberPerSide = 20; var size = 10; var pixelsPerSide = 400; var grid = function(numberPerSide, size, pixelsPerSide, colors) { var svg = document.createSvg("svg"); svg.setAttribute("width", pixelsPerSide); svg.setAttribute("height", pixelsPerSide); svg.setAttribute("viewBox", [0, 0, numberPerSide * size, numberPerSide * size].join(" ")); for(var i = 0; i < numberPerSide; i++) { for(var j = 0; j < numberPerSide; j++) { var color1 = colors[(i+j) % colors.length]; var color2 = colors[(i+j+1) % colors.length]; var g = document.createSvg("g"); g.setAttribute("transform", ["translate(", i*size, ",", j*size, ")"].join("")); var number = numberPerSide * i + j; var box = document.createSvg("rect"); box.setAttribute("width", size); box.setAttribute("height", size); box.setAttribute("fill", color1); box.setAttribute("id", "b" + number); g.appendChild(box); svg.appendChild(g); } } svg.addEventListener( "click", function(e){ var id = e.target.id; if(id) alert(id.substring(1)); }, false); return svg; }; var container = document.getElementById("container"); container.appendChild(grid(100, 10, 2000, ["gray", "white"]));
 <div id="container"> </div>

I will be trying implementing the given answers and ASAP I'll accept or update this question.我将尝试实施给定的答案,我会尽快接受或更新这个问题。 Thanks.谢谢。

SOLUTION解决方案

Just to record, I managed to do it using canvas to draw the grid and the clicked squares and added an event listener to know where the user clicks.只是为了记录,我设法使用 canvas 来绘制网格和单击的方块,并添加了一个事件侦听器以了解用户单击的位置。

Here is the code in JavaScript and HTML:这是 JavaScript 和 HTML 中的代码:

 function getSquare(canvas, evt) { var rect = canvas.getBoundingClientRect(); return { x: 1 + (evt.clientX - rect.left) - (evt.clientX - rect.left)%10, y: 1 + (evt.clientY - rect.top) - (evt.clientY - rect.top)%10 }; } function drawGrid(context) { for (var x = 0.5; x < 10001; x += 10) { context.moveTo(x, 0); context.lineTo(x, 10000); } for (var y = 0.5; y < 10001; y += 10) { context.moveTo(0, y); context.lineTo(10000, y); } context.strokeStyle = "#ddd"; context.stroke(); } function fillSquare(context, x, y){ context.fillStyle = "gray" context.fillRect(x,y,9,9); } var canvas = document.getElementById('myCanvas'); var context = canvas.getContext('2d'); drawGrid(context); canvas.addEventListener('click', function(evt) { var mousePos = getSquare(canvas, evt); fillSquare(context, mousePos.x, mousePos.y) }, false);
 <body> <canvas id="myCanvas" width="10000" height="10000"></canvas> </body>

Generating such a large grid with HTML is bound to be problematic. 用HTML生成如此大的网格肯定会有问题。 Drawing the grid on a Canvas and using a mouse-picker technique to determine which cell was clicked would be much more efficient. 在Canvas上绘制网格并使用鼠标选择器技术来确定单击哪个单元格会更有效。

This would require 1 onclick and/or hover event instead of 1,000,000. 这将需要1个onclick和/或悬停事件而不是1,000,000。 It also requires much less HTML code. 它还需要更少的HTML代码。

I wouldn't initialize all the squares right off, but instead as they are clicked - 我不会立即初始化所有正方形,而是点击它们 -

 (function() { var divMain = document.getElementById('main'), divMainPosition = divMain.getBoundingClientRect(), squareSize = 4, square = function(coord) { var x = coord.clientX - divMainPosition.x + document.body.scrollLeft + document.documentElement.scrollLeft, y = coord.clientY - divMainPosition.y + document.body.scrollTop + document.documentElement.scrollTop; return { x:Math.floor(x / squareSize), y:Math.floor(y / squareSize) } } divMain.addEventListener('click', function(evt) { var sqr = document.createElement('div'), coord = square(evt); sqr.className = 'clickedSquare'; sqr.style.width = squareSize + 'px'; sqr.style.height = squareSize + 'px'; sqr.style.left = (coord.x * squareSize) + 'px'; sqr.style.top = (coord.y * squareSize) + 'px'; sqr.addEventListener('click', function(evt) { console.log(this); this.parentNode.removeChild(this); evt.stopPropagation(); }); this.appendChild(sqr); }); }()); 
 #main { width:4000px; height:4000px; background-color:#eeeeee; position:relative; } .clickedSquare { background-color:#dd8888; position:absolute; } 
 <div id="main"> </div> 

  • Uses CSS positioning to determine which square was clicked on, 使用CSS定位来确定单击了哪个方块,
  • doesn't initialize a square until it's needed. 在需要之前不会初始化正方形。

Granted I imagine this would start to have a negative impact to use r experience, but that would ultimately depend on their browser and machine. 当然,我想这将开始对使用r体验产生负面影响,但这最终将取决于他们的浏览器和机器。

Use the same format you noramlly use, but add this: 使用您同时使用的相同格式,但添加以下内容:

sqauareElement.height = 10 //height to use
squareElement.width = 10 //width to use

This will add quite a large scroll due to the size, but it's the only logical explanation I can come up with. 由于尺寸的原因,这将添加相当大的滚动,但这是我能想出的唯一合理的解释。

The canvas approach is fine, but event delegation makes it possible to do this with a table or <div> elements with a single listener: canvas 方法很好,但是事件委托可以通过单个侦听器使用表或<div>元素来执行此操作:

 const tbodyEl = document.querySelector("table tbody"); tbodyEl.addEventListener("click", event => { const cell = event.target.closest("td"); if (.cell ||;tbodyEl.contains(cell)) { return; } const row = +cell.getAttribute("data-row"); const col = +cell.getAttribute("data-col"), console;log(row; col); }); const rows = 100; const cols = 100; for (let i = 0. i < rows; i++) { const rowEl = document.createElement("tr"); tbodyEl;appendChild(rowEl); for (let j = 0. j < cols; j++) { const cellEl = document.createElement("td"); rowEl.appendChild(cellEl). cellEl;classList.add("cell"). cellEl;dataset.row = i. cellEl;dataset.col = j; } }
 .cell { height: 4px; width: 4px; cursor: pointer; border: 1px solid black; } table { border-collapse: collapse; }
 <table><tbody></tbody></table>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM