캔버스에 hilbert 곡선을 생성하는이 코드 ctx.lineTo
는 호출 될 때마다 애니메이션을 만들려고합니다 . 내가 사용하는 많은 솔루션을 시도 setInterval
하고를 requestAnimationFrame
하지만 그들 중 누구도 작동하지 않습니다.
다음은 코드입니다.
const bw = 904;
const bh = 820;
const pixelX = 10;
const canvas = document.getElementById("board");
canvas.setAttribute("width", bw);
canvas.setAttribute("height", bh);
const ctx = canvas.getContext("2d");
const hilbertCurve = (x, y, Xi, Xj, Yi, Yj, n) => {
if (n < 0) {
ctx.lineTo(x + (Xi + Yi) / 2, y + (Xj + Yj) / 2);
} else {
hilbertCurve(x, y, Yi / 2, Yj / 2, Xi / 2, Xj / 2, n - 1);
hilbertCurve(x + Xi / 2, y + Xj / 2, Xi / 2, Xj / 2, Yi / 2, Yj / 2, n - 1);
hilbertCurve(
x + Xi / 2 + Yi / 2,
y + Xj / 2 + Yj / 2,
Xi / 2,
Xj / 2,
Yi / 2,
Yj / 2,
n - 1
);
hilbertCurve(
x + Xi / 2 + Yi,
y + Xj / 2 + Yj,
-Yi / 2,
-Yj / 2,
-Xi / 2,
-Xj / 2,
n - 1
);
}
};
function draw() {
ctx.beginPath();
hilbertCurve(0, 0, bw, 0, 0, bh, 7);
ctx.strokeStyle = "red";
ctx.stroke();
}
function init() {
window.requestAnimationFrame(draw);
}
init();
<canvas id="board"></canvas>
한 가지 쉬운 해결책은 stroke-dash-array
SVG에 익숙한 사람들이 이미 알고 있는 트릭 을 사용하는 것입니다.
경로를 정의하고를 경로 stroke-dash-array
의 길이로 설정 한 다음 반복 할 때마다을 늘려 stroke-dash-offset
계속 그려지는 것처럼 보이게합니다.
이 솔루션의 가장 큰 문제는 경로의 길이를 파악할 수 있어야한다는 것입니다.
불행히도 어떤 이유인지 모르겠 기 때문에 Path2D 인터페이스는 그렇게 할 수있는 쉬운 방법을 제공하지 않습니다. 반면 SVGGeometryElement에는 매우 편리한 getTotalLength()
메서드가 있습니다. Path2d 및 svg <path> 요소는 동일한 문자열 경로 정의를 허용 할 수 있으므로 hilbertCurve
함수가 문자열 정의를 반환하도록 만든 다음이 문자열을 svg <path> 및 컨텍스트의 Path2D 개체 드로어 블 모두에 사용할 수 있습니다.
const bw = 904;
const bh = 820;
const pixelX = 10;
let path_as_string = "" + hilbertCurve( 0, 0, bw, 0, 0, bh, 7).replace('L', 'M');
const path = new Path2D( path_as_string );
const speed = 5;
const totalLength = getPathLength( path_as_string );
let offset = 0;
const canvas = document.getElementById("board");
canvas.setAttribute("width", bw);
canvas.setAttribute("height", bh);
const ctx = canvas.getContext("2d");
function hilbertCurve( x, y, Xi, Xj, Yi, Yj, n ) {
if (n < 0) {
return "L" + (x + (Xi + Yi) / 2) + "," + (y + (Xj + Yj) / 2);
} else {
return (
hilbertCurve(x, y, Yi / 2, Yj / 2, Xi / 2, Xj / 2, n - 1) +
hilbertCurve(x + Xi / 2, y + Xj / 2, Xi / 2, Xj / 2, Yi / 2, Yj / 2, n - 1) +
hilbertCurve(
x + Xi / 2 + Yi / 2,
y + Xj / 2 + Yj / 2,
Xi / 2,
Xj / 2,
Yi / 2,
Yj / 2,
n - 1
) +
hilbertCurve(
x + Xi / 2 + Yi,
y + Xj / 2 + Yj,
-Yi / 2,
-Yj / 2,
-Xi / 2,
-Xj / 2,
n - 1
)
);
}
};
function draw() {
ctx.clearRect(0,0,canvas.width,canvas.height)
ctx.lineDashOffset = offset;
ctx.stroke(path);
offset += speed;
if( offset < totalLength ) {
requestAnimationFrame(draw);
}
}
function init() {
ctx.strokeStyle = "red";
ctx.setLineDash( [ 0, totalLength, totalLength ] );
requestAnimationFrame(draw);
}
init();
// returns the length of a path from a string definition
function getPathLength( path ) {
const elem = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
elem.setAttribute( 'd', path );
return elem.getTotalLength();
}
canvas { border: 1px solid; }
The animation starts at the bottom left corner<br>
<canvas id="board"></canvas>
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다