canvas 繪制不規則多邊形,包涵里面的元素不能超出多邊形。
canvas繪制多邊形,並且判斷某個點是否在區域內。
涉及canvas畫點,畫線,成面。
x,y坐標系,斜率,js拖拽等。
斜率: k=(y2-y1)/(x2-x1);
canvas畫點,畫線,成面:
// 繪制連接的折線 this.cxt.beginPath(); this.cxt.strokeStyle='#666'; this.cxt.lineWidth = 1; this.cxt.moveTo(maxXyArr[0].x,maxXyArr[0].y ); for(let i=1,len=maxXyArr.length;i<len;i++){ this.cxt.lineTo(maxXyArr[i].x,maxXyArr[i].y); } this.cxt.closePath(); //雖然我們只繪制了兩條線段,但是closePath會closePath,仍然是一個3角形 this.cxt.stroke(); // 描邊。stroke不會自動closePath()
maxXyArr,就是坐標點。錄入三個以上坐標就能成面。
demo坐標例子maxXyArr:[{x:100,y:100},{x:100,y:400},{x:400,y:400},{x:400,y:100}],
當然這個是一個規矩的四邊形,判斷某個點是否在區域內,可以是任意圖形。
判斷某個點在多邊形內部
問題假設:有一個點P,有一個多邊形A,我們要判斷A是否包含P。
基礎知識–光線投射法
原理:
1、從點P出發,任意引一條射線(模擬光線)。
2、記錄該條射線與多邊形A的邊相交點的個數。
3、判斷交點的個數,若為偶數表示在圖形外,若為奇數表示在圖像內。
光線投射法【升級版】
原理:
1、從點P出發,任意引一條射線(模擬光線)。
2、該條射線與多邊形A的邊相交時,若射線從邊的左側貫穿記錄leftCount加1,若射線從邊的右側貫穿記錄rightCount加1。
3、若leftCount-rightCount等於0表示在圖形外部,若不等於0表示圖形內部。
/** * @param dot {{x,y}} 需要判斷的點 * @param coordinates {{x,y}[]} 多邊形點坐標的數組,為保證圖形能夠閉合,起點和終點必須相等。 * 比如三角形需要四個點表示,第一個點和最后一個點必須相同。
* @param noneZeroMode 對不規則圖形進行判斷 */ function judge(dot,coordinates,noneZeroMode) { // 默認啟動none zero mode noneZeroMode=noneZeroMode||1; var x = dot.x,y=dot.y; var crossNum = 0; // 點在線段的左側數目 var leftCount = 0; // 點在線段的右側數目 var rightCount = 0; for(var i=0;i<coordinates.length-1;i++){ var start = coordinates[i]; var end = coordinates[i+1]; // 起點、終點斜率不存在的情況 if(start.x===end.x) { // 因為射線向右水平,此處說明不相交 if(x>start.x) continue; // 從左側貫穿 if((end.y>start.y&&y>=start.y && y<=end.y)){ leftCount++; crossNum++; } // 從右側貫穿 if((end.y<start.y&&y>=end.y && y<=start.y)) { rightCount++; crossNum++; } continue; } // 斜率存在的情況,計算斜率 var k=(end.y-start.y)/(end.x-start.x); // 交點的x坐標 var x0 = (y-start.y)/k+start.x; // 因為射線向右水平,此處說明不相交 if(x>x0) continue; if((end.x>start.x&&x0>=start.x && x0<=end.x)){ crossNum++; if(k>=0) leftCount++; else rightCount++; } if((end.x<start.x&&x0>=end.x && x0<=start.x)) { crossNum++; if(k>=0) rightCount++; else leftCount++; } } return noneZeroMode===1?leftCount-rightCount!==0:crossNum%2===1; },
通過獲取點擊的坐標點進行判斷,於canvas畫矩形
let dot = {x: e.offsetX, y: e.offsetY} let maxArray = JSON.parse(JSON.stringify(maxXyArr)) maxArray.push(coordinates[0]) let flag = judge(dot,maxArray)
console.log(flag)
完成。
這樣的不規則圖形UI才能很方便的響應舞台的事件。
沒有終點,沒有彼岸,堅持就好,願歲月如初
