나는 캔버스를 배우거나 프로젝트 개발에서 캔버스를 사용할 때 모든 사람이 작성할 수 있는 스케치패드 가젯을 구현하는 것과 같은 필요성에 직면했어야 한다고 믿습니다.
글쎄요, 저는 캔버스에 더 익숙한 어린이라면 수십 줄의 코드만으로 이 작업을 수행할 수 있다고 믿습니다. 다음 데모는 간단한 예입니다.
<!DOCTYPE html><html><head> <title>스케치패드 데모</title> <style type=text/css> canvas { border: 1px blue solid } </style></head><body> <canvas; id=canvas width=800 height=500></canvas> <script type=text/javascript> let isDown = false; let startPoint = null; document.querySelector('#canvas'); // 선 색상 설정 ctx.lineWidth = ctx.lineJoin; .lineCap = 'round'; canvas.addEventListener('mousedown', down, false); move, false); canvas.addEventListener('mouseout', up, false); function down(evt) { isDown = true; move(evt) { if (!isDown) return; const endPoint = getPos(evt); startPoint = endPoint }; up(evt) { if (!isDown) return; const endPoint = getPos(evt); startPoint = null; isDown = false } return { x: evt.clientX, y: evt.clientY } } function drawLine(beginPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, startPoint.y); ctx.lineTo(endPoint.x, endPoint.y) ctx.closePath(); >
구현 논리도 매우 간단합니다.
mousedown
, mouseup
및 mousemove
의 세 가지 이벤트를 수신하고 isDown
변수도 생성합니다.mousedown
) isDown
true
로 설정하고, 마우스를 눌렀을 때( mouseup
) false
로 설정하면 사용자가 현재 그리기 상태인지 확인할 수 있다는 장점이 있습니다. ;mousemove
이벤트를 통해 마우스가 통과하는 좌표점을 지속적으로 수집합니다. isDown
이 true
(즉, 쓰기 상태)인 경우에만 lineTo
메서드를 통해 현재 지점이 이전 지점과 연결되어 그려집니다. 캔버스;위의 단계를 통해 기본 드로잉 보드 기능을 구현할 수 있습니다. 그러나 조심성 있는 어린이 신발은 매우 심각한 문제를 발견할 수 있습니다. 이렇게 그린 선은 고르지 않고 매끄럽지 않습니다. 그릴수록 파선의 느낌이 강해집니다. 성능은 아래와 같습니다.
왜 이런 일이 발생합니까? 문제 분석이 현상의 주요 원인은 다음과 같습니다.
캔버스의 lineTo
메소드를 사용하여 점을 연결합니다. 인접한 두 점을 연결하는 것은 곡선이 아니라 직선이므로 이렇게 그리는 것은 폴리라인입니다.
브라우저의 mousemove
이벤트 수집 빈도에 따라 제한되므로 mousemove
동안 브라우저는 짧은 시간마다 현재 마우스의 좌표를 수집합니다. 따라서 마우스가 더 빨리 움직일수록 수집된 두 인접한 지점 사이의 거리는 더 멀어집니다. 멀어질수록 접는 선의 느낌이 더욱 분명해집니다.
실제로 부드러운 곡선을 그리는 방법이 있습니다. lineTo
가 신뢰할 수 없는 경우 2차 베지어 곡선을 그리는 데 사용되는 캔버스의 또 다른 그리기 API( quadraticCurveTo
를 사용할 수 있습니다.
2차 베지어 곡선
quadraticCurveTo(cp1x, cp1y, x, y)
quadraticCurveTo
메서드를 호출하려면 제어점을 설명하는 4개의 매개변수 cp1x
와 cp1y
필요하고, x
와 y
곡선의 끝점입니다.
더 자세한 정보는 MDN에서 확인하실 수 있습니다.
베지어 곡선을 사용하려고 하기 때문에 데이터가 충분하지 않다는 것이 분명합니다. 2차 베지어 곡선을 완전히 설명하려면 시작점, 제어점 및 끝점이 필요합니다.
이 정보를 얻는 데 도움이 되는 매우 영리한 알고리즘이 있습니다.
2차 베지어 키 포인트를 얻기 위한 알고리즘이 알고리즘은 이해하기 어렵지 않습니다. 직접 예를 들어 보겠습니다.
그림에서 총 6개의 마우스 좌표, 즉 A, B, C, D, E, F
수집하고 이전 세 점 A, B, C
가져와 B
와 C
의 중간점 B1
계산하고 A
사용한다고 가정합니다. 시작점, B
는 제어점, B1
은 끝점입니다. quadraticCurveTo
사용하여 2차 베지어 곡선 세그먼트를 그립니다.
다음으로, 점 C
와 D
사이의 중간점 C1
계산하고 B1
시작점으로, C
제어점으로, C1
끝점으로 하여 곡선을 계속 그립니다.
마지막 점 F
에 도달하면 D1
지어 곡선은 D
과 E
의 중간점을 시작점으로, E
제어점으로, F
끝점으로 끝납니다.
좋습니다. 알고리즘은 다음과 같습니다. 그러면 이 알고리즘을 기반으로 기존 코드를 업그레이드하겠습니다.
let isDown = false;let points = [];let BeginPoint = null;const canvas = document.querySelector('#canvas');const ctx = canvas.getContext('2d');//선 색상 설정 ctx.strokStyle = '빨간색';ctx.lineWidth = 1;ctx.lineJoin = '둥근';ctx.lineCap = 'round';canvas.addEventListener('mousedown', down, false);canvas.addEventListener('mousemove', move, false);canvas.addEventListener('mouseup', up, false);canvas.addEventListener('mouseout' , up, false); function down(evt) { isDown = true; const { x, y } = getPos(evt); points.push({x, y}); startPoint = {x, y};}function move(evt) { if (!isDown) return; const { x, y} = getPos(evt); x, y}); if (points.length > 3) { const lastTwoPoints = points.slice(-2); const controlPoint = lastTwoPoints[0]; x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2, y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2, } drawLine(beginPoint, controlPoint, endPoint); BeginPoint = endPoint; }}function up(evt) { if (!isDown) return; const { x, y } = getPos(evt); points.push({x, y}); if (points.length > 3) { const lastTwoPoints = points.slice(-2); const controlPoint = lastTwoPoints[0]; , controlPoint, endPoint); } startPoint = null; isDown = false; points = [];}function getPos(evt) { return { x: evt.clientX, y: evt.clientY }}function drawLine(beginPoint, controlPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, startPoint.y); y, endPoint.x, endPoint.y); ctx.closePath();}
원본을 기반으로 이전 mousemove
이벤트에서 마우스가 통과한 지점을 저장하기 위해 변수 points
생성했습니다. 이 알고리즘에 따르면 2차 베지어 곡선을 그리는 데는 최소 3개의 지점이 필요하므로 points
포인트 수가 3보다 큰 경우에만 그리기가 시작됩니다. 후속 처리는 이 알고리즘과 완전히 동일하므로 여기서는 자세히 설명하지 않겠습니다.
코드 업데이트 후 아래 그림과 같이 곡선이 훨씬 부드러워졌습니다.
이번 글은 모두들 캔버스에 즐겁게 그리시길 바랍니다~ 다음에 또 만나요:)
아동용 신발에 관심이 있으시면 여기를 클릭하여 내 블로그를 팔로우하세요. 새롭고 흥미로운 블로그 게시물이 가능한 한 빨리 여기에서 공유될 것입니다~
위 내용은 이 기사의 전체 내용입니다. 모든 분들의 학습에 도움이 되기를 바랍니다. 또한 모든 분들이 VeVb Wulin Network를 지지해 주시길 바랍니다.