首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >画布:理解globalCompositeOperation删除部分图像覆盖

画布:理解globalCompositeOperation删除部分图像覆盖
EN

Stack Overflow用户
提问于 2016-10-17 03:47:01
回答 1查看 1.6K关注 0票数 1

我试图通过将这两个示例( JSFiddle科德芬 )结合起来,来了解JSFiddle属性。

前者使用destination-out,后者使用source-over。是否可以在Codepen中使用炽热的光标,但也可以删除用户单击的覆盖填充部分,就像在Fiddle中一样?

如能提供任何协助,将不胜感激。如果需要的话,我可以结合Codepen上的演示来使用相同的方法。

相关的Fiddle代码:

代码语言:javascript
复制
function drawDot(mouseX,mouseY){
    bridgeCanvas.beginPath();
    bridgeCanvas.arc(mouseX, mouseY, brushRadius, 0, 2*Math.PI, true);
    bridgeCanvas.fillStyle = '#000';
    bridgeCanvas.globalCompositeOperation = "destination-out";
    bridgeCanvas.fill();
}

相关代码:

代码语言:javascript
复制
Fire.prototype.clearCanvas = function(){
    this.ctx.globalCompositeOperation = "source-over";
    this.ctx.fillStyle = "rgba( 15, 5, 2, 1 )";
    this.ctx.fillRect( 0, 0, window.innerWidth, window.innerHeight );

    this.ctx.globalCompositeOperation = "lighter";
    this.ctx.rect(0, 0, this.canvas.width, this.canvas.height);
    this.ctx.fillStyle = this.pattern;
    this.ctx.fill();/**/
}    
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-24 13:53:54

正如我在评论中所说的,您必须至少将代码分成两部分。

cropper函数使用"destination-out"复合操作来删除画布中已经绘制的像素,其中应该绘制新像素。在您的版本中,它使用一个背景图像,一旦前景像素被移除,您就可以看到这个背景,因为在现在透明的画布区域。

火焰一方在另一方面,使用‘打火机’,"color-dodge""soft-light"混合操作。这将添加已经存在的和新绘制的像素的颜色。

至少第一个操作(如果用于透明区域)将与默认的"source-over"复合操作相同。因此,您需要将背景图像绘制到画布上,以便能够在混合中使用它。

为此,您必须使用第二个屏幕外画布,其中只应用橡皮擦"destination-out"操作。然后,在可见的帆布上,在每一个新的橡皮擦框架上,你必须在可见的帆布上画背景图像,然后在橡皮擦上画一个有洞的橡皮擦,最后画一个混合的橡皮擦,它将所有的东西混合在一起。

这里有一个快速的代码转储,在这里我重写了一点橡皮擦,并修改了Fire,以便使我们的主要功能同时处理事件和动画循环。

代码语言:javascript
复制
function MainDrawing(){
  this.canvas = document.getElementById('main');
  this.ctx = this.canvas.getContext('2d');
  this.background = new Image();
  this.background.src = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/calgary-bridge-1943.jpg"
  this.eraser = new Eraser(this.canvas);
  this.fire = new Fire(this.canvas);
  this.attachEvents();
  }
MainDrawing.prototype = {
   anim: function(){
     if(this.stopped)
        return;
     this.ctx.globalCompositeOperation = 'source-over';
     this.ctx.drawImage(this.background, 0,0);
     this.ctx.drawImage(this.eraser.canvas, 0,0);
     this.fire.run();
     requestAnimationFrame(this.anim.bind(this));
     },
  stop: function(){
      this.stopped = true;
    },
  attachEvents: function(){
    var mouseDown = false;
	this.canvas.onmousedown = function(){
		mouseDown = true;
		};
	this.canvas.onmouseup = function(){
		mouseDown = false;
		};
    this.canvas.onmousemove = function(e){
    	if(mouseDown){
	    	this.eraser.handleClick(e);
	    	}
	    this.fire.updateMouse(e);
	    }.bind(this);
    }
 };

