我正在使用 HTML 和 JS 创建一个持久白板应用程序,用户在画布上绘图并单击“保存”,这会将画布图像数据存储到 MySQL DB。当页面重新加载时,画布应该从数据库中获取存储的图像数据并将其重新绘制在画布上,从而创建一个持久的白板。
获取函数工作正常,图像数据被正确检索并存储在数据结构中。但是,当我重新加载页面时,图像不会被绘制回画布上。具体来说,当我使用
imageData.data.set(latestDrawing)
时,imageData
的长度与预期的 latestDrawing
的长度不匹配,我认为这是问题的原因。有谁知道如何使用预先存在的数据创建新的图像数据?
WhiteBoard.js中的保存和重绘功能:
window.addEventListener('load', () => {
resize();
redraw();
window.addEventListener('click', handleOutsideClick);
document.addEventListener("mousedown", startdrawing);
document.addEventListener("mousemove", sketch);
document.addEventListener("mouseup", stopdrawing);
document.addEventListener("mouseout", stopdrawing);
window.addEventListener('resize', resize);
});
async function saveState() {
// console.log("before save")
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
await fetch('/WhiteBoard', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ type: 'canvasState', data: imageData }),
});
console.log("saved")
}
async function redraw() {
try {
const response = await fetch('/WhiteBoard');
var latestDrawing = await response.json();
if (latestDrawing) {
//get db data into readable image data form
latestDrawing = JSON.parse(latestDrawing.data);
//create a new blank image data
var imageData = ctx.createImageData(canvas.width, canvas.height);
imageData.data.set(latestDrawing);
ctx.putImageData(imageData, 0, 0);
}
} catch (error) {
console.error('Error:', error);
}
}
Server.js 中的 fetch 函数:
app.get('/WhiteBoard', (req,res) => {
// Set the content type to JSON
res.setHeader('Content-Type', 'application/json');
// Your existing query and response logic
db.query('SELECT * FROM canvas_state ORDER BY id DESC LIMIT 1', (error, results) => {
if (error) {
console.error(error);
res.status(500).send('Internal Server Error');
} else {
res.json(results[0]);
}
});
});
我尝试创建一个
new Uint8ClampedArray
,因为我阅读了另一篇建议这样做的文章,但是画布仍然没有重新绘制保存的图像。
const dataArray = new Uint8ClampedArray(drawingData);
我认为后端与这里无关,尽管很高兴看到上下文和更广泛的用例。一旦您可以通过
JSON.stringify()
和 JSON.parse()
传递数据而不丢失信息,问题就变成纯粹的前端(目前 - 可能存在 API 或数据库问题,但这些问题具有不同的性质,应与前端隔离)画布图像数据获取/放置操作)。
这是一种在一个画布上绘制内容的方法,通过 JSON 字符串传递数据并将其写入另一个画布:
const canvasToArray = canvas => {
const ctx = canvas.getContext("2d");
const {data} = ctx.getImageData(0, 0, canvas.width, canvas.height);
return [...new Uint8ClampedArray(data.buffer)];
};
const writeDataToCanvas = (canvas, data) => {
const ctx = canvas.getContext("2d");
const imageData = ctx.createImageData(canvas.width, canvas.height);
imageData.data.set(data);
ctx.putImageData(imageData, 0, 0);
};
const [canvasA, canvasB] = document.querySelectorAll("canvas");
canvasA.getContext("2d").fillRect(10, 10, 20, 20);
const json = JSON.stringify(canvasToArray(canvasA));
// store `json` to the backend ...
// ... later on, restore it from a response:
writeDataToCanvas(canvasB, JSON.parse(json));
canvas {
border: 1px solid black;
}
<canvas></canvas>
<canvas></canvas>
从中,您可以看到反序列化过程与您的尝试相比没有改变,但序列化过程确实按照您的建议使用了
Uint8ClampedArray
以及 Array.from()
或扩展。在原始代码中记录 JSON.stringify({ type: 'canvasState', data: imageData })
的结果应该表明画布数据未完成序列化过程。
现在,将数据 blob 存储在数据库中通常不是一个好主意。最好使用 S3 存储桶或其他一些优化的文件存储系统,并在数据库中存储数据的链接。