前端小功能: 绘制多边形,并判断某个点是否在区域内

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才能很方便的响应舞台的事件。

 

没有终点,没有彼岸,坚持就好,愿岁月如初

posted @ 2019-08-29 09:33  smallbore  阅读(2752)  评论(0编辑  收藏  举报
回顶部