我需要一些關于這種特定影片的幫助。它是一個方形螺旋圖案,不斷向內,直到完全完成。我確實設法讓它開始,但我不知道如何正確停止影片,我不確定它背后的數學是否大部分有效/正確。
這是我現在所擁有的:
function createSquareSpiralPath(
strokeWidth,
width,
height,
) {
const maxIterations = Math.trunc(Math.min(width, height) / 2 / strokeWidth); // ???
let path = '';
for (let i = 0; i <= maxIterations; i ) {
const step = strokeWidth * i;
const computed = [
`${step},${height - step}`,
`${step},${step}`,
`${width - step - strokeWidth},${step}`,
`${width - step - strokeWidth},${height - step - strokeWidth} `,
];
path = computed.join(' ');
}
return path.trim();
}
.spiral {
stroke-dasharray: 6130;
stroke-dashoffset: 6130;
animation: moveToTheEnd 5s linear forwards;
}
@keyframes moveToTheEnd {
to {
stroke-dashoffset: 0;
}
}
<svg viewBox="-10 -10 350 350" height="350" width="350">
<polyline class="spiral" points="
0,350 0,0 330,0 330,330 20,330 20,20 310,20 310,310 40,310 40,40 290,40 290,290 60,290 60,60 270,60 270,270 80,270 80,80 250,80 250,250 100,250 100,100 230,100 230,230 120,230 120,120 210,120 210,210 140,210 140,140 190,140 190,190 160,190 160,160 170,160 170,170"
style="fill:transparent;stroke:black;stroke-width:20" />
Sorry, your browser does not support inline SVG.
</svg>
我添加了 js 函式只是為了演示我是如何生成點的。如您所見,影片完全按照我的意愿播放,我只是找不到正確包裝它的方法。另外,我不確定這個函式是否會為不同的寬度/高度/筆畫寬度生成正確的點。
我很感激任何幫助!提前致謝。:)
PS.:我找不到這種模式的數學術語(方形螺旋),所以我很高興學習如何正確呼叫它。
編輯
根據@enxaneta 的回答(謝謝!),我似乎錯誤地計算了最大迭代次數。這在任何時候都可以看到width !== height。我將對如何產生這個值進行一些研究,也許這個公式不足以在沒有任何空白的情況下正確“停止”影片。
uj5u.com熱心網友回復:
我想您還需要檢查您當前的繪圖位置是否已經達到最大 x/y(靠近您的中心)。
回圈迭代的計算作業正常。
目前,您在每個步驟中繪制 4 個新點。
根據您stroke-width的情況,當您接近中心 X/Y 坐標時,您可能需要在 2. 或 3. 點之后停止繪圖。
let spiral1 = createSquareSpiralPath(50, 500, 1000);
let spiral1_2 = createSquareSpiralPath(20, 1000, 500);
let spiral2 = createSquareSpiralPath(150, 300, 300);
function createSquareSpiralPath(strokeWidth, width, height) {
let maxIterations = Math.trunc(Math.min(width, height) / 2 / strokeWidth);
let coords = [];
//calculate max X/Y coordinates according to stroke-width
let strokeToWidthRatio = width * 1 / strokeWidth;
let strokeToHeightRatio = height * 1 / strokeWidth;
let maxX = (width - strokeWidth / strokeToWidthRatio) / 2;
let maxY = (height - strokeWidth / strokeToHeightRatio) / 2;
for (let i = 0; i <= maxIterations; i ) {
const step = strokeWidth * i;
// calculate points in iteration
let [x1, y1] = [step, (height - step)];
let [x2, y2] = [step, step];
let [x3, y3] = [(width - step - strokeWidth), step];
let [x4, y4] = [(width - step - strokeWidth), (height - step - strokeWidth)];
//stop drawing if max X/Y coordinates are reached
if (x1 <= maxX && y1 >= maxY) {
coords.push(x1, y1)
}
if (x2 <= maxX && y2 <= maxY) {
coords.push(x2, y2)
}
if (x3 >= maxX && y3 <= maxY) {
coords.push(x3, y3)
}
if (x4 >= maxX && y4 >= maxY) {
coords.push(x4, y4)
}
}
let points = coords.join(' ');
//calc pathLength from coordinates
let pathLength = 0;
for (let i = 0; i < coords.length - 2; i = 2) {
let x1 = coords[i];
let y1 = coords[i 1];
let x2 = coords[i 2];
let y2 = coords[i 3];
let length = Math.sqrt(Math.pow(x2 - x1, 2) Math.pow(y2 - y1, 2));
pathLength = length;
}
//optional: render svg
renderSpiralSVG(points, pathLength, width, height, strokeWidth);
return [points, pathLength];
}
function renderSpiralSVG(points, pathLength, width, height, strokeWidth) {
const ns = "http://www.w3.org/2000/svg";
let svgTmp = document.createElementNS(ns, "svg");
svgTmp.setAttribute(
"viewBox", [-strokeWidth / 2, -strokeWidth / 2, width, height].join(" ")
);
let newPolyline = document.createElementNS(ns, "polyline");
newPolyline.classList.add("spiral");
newPolyline.setAttribute("points", points);
svgTmp.appendChild(newPolyline);
document.body.appendChild(svgTmp);
newPolyline.setAttribute(
"style",
`fill:transparent;
stroke:black;
stroke-linecap: square;
stroke-width:${strokeWidth};
stroke-dashoffset: ${pathLength};
stroke-dasharray: ${pathLength};`
);
}
svg {
border: 1px solid red;
}
svg {
display: inline-block;
height: 20vw;
}
.spiral {
stroke-width: 1;
animation: moveToTheEnd 1s linear forwards;
}
.spiral:hover {
stroke-width: 1!important;
}
@keyframes moveToTheEnd {
to {
stroke-dashoffset: 0;
}
}
<p> Hover to see spiral lines</p>
uj5u.com熱心網友回復:
要控制影片,而不是 CSS,請使用 Web Animations API
https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API
使用 shadowDOM將所有內容包裝在一個標準的 Web 組件
<svg-spiral>中,這樣您就可以在螢屏上擁有多個組件,而不會出現任何全域 CSS 沖突。在多邊形上設定 a
pathLenght="100",因此您不必進行計算stroke-dasharray必須寫為:strokeDasharray在 WAAPI 中影片觸發一個
onfinish函式單擊
<svg-spiral>下面的 SO 代碼段中的 將重新啟動影片
<div style="display:grid;grid:1fr/repeat(4,1fr)">
<svg-spiral></svg-spiral>
<svg-spiral stroke="rebeccapurple" width="1000" strokewidth="10"></svg-spiral>
<svg-spiral stroke="blue" duration="10000"></svg-spiral>
<svg-spiral stroke="red" width="6000" duration="1e4"></svg-spiral>
</div>
<script>
customElements.define("svg-spiral", class extends HTMLElement {
connectedCallback() {
let strokewidth = this.getAttribute("strokewidth") || 30;
let width = this.getAttribute("width") || 500; let height = this.getAttribute("height") || width;
let points = '';
for (let i = 0; i <= ~~(Math.min(width, height) / 2 / strokewidth); i ) {
const step = strokewidth * i;
points = `${step},${height - step} ${step},${step} ${width - step - strokewidth},${step} ${width - step - strokewidth},${height - step - strokewidth} `;
}
this.attachShadow({mode:"open"}).innerHTML = `<svg viewBox="-${strokewidth/2}-${strokewidth/2} ${width} ${height}"><polyline pathLength="100" points="${points}z"
fill="transparent" stroke-width="${strokewidth}" /></svg>`;
this.onclick = (e) => this.animate();
this.animate();
}
animate() {
let spiral = this.shadowRoot.querySelector(".spiral");
spiral.setAttribute("stroke", this.getAttribute("stroke") || "black");
let player = spiral.animate(
[{ strokeDashoffset: 100, strokeDasharray: 100, opacity: 0 },
{ strokeDashoffset: 0, strokeDasharray: 100, opacity: 1 }],
{
duration: ~~(this.getAttribute("duration") || 5000),
iterations: 1
});
player.onfinish = (e) => { spiral.setAttribute("stroke", "green") }
}
})
</script>
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/480118.html
