马黑黑 发表于 2024-9-10 11:56

二次贝塞尔曲线在线绘制

本帖最后由 马黑黑 于 2024-9-10 13:23 编辑

代码:<style>
      #pa { margin: 20px auto; padding: 0; width: 400px; height: 400px; min-width: 100px; min-height: 100px; border: 1px solid gray; resize: both; overflow: hidden; position: relative; }
      #stage > circle { cursor: pointer; }
      #sizeMsg { transform: translateY(20px); }
      #pathMsg:active { user-select: all; }
      .msgbox { margin: 0 auto; width: 400px; font: normal 18px/24px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; }
</style>

<div id="sizeMsg" class="msgbox">400*400</div>
<div id="pa" data-size="400*400">
      <svg id="stage" width="400" height="400">
                <path id="cPath" d="M10 200, C10 10, 390 10, 390 200" fill="none" stroke="steelblue"></path>
                <circle id="start" cx="10" cy="200" r="5" fill="teal"></circle>
                <circle id="c1" cx="200" cy="10" r="5" fill="red"></circle>
                <circle id="end" cx="390" cy="200" r="5" fill="teal"></circle>
      </svg>
</div>
<div id="pathMsg" class="msgbox"></div>

<script>
var balls = ;
var currentball = null;

var ro = new ResizeObserver(elms => {
      var rect = elms.contentRect;
      var data = {
                stage: { w: stage.getAttribute('width'), h: stage.getAttribute('height') },
                start: { x : start.getAttribute('cx'), y: start.getAttribute('cy') },
                c1: { x : c1.getAttribute('cx'), y: c1.getAttribute('cy') },
                end: { x : end.getAttribute('cx'), y: end.getAttribute('cy') },
      };
      setPos(stage, 'width', rect.width);
      setPos(stage, 'height', rect.height);
      setPos(start, 'cx', (data.start.x * rect.width / data.stage.w).toFixed(2));
      setPos(start, 'cy', (data.start.y * rect.height / data.stage.h).toFixed(2));
      setPos(c1,'cx', (data.c1.x * rect.width / data.stage.w).toFixed(2));
      setPos(c1, 'cy', (data.c1.y * rect.height / data.stage.h).toFixed(2));
      setPos(end, 'cx', (data.end.x * rect.width / data.stage.w).toFixed(2));
      setPos(end, 'cy', (data.end.y * rect.height / data.stage.h).toFixed(2));
      cPath.setAttribute('d', setPath(start,c1,end));
      pathMsg.innerText = `d='${cPath.getAttribute('d')}'`;
      pathMsg.style.setProperty('width', rect.width + 'px');
      sizeMsg.style.setProperty('width', rect.width + 'px');
      sizeMsg.innerText = rect.width + '*'+ rect.height;
});

ro.observe(pa);

setPath = (e1,e2,e3) => `M${e1.getAttribute('cx')} ${e1.getAttribute('cy')},Q${e2.getAttribute('cx')} ${e2.getAttribute('cy')},${e3.getAttribute('cx')} ${e3.getAttribute('cy')}`;

setPos = (elm,name, val) => elm.setAttribute(name, val);

balls.forEach(ball => {
      ball.onmousedown = () => currentball = ball;
      ball.onmouseup = () => currentball = null;
});

document.onmouseup = () => currentball = null;

stage.onmousemove = (e) => {
      if(!currentball) return;
      setPos(currentball, 'cx', e.offsetX);
      setPos(currentball, 'cy', e.offsetY);
      cPath.setAttribute('d', setPath(start,c1,end));
      pathMsg.innerText = `d='${cPath.getAttribute('d')}'`;
};
</script>链接:二次贝塞尔曲线在线绘制 (52qingyin.cn)

马黑黑 发表于 2024-9-10 12:03

两端的线头、控制点都可以拖曳。控制点被限制在svg场景中,实际上它可以脱离svg元素,但这样一来会看不到也控制不了控制点,所以简化了;如果需要更陡峭的控制点数值,可以在拿到路径后修改控制点的值。

盒子可以改变大小,操作入口在右下角,向右下或左上拖曳,盒子会变大变小,盒子的尺寸信息实时呈现在盒子的左上方。

三次贝塞尔曲线在线绘制正在测试中,最迟明天发布。

彩云归 发表于 2024-9-10 12:53

