我有一个想法,我正在尝试使用Javascript和html5 Canvas进行编码,但我不确定从哪里开始。
假设您有多个不同颜色的多边形(现在假设为矩形,但理想情况下是伪随机不规则多边形)。您可以通过单击并拖动来移动多边形。
当您将其中一个多边形拖到另一个多边形上时,我想在相交的区域中显示一个图像。想象一下,在红色多边形上拖动一个蓝色多边形以创建一个紫色区域,除了紫色外,它是一个豹纹图案,一个照片或类似物。
任何帮助将不胜感激!谢谢!
答案 0 :(得分:1)
使用2d上下文剪辑功能。正常绘制形状然后再次绘制它们,而不是在每个形状后填充使用剪辑。
每个剪辑都应用于上一个剪辑。
当设置了所有剪辑形状后,在顶部绘制图像/形状,只显示剪辑区域内的部分。
要删除剪辑,您需要使用保存和恢复(请参阅演示);
使用我刚写的另一个例子的代码,有点懒。
示例显示使用2D上下文的剪辑功能将3个框合并为蓝色。
/** SimpleUpdate.js begin **/
// short cut vars
var ctx = canvas.getContext("2d");
var w = canvas.width;
var h = canvas.height;
ctx.font = "18px arial";
var cw = w / 2; // center
var ch = h / 2;
var angle = 0;
var focused = false;
var rotated = false;
// Handle all key input
const keys = { // key input object
ArrowLeft : false, // only add key names you want to listen to
ArrowRight : false,
keyEvent (event) {
if (keys[event.code] !== undefined) { // are we interested in this key
keys[event.code] = event.type === "keydown";
rotated = true; // to turn off help
}
}
}
// add key listeners
document.addEventListener("keydown", keys.keyEvent)
document.addEventListener("keyup", keys.keyEvent)
// check if focus click
canvas.addEventListener("click",()=>focused = true);
// main update function
function update (timer) {
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
ctx.clearRect(0,0,w,h);
// draw outside box
ctx.fillStyle = "red"
ctx.fillRect(50, 50, w - 100, h - 100);
// rotate if input
angle += keys.ArrowLeft ? -0.1 : 0;
angle += keys.ArrowRight ? 0.1 : 0;
// set orgin to center of canvas
ctx.setTransform(1, 0, 0, 1, cw, ch);
// rotate
ctx.rotate(angle);
// draw rotated box
ctx.fillStyle = "Black"
ctx.fillRect(-50, -50, 100, 100);
// set transform to center
ctx.setTransform(1, 0, 0, 1, cw, ch);
// rotate
ctx.rotate(angle);
// move to corner
ctx.translate(50,50);
// rotate once more, Doubles the rotation
ctx.rotate(angle);
ctx.fillStyle = "yellow"
ctx.fillRect(-40, -40,80, 80);
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
// set up the clip area
ctx.save(); // save the non cliped canvas state
ctx.beginPath();
ctx.rect(50, 50, w - 100, h - 100);
ctx.clip(); // clip main box
// set orgin to center of canvas
ctx.setTransform(1, 0, 0, 1, cw, ch);
ctx.rotate(angle);
ctx.beginPath();
ctx.rect(-50, -50, 100, 100);
ctx.clip(); // add to clip (reduces area
ctx.setTransform(1, 0, 0, 1, cw, ch);
ctx.rotate(angle);
ctx.translate(50,50);
ctx.rotate(angle);
ctx.beginPath();
ctx.rect(-40, -40,80, 80);
ctx.clip();
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
ctx.fillStyle = "blue"
ctx.fillRect(0, 0, w, h);
ctx.restore(); // this removes the clip. It is the only way to remove it
// apart from reseting the context
ctx.fillStyle = "white"
ctx.lineWidth = 3;
if(!focused){
ctx.strokeText("Click on canvas to get focus.",10,20);
ctx.fillText("Click on canvas to get focus.",10,20);
}else if(!rotated){
ctx.strokeText("Left right arrow to rotate.",10,20);
ctx.fillText("Left right arrow to rotate.",10,20);
}else{
ctx.strokeText("Blue is the union of the...",10,20);
ctx.fillText("Blue is the union of the...",10,20);
ctx.strokeText("...yellow, black, and red boxes.",10,h-5);
ctx.fillText("...yellow, black, and red boxes.",10,h-5);
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
/** SimpleUpdate.js end **/

<canvas id = canvas></canvas>
&#13;
答案 1 :(得分:1)
SVG有点简单。 :)
<svg viewBox="0 0 800 500">
<defs>
<circle id="left" cx="250" cy="250" r="250"/>
<circle id="right" cx="550" cy="250" r="250"/>
<mask id="intersect">
<rect width="100%" height="100%" fill="black"/>
<use xlink:href="#right" fill="white" mask="url(#maskleft)"/>
</mask>
<mask id="maskleft">
<rect width="100%" height="100%" fill="black"/>
<use xlink:href="#left" fill="white"/>
</mask>
</defs>
<use xlink:href="#left" fill="red"/>
<use xlink:href="#right" fill="blue"/>
<image xlink:href="http://lorempixel.com/output/animals-q-c-500-500-8.jpg"
x="280" y="0" width="500" height="500" mask="url(#intersect)"/>
</svg>
&#13;
动画版
var start = null;
var maskleftcircle = document.getElementById("maskleftcircle");
var puppygroup = document.getElementById("puppygroup");
function step(timestamp) {
if (!start) start = timestamp;
var angle = ((timestamp - start)/250) % 360;
var dx = 100 * Math.cos(angle);
var dy = -100 * Math.sin(angle);
puppygroup.setAttribute("transform", "translate("+dx+","+dy+")");
maskleftcircle.setAttribute("transform", "translate("+(-dx)+","+(-dy)+")");
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
&#13;
<svg viewBox="0 0 800 500">
<defs>
<circle id="left" cx="250" cy="250" r="250"/>
<circle id="right" cx="550" cy="250" r="250"/>
<mask id="intersect">
<rect width="100%" height="100%" fill="black"/>
<use xlink:href="#right" fill="white" mask="url(#maskleft)"/>
</mask>
<mask id="maskleft">
<rect width="100%" height="100%" fill="black"/>
<use xlink:href="#left" fill="white" id="maskleftcircle"/>
</mask>
</defs>
<use xlink:href="#left" fill="red"/>
<g id="puppygroup">
<use xlink:href="#right" fill="blue"/>
<image xlink:href="http://lorempixel.com/output/animals-q-c-500-500-8.jpg"
x="300" y="0" width="500" height="500" mask="url(#intersect)"/>
</g>
</svg>
&#13;
答案 2 :(得分:0)
对于那些不喜欢剪辑的人(比如我),你也可以通过合成实现它。
基本上,您需要两次绘制形状:一次在可见画布上,一次在隐藏的画布上,仅用于创建交叉区域。
使用正常合成模式'source-over'
绘制第一个形状
然后,使用合成模式'source-in'
绘制所有形状。这将仅保留与先前绘制的像素重叠的新像素。
当您完成绘制形状时,只有交叉部分应保留在此隐藏的画布上。因此,使用此合成模式,您可以绘制图像,画布的大小。您的图片将被剪裁。
由于我也很懒,我无耻地接受了Blindman67的代码*,并且甚至不打算以更优雅的方式重写它以避免样板,而它应该可以完成。
/** SimpleUpdate.js begin **/
// short cut vars
var ctx = canvas.getContext("2d");
// create an hidden canvas' context
var ctx1 = canvas.cloneNode().getContext('2d');
var w = canvas.width;
var h = canvas.height;
ctx.font = "18px arial";
var cw = w / 2; // center
var ch = h / 2;
var angle = 0;
var focused = false;
var rotated = false;
var img = new Image();
img.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/55/John_William_Waterhouse_A_Mermaid.jpg/100px-John_William_Waterhouse_A_Mermaid.jpg';
// Handle all key input
const keys = { // key input object
ArrowLeft: false, // only add key names you want to listen to
ArrowRight: false,
keyEvent(event) {
if (keys[event.code] !== undefined) { // are we interested in this key
keys[event.code] = event.type === "keydown";
rotated = true; // to turn off help
}
}
}
// add key listeners
document.addEventListener("keydown", keys.keyEvent)
document.addEventListener("keyup", keys.keyEvent)
// check if focus click
canvas.addEventListener("click", () => focused = true);
// main update function
function update(timer) {
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
ctx1.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, w, h);
ctx1.clearRect(0, 0, w, h);
// draw outside box
ctx.fillStyle = "red"
ctx.fillRect(50, 50, w - 100, h - 100);
// reset default compositing mode
ctx1.globalCompositeOperation = 'source-over';
// and draw the first shape
ctx1.fillRect(50, 50, w - 100, h - 100);
// now we will keep only the new pixels which overlap with existing ones
ctx1.globalCompositeOperation = 'source-in';
// rotate if input
angle += keys.ArrowLeft ? -0.1 : 0;
angle += keys.ArrowRight ? 0.1 : 0;
// set origin to center of canvas
ctx.setTransform(1, 0, 0, 1, cw, ch);
// apply all the same transforms to the hidden canvas
ctx1.setTransform(1, 0, 0, 1, cw, ch);
// rotate
ctx.rotate(angle);
ctx1.rotate(angle);
// draw rotated box
ctx.fillStyle = "Black"
ctx.fillRect(-50, -50, 100, 100);
ctx1.fillRect(-50, -50, 100, 100);
// set transform to center
ctx.setTransform(1, 0, 0, 1, cw, ch);
ctx1.setTransform(1, 0, 0, 1, cw, ch);
// rotate
ctx.rotate(angle);
ctx1.rotate(angle);
// move to corner
ctx.translate(50, 50);
ctx1.translate(50, 50);
// rotate once more, Doubles the rotation
ctx.rotate(angle);
ctx1.rotate(angle);
ctx.fillStyle = "yellow"
ctx.fillRect(-40, -40, 80, 80);
ctx1.fillRect(-40, -40, 80, 80);
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
ctx1.setTransform(1, 0, 0, 1, 0, 0);
// our hidden canvas only contains the overlapping of all our shapes
// we can draw our image on this intersection area
ctx1.drawImage(img, 0, 0, w, h);
// and draw this back on the main canvas
ctx.drawImage(ctx1.canvas, 0, 0);
ctx.fillStyle = "white"
ctx.lineWidth = 3;
if (!focused) {
ctx.strokeText("Click on canvas to get focus.", 10, 20);
ctx.fillText("Click on canvas to get focus.", 10, 20);
} else if (!rotated) {
ctx.strokeText("Left right arrow to rotate.", 10, 20);
ctx.fillText("Left right arrow to rotate.", 10, 20);
} else {
ctx.strokeText("Image is the union of the...", 10, 20);
ctx.fillText("Image is the union of the...", 10, 20);
ctx.strokeText("...yellow, black, and red boxes.", 10, h - 5);
ctx.fillText("...yellow, black, and red boxes.", 10, h - 5);
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
/** SimpleUpdate.js end **/
&#13;
<canvas id="canvas"></canvas>
&#13;
*我希望他不会介意,如果他这样做,他只需告诉我。