function Eraser(canvas){
  this.main = canvas;
  this.canvas = canvas.cloneNode();
  var ctx = this.ctx = this.canvas.getContext('2d');
  this.img = new Image();
  this.img.onload = function(){
  	ctx.drawImage(this, 0, 0);
  	ctx.globalCompositeOperation = 'destination-out';
  	};
  this.img.src = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/calgary-bridge-2013.jpg";
  this.getRect();
}
Eraser.prototype = {
  getRect: function(){
      this.rect = this.main.getBoundingClientRect();
    },
  handleClick: function(evt){
    var x = evt.clientX - this.rect.left;
    var y = evt.clientY - this.rect.top;
    this.draw(x,y);
    },
  draw: function(x, y){
    this.ctx.beginPath();
    this.ctx.arc(x, y, 30, 0, Math.PI*2);
    this.ctx.fill();
    }
 };
  

var Fire  = function(canvas){

	this.canvas 		= canvas;
	this.ctx 			= this.canvas.getContext('2d');

	this.aFires 		= [];
	this.aSpark 		= [];
	this.aSpark2 		= [];



	this.mouse = {
		x : this.canvas.width * .5,
		y : this.canvas.height * .75,
	}

}

Fire.prototype.run = function(){
	
	this.update();
	this.draw();

}
Fire.prototype.start = function(){

	this.bRuning = true;
	this.run();

}
Fire.prototype.stop = function(){

	this.bRuning = false;

}
Fire.prototype.update = function(){

	this.aFires.push( new Flame( this.mouse ) );
	this.aSpark.push( new Spark( this.mouse ) );
	this.aSpark2.push( new Spark( this.mouse ) );



	for (var i = this.aFires.length - 1; i >= 0; i--) {

		if( this.aFires[i].alive )
			this.aFires[i].update();
		else
			this.aFires.splice( i, 1 );

	}

	for (var i = this.aSpark.length - 1; i >= 0; i--) {

		if( this.aSpark[i].alive )
			this.aSpark[i].update();
		else
			this.aSpark.splice( i, 1 );

	}


	for (var i = this.aSpark2.length - 1; i >= 0; i--) {

		if( this.aSpark2[i].alive )
			this.aSpark2[i].update();
		else
			this.aSpark2.splice( i, 1 );

	}

}

Fire.prototype.draw = function(){

	this.drawHalo();
	
	this.ctx.globalCompositeOperation = "overlay";//or lighter or soft-light

	for (var i = this.aFires.length - 1; i >= 0; i--) {

		this.aFires[i].draw( this.ctx );

	}

	this.ctx.globalCompositeOperation = "soft-light";//"soft-light";//"color-dodge";

	for (var i = this.aSpark.length - 1; i >= 0; i--) {
		
		if( ( i % 2 ) === 0 )
			this.aSpark[i].draw( this.ctx );

	}

	this.ctx.globalCompositeOperation = "color-dodge";//"soft-light";//"color-dodge";

	for (var i = this.aSpark2.length - 1; i >= 0; i--) {

		this.aSpark2[i].draw( this.ctx );

	}


}

Fire.prototype.updateMouse = function( e ){

	this.mouse.x = e.clientX;
	this.mouse.y = e.clientY;

}


Fire.prototype.drawHalo = function(){

	var r = rand( 300, 350 );
	this.ctx.globalCompositeOperation = "lighter";
	this.grd = this.ctx.createRadialGradient( this.mouse.x, this.mouse.y,r,this.mouse.x, this.mouse.y, 0 );
	this.grd.addColorStop(0,"transparent");
	this.grd.addColorStop(1,"rgb( 50, 2, 0 )");
	this.ctx.beginPath();
	this.ctx.arc( this.mouse.x, this.mouse.y - 100, r, 0, 2*Math.PI );
	this.ctx.fillStyle= this.grd;
	this.ctx.fill();

}


