我可以有一个互动的html5画布与破折号,情节

2024-03-28 18:59:37 发布

您现在位置:Python中文网/ 问答频道 /正文

是否可以将交互式html5画布与dash一起使用?我希望能够像康威的《生命游戏》那样画出一个网格。让它成为交互式的,我可以点击一个单元格并激活/停用它。并且能够设置画布大小。 谢谢


Tags: 网格游戏画布html5dash
1条回答
网友
1楼 · 发布于 2024-03-28 18:59:37

Note: From the wording of the question the focus seems to be on having a canvas grid with clickable cells that can be toggled on and of in Dash, so I will address this in my answer. I won't go into Conway's Game of Life here, but this answer could serve as a starting point if you wanted to implement it or a variation of it.

^{}模块允许我们访问^{}组件

我们可以做的是创建一个运行一次的clientside callback,通过它我们可以使用Javascript访问DOM,这样我们就可以基于由CanvasDash组件呈现的canvas元素创建网格,并将click事件侦听器附加到它

Dash应用程序可能看起来像这样:

from dash import Dash
import dash_html_components as html
from dash.dependencies import ClientsideFunction, Output, Input

app = Dash(__name__)
app.layout = html.Canvas(id="canvas")


app.clientside_callback(
    ClientsideFunction(namespace="clientside", function_name="init_grid"),
    Output("canvas", "children"),
    Input("canvas", "children"),
)


if __name__ == "__main__":
    app.run_server()

然后,您可以在assets目录中添加一个.js文件,其中包含以下内容:

window.dash_clientside = Object.assign({}, window.dash_clientside, {
  clientside: {
    init_grid: function (_) {
      const canvas = document.querySelector("canvas");
      canvas.width = 400;
      canvas.height = 400;
      const ctx = canvas.getContext("2d");
      const cellWidth = 50;
      const cellHeight = 50;
      const numRows = canvas.height / cellHeight;
      const numCols = canvas.width / cellWidth;

      const drawGrid = () => {
        const coordinates = [];
        for (let row = 0; row < numRows; row++) {
          for (let col = 0; col < numCols; col++) {
            ctx.strokeRect(
              col * cellWidth,
              row * cellHeight,
              cellWidth,
              cellHeight
            );
            coordinates.push({ row, col, filledIn: false });
          }
        }
        return coordinates;
      };

      const grid = drawGrid();

      canvas.addEventListener("click", (event) => {
        const clickedRow = Math.floor(event.offsetY / cellHeight);
        const clickedCol = Math.floor(event.offsetX / cellWidth);

        const cell = grid.filter((cell) => {
          return cell.row === clickedRow && cell.col === clickedCol;
        })[0];

        const rectDimensions = [
          clickedCol * cellWidth, // x
          clickedRow * cellHeight, // y
          cellWidth,
          cellHeight,
        ];

        if (!cell.filledIn) {
          ctx.fillStyle = "black";
        } else {
          ctx.fillStyle = "white";
        }

        ctx.fillRect(...rectDimensions);
        ctx.fillStyle = "black";
        ctx.strokeRect(...rectDimensions);

        cell.filledIn = !cell.filledIn;
      });

      return [];
    },
  },
});

有关在Dash应用程序中包含Javascript的更多信息,请参阅文档here

因此,上面代码的思想是使用嵌套循环来创建网格。我们根据当前行数、列数以及为所有单元格设置的宽度和高度绘制矩形

除了绘制网格外,还保存了所有网格坐标,以便我们可以确定用户单击哪个单元格时,该单元格是否应填充或清除。为了知道是否应该清除或填充单元格,为所有xy坐标对设置了filledIn属性


结果:

grid showcase

相关问题 更多 >