文章目录
- [一、判断点是否在闭合路径内(射线法 / 奇偶规则)](#一、判断点是否在闭合路径内(射线法 / 奇偶规则))
-
- [1. 算法原理(射线法)](#1. 算法原理(射线法))
- [2. 通用代码(支持任意多边形 / 闭合路径)](#2. 通用代码(支持任意多边形 / 闭合路径))
- [3. Canvas 原生简化方案](#3. Canvas 原生简化方案)
- 二、判断点是否在圆形内
- 三、线段相交判断
- 四、贝塞尔曲线点判断
- 面试回答万能模板(背这个)
一、判断点是否在闭合路径内(射线法 / 奇偶规则)
这是 Canvas 面试100% 会考的题,用于判断鼠标点击是否在多边形、不规则图形内。
1. 算法原理(射线法)
- 从目标点向右发射一条水平无限长射线
- 统计射线与闭合路径边的相交次数
- 奇数次 = 在图形内,偶数次 = 在图形外
2. 通用代码(支持任意多边形 / 闭合路径)
javascript
/**
* 判断点是否在多边形内部 (射线法)
* @param {Object} point - 目标点 {x, y}
* @param {Array} polygon - 多边形顶点数组 [{x,y}, {x,y}, ...]
* @returns {Boolean} 在内返回 true,在外 false
*/
function isPointInPolygon(point, polygon) {
let inside = false;
const px = point.x;
const py = point.y;
// 遍历多边形所有边(首尾相连)
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i].x, yi = polygon[i].y;
const xj = polygon[j].x, yj = polygon[j].y;
// 核心判断:点的y坐标在边的y区间内 + 射线与边相交
const intersect =
((yi > py) !== (yj > py))
&&
(px < (xj - xi) * (py - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
}
3. Canvas 原生简化方案
Canvas 自带 isPointInPath() API,性能更高、支持圆弧 / 贝塞尔曲线:
javascript
// 绘制闭合路径
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(200, 100);
ctx.lineTo(150, 200);
ctx.closePath();
// 判断点 (150,150) 是否在路径内
const isInPath = ctx.isPointInPath(150, 150);
二、判断点是否在圆形内
超简单,勾股定理计算距离即可。
javascript
/**
* 判断点是否在圆内
* @param {Object} point - 点 {x,y}
* @param {Object} circle - 圆 {x,y,r}
* @returns {Boolean}
*/
function isPointInCircle(point, circle) {
const dx = point.x - circle.x;
const dy = point.y - circle.y;
// 距离平方 < 半径平方(避免开方,提升性能)
return dx * dx + dy * dy <= circle.r * circle.r;
}
三、线段相交判断
用于碰撞检测、路径裁剪。
javascript
/**
* 判断两条线段是否相交
*/
function isSegmentsIntersect(a1, a2, b1, b2) {
// 向量叉乘计算
function cross(p1, p2, p0) {
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
const d1 = cross(b1, b2, a1);
const d2 = cross(b1, b2, a2);
const d3 = cross(a1, a2, b1);
const d4 = cross(a1, a2, b2);
// 跨立实验(快速判断)
if (d1 * d2 < 0 && d3 * d4 < 0) return true;
return false;
}
四、贝塞尔曲线点判断
直接用 Canvas 原生 API,手写算法复杂且没必要:
javascript
// 绘制二次贝塞尔曲线
ctx.beginPath();
ctx.moveTo(50,50);
ctx.quadraticCurveTo(100,100, 150,50);
ctx.lineTo(150,100);
ctx.lineTo(50,100);
ctx.closePath();
// 判断点是否在曲线围成的区域内
ctx.isPointInPath(x, y);
面试回答万能模板(背这个)
面试官问:如何判断点在 Canvas 闭合图形内?
标准回答:
- 对于多边形,我使用射线法:从点向右发射水平射线,统计与边的相交次数,奇数在内、偶数在外;
- 对于圆形,用距离公式判断点到圆心距离是否小于半径;
- 实际开发中,我优先使用 Canvas 原生 isPointInPath(),支持所有路径(多边形、圆弧、贝塞尔曲线),性能最优、代码简洁。
总结
- 核心必考:射线法判断点在多边形内 + isPointInPath 原生 API;
- 基础算法:点圆、点矩形、矩形碰撞、线段相交;
- 面试技巧:先讲原理,再写代码,最后提原生 API 优化。