var Flame = function( mouse ){

	this.cx = mouse.x;
	this.cy = mouse.y;
	this.x = rand( this.cx - 25, this.cx + 25);
	this.y = rand( this.cy - 5, this.cy + 5);
	this.lx = this.x;
	this.ly = this.y;
	this.vy = rand( 1, 3 );
	this.vx = rand( -1, 1 );
	this.r = rand( 30, 40 );
	this.life = rand( 2, 7 );
	this.alive = true;
	this.c = {

		h : Math.floor( rand( 2, 40) ),
		s : 100,
		l : rand( 80, 100 ),
		a : 0,
		ta : rand( 0.8, 0.9 )

	}




}
Flame.prototype.update = function()
{

	this.lx = this.x;
	this.ly = this.y;

	this.y -= this.vy;
	this.vy += 0.08;


	this.x += this.vx;

	if( this.x < this.cx )
		this.vx += 0.2;
	else
		this.vx -= 0.2;




	if(  this.r > 0 )
		this.r -= 0.3;
	
	if(  this.r <= 0 )
		this.r = 0;



	this.life -= 0.12;

	if( this.life <= 0 ){

		this.c.a -= 0.05;

		if( this.c.a <= 0 )
			this.alive = false;

	}else if( this.life > 0 && this.c.a < this.c.ta ){

		this.c.a += .08;

	}

}
Flame.prototype.draw = function( ctx ){

	this.grd1 = ctx.createRadialGradient( this.x, this.y, this.r*3, this.x, this.y, 0 );
	this.grd1.addColorStop( 0.5, "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a/20) + ")" );
	this.grd1.addColorStop( 0, "transparent" );

	this.grd2 = ctx.createRadialGradient( this.x, this.y, this.r, this.x, this.y, 0 );
	this.grd2.addColorStop( 0.5, "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + this.c.a + ")" );
	this.grd2.addColorStop( 0, "transparent" );


	ctx.beginPath();
	ctx.arc( this.x, this.y, this.r * 3, 0, 2*Math.PI );
	ctx.fillStyle = this.grd1;
	//ctx.fillStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a/20) + ")";
	ctx.fill();


	ctx.globalCompositeOperation = "overlay";
	ctx.beginPath();
	ctx.arc( this.x, this.y, this.r, 0, 2*Math.PI );
	ctx.fillStyle = this.grd2;
	ctx.fill();



	ctx.beginPath();
	ctx.moveTo( this.lx , this.ly);
	ctx.lineTo( this.x, this.y);
	ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, 1)";
	ctx.lineWidth = rand( 1, 2 );
	ctx.stroke();
	ctx.closePath();

}


var Spark = function( mouse ){

	this.cx = mouse.x;
	this.cy = mouse.y;
	this.x = rand( this.cx -40, this.cx + 40);
	this.y = rand( this.cy, this.cy + 5);
	this.lx = this.x;
	this.ly = this.y;
	this.vy = rand( 1, 3 );
	this.vx = rand( -4, 4 );
	this.r = rand( 0, 1 );
	this.life = rand( 4, 8 );
	this.alive = true;
	this.c = {

		h : Math.floor( rand( 2, 40) ),
		s : 100,
		l : rand( 40, 100 ),
		a : rand( 0.8, 0.9 )

	}

}
Spark.prototype.update = function()
{

	this.lx = this.x;
	this.ly = this.y;

	this.y -= this.vy;
	this.x += this.vx;

	if( this.x < this.cx )
		this.vx += 0.2;
	else
		this.vx -= 0.2;

	this.vy += 0.08;
	this.life -= 0.1;

	if( this.life <= 0 ){

		this.c.a -= 0.05;

		if( this.c.a <= 0 )
			this.alive = false;

	}

}
Spark.prototype.draw = function( ctx ){

	ctx.beginPath();
	ctx.moveTo( this.lx , this.ly);
	ctx.lineTo( this.x, this.y);
	ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a / 2) + ")";
	ctx.lineWidth = this.r * 2;
	ctx.lineCap = 'round';
	ctx.stroke();
	ctx.closePath();

	ctx.beginPath();
	ctx.moveTo( this.lx , this.ly);
	ctx.lineTo( this.x, this.y);
	ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + this.c.a + ")";
	ctx.lineWidth = this.r;
	ctx.stroke();
	ctx.closePath();

}

rand = function( min, max ){ return Math.random() * ( max - min) + min; };

var app = new MainDrawing();
app.anim();
代码语言:javascript
复制
<canvas id="main" width="750" height="465"></canvas>

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40078206

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档