繁体   English   中英

在画布中通过for循环创建形状

[英]Create shapes by for loop in canvas

编辑:我将我所有的代码发布为html和js,请原谅我太多评论

我正在尝试通过for循环在画布上创建矩形(有输入用户),我想在另一个函数中访问它们来做一些事情,主要的问题是循环后如何访问形状的名称,但是我尝试了在给我的另一个函数中调用它们

未定义的“对象名称”

 var canvas = document.querySelector('canvas'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; var c = document.getElementById("myCanvas"); //drawing the base off the towers var base_twr1 = c.getContext("2d"); base_twr1.beginPath(); base_twr1.moveTo(550, 500); base_twr1.lineTo(300, 500); base_twr1.lineWidth = 10; base_twr1.strokeStyle = '#ff0000'; base_twr1.closePath(); base_twr1.stroke(); var base_twr2 = c.getContext("2d"); base_twr2.beginPath(); base_twr2.moveTo(900, 500); base_twr2.lineTo(650, 500); base_twr2.closePath(); base_twr2.stroke(); var base_twr3 = c.getContext("2d"); base_twr3.beginPath(); base_twr3.moveTo(1250, 500); base_twr3.lineTo(1000, 500); base_twr3.closePath(); base_twr3.stroke(); //drawing the towers var twr1 = c.getContext("2d"); twr1.beginPath(); twr1.moveTo(430, 300); twr1.lineTo(430, 500); twr1.closePath(); twr1.stroke(); var twr2 = c.getContext("2d"); twr2.beginPath(); twr2.moveTo(780, 300); twr2.lineTo(780, 500); twr2.closePath(); twr2.stroke(); var twr3 = c.getContext("2d"); twr3.beginPath(); twr3.moveTo(1130, 300); twr3.lineTo(1130, 500); twr3.closePath(); twr3.stroke(); //array to know each tower what contains //to avoid collisions var disks_in_twrs = []; var twr1_holder = []; var twr2_holder = []; var twr3_holder = []; //start function check the user input //and call another function if everthing //is fine function btn_start() { disks_number = document.getElementById("disk_input").value; disks_number = parseInt(disks_number); if (disks_number > 0) { if (disks_number < 8) put_disks(disks_number); } else alert('write number'); } var width_disks_start = 305; var height_disks_start = 490; var disk_width = 220; function put_disks(disks) { for (i = 0; i < disks; i++) { // var r = Math.floor((Math.random() * 256)); // var g = Math.floor((Math.random() * 256)); // var b = Math.floor((Math.random() * 256)); str1 = "disk"; width_disks_start = width_disks_start + 10; height_disks_start = height_disks_start - 20; disk_width = disk_width - 30; // eval("disks_in_twrs.push(str1 + i)" ); // disks_in_twrs[i]=c.getContext("2d"); // disks_in_twrs[i].rect((Math.random)*100,(Math.random)*100,150,100); // disks_in_twrs[i].stroke(); // alert(disks_in_twrs); twr1_holder.push(str1 + i); // ctx.fillStyle = 'rgb(' + r + ',' + g + ', ' + b + ')'; // alert(str1 + i); //twr1_holder[i] = c.getContext("2d"); eval("var disk"+i+"= c.getContext('2d');"); // twr1_holder[i].rect(width_disks_start, height_disks_start, disk_width, 20); eval("disk"+i+".rect(width_disks_start, height_disks_start, disk_width, 20);"); // twr1_holder[i].strokeStyle = "black"; eval("disk"+i+".strokeStyle = 'black';"); // twr1_holder[i].stroke(); eval("disk"+i+".stroke();"); // alert(disk1.toSource()); } } function hide_me(){ alert("byeeeeeeeeeeeeeeeee"); twr1.fillRect(430, 500, 250, 250); // disk2.rect(515, 51, 6, 20); // disk2.strokeStyle = 'red'; } 
 <!DOCTYPE html> <html> <head> <title>tower of Hanoi</title> <style type="text/css"> canvas{ border : 1px solid black; } </style> </head> <body> <label>how many disk do you want ?</label> <input type="text" id="disk_input"> <button id="start" onclick="btn_start()">start</button> <label>note that maximum disk is 8 :P</label> <button id="make_hidden" onclick="hide_me()" >make me hide</button> <canvas id="myCanvas" > </canvas> <script src="tower.js"> </script> </body> </html> 

这里有很多事情! 我建议分别攻击代码中的每个问题并逐步建立理解,因为这是一个需要大量不同组件(DOM操作/事件处理程序,JS画布,对象/数组/循环,设计等)的应用程序。 如果您对以上任何一个概念都不满意,请选择一个领域(例如DOM操作)并花时间研究简单易懂的示例,然后将学到的内容应用到主应用程序中。

首先,几乎总是完全避免eval Mozilla说永远不要使用它 如果您正在使用它,则可能意味着您的设计已经走到了尽头,在我看来,情况就是如此。

至于事件处理程序和文档处理,我建议避免使用onclick 在脚本中添加事件侦听器可以完成这项工作。 您很可能会监听画布上的点击,以便以后进行交互。

下一步:使用画布。 通常,每个应用程序只需要检索一次上下文,而不是每个图形之前。 除此之外,您的绘图代码看起来还不错,除了它不是非常 ,这通常是重新设计的信号。

最难的部分是设计代码以实现您的目标,我对此尚不完全清楚。 您是在制作交互式的Hanoi塔应用程序,还是只是为求解器算法设置动画并且不需要用户输入的应用程序? 无论哪种方式,我都选择使用对象构造函数来表示塔和磁盘。 使用数组保存这些对象意味着您通过塔和磁盘在数组中的位置来标识它们,而不用eval字符串名称。 每当您要对塔进行操作(例如绘制塔)时,您所需要做的就是遍历塔并在每个塔上调用draw 后来,当涉及到处理用户输入或编写求解器算法时,应该很容易操纵这些数组以满足您的需要(例如,确定单击了哪个磁盘,在塔之间移动磁盘等)。

请记住,下面的示例只是一个快速入门,它可能不会遵循最佳设计原则或满足您需求的原则。 例如,我已经对大多数图形坐标值进行了硬编码,因此它没有响应,因此有许多练习可供读者改进。

 const Disk = function(width, color) { this.width = width; this.color = color; }; const Tower = function(x, disks) { this.x = x; this.disks = []; this.width = 20; }; Tower.prototype.draw = function(c, ctx) { ctx.lineWidth = this.width; ctx.strokeStyle = "#000"; ctx.beginPath(); ctx.moveTo(this.x, 0); ctx.lineTo(this.x, c.height); ctx.stroke(); this.disks.forEach((e, i) => { ctx.fillStyle = e.color; ctx.fillRect( this.x - e.width / 2, c.height - (i + 1) * this.width, e.width, this.width ); }); }; const draw = (c, ctx, towers) => { ctx.clearRect(0, 0, c.width, c.height); towers.forEach(t => t.draw(c, ctx)); }; const initialize = disks => { const towers = [ new Tower(c.width / 5), new Tower(c.width / 2), new Tower(c.width - c.width / 5) ]; for (let i = disks; i > 0; i--) { towers[0].disks.push( new Disk(i * 30, `hsl(${Math.random() * 360}, 50%, 50%`) ); } return towers; }; document.getElementById("initialize-form") .addEventListener("submit", e => { e.preventDefault(); towers = initialize(parseInt(e.target.elements[0].value), towers); draw(c, ctx, towers); }); document.getElementById("btn-hide").addEventListener("click", e => document.getElementById("menu").style.display = "none" ); const c = document.getElementById("hanoi"); c.width = 600; c.height = 200; const ctx = c.getContext("2d"); let towers; 
 body { margin: 0; } #hanoi { padding: 0.5em; } #initialize-form { display: inline-block; } #menu { padding: 0.5em; display: inline-block; } 
 <div id="menu"> <form id="initialize-form"> <label>Enter disks:</label> <input type="number" min="1" max="8" value="6"> <button type="submit">start</button> </form> <button id="btn-hide">hide</button> </div> <canvas id="hanoi"></canvas> 

对于您尝试做的事情,您应该考虑使用画布库,也许是Konva:
https://konvajs.github.io/

这是一个例子:

 <script src="https://cdn.rawgit.com/konvajs/konva/2.1.7/konva.min.js"></script> <div id="container"></div> <script> function KonvaRect(x, y, fill, draggable) { return new Konva.Rect({ x: x, y: y, width: 50, height: 50, fill: fill, stroke: 'black', strokeWidth: 4, draggable: draggable }); } var boxes = []; boxes.push(KonvaRect(50, 10, '#00D2FF', true)); boxes.push(KonvaRect(200, 10, '#0000FF', true)); boxes.push(KonvaRect(125, 10, '#FF0000', false)); var layer = new Konva.Layer(); boxes.forEach(function(b) { layer.add(b) }); var stage = new Konva.Stage({ container: 'container', width: 600, height: 170 }); stage.add(layer); function moveCenter() { boxes.forEach(function(b) { b.move({ x:0, y: Math.random() * 10 }) }); layer.batchDraw(); } boxes[0].on('mouseover', function() { moveCenter(); }); </script> 

在此示例中,我将3个框放在一个数组中,当我们在浅蓝色框上检测到鼠标时,所有框都随机向下移动,两个框都可以单击并在画布上拖动。

为了记录在外,还有许多其他图书馆...

暂无
暂无

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

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