javascript - 如何将物体从头到尾移动半圈?

标签 javascript html css math geometry

我有一个半圆( green )和一个对象( blue )。我想将该圆上的对象从开始( left )移动到结束( right )。对象应遵循半圆的路径 (black)。
enter image description here
对象应根据特定值移动。值是从 0 到 1 的数字。开始 = 0,结束 = 1。
我目前的解决方案:

  • 通过将值乘以 100 将值转换为百分比。因此,0 = 0%、0.5 = 50%、1 = 100%
  • 该对象是一个绝对元素,放置在相对内部
    容器
  • 半圆也放在相对容器内,但不是绝对的
  • 对象将使用 CSS left 移动和 bottom , 初始值为 0%
  • 半圆的前半部分是 0-49% , 后半部分是 50-100%
  • 我也在使用 padding对于半圆和 translate为对象。 padding只需要美观,实际上并不影响解决方案。 translate left 的正确位置是必需的和 bottom相对于“相对容器”

  • enter image description here
    我想出了如何在 Y 轴上移动对象:
    // p is from 0 to 100
    const bottom = (
        p < 50 ?
        p * 2 :
        100 - (p - 50) * 2
    );
    
    但我不知道如何正确移动 X 轴。目前我有这个:
    const left = p;
    
    这给了我这个结果:
    enter image description here
    那么,如何正确地将对象移动到 X 轴上呢? 或者也许对 X 轴和 Y 轴都有更好的解决方案?
    请注意:
  • 很可能它应该是依赖于 JavaScript 的解决方案,而不仅仅是 CSS。我需要控制 value .我将手动设置它并手动更新它。有时根本不会有动画,因为我不会从0迭代到1,而是只设置一次。
  • 我需要和这两个互动<svg>元素,而不是创建我自己的元素。原因是每个 <svg>具有线性渐变填充,无法使用 border 正确完成.

  • 这是我当前解决方案的片段:

    async function main() {
        let value = 0; // from 0 to 1
    
        while (value < 1) {
            await new Promise((resolve) => {
                window.setTimeout(resolve, 10);
            });
            value += 0.01;
            move(value);
        }
    
    }
    
    function move(value) {
        const p = 100 * value;
        const bottom = (
            p < 50 ?
            p * 2 :
            100 - (p - 50) * 2
        );
        const left = p;
        const css = {
            left: `${left}%`,
            bottom: `${bottom}%`,
            transform: `translate(-${left}%, ${bottom}%)`,
        };
        const element = document.getElementById("ellipse-2-container")
    
        element.style.left = css.left;
        element.style.bottom = css.bottom;
        element.style.transform = css.transform;
    }
    
    main()
    .root {
        position: relative;
        width: 20rem;
    }
    
    .ellipse-1 {
        width: 100%;
        height: auto;
        box-sizing: border-box;
        padding: 0.3rem;
    }
    
    .ellipse-2 {
        width: 1.5rem;
        height: auto;
    }
    
    .ellipse-2-container {
        position: absolute;
        left: 0;
        bottom: 0;
        display: flex;
    }
    <div class="root">
        <svg class="ellipse-1" xmlns="http://www.w3.org/2000/svg" width="272" height="125" viewBox="0 0 272 125"
            fill="none">
            <path
                d="M265.2 124.5C268.956 124.5 272.021 121.452 271.797 117.703C269.975 87.1607 255.916 58.2064 232.167 36.4652C206.662 13.1169 172.069 2.4929e-06 136 0C99.9306 -2.4929e-06 65.3384 13.1169 39.8335 36.4652C16.084 58.2064 2.0254 87.1607 0.202617 117.703C-0.0211153 121.452 3.04446 124.5 6.8 124.5C10.5555 124.5 13.5766 121.451 13.8251 117.704C15.6319 90.4658 28.2517 64.6746 49.4501 45.2687C72.4046 24.2552 103.538 12.45 136 12.45C168.463 12.45 199.595 24.2552 222.55 45.2687C243.748 64.6746 256.368 90.4658 258.175 117.704C258.423 121.451 261.444 124.5 265.2 124.5Z"
                fill="green">
            </path>
        </svg>
    
        <div class="ellipse-2-container" id="ellipse-2-container">
            <svg
                class="ellipse-2" xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30"
                fill="none">
                <path
                    d="M27.1759 15C27.1759 21.9292 21.6265 27.5 14.838 27.5C8.04943 27.5 2.5 21.9292 2.5 15C2.5 8.07077 8.04943 2.5 14.838 2.5C21.6265 2.5 27.1759 8.07077 27.1759 15Z"
                    fill="blue">
                </path>
            </svg>
        </div>
    </div>

    注意解决方案。
    我使用了 Temani Afif 解决方案,但几乎没有修改。在问题中我指出我需要保留这两个 <svg>元素。所以,我设置了div.arc边框颜色为透明,去掉不必要的:before, :after .设置 div.arcposition: relative和我的 children <svg>position: absolute .对齐后,它看起来像是在 <svg> 上移动的对象。元素,但实际上它在 div.arc 上移动.

    最佳答案

    仅使用 CSS 且更简单的解决方案怎么样:

    .arc {
      width:250px;
      aspect-ratio:2/1;
      border:20px solid blue;
      border-bottom:0;
      border-radius:200px 200px 0 0;
      box-sizing:border-box;
      display:grid;
    }
    .arc:before,
    .arc:after,
    .arc div{
      content:"";
      width:20px;
      aspect-ratio:1/1;
      border-radius:50%;
      grid-area:1/1;
      background:blue;
    }
    .arc > div {
      background:lightgreen;
      margin:auto auto -10px;
      animation:a 3s linear both 1s;
    }
    @keyframes a{ /* 115px = (250px - 20px)/2 */
      from {transform:rotate(-180deg) translate(115px)}
      to   {transform:rotate(   0deg) translate(115px)}
    }
    
    .arc:before {
      margin:auto auto -10px -20px;
    }
    .arc:after {
      margin:auto -20px -10px auto;
    }
    <div class="arc">
      <div></div>
    </div>

    使用 CSS 变量控制值:

    .arc {
      width:250px;
      aspect-ratio:2/1;
      border:20px solid blue;
      border-bottom:0;
      border-radius:200px 200px 0 0;
      box-sizing:border-box;
      display:grid;
    }
    .arc:before,
    .arc:after,
    .arc div{
      content:"";
      width:20px;
      aspect-ratio:1/1;
      border-radius:50%;
      grid-area:1/1;
      background:blue;
    }
    .arc > div {
      background:lightgreen;
      margin:auto auto -10px;
      transform:rotate(calc(180deg*var(--x) - 180deg)) translate(115px)
    }
    
    
    .arc:before {
      margin:auto auto -10px -20px;
    }
    .arc:after {
      margin:auto -20px -10px auto;
    }
    <div class="arc" style="--x:0">
      <div></div>
    </div>
    
    <div class="arc" style="--x:0.2">
      <div></div>
    </div>
    
    <div class="arc" style="--x:0.6">
      <div></div>
    </div>
    <div class="arc" style="--x:1">
      <div></div>
    </div>

    关于javascript - 如何将物体从头到尾移动半圈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70037322/

    相关文章:

    javascript - 单独或一起检查属性是否有意义?

    javascript - 通过 Selenium 在 AngularJS 中自动上传文件

    html - innerHTML 和改变颜色

    javascript - {{ }} 内的字符串作为插值代码

    javascript - 将 requireJS 模块作为单例使用是一种不好的做法吗?

    css - 嵌套按钮 + 在屏幕上的位置

    javascript - Html5 canvas 不会在 Rails 中使用 javascript 进行迭代

    javascript - 为什么这段 HTML/CSS/jQuery 代码只能在 CodePen 中运行?

    html - 将脚放在页面底部

    javascript - 使用 SelectAll 函数的复选框样式