html5 canvas venn 3个圈子
问题描述:
在画布上创建维恩图表。我试图为每个交叉路口和每个圆圈设置不同的颜色。虽然我可以用重叠的圆圈来做到这一点,但我需要让每个交点成为自己的一部分,这样我就可以操纵每个交点的颜色,因为我将在悬停时进行这种操作。html5 canvas venn 3个圈子
问题是我可以完成所有部分,但最终重叠。以下是现有解决方案的图像:venn diagram image。需要标记/显示来自黄色和蓝色圆圈的重叠而不影响底部圆圈重叠。这里是我到目前为止(我知道这不是最干净的,在简化工作):
<script>
window.LENS = {};
LENS.init = function(){
var self = this;
this.canvas = document.getElementById('canvas');
this.ctx = canvas.getContext('2d');
this.width = window.innerWidth;
this.height = window.innerHeight;
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight+50; //compensate for margin
this.drawLens(this.ctx, this.width, this.height);
}
LENS.drawLens = function (ctx, windowWidth, windowHeight){
var self = this;
var radius=windowWidth/5.25;
var circle1={x:windowWidth/2.5, y:windowHeight/3, r:radius, color: 'rgb(130,205,240)'};
var circle2={x:windowWidth/1.75, y:windowHeight/3, r:radius, color: 'rgb(255,240,180)'};
var circle3={x:circle1.x+circle1.r/2, y:circle1.y+circle1.r/1.2, r:radius, color: 'rgb(245,120,125)'}; //dividing by 1.2 for visual purposes. radius would be centered, but provides optical illusiion
var intersect1={color:'rgb(0,170,145)'};
var intersect2={color:'rgb(130,70,110)'};
var intersect3={color:'rgb(255,160,75)'};
var intersectCenter={color:'rgb(55,55,55)'};
//draw circle1
//ctx.save(); //important or we lose the context and will hold all drawing
ctx.beginPath();
ctx.arc(circle1.x, circle1.y, circle1.r, 0, 2*Math.PI, false);
ctx.fillStyle=circle1.color;
ctx.strokeStyle=circle1.color;
ctx.stroke();
ctx.fill();
//intersection1 top
ctx.beginPath();
ctx.fillStyle=intersect1.color;
ctx.strokeStyle=intersect1.color;
ctx.globalCompositeOperation='source-atop';
ctx.arc(circle2.x,circle2.y,circle2.r, 0, 2*Math.PI, false);
ctx.fill();
//intersection2 top
ctx.beginPath();
ctx.fillStyle=intersect2.color;
ctx.strokeStyle=intersect2.color;
ctx.globalCompositeOperation='source-atop';
ctx.arc(circle3.x,circle3.y,circle3.r, 0, 2*Math.PI, false);
ctx.fill();
//intersect Center
ctx.beginPath();
ctx.globalCompositeOperation='source-atop'
ctx.arc(circle2.x, circle2.y, circle2.r, 0, 2*Math.PI, false);
ctx.fillStyle=intersectCenter.color;
ctx.strokeStyle=intersectCenter.color;
ctx.stroke();
ctx.fill();
//draw intersection3 bottom
ctx.beginPath();
ctx.fillStyle=intersect3.color;
ctx.strokeStyle=intersect3.color;
ctx.globalCompositeOperation='destination-over';
ctx.arc(circle2.x, circle2.y, circle2.r, 0, 2*Math.PI, false);
ctx.fill();
ctx.stroke();
//intersection 3
ctx.beginPath();
ctx.fillStyle=intersect3.color;
ctx.strokeStyle=intersect3.color;
ctx.globalCompositeOperation='destination-in';
ctx.arc(circle3.x, circle3.y, circle3.r, 0, 2*Math.PI, false);
ctx.fill();
ctx.stroke();
//circle3
ctx.beginPath();
ctx.fillStyle=circle3.color;
ctx.globalCompositeOperation='destination-over';
ctx.arc(circle3.x,circle3.y,circle3.r, 0, 2*Math.PI, false);
ctx.fill();
//redraw circle 1
ctx.beginPath();
ctx.globalCompositeOperation='destination-over';
ctx.arc(circle1.x, circle1.y, circle1.r, 0, 2*Math.PI, false);
ctx.fillStyle=circle1.color;
ctx.strokeStyle=circle1.color;
ctx.stroke();
ctx.fill();
//redraw circle 2
ctx.beginPath();
ctx.globalCompositeOperation='destination-over'
ctx.arc(circle2.x, circle2.y, circle2.r, 0, 2*Math.PI, false);
ctx.fillStyle=circle2.color;
ctx.strokeStyle=circle2.color;
ctx.stroke();
ctx.fill();
}
</script>
答
您可以使用使用合成来创建维恩工会的屏幕外的画布。
如果合成被设置为“源极 - 在”那么任何新的附图将仅显示在现有的和新的附图重叠。其他一切都会被清除(变得透明)。
“源内”合成对绘制维恩结合非常理想,因为只有2个圆的交集才能存活。
如果合成设置为“目标输出”,那么任何新图形都会清除新图形重叠的图形。 (这就像一个“擦除”操作)
这个伪代码会显示您的蓝色和黄色的圆圈(一切,但工会将被删除)的工会:
- 绘制蓝色圆圈
- 集合成以 “源式”
- 画黄圈
这个伪代码会显示您遇到麻烦顶蓝黄联盟:
- 绘制蓝色圆圈
- 集合成以“源式”
- 画黄圈
- 集合成以 “目的地出”
- 画红圈
代码和演示:http://jsfiddle.net/m1erickson/XLhT9/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: white; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvas1=document.createElement("canvas");
var ctx1=canvas1.getContext("2d");
var circleBlue={x:50,y:50,r:40};
var circleYellow={x:100,y:50,r:40};
var circleRed={x:75,y:85,r:40};
drawCircle(ctx,circleRed,"salmon");
drawCircle(ctx,circleYellow,"lemonchiffon");
drawCircle(ctx,circleBlue,"lightblue");
$r=$("#r")[0];
$y=$("#y")[0];
$b=$("#b")[0];
$by=$("#by")[0];
$br=$("#br")[0];
$yr=$("#yr")[0];
$byNotR=$("#byNotR")[0];
$brNotY=$("#brNotY")[0];
$yrNotB=$("#yrNotB")[0];
$yrb=$("#yrb")[0];
$r.checked=true;
$y.checked=true;
$b.checked=true;
$(":checkbox").change(function(){drawAll()});
function drawIntersect(a,b,c,notC,color){
ctx1.clearRect(0,0,canvas1.width,canvas1.height);
ctx1.save();
// a
drawCircle(ctx1,a,color);
// b
ctx1.globalCompositeOperation="source-in";
drawCircle(ctx1,b,color);
// c
if(c){drawCircle(ctx1,c,color); }
// notC
ctx1.globalCompositeOperation="destination-out";
if(notC){ drawCircle(ctx1,notC,color); }
ctx1.restore();
ctx.drawImage(canvas1,0,0);
}
function drawCircle(ctx,circle,color){
ctx.beginPath();
ctx.arc(circle.x,circle.y,circle.r,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=color;
ctx.fill();
}
function drawAll(){
ctx.clearRect(0,0,canvas.width,canvas.height);
if($r.checked){drawCircle(ctx,circleRed,"salmon");}
if($y.checked){drawCircle(ctx,circleYellow,"lemonchiffon");}
if($b.checked){drawCircle(ctx,circleBlue,"lightblue");}
if($by.checked){drawIntersect(circleBlue,circleYellow,null,null,"green");}
if($br.checked){drawIntersect(circleBlue,circleRed,null,null,"blue");}
if($yr.checked){drawIntersect(circleYellow,circleRed,null,null,"red");}
if($byNotR.checked){drawIntersect(circleBlue,circleYellow,null,circleRed,"green");}
if($brNotY.checked){drawIntersect(circleBlue,circleRed,null,circleYellow,"blue");}
if($yrNotB.checked){drawIntersect(circleYellow,circleRed,null,circleBlue,"red");}
if($yrb.checked){drawIntersect(circleYellow,circleRed,circleBlue,null,"black");}
}
}); // end $(function(){});
</script>
</head>
<body>
<input type="checkbox" id="r">Red Circle<br>
<input type="checkbox" id="y">Yellow Circle<br>
<input type="checkbox" id="b">Blue Circle<br>
<input type="checkbox" id="by">Blue+Yellow<br>
<input type="checkbox" id="br">Blue+Red<br>
<input type="checkbox" id="yr">Yellow+Red<br>
<input type="checkbox" id="byNotR">Blue+Yellow-Red<br>
<input type="checkbox" id="brNotY">Blue+Red-Yellow<br>
<input type="checkbox" id="yrNotB">Yellow+Red-Blue<br>
<input type="checkbox" id="yrb">Yellow+Red+Blue<br>
<canvas id="canvas" width=150 height=150></canvas>
</body>
</html>