我有一個想法,我試圖用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