有没有办法从画布上清除一个元素而不消除其他元素? [英] Is there a way to clear an element from a canvas without eliminating the others?
问题描述
我正在用画布构建页面加载器,并使用es6类...尽管目前无法使其正常工作..原因之一是我找不到清除方法.进行中的画布.
I' m building a page loader with canvas, and using the es6 classes... ALthough at the moment I can't make it work properly.. one of the reason is that I can't find a way to clear the canvas in progression.
到目前为止,这是我的代码:
This is my code so far :
class Loader {
constructor (width, height) {
this.width = width
this.height = height
}
_init() {
this._createCanvas()
this._bindEvents()
}
// create canvas
_createCanvas () {
this.canvas = document.createElement("canvas")
document.body.appendChild(this.canvas)
this.canvas.id = "canvas"
this.canvas.width = loader.width
this.canvas.height = loader.height
}
_throttle (callback, delay) {
let last
let timer
return function () {
let context = this
let now = +new Date()
let args = arguments
if (last && now < last + delay) {
clearTimeout(timer)
timer = setTimeout(function () {
last = now
callback.apply(context, args)
}, delay)
} else {
last = now
callback.apply(context, args)
}
}
}
// resize canvas
_resizeCanvas () {
// resize canvas
var canvasRatio = this.canvas.height / this.canvas.width;
var windowRatio = window.innerHeight / window.innerWidth;
var width;
var height;
if (windowRatio < canvasRatio) {
height = window.innerHeight;
width = height / canvasRatio;
} else {
width = window.innerWidth;
height = width * canvasRatio;
}
this.canvas.width = width
this.canvas.height = height
}
_bindEvents () {
// create events listeners
this.resizeCanvas = this._throttle(function (event) {
this._resizeCanvas()
}.bind(this), 250)
window.addEventListener('resize', this.resizeCanvas, false)
}
_unbindEvents () {
// remove events listeners
window.removeEventListener('resize', this.resizeCanvas, false)
}
}
class Snake {
constructor( options = {} ) {
this.options = {
x: options.x,
y: options.y,
height: options.height,
width: options.width,
isMoving: options.isMoving || false,
hasDispatched: options.hasDispatched || false,
nextSnakeCallback: options.nextSnakeCallback || null,
speed: options.speed || 4
}
}
_init() {
this._drawSnake()
}
start () {
this.options.isMoving = true;
}
reset () {
this.options.hasDispatched = false;
}
setNextSnakeCallback (callback) {
this.options.nextSnakeCallback = callback;
}
_drawSnake() {
this.canvas = document.getElementById("canvas")
this.ctx = this.canvas.getContext("2d")
this.ctx.beginPath()
this.ctx.rect(
this.options.x,
this.options.y,
this.options.width,
this.options.height)
this.ctx.fillStyle = "#f44242"
this.ctx.fill()
}
_clearSnake () {
this.ctx.clearRect(this.options.x, this.options.y, this.options.width, this.options.height);
}
}
class SnakeTop extends Snake {
constructor (options) {
super(options)
}
_init () {
super._drawSnake()
this._moveSnakeToRight()
super._clearSnake()
}
reset () {
this.options.x = this.options.height;
}
_moveSnakeToRight () {
if(this.options.isMoving){
this._clearSnake()
this._drawSnake()
if(this.options.x > loader.width - this.options.width && !this.options.hasDispatched){
this.options.hasDispatched = true;
if(this.options.nextSnakeCallback) {
this.setNextSnakeCallback()
}
} else if(this.options.x >= loader.width){
this.options.isMoving = false;
}
this.options.x += this.options.speed
}
window.requestAnimationFrame(this._moveSnakeToRight.bind(this));
}
}
class SnakeRight extends Snake {
constructor (options = {}) {
super(options)
}
_init() {
super._drawSnake()
this._moveSnakeDown()
super._clearSnake()
}
_moveSnakeDown () {
if(this.options.isMoving) {
this._clearSnake()
this._drawSnake()
if(this.options.y > loader.height - this.options.height && !this.options.hasDispatched){
this.options.hasDispatched = true;
if(this.options.nextSnakeCallback) {
this.setNextSnakeCallback()
}
} else if (this.options.y > loader.height) {
this.options.isMoving = false
}
this.options.y += this.options.speed
}
window.requestAnimationFrame(this._moveSnakeDown.bind(this));
}
}
class SnakeBottom extends Snake {
constructor (options = {} ) {
super(options)
}
_init() {
super._drawSnake()
this._moveSnakeToLeft()
super._clearSnake()
}
_moveSnakeToLeft () {
if (this.options.isMoving) {
this._clearSnake()
this._drawSnake()
if(this.options.x < 0 && !this.options.hasDispatched){
this.options.hasDispatched = true
if(this.options.nextSnakeCallback) {
this.setNextSnakeCallback()
}
} else if (this.options.x < this.options.width) {
this.options.isMoving = false
}
this.options.x -= this.options.speed
}
window.requestAnimationFrame(this._moveSnakeToLeft.bind(this));
}
}
class SnakeLeft extends Snake {
constructor(options = {}) {
super(options)
}
_init() {
super._drawSnake()
this._moveSnakeUp()
super._clearSnake()
}
_moveSnakeUp () {
if(this.options.isMoving) {
this._clearSnake()
this._drawSnake()
if(this.options.y < 0 && !this.options.hasDispatched) {
this.options.hasDispatched = true
if(this.options.nextSnakeCallback) {
this.setNextSnakeCallback()
}
} else if ( this.options.y > - this.canvas.height) {
this.options.isMoving = false
}
this.options.y -= this.options.speed
}
window.requestAnimationFrame(this._moveSnakeUp.bind(this));
}
}
// defining the elements on the DOM
let loader = new Loader (600, 600)
loader._init()
//CREATE SNAKES
let snakeT = new SnakeTop ({
x: - 300,
y: 0,
height: 20,
width: 300
})
snakeT._init()
//ASSIGN NEXT SNAKE callback
snakeT.setNextSnakeCallback (()=>{
snakeR.reset();
snakeR.start();
});
//START FIRST SNAKE
snakeT.start();
以此类推,以构建其他3个元素.
and so on building the other 3 elements.
从jsfiddle中可以看到,我的函数drawSnake()继续在另一个之后绘制矩形
As you can see from the jsfiddle, my function drawSnake() keeps drawning a rectangle after the other
https://jsfiddle.net/ombqfzjq/
在研究过程中,我发现可以清除矩形,而不是使用
During my research I found that to clear a rectangle, instead of using
ctx.clearRect(0,0,canvasWidth,canvasHeight);
可以清洁画布,我可以使用
that cleans the canvas, I can use
ctx.clearRect(square.x,square.y,square.w,square.h);
应该清除每个矩形...因此,在我的Snake类中,我构建了_clearSnake()函数,然后在需要时将其调用到我的子类中.
that should clean instead each single rectangle... So in my class Snake I built the _clearSnake() function, and then call it to my subclasses when needed it.
我的逻辑有什么问题?如何改善我的代码?
What's wrong in my logic? How can I improve my code?
推荐答案
一旦在画布上绘制了东西,就不能简单地删除该对象.
Once you've painted something onto a canvas you cannot simply remove that object.
画布"并不像HTML元素那样分层,因此删除对象不会在下面显示对象.
Canvas' aren't layered like HTML elements, so removing an object wouldn't show the objects beneath.
最干净的方法是重画之前的状态.
The cleanest way would be to re-paint the state before.
这篇关于有没有办法从画布上清除一个元素而不消除其他元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!