我有一个想法,我试图用Javascript和HTML5画布编码,但我不知道从哪里开始。如何在两个多边形之间的交集中显示图像?
假设你有多个不同颜色的多边形(假设为矩形,但现在最好的伪随机不规则多边形)。您可以通过单击和拖动来移动多边形。
当你拖动多边形对另一多边形的一个,我想在相交区域显示图像。想象一下,将蓝色多边形拖到红色多边形上以创建一个紫色区域,除了紫色是豹纹图案或照片或类似物。
任何帮助,将不胜感激!谢谢!
我有一个想法,我试图用Javascript和HTML5画布编码,但我不知道从哪里开始。如何在两个多边形之间的交集中显示图像?
假设你有多个不同颜色的多边形(假设为矩形,但现在最好的伪随机不规则多边形)。您可以通过单击和拖动来移动多边形。
当你拖动多边形对另一多边形的一个,我想在相交区域显示图像。想象一下,将蓝色多边形拖到红色多边形上以创建一个紫色区域,除了紫色是豹纹图案或照片或类似物。
任何帮助,将不胜感激!谢谢!
使用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>
或者用合成:HTTPS: //jsfiddle.net/83Lj1b34/ – Kaiido
对于那些不喜欢削波(像我一样)中的那些,你也可以合成实现它。
基本上,你需要绘制形状两次:一次是在可视的画布,一旦上隐藏的一个,仅用于创建交叉区域。
绘制与正常合成模式'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 **/
<canvas id="canvas"></canvas>
*我希望他不会介意,如果他这样做,他只是让我知道。
这对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>
动画版
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);
<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>
寻找对象之间的交集是一个不平凡的任务 – Dummy