javascript - 画布:删除对象后恢复图像
问题描述
我有以下代码:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const image = new Image(60, 45); // Using optional size for image
image.onload = drawImageActualSize; // Draw when image has loaded
// Load an image of intrinsic size 300x227 in CSS pixels
image.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
function drawImageActualSize() {
// Use the intrinsic size of image in CSS pixels for the canvas element
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
// Will draw the image as 300x227, ignoring the custom size of 60x45
// given in the constructor
ctx.drawImage(this, 0, 0);
// To use the custom size we'll have to specify the scale parameters
// using the element's width and height properties - lets draw one
// on top in the corner:
ctx.drawImage(this, 0, 0, this.width, this.height);
ctx.save();
ctx.fillStyle = 'green';
ctx.fillRect(10, 10, 150, 100);
ctx.restore();
ctx.clearRect(10, 10, 150, 100);
}
<canvas id="canvas" width=300 height=200></canvas>
这里 ctx.clearRect(10, 10, 150, 100) 方法,删除绿色部分以及图像并显示白色画布。
我只想删除绿色部分并恢复以前的图像。
我怎样才能做到这一点?
解决方案
重绘
添加和删除动态内容的标准方法是在每次发生更改时重新渲染画布。这就是以 60fps 运行的 HTML 画布游戏如何做到这一点的,它们每帧可以更改 100 多个项目。
还有其他方法需要在每次绘制矩形时复制矩形下方的内容,然后在您希望删除矩形时将副本绘制在矩形上。
这很复杂,每个正在绘制的动态对象至少需要一个额外的画布,因此会占用大量内存。或者使用getImageData
和putImageData也是一个内存猪,超级慢,会导致大量 GC 操作,并且不适用于不安全的内容(跨域的图像,或来自本地文件存储的图像)。
重绘是迄今为止最简单的方法。如果渲染所有内容的时间超过 100 毫秒,您只会考虑其他方法(对于非动画内容)
例子
在示例中,变量rectOn
if true 将绿色矩形添加到画布(同时绘制图像和矩形)。如果不正确,则删除矩形(仅绘制图像)。
函数draw
根据变量的状态渲染画布rectOn
单击按钮添加/删除矩形。
const ctx = canvas.getContext('2d');
var rectOn = false;
const image = new Image();
image.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
image.addEventListener("load", ready, {once:true});
function ready() {
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
loading.classList.add("hide");
addRemove.classList.remove("hide");
addRemove.addEventListener("click", toggle);
draw();
}
function draw() {
ctx.drawImage(image, 0, 0);
if (rectOn) {
ctx.fillStyle = "#0F0";
ctx.fillRect(10, 50, 150, 100);
}
}
function toggle() {
rectOn = !rectOn;
addRemove.textContent = (rectOn ? "Remove": "Add" ) + " rect";
draw();
}
button { cursor: pointer; width: 120px }
.hide {display:none}
canvas { position: absolute; top: 0px; left: 0px; z-index:-1; }
<span id="loading">Loading image</span><button id="addRemove" class="hide">Add green rect</button><br>
<canvas id="canvas"></canvas>
推荐阅读
- python - 将scrapy-splash与 crawlera 一起使用时出现 504 超时异常
- sql - Hasura 计算字段与 Postgres 生成的列与 Postgres 视图
- c# - 如何在 Unity 中单击缩放多个按钮
- python - 如何在python中为多进程预先分配参数
- docker - 系统升级后无法运行任何 docker 映像
- android - 如何使用 android Studio 调试 android 应用
- javascript - 使用 Express 和 Javascript 通过 POST 登录后重定向
- python - 迭代可变列表
- java - Android Google Maps URL 查询 - 离线放置标记
- swiftui - 如何通过函数从 ParentView 正确更改子视图的 (@State/@Binding) 变量?(不在构造函数中)