我需要一些关于这种特定动画的帮助.这是一个方形螺旋图案,不断向内延伸,直到完全完成.我确实设法让它继续运行,但我不知道如何正确地停止动画,而且我不确定它背后的数学是否基本有效/正确.

以下是我目前的情况:

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函数只是为了演示如何生成点.正如你所看到的动画正是我想要的那样,我只是找不到一种方法来正确地包装它.此外,我不确定此函数是否会为不同的宽度/高度/冲程宽度生成正确的点.

非常感谢您的帮助!提前感谢.:)

附言:我找不到这个模式的数学术语(方形螺旋),所以我非常乐意学习如何正确地调用它.

Edit

基于@enxaneta答案(谢谢!)似乎我没有正确计算最大迭代次数.这可以在width !== height时看到.我将研究如何生成这个值,也许这个公式不足以在没有任何空格的情况下正确地"停止"动画.

推荐答案

我想您还需要判断当前绘图位置是否已达到最大x/y(靠近您的中心).

The calculation for the loops iterations works fine.
Currently you're drawing 4 new points in each step.

根据您的stroke-width,您可能需要停止绘制,例如在2之后.或3.接近中心X/Y坐标时指向.

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>

Css相关问答推荐

MUI Reaction移除焦点上的轮廓边框

Mat-Form-字段占用更多区域,导致其他控件远离它

寻找组件中最大的元素来设置其他组件的高度

输入中的框始终显示在MUI文本字段中

如何在css中创建文件div效果

如何使用CSS滚动驱动动画重复时间轴范围

我无法在css中设置填充或边距

为什么 CSS Calc() 函数只需要+或-运算符前后有空格

带插值的 Sass 数学函数

如何在 VS Code 中获得 JavaFX CSS 属性的自动完成功能?

如何更改导航栏标题中链接的文本 colored颜色 和导航丸中的链接(在shiny 的应用程序中)?

父母是内联块,子元素有%填充=奇怪的行为

对 CSS 容器查询使用多个条件

如何断言 CSS 属性包含Cypress 测试中的一些文本?

在 vuetify 中跨 `default.vue` 和 `index.vue` 维护网格系统

CSS - 在 id 中 Select 类的语法

什么是 ::content/::slotted 伪元素,它是如何工作的?

如何让 Firefox 在文件更改时自动刷新?

将未知大小的大图像居中在一个较小的 div 中,并隐藏溢出

CSS停止图像下的文本换行