贝赛尔曲线

78 篇文章 2 订阅
17 篇文章 0 订阅

在这里插入图片描述

<template>
    <svg width="400" height="400" class="BG" @mousemove="mousemove">
        <!-- 这样拼字符串,少些点加号,方便改一些 -->
        <path class="Line"
            :d="`M${StartPoint[0]} ${StartPoint[1]} S${ControlPoint[0]} ${ControlPoint[1]} ${EndPoint[0]} ${EndPoint[1]}`" />
        <!-- 起始点 -->
        <circle :cx="StartPoint[0]" :cy="StartPoint[1]" r="5" style="fill:pink; stroke:red; stroke-width:2;" />
        <!-- 结束点示意位置 -->
        <circle :cx="EndPoint[0]" :cy="EndPoint[1]" r="5" style="fill:pink; stroke:red; stroke-width:2;" />
        <!-- 控制点示意位置 -->
        <circle :cx="ControlPoint[0]" :cy="ControlPoint[1]" r="5" style="fill:pink; stroke:red; stroke-width:2;" />
    </svg>
</template>
<script setup>
import { nextTick, ref } from 'vue';
const StartPoint = ref([200, 200]);
const EndPoint = ref([400, 200])
const ControlPoint = ref([300, 200])

const ConstantAngle = 45;

// 未优化的计算方法
const ControlPointCompute = () => {
    // 计算起始坐标点 的 弧度值
    const radian = Math.atan2((EndPoint.value[1] - StartPoint.value[1]), (EndPoint.value[0] - StartPoint.value[0]));
    // 用 cos 弧度 来计算 偏移的角度量
    // CosRadian 弧度值为 -1 ~ 0 ~ 1 的值,可以用来进行判断坐标点左侧还是右侧
    const CosRadian = Math.cos(radian);
    // 当前两点之间的角度值
    const Angle = radian * (180 / Math.PI);
    // 控制点与原点的角度值
    const ControlAngle = Angle - (CosRadian * ConstantAngle);
    // 三角函数求 两点之间的距离(也就是斜边长)
    const distance = Math.sqrt(Math.pow(Math.abs(EndPoint.value[0] - StartPoint.value[0]), 2) + Math.pow(Math.abs(EndPoint.value[1] - StartPoint.value[1]), 2));
    // 根据弧度值,计算一个根据距离和角度决定的半径长度来计算控制点
    const distanceByCosRadian = distance / (2 - Math.abs(CosRadian) * (1 - 0.414));
    // 已知夹角,求临边长及对变长,即为二维坐标值
    const X = Math.cos(((2 * Math.PI) / 360) * ControlAngle) * distanceByCosRadian;
    const Y = Math.sin(((2 * Math.PI) / 360) * ControlAngle) * distanceByCosRadian;
    // 加上原点值,就可得出当前控制点的实际坐标值
    ControlPoint.value = [X + 200, Y + 200];
}




// 弧度值转角度值的常量
const R2A = 180 / Math.PI;
// 角度值转弧度值的常量
const A2R = (2 * Math.PI) / 360

// 优化后的计算方法(减少计算为优先)
// 优化原则:1、同样的计算不计算两次(减少计算时间);
//          2、不创建只使用一次的变量(减少创建变量时的内存消耗)
//          3、测试完全部功能再优化(计算优化后的代码基本上是没有可读性的,所以在优化时,尽量先测试)
const TestCompute = (X, Y) => {
    // X轴坐标点差值
    const DX = Y[0] - X[0];
    // Y轴坐标点差值
    const DY = Y[1] - X[1];
    // 鼠标位置与原点的弧度值
    const radian = Math.atan2(DY, DX);
    // 鼠标点与坐标点的 余弦 值
    const CosRadian = Math.cos(radian);
    // 计算控制点与原点的距离
    const dis = Math.sqrt(Math.pow(Math.abs(DX), 2) + Math.pow(Math.abs(DY), 2)) / (2 - Math.abs(CosRadian) * (1 - 0.414));
    // 计算控制点的弧度值
    const ControlRadian = A2R * (radian * R2A - (CosRadian * ConstantAngle));
    // 计算控制点位置
    ControlPoint.value = [Math.cos(ControlRadian) * dis + X[0], Math.sin(ControlRadian) * dis + X[1]];
}

// ControlPointCompute();
TestCompute(StartPoint.value, EndPoint.value);
const mousemove = (e) => {
    // 获取当前鼠标相对父级位置
    const { offsetX, offsetY } = e;
    EndPoint.value[0] = offsetX;
    EndPoint.value[1] = offsetY;
    // ControlPointCompute();
    TestCompute(StartPoint.value, EndPoint.value);
}




</script>
<style lang="less" scoped>
.BG {
    background-color: rgba(255, 255, 255, 0.1);
}

.Line {
    fill: none;
    stroke: red;
    stroke-width: 2;
}
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值