캔버스 내부 요소는 DOM 요소만큼 편리하게 대화형 이벤트 리스너를 추가할 수 없습니다. 왜냐하면 캔버스에는 요소에 대한 개념이 없고 단지 캔버스로 그린 그래픽일 뿐이기 때문입니다. 이는 인터랙티브 개발에 꼭 필요한 장애물입니다. 그래픽의 클릭 이벤트를 모니터링하는 아이디어는 매우 간단합니다. 캔버스 요소 자체의 클릭 이벤트를 듣고 클릭 좌표가 내부에 있는지 확인하면 됩니다. 그러면 그래픽 클릭 이벤트가 위장되어 실현될 수 있습니다. 이 기사에서는 좌표점이 캔버스 그래픽 내부에 있는지 확인하는 세 가지 방법을 소개합니다.
합의이 기사에 소개된 세 가지 방법은 캔버스에서 불규칙한 모양과 불규칙한 위치가 있는 그래픽 클릭 이벤트를 식별하는 데 적합합니다. 규칙적인 모양이나 규칙적인 위치가 있는 장면의 경우 여기서는 설명하지 않겠습니다.
픽셀 방식픽셀 감지 방법의 아이디어는 캔버스(여러 개가 있는 경우)에 개별적으로 오프스크린에 여러 그래픽을 그리고 getImageData() 메서드를 사용하여 픽셀 데이터를 얻고 저장하는 것입니다. 캔버스 요소가 클릭 이벤트를 수신할 때 클릭 좌표를 사용하여 클릭이 발생한 캔버스의 픽셀을 직접 계산한 다음 이전에 저장된 그래픽 데이터를 탐색하여 이 픽셀의 알파 값이 0인지 확인할 수 있습니다. 0이면 착륙 지점이 현재 수치 내에 있지 않음을 의미하고, 그렇지 않으면 해당 지점이 이 수치에 도달했음을 의미합니다.
클릭 좌표를 기반으로 클릭된 픽셀 수를 얻는 방법:
픽셀수 = (세로-1) * 캔버스 너비 + 가로좌표
예를 들어 너비가 5인 캔버스에서 좌표 (3,3)을 클릭하면 그림과 같이 위 공식에 따라 구한 픽셀 수는 (3-1) * 5 + 3 = 18입니다.
캔버스에서 내보낸 그래픽 데이터는 rgba 순서로 4개의 숫자 배열로 각 픽셀을 저장하므로 지정된 픽셀의 알파 값에 액세스하려면 이 배열의 pIndex * 4 + 3 값만 읽으면 됩니다. , 이 값이 0이 아니면 픽셀이 표시된다는 의미, 즉 그래픽이 클릭되었다는 의미입니다.
이 방법은 가장 직접적인 아이디어, 가장 정확한 결과를 제공하고 그래픽의 모양에 대한 요구 사항이 없는 방법이라고 생각합니다. 결과가 정확하도록 데이터 캐시를 자주 생성해야 하며, getImageData() 메서드의 성능은 심각한 병목 현상을 발생시킵니다. 따라서 캔버스 그래픽이 정적인 경우에는 이 방법이 매우 적합하고, 그렇지 않은 경우에는 이 방법을 사용하는 것이 적합하지 않습니다.
각도법각도 판단 방법의 원리는 이해하기 쉽습니다. 점이 다각형 내부에 있는 경우 점과 다각형의 모든 꼭지점 사이의 각도를 더하면 정확히 360°가 되어야 합니다.
계산 프로세스는 다음 세 단계로 변환될 수 있습니다.
1. 알려진 다각형 정점과 알려진 좌표가 주어지면 좌표와 정점을 쌍으로 결합하여 3점 대기열을 형성합니다.
2. 알려진 세 점 사이의 각도를 찾으려면 Yu Xuan의 정리를 사용할 수 있습니다.
3. 끼인각의 합이 360°인지 확인
각 단계는 간단하며 다음과 같이 구현됩니다.
//두 점 사이의 거리를 계산합니다. const getDistence = function (p1, p2) { return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2. y) * (p1.y - p2.y))};//angle 메소드는 점이 다각형 내부에 있는지 확인합니다. const checkPointInPolyline = (point, polylinePoints) => { let totalA = 0; const A = 포인트; for (let i = 0; i < 폴리라인포인트.길이; i++) { let B, C; if (i === 폴리라인포인트.길이 - 1) { B = { x: 폴리라인포인트[i][0 ], y: 폴리라인포인트[i][1] }; C = { x: 폴리라인포인트[0][0], y: 폴리라인포인트[0][1] } } else { B = { x: 폴리라인포인트[i][0], y: 폴리라인포인트[i][1] }; C = { x: 폴리라인포인트[i + 1][0], y: 폴리라인포인트[i + 1][1] }; } //각도 계산 const angleA = Math.acos((Math.pow(getDistence(A, C), 2) + Math.pow(getDistence(A, B), 2) - Math.pow(getDistence(B, C), 2)) / (2 * getDistence(A, C) * getDistence(A, B))) totalA += angleA } //합계를 판단합니다. 각도는 totalA를 반환합니다. === 2 * Math.PI}이 방법의 한 가지 제한 사항은 모양이 볼록한 다각형이어야 한다는 것입니다. 다각형이 볼록 다각형이 아닌 경우 계산하기 전에 볼록 다각형으로 잘라야 하며 이는 더 복잡합니다.
비슷한 개념으로, 점이 다각형 내부에 있는 경우 점과 다각형의 모든 꼭지점으로 이루어진 삼각형의 면적의 합이 다각형의 면적과 같아야 합니다. 폴리곤의 면적을 먼저 계산하는 것은 매우 번거롭기 때문에 이 방법으로 직접 전달할 수 있습니다.
레이 방식레이 방식은 명확하게 설명할 수는 없지만 사용하기 매우 쉬운 방식입니다. 한 점과 다각형의 한 변이 만나는 지점의 개수가 홀수이면 그 점이 다각형 안에 있게 됩니다. 왼쪽과 같은 모든 면의 초점 포인트 수만 계산하면 됩니다. 이 방법은 다각형의 유형을 제한하지 않으며 볼록한 다각형, 오목한 다각형 또는 링도 허용됩니다.
구현하는 것도 매우 간단합니다.
const checkPointInPolyline = (point, polylinePoints) => { //Ray 메서드 let leftSide = 0; const A = point; for (let i = 0; i < polylinePoints.length; i++) { let B, C; == 폴리라인포인트.길이 - 1) { B = { x: 폴리라인포인트[i][0], y: 폴리라인포인트[i][1] } C = { x: 폴리라인포인트[0][0], y: 폴리라인포인트[0][1] } } else { B = { x: 폴리라인포인트[i][0], y: 폴리라인포인트[i][1] }; : 폴리라인포인트[i + 1][0], y: 폴리라인포인트[i + 1][1] } } //왼쪽 교차점 판단 let sortByY = [By, Cy].sort((a,b) => ab) if (sortByY[0] < Ay && sortByY[1] > Ay){ if(Bx<Ax || Cx < Ax){ leftSide++ } } } return leftSide % 2 === 1}광선법에는 특별한 경우가 있는데, 점이 다중 변형의 가장자리에 있을 때 특별한 처리가 필요합니다. 하지만 엔지니어링에서는 처리할 필요가 없다고 생각합니다. 사용자가 우연히 그래픽의 경계를 클릭하면 프로그램은 클릭하지 않았으며 통과할 수 있다고 생각하기 때문입니다.
요약위의 세 가지 방법은 모두 캔버스에서 불규칙한 그래픽의 클릭 감지를 실현할 수 있습니다. 그 중 픽셀 방식의 장점은 모양을 선택하지 않고 정적 장면에서 특정 성능 이점을 갖는다는 것입니다. 각도 방식은 이론적인 가치만 있고 실용성이 좋지 않다고 말해야 합니다. 공학에서 가장 실용적인 방식은 광선 방식입니다. , 제한이 거의 없고 구현하기 쉽습니다. 간단하며 대부분의 경우 광선 방법만 알면 됩니다.