Javascript 在画布上绘制3个圆圈的重叠

Javascript 在画布上绘制3个圆圈的重叠,javascript,html,canvas,Javascript,Html,Canvas,我需要在没有临时画布的HTML5画布上绘制以下图像: 使用临时画布很容易,因为我可以独立处理重叠,就像您在这里看到的那样: // init var canvas = document.getElementById('canvas'); var tempCanvas = document.getElementById('tempCanvas'); var ctx = canvas.getContext('2d'); var tempCtx = tempCanvas.getContext('2d

我需要在没有临时画布的HTML5画布上绘制以下图像:

使用临时画布很容易,因为我可以独立处理重叠,就像您在这里看到的那样:

// init
var canvas = document.getElementById('canvas');
var tempCanvas = document.getElementById('tempCanvas');
var ctx = canvas.getContext('2d');
var tempCtx = tempCanvas.getContext('2d');

// draw circle function
var drawCircle = function( c, color ) {
  ctx.beginPath();
  ctx.arc( c.x, c.y, 50, 0, 2 * Math.PI, false );
  ctx.fillStyle = color;
  ctx.fill();
}

// draw overlap function
var drawOverlap = function( c1, c2, color ) {
  tempCtx.clearRect( 0, 0, 300, 300 );
  // first circle
  tempCtx.globalCompositeOperation = 'source-over';
  tempCtx.beginPath();
  tempCtx.arc( c1.x, c1.y, 50, 0, 2 * Math.PI, false );
  tempCtx.fillStyle = color;
  tempCtx.fill();
  // second circle
  tempCtx.globalCompositeOperation = 'destination-in';
  tempCtx.beginPath();
  tempCtx.arc( c2.x, c2.y, 50, 0, 2 * Math.PI, false );
  tempCtx.fill();
  // draw on main canvas
  ctx.drawImage( tempCanvas, 0, 0 );
}

// circle objects
var c1 = { x:100, y: 200 };
var c2 = { x:180, y: 200 };
var c3 = { x:140, y: 140 };

// draw background
ctx.beginPath();
ctx.rect( 0, 0, 300, 300 );
ctx.fillStyle = 'black';
ctx.fill();

// draw circles
drawCircle( c1, 'grey' );
drawCircle( c2, 'white' );
drawCircle( c3, 'white' );

// draw overlaps
drawOverlap( c1, c2, 'red' );
drawOverlap( c1, c3, 'blue' );
drawOverlap( c2, c3, 'blue' );
你知道一种不用第二块画布就能画出来的方法吗?非常感谢


编辑: 多亏@user13500,我才解决了这个问题。仍然有丑陋的边界,但速度非常快:


您可以使用剪裁区域--context.clip()在没有临时画布的情况下执行此操作

如果您需要,我可以编写解决方案,但由于您知道如何进行合成,您可能可以很快找到答案;)

但更重要的是

为什么不使用临时画布来禁用工具选择

您可以使用document.createElement(“canvas”)创建一个在屏幕上看不到的临时画布。

Ai,我的头很痛

这不是一个很好的解决方案。我想一个也没有。但是,如果我们不关心背景,我们有:

更新至新版本,如下所示

告诉我们:

试图仅使用
全局复合操作解决此问题
-P


编辑: 嗯。离开它几分钟,我们又开始了。这次的结果是这样的。红色圆圈周围的杂散线仍然存在问题:

虽然它可能不是你想要的,但它在这里;-)在这个问题上的权威是另一个领域

代码:


我使用了KinectJS框架,它有一个层系统。真正好的画布使用框架!谢谢@Timo002。我知道kineticjs,也很喜欢它,但在这种情况下,该项目将进一步实现另一个框架。就像@markE所说的,为什么不使用屏幕外的画布呢?谢谢@markE。也许剪裁区域就是解决方案。在我给你打勾之前,让我玩一下这个;)我不只是画它,而是圆在移动,我使用requestAnimationFrame和数百个圆。使用临时画布并将剪辑“复制”到主画布对于60 FPS来说太昂贵了。酷!仅供参考,在html画布学会自动双缓冲之前,提高性能的一个好方法是维护屏幕外画布。在屏幕外画布上绘制下一个动画。当需要下一帧时,您只需绘制图像(offscreenCanvas)。如今,画布到画布的绘制速度非常快……特别是因为这个过程实际上是GPU将屏幕外的图像数据点到屏幕上的图像数据。祝你的项目好运!:)非常感谢@markE!我尝试在下一帧之前预渲染动画,如果我理解正确的话?也许会快一点。将需要几分钟…不幸的是预渲染太慢了,但感谢您的知识!FWIW…我提出了这些非正式的基准,用于反复绘制3个相交圆1000次。合成:IE=1149ms,Chrome=80ms,FF=2398ms(哎哟!?)。剪辑:IE=1110ms,Chrome=159ms,FF=998ms。我还用一个纯数学解画了1000次:IE=311ms,Chrome=75ms,FF=398ms。在这些快速测试中,我没有尝试使用屏幕外的画布。这是因为屏幕外画布的性能优势/非优势在很大程度上取决于代码的其他部分。干杯好极了!今天我和你一样玩了好几个小时,但不幸的是背景很重要。@Tobias:是的,我也这么想;),但是试了一下。我必须承认,当我使用心灵之眼编写各种
globalCompositeOperation
方法时,我遇到了一个挑战。这就是我一直在寻找的。这是超级流体,非常感谢。不幸的是,边界有点难看,但目前还可以。干得好@托拜厄斯:是的,我正在努力解决如何去除边框等问题。但我想这是一个开始。还有一件事:因为画布上有数百种其他东西,我不能使用xor,因为在每一帧中渲染整个菜单太贵了。这意味着我总是需要先渲染背景。你认为可以放弃异或吗?
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var ct = [
    'source-over',         //  0
    'source-in',           //  1
    'source-out',          //  2
    'source-atop',         //  3
    'destination-over',    //  4
    'destination-in',      //  5
    'destination-out',     //  6
    'destination-atop',    //  7
    'lighter',             //  8
    'darker',              //  9
    'copy',                // 10
    'xor'                  // 11
];

ctx.beginPath();
ctx.globalCompositeOperation = ct[0];
ctx.fillStyle = "#888";
ctx.arc(100,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[6];
ctx.fillStyle = "#fff";
ctx.arc(180,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[11];
ctx.fillStyle = "#f00";
ctx.arc(100,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[4];
ctx.fillStyle = "#888";
ctx.arc(100,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[9];
ctx.fillStyle = "#fff";
ctx.arc(180,200,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[11];
ctx.fillStyle = "#fff";
ctx.arc(140,140,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[4];
ctx.fillStyle = "#00f";
ctx.arc(140,140,50,0,2*Math.PI);
ctx.fill();

ctx.beginPath();
ctx.globalCompositeOperation = ct[4];
ctx.rect( 0, 0, 300, 300 );
ctx.fillStyle = '#000';
ctx.fill();