Javascript 在Web浏览器中创建可单击的网格

Javascript 在Web浏览器中创建可单击的网格,javascript,html,canvas,Javascript,Html,Canvas,我想在HTML5画布上绘制一个由10 x 10个正方形组成的网格,正方形上显示数字1-100。单击一个方块应该调用一个JavaScript函数,并将方块的数字作为变量传递给该函数。首先,我建议您阅读涉及HTML5画布的另一个问题。你需要明白没有正方形。为了检测对“正方形”的点击,您必须跟踪从每个画布坐标到其逻辑上包含的正方形的映射,处理整个画布上的单击事件,确定要更改的正方形,然后使用所需更改重新绘制画布 既然您似乎不反对使用更合适的技术,我鼓励您使用HTML(其中每个“正方形”类似于,使用CS

我想在HTML5画布上绘制一个由10 x 10个正方形组成的网格,正方形上显示数字1-100。单击一个方块应该调用一个JavaScript函数,并将方块的数字作为变量传递给该函数。

首先,我建议您阅读涉及HTML5画布的另一个问题。你需要明白没有正方形。为了检测对“正方形”的点击,您必须跟踪从每个画布坐标到其逻辑上包含的正方形的映射,处理整个画布上的单击事件,确定要更改的正方形,然后使用所需更改重新绘制画布

既然您似乎不反对使用更合适的技术,我鼓励您使用HTML(其中每个“正方形”类似于
,使用CSS绝对定位、调整大小和颜色)或SVG(如果您需要正方形能够旋转,或者希望引入其他形状,请使用

HTML和SVG都是“保留模式”图形模式系统,其中绘制形状“保留”了该形状的概念。您可以移动形状、更改其颜色、大小等,计算机将自动为您重新绘制。此外,更重要的是,对于您的用例,您可以(使用HTML和SVG):


编辑:我用JavaScript和HTML创建了一个简单的实现:

以下是JSFIDLE关闭时的核心代码:

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'));
      cell.innerHTML = ++i;
      cell.addEventListener('click',(function(el,r,c,i){
        return function(){ callback(el,r,c,i); }
       })(cell,r,c,i),false);
    }
  }
  return grid;
}
函数clickableGrid(行、列、回调){
var i=0;
var grid=document.createElement('table');
grid.className='grid';

对于(var r=0;rEDIT):使用HTML元素而不是在画布上绘制这些东西或使用SVG是另一种选择,而且可能更可取

按照Phrogz的建议,请参见此处了解SVG实现:

document.createSvg=函数(标记名){
var svgNS=”http://www.w3.org/2000/svg";
返回此.createElements(svgNS,标记名);
};
var numberPerSide=20;
变量大小=10;
var pixelsPerSide=400;
var grid=函数(数字版本、大小、像素版本、颜色){
var svg=document.createSvg(“svg”);
setAttribute(“宽度”,pixelsPerSide);
setAttribute(“高度”,pixelsPerSide);
setAttribute(“viewBox”,[0,0,numberPerSide*size,numberPerSide*size].join(“”);
对于(变量i=0;i
如图所示,如果这是您的全部设计内容,那么在HTML/CSS中执行此操作是最简单的,但下面是一个使用画布作为备选方案的示例,供那些用例在画布中可能更有意义的人使用(并与HTML/CSS并置)

问题的第一步归结为找出用户鼠标在画布中的位置,这需要知道画布元素的偏移量。这与相同,因此在这方面画布没有什么独特之处。我使用
event.offsetX/Y
来完成这一点

在画布上绘制网格相当于行和列的嵌套循环。使用
tileSize
变量来控制步长。基本数学可以计算出哪个tile(坐标和/或单元格编号)您的鼠标基于宽度和高度以及行和列的值处于中。请使用
上下文。填充…
方法来编写文本和绘制正方形。我将所有内容都保留为0索引以确保其完整性,但您可以在显示之前将其标准化为最后一步(不过,不要在逻辑中混合使用1索引)

最后,添加到canvas元素以检测鼠标动作,这将触发鼠标位置和选定平铺的重新计算,并重新渲染画布。我将大部分逻辑附加到mousemove,因为它更易于可视化,但如果您选择,相同的代码适用于单击事件

记住下面的方法并不是特别有意识的;当光标在单元格之间移动时,我只重新渲染,但是部分重新绘制或移动叠加来显示突出显示的元素会更快(如果可用的话)。我忽略了很多微优化。

constdrawgrid=(画布、ctx、tileSize、highlightNum)=>{
对于(让y=0;yfunction 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'));
      cell.innerHTML = ++i;
      cell.addEventListener('click',(function(el,r,c,i){
        return function(){ callback(el,r,c,i); }
       })(cell,r,c,i),false);
    }
  }
  return grid;
}
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);
          var text = document.createSvg("text");
          text.appendChild(document.createTextNode(i * numberPerSide + j));
          text.setAttribute("fill", color2);
          text.setAttribute("font-size", 6);
          text.setAttribute("x", 0);
          text.setAttribute("y", size/2);
          text.setAttribute("id", "t" + number);
          g.appendChild(text);
          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(5, 10, 200, ["red", "white"]));
container.appendChild(grid(3, 10, 200, ["white", "black", "yellow"]));
container.appendChild(grid(7, 10, 200, ["blue", "magenta", "cyan", "cornflowerblue"]));
container.appendChild(grid(2, 8, 200, ["turquoise", "gold"]));