是否可以使用带有破折号的交互式 html5 画布?我希望能够像康威的生活游戏一样绘制网格。让它是交互式的,我可以点击一个单元格并激活/停用它。并且能够设置画布大小。谢谢
问问题
512 次
1 回答
0
注意:从问题的措辞来看,重点似乎是拥有一个带有可点击单元格的画布网格,这些单元格可以在 Dash 中打开和关闭,所以我将在我的回答中解决这个问题。我不会在这里讨论康威的生命游戏,但如果你想实现它或它的变体,这个答案可以作为一个起点。
该dash_html_components
模块使我们可以访问Canvas
组件。
我们可以做的是创建一个运行一次的客户端回调,通过它我们可以使用 Javascript 访问 DOM,这样我们就可以基于Dash 组件canvas
呈现的元素创建网格Canvas
并将点击事件侦听器附加到它。
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()
然后你可以.js
在你的目录中添加一个文件,assets
里面有这个:
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 的更多信息,请参阅此处的文档。
所以上面代码的想法是使用嵌套循环来创建一个网格。我们根据当前行号、列号以及我们为所有单元格设置的宽度和高度绘制矩形。
除了绘制网格之外,还保存了所有网格坐标,因此我们可以确定用户单击了哪个单元格,是否应该填充或清除该单元格。为了知道是否应该清除或填充单元格filledIn
,为所有 xy 坐标对设置了一个属性。
结果:
于 2021-07-17T16:54:56.537 回答