我想创建类似刮刮卡的东西。 我创建了一个画布并向其中添加了文本。我在文本上方添加了一个框来隐藏它。最后写下代码以擦除(刮擦)该框。
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.font = "30px Arial";
ctx.fillText("Hello World",10,50);
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle='red';
ctx.fillRect(0,0,500,500);
function myFunction(event) {
var x = event.touches[0].clientX;
var y = event.touches[0].clientY;
document.getElementById("demo").innerHTML = x + ", " + y;
ctx.globalCompositeOperation = 'destination-out';
ctx.arc(x,y,30,0,2*Math.PI);
ctx.fill();
}
但是问题在于它也删除了文本。
如何只删除该框而不删除文本?
答案 0 :(得分:1)
我如何只删除该框而不删除文本?
您不能,必须重绘文本。一旦在文本上方绘制了框,就将其抹掉了,它不再存在。画布是基于像素的,而不是像SVG一样基于形状的。
答案 1 :(得分:1)
画布上下文仅保留一种绘制状态,即一种绘制状态。如果修改像素,它将不记得它以前的样子,并且由于它没有内置的图层概念,因此当您清除像素时,它只是一个透明像素。
因此,要实现您想要的目标,最简单的方法就是自己构建分层逻辑,例如,通过创建两个“ 屏幕外”画布,如“未附加在DOM中”,其中一个用于可刮擦的区域,以及应该显示的背景区域。
然后在第三个画布上,每次都绘制两个画布。这是将向您的用户展示的第三张画布:
var canvas = document.getElementById("myCanvas");
// the context that will be presented to the user
var main = canvas.getContext("2d");
// an offscreen one that will hold the background
var background = canvas.cloneNode().getContext("2d");
// and the one we will scratch
var scratch = canvas.cloneNode().getContext("2d");
generateBackground();
generateScratch();
drawAll();
// the events handlers
var down = false;
canvas.onmousemove = handlemousemove;
canvas.onmousedown = handlemousedown;
canvas.onmouseup = handlemouseup;
function drawAll() {
main.clearRect(0,0,canvas.width,canvas.height);
main.drawImage(background.canvas, 0,0);
main.drawImage(scratch.canvas, 0,0);
}
function generateBackground(){
background.font = "30px Arial";
background.fillText("Hello World",10,50);
}
function generateScratch() {
scratch.fillStyle='red';
scratch.fillRect(0,0,500,500);
scratch.globalCompositeOperation = 'destination-out';
}
function handlemousedown(evt) {
down = true;
handlemousemove(evt);
}
function handlemouseup(evt) {
down = false;
}
function handlemousemove(evt) {
if(!down) return;
var x = evt.clientX - canvas.offsetLeft;
var y = evt.clientY - canvas.offsetTop;
scratch.beginPath();
scratch.arc(x, y, 30, 0, 2*Math.PI);
scratch.fill();
drawAll();
}
<canvas id="myCanvas"></canvas>
现在,所有这些都可以在同一画布上完成,但是从性能角度来看,这可能不是最好的,因为这意味着生成了一个过于复杂的子路径,应该在每次绘制时重新渲染它,这是实施起来并不容易:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext('2d');
ctx.font = '30px Arial';
drawAll();
// the events handlers
var down = false;
canvas.onmousemove = handlemousemove;
canvas.onmousedown = handlemousedown;
canvas.onmouseup = handlemouseup;
function drawAll() {
ctx.globalCompositeOperation = 'source-over';
// first draw the scratch pad, intact
ctx.fillStyle = 'red';
ctx.fillRect(0,0,500,500);
// then erase with the currently being defined path
// see 'handlemousemove's note
ctx.globalCompositeOperation = 'destination-out';
ctx.fill();
// finally draw the text behind
ctx.globalCompositeOperation = 'destination-over';
ctx.fillStyle = 'black';
ctx.fillText("Hello World",10,50);
}
function handlemousedown(evt) {
down = true;
handlemousemove(evt);
}
function handlemouseup(evt) {
down = false;
}
function handlemousemove(evt) {
if(!down) return;
var x = evt.clientX - canvas.offsetLeft;
var y = evt.clientY - canvas.offsetTop;
// note how here we don't create a new Path,
// meaning that all the arcs are being added to the single one being rendered
ctx.moveTo(x, y);
ctx.arc(x, y, 30, 0, 2*Math.PI);
drawAll();
}
<canvas id="myCanvas"></canvas>