前端小功能: 绘制多边形,并判断某个点是否在区域内
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才能很方便的响应舞台的事件。
没有终点,没有彼岸,坚持就好,愿岁月如初
没有终点,没有彼岸,坚持就好,愿岁月如初