谢谢老师教材!

梦江南 发表于 2024-9-10 17:46

谢谢老师辛苦!

红影 发表于 2024-9-10 19:28

这个厉害了,拖曳盒子的时候,三个点还能自动保持和盒子的相对关系呢{:4_187:}

红影 发表于 2024-9-10 19:38

而且盒子也一直自动居中,把盒子拉大了,在上面任意调着3个点,感受着曲线的变化。
当头尾两个点在不同高度上,也可以调整中间的点得到一段比较规整的圆弧,貌似要得到一个斜向的正圆弧,计算出来的值比这样调出来的更准确些{:4_173:}

红影 发表于 2024-9-10 19:44

马黑黑 发表于 2024-9-10 12:03
两端的线头、控制点都可以拖曳。控制点被限制在svg场景中,实际上它可以脱离svg元素,但这样一来会看不到也 ...

三次贝塞尔曲线多了一个控制点,更复杂了。
黑黑厉害,让计算机去处理计算公式,我们只要用鼠标去拉动一下,就能看到它的样子和得到路径{:4_187:}

花飞飞 发表于 2024-9-10 20:06

所有的点都可以画面内的任意位置,比之前想象的更灵活。。可以实现各种形状的需要。。太厉害了。。

花飞飞 发表于 2024-9-10 20:10

看了说明才发现,页面中画面大小可更改,以适合各种大小的贴子。。真是只要能想到的老师都能做到。。帅。

马黑黑 发表于 2024-9-10 20:51

花飞飞 发表于 2024-9-10 20:10
看了说明才发现,页面中画面大小可更改,以适合各种大小的贴子。。真是只要能想到的老师都能做到。。帅。

{:4_172:}

马黑黑 发表于 2024-9-10 20:51

彩云归 发表于 2024-9-10 12:53
谢谢老师教材!

{:4_190:}

马黑黑 发表于 2024-9-10 20:52

梦江南 发表于 2024-9-10 17:46
谢谢老师辛苦!

{:4_190:}

马黑黑 发表于 2024-9-10 20:52

红影 发表于 2024-9-10 19:28
这个厉害了,拖曳盒子的时候,三个点还能自动保持和盒子的相对关系呢

这是做了计算的,看源码应该可以看得出来

马黑黑 发表于 2024-9-10 20:54

花飞飞 发表于 2024-9-10 20:06
所有的点都可以画面内的任意位置,比之前想象的更灵活。。可以实现各种形状的需要。。太厉害了。。

难点就在这里,所有的点都要计算,不过万变不离其宗,曲线的原理就在那里。实现这个,函数的作用就很明显了。

马黑黑 发表于 2024-9-10 20:55

红影 发表于 2024-9-10 19:44
三次贝塞尔曲线多了一个控制点,更复杂了。
黑黑厉害,让计算机去处理计算公式,我们只要用鼠标去拉动一 ...

实际上是先做了三次再做二次。过去有过演示三次的,但没有演示二次的,且起点和终点不可变,现在曲线上所有的点都可变。

红影 发表于 2024-9-10 23:45

马黑黑 发表于 2024-9-10 20:52
这是做了计算的,看源码应该可以看得出来

嗯嗯,这些是被设定好的{:4_187:}

红影 发表于 2024-9-10 23:46

马黑黑 发表于 2024-9-10 20:55
实际上是先做了三次再做二次。过去有过演示三次的,但没有演示二次的,且起点和终点不可变,现在曲线上所 ...

所有点都能变,需要考虑和设计的更多了{:4_187:}

马黑黑 发表于 2024-9-10 23:47

红影 发表于 2024-9-10 23:45
嗯嗯,这些是被设定好的

这就是所谓的编程了:很多情况都是处理数学问题。

马黑黑 发表于 2024-9-10 23:47

红影 发表于 2024-9-10 23:46
所有点都能变,需要考虑和设计的更多了

其实倒也不是酱紫,就是要操作的点多了,比较繁琐而已。

红影 发表于 2024-9-11 11:04

马黑黑 发表于 2024-9-10 23:47
这就是所谓的编程了:很多情况都是处理数学问题。

处理好了以后,就可以交给计算机去运作了。编程也是指挥计算机工作的指挥行为{:4_204:}
页: [1] 2 3 4 5
查看完整版本: 二次贝塞尔曲线在线绘制