2017-04-11 22 views
0

我有一個想法,我試圖用Javascript和HTML5畫布編碼,但我不知道從哪裏開始。如何在兩個多邊形之間的交集中顯示圖像?

假設你有多個不同顏色的多邊形(假設爲矩形,但現在最好的僞隨機不規則多邊形)。您可以通過單擊和拖動來移動多邊形。

當你拖動多邊形對另一多邊形的一個,我想在相交區域顯示圖像。想象一下,將藍色多邊形拖到紅色多邊形上以創建一個紫色區域,除了紫色是豹紋圖案或照片或類似物。

任何幫助,將不勝感激!謝謝!

+0

尋找對象之間的交集是一個不平凡的任務 – Dummy

回答

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>

+0

或者用合成:HTTPS: //jsfiddle.net/83Lj1b34/ – Kaiido

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 **/
<canvas id="canvas"></canvas>

*我希望他不會介意,如果他這樣做,他只是讓我知道。

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>

動畫版

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>

+0

除了當你需要使所有這些形狀動態地移動/出現/消失時;-) – Kaiido

+0

接受的挑戰:) –

+0

我沒有說不可能;-)只是沒有從你的代碼片段看起來那麼簡單。 Canvas代碼也會更簡單,與您的結果完全相同。 (Ps:沒有libs允許這個挑戰:-D) – Kaiido