이 같은 라인을 부드럽게 추기경 스플라인을 사용할 수 있습니다 @Pointy 이미 설명한 바와 같이
원인으로 인해 브라우저가 이벤트에 응답 할 수 있습니다 얼마나 빨리이다 (mousemove
). 더 낮은 수준이기 때문에 나중에 이것을 해결하는 데 도움이되는 Pointer Lock API이라는 API가 있습니다. 그러나 지금은 알고리즘을 사용하여 세그먼트 화 된 라인을 부드럽게 처리해야합니다.
스무딩 외에도 세부 스무딩, 포인트 감소, 테이퍼 및 결과를 향상시키는 데 적용 할 수있는 다른 사항이 있습니다.
하지만이 특별한 경우 캔버스의 확장 기능으로 다음과 같은 기능을 사용할 수 있습니다. 그냥 전화 :
는
ctx.curve(myPointArray, tension, segments);
ctx.stroke();
배열은 x와 y 포인트 [x1, y1, x2, y2, ... xn, yn
같은 명령이 포함되어 있습니다.
tension
의 일반적인 값은 0.5입니다. segments
(기본값 16)은 선택 사항입니다.
긴장이 길수록 커브가 나타납니다. 세그먼트는 배열의 각 점 사이의 해상도입니다. 그리기 응용 프로그램의 경우 값 5가 좋을 수 있습니다 (결과 점이 적음).
원래의 선을 그리는 별도의 캔버스에서 포인트를 등록하는 것이 좋습니다. 마우스를 사용하여이 함수로 선을 처리하고 주 캔버스에 그려서 그리기 캔버스를 지 웁니다.
이 함수는 매우 최적화되어 있으며 매번 다시 처리하는 대신 결과를 저장할 수 있도록 처리 된 점도 반환합니다.
/**
* curve() by Ken Fyrstenberg (c) 2013 Epistemex
* See Code Project for full source:
* http://www.codeproject.com/Tips/562175/Draw-Smooth-Lines-on-HTML5-Canvas
*/
CanvasRenderingContext2D.prototype.curve = function(pts, ts, nos) {
nos = (typeof numOfSegments === 'undefined') ? 16 : nos;
var _pts = [], res = [], // clone array
x, y, // our x,y coords
t1x, t2x, t1y, t2y, // tension vectors
c1, c2, c3, c4, // cardinal points
st, st2, st3, st23, st32, // steps
t, i, l = pts.length,
pt1, pt2, pt3, pt4;
_pts.push(pts[0]); //copy 1. point and insert at beginning
_pts.push(pts[1]);
_pts = _pts.concat(pts);
_pts.push(pts[l - 2]); //copy last point and append
_pts.push(pts[l - 1]);
this.moveTo(pts[0], pts[1])
for (i = 2; i < l; i+=2) {
pt1 = _pts[i];
pt2 = _pts[i+1];
pt3 = _pts[i+2];
pt4 = _pts[i+3];
// calc tension vectors
t1x = (pt3 - _pts[i-2]) * ts;
t2x = (_pts[i+4] - pt1) * ts;
t1y = (pt4 - _pts[i-1]) * ts;
t2y = (_pts[i+5] - pt2) * ts;
for (t = 0; t <= nos; t++) {
// pre-calc steps
st = t/nos;
st2 = st * st;
st3 = st2 * st;
st23 = st3 * 2;
st32 = st2 * 3;
// calc cardinals
c1 = st23 - st32 + 1;
c2 = st32 - st23;
c3 = st3 - 2 * st2 + st;
c4 = st3 - st2;
res.push(c1 * pt1 + c2 * pt3 + c3 * t1x + c4 * t2x);
res.push(c1 * pt2 + c2 * pt4 + c3 * t1y + c4 * t2y);
} //for t
} //for i
l = res.length;
for(i=0;i<l;i+=2) this.lineTo(res[i], res[i+1]);
return res;
} //func ext
카디널 스플라인 구현에 대해서는 this answer을 참조하십시오.
mousemove 포인트 (위의 스크린 샷에 표시된 정점)를 사용하여 실험 해 볼 수 있습니다. 그러나 직선보다는 곡선을 그리는 것이 좋습니다. 직선을 사용하면 브라우저가 빨리 캔버스를 다시 렌더링 할 수 있습니다 (브라우저 또는 OS가 다른 작업을 수행하는 경우 가끔 발생하는 딸꾹질). –
예, 좋은 생각입니다. Bezier 나 Catmull-Rom 스플라인을 사용하여 부드럽게 만들 수 있지만 때때로 이상한 결과가 발생할 수 있습니다. – Pointy
예, 그렇지만 뇌졸중이 내 마우스 움직임과 유사하지는 않습니다. 이것은 보간법 일뿐입니다. 그리고 곡선을 계산하려면 여분의 시간이 걸릴 것입니다. – daisy