MyPrint打印设计器(七)svg篇-二阶贝塞尔曲线

svg-二阶贝塞尔曲线

介绍一款强大的svg操作库,能够通过简单的代码,实现svg绘制与操纵,实现拖拽等功能

代码仓库

在线体验

代码仓库:github

代码仓库:gitee

实战项目:MyPrint

操作简单,组件丰富的一站式打印解决方案打印设计器

体验地址:前往

代码仓库:github

代码仓库:gitee

本文将通过一个简单的示例,介绍如何在SVG中绘制一条可拖拽的二次贝塞尔曲线

demo 效果

在这里插入图片描述

实战项目效果

在这里插入图片描述

正文

基础HTML结构

首先,我们需要在HTML中设置基本的SVG元素,以便绘制图形。

<head><meta charset="UTF-8"><title>MyPrint|打印设计|SVG|二阶贝塞尔曲线</title><script src="https://cdn.jsdelivr.net/npm/d3@7"></script><script src="./d3-utils.js"></script><style>body {width: 100vw;height: 100vh;margin: 0;display: flex;justify-content: center;align-items: center;}.chart {width: 100%;height: 100%;overflow: visible;}.chart_wrapper {width: 700px;height: 700px;box-shadow: 2px 2px 10px rgba(10, 10, 10, 0.1);border-radius: 10px;}</style>
</head><body>
<div class="chart_wrapper"><svg id="chartRef" class="chart"><path class="u-path" :d="path"/><line class="u-line"/><line class="u-line"/></svg>
</div>
</body>
</html>

在这个HTML结构中,<svg>元素用于承载我们即将绘制的二次贝塞尔曲线和相关的辅助线。id=“chartRef” 使我们能够在JavaScript中轻松获取到这个元素。

定义初始点和绘制曲线

接下来,我们定义二次贝塞尔曲线的起点、终点和控制点,并绘制曲线。

const chartElement = document.getElementById('chartRef')
const x0 = 100,y0 = 200,cpx = 350,cpy = 450,x = 600,y = 200;function freshSvg() {const path = d3.path();path.moveTo(x0, y0);path.quadraticCurveTo(cpx, cpy, x, y);// 控制点const points = [[x0, y0], [cpx, cpy], [x, y]],// 标题labels = ["开始", "控制点", "结束"],// 辅助线lines = [[points[0], points[1]], [points[1], points[2]]],// 绘制方法draw = () => {const path = d3.path();path.moveTo(...points[0]);path.quadraticCurveTo(...points[1], ...points[2]);return path;};draggable(chartElement, points, labels, lines, draw);
}freshSvg()

在 freshSvg 函数中,首先定义了起点 (x0, y0)、控制点 (cpx, cpy) 和终点 (x, y),然后使用 d3.path() 创建一个路径对象,并通过 moveTo 和 quadraticCurveTo 方法来绘制曲线。

可拖拽的实现

为了使这条曲线更加动态,我们通过 draggable 函数将曲线的控制点、起点和终点设置为可拖拽的。这意味着用户可以拖动这些点,实时改变贝塞尔曲线的形状。

function draggable(chartElement, points, labels, lines, draw) {d3.select(chart).on("mousemove", event => dragSubject({sourceEvent: event})).call(d3.drag().subject(dragSubject).on("start", event => {if (subject) {d3.select(chart).style("cursor", "grabbing");dx = subject[0] - event.x;dy = subject[1] - event.y;}}).on("drag", event => {if (subject) {subject[0] = event.x + dx;subject[1] = event.y + dy;}}).on("end", () => {d3.select(chart).style("cursor", "grab");}).on("start.render drag.render end.render", () =>update(chart, points, labels, lines, draw)));
}

draggable 函数的实现需要处理鼠标或触摸事件,在用户拖拽时动态更新曲线。这部分代码较为复杂,但其核心思想是监听并更新各个点的坐标,然后重新绘制曲线。

完整实现

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdn.jsdelivr.net/npm/d3@7"></script><script src="./d3-utils.js"></script><style>body {width: 100vw;height: 100vh;margin: 0;display: flex;justify-content: center;align-items: center;}.chart {width: 100%;height: 100%;overflow: visible;}.chart_wrapper {width: 700px;height: 700px;box-shadow: 2px 2px 10px rgba(10, 10, 10, 0.1);border-radius: 10px;}</style>
</head><body><div class="chart_wrapper"><svg id="chartRef" class="chart"><path class="u-path" :d="path" /><line class="u-line" /><line class="u-line" /></svg></div>
</body><script>const chartElement = document.getElementById('chartRef')const x0 = 100,y0 = 200,cpx = 350,cpy = 450,x = 600,y = 200;function freshSvg() {const path = d3.path();path.moveTo(x0, y0);path.quadraticCurveTo(cpx, cpy, x, y);// 控制点const points = [[x0, y0], [cpx, cpy], [x, y]],// 标题labels = ["开始", "控制点", "结束"],// 辅助线lines = [[points[0], points[1]], [points[1], points[2]]],// 绘制方法draw = () => {const path = d3.path();path.moveTo(...points[0]);path.quadraticCurveTo(...points[1], ...points[2]);return path;};draggable(chartElement, points, labels, lines, draw);}function update(chart, points, labels, lines, draw) {d3.select(chart).select(".u-path").style("stroke", "orange").style("fill", "none").attr("d", draw());d3.select(chart).selectAll(".u-point").style("stroke", "orange").data(points).join(enter =>enter.append("g").classed("u-point", true).call(g => {g.append("circle").attr("r", 3);g.append("text").text((d, i) => labels[i]).attr("dy", d => (d[1] > 100 ? 15 : -5));})).attr("transform", d => `translate(${d})`);d3.select(chart).selectAll(".u-line").style("stroke", "#aaa").style("stroke-dasharray", "2 2").data(lines).join("line").attr("x1", d => d[0][0]).attr("y1", d => d[0][1]).attr("x2", d => d[1][0]).attr("y2", d => d[1][1]).classed("u-line", true);}function draggable(chart, points, labels, lines, draw) {update(chart, points, labels, lines, draw);const dist = (p, m) => {return Math.sqrt((p[0] - m[0]) ** 2 + (p[1] - m[1]) ** 2);};var subject, dx, dy;function dragSubject(event) {const p = d3.pointer(event.sourceEvent, chart);subject = d3.least(points, (a, b) => dist(p, a) - dist(p, b));if (dist(p, subject) > 48) subject = null;if (subject)d3.select(chart).style("cursor", "hand").style("cursor", "grab");else d3.select(chart).style("cursor", null);return subject;}d3.select(chart).on("mousemove", event => dragSubject({sourceEvent: event})).call(d3.drag().subject(dragSubject).on("start", event => {if (subject) {d3.select(chart).style("cursor", "grabbing");dx = subject[0] - event.x;dy = subject[1] - event.y;}}).on("drag", event => {if (subject) {subject[0] = event.x + dx;subject[1] = event.y + dy;}}).on("end", () => {d3.select(chart).style("cursor", "grab");}).on("start.render drag.render end.render", () =>update(chart, points, labels, lines, draw)));}freshSvg()</script>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1523602.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Ovirt-Engine(4.3.10 )备份恢复

介绍如何进行 oVirt Engine 的备份、恢复以及相关操作&#xff0c;包括自动备份脚本、手动备份步骤、托管引擎的恢复流程&#xff0c;以及恢复后的配置和验证步骤。 1. Engine 备份部分 1.1 备份使用的脚本 以下是一个用于自动备份 oVirt Engine 的 Bash 脚本&#xff1a; …

标签中的ref属性

之前说过了 ref() 函数&#xff0c;现在说的标签中的 ref 属性 和 ref() 函数也存在一定关联。 2、 标签中的 ref 属性分为两种情况&#xff1a; 用在普通DOM标签上&#xff0c;获取的是DOM节点。 用在组件标签上&#xff0c;获取的是组件实例对象 Vue2 中标签上的 ref 属性…

掌握AIGC的魔法:编写高质量提示词的艺术与科学

嘿&#xff0c;技术达人们&#xff0c;&#x1f680; 今天我们来聊聊AIGC界的超级明星——提示词&#xff08;Prompt&#xff09;。在AI生成内容的奇妙世界里&#xff0c;提示词就是那个点石成金的魔法棒。想要AI小伙伴听你的指挥&#xff0c;创造出令人惊叹的内容吗&#xff1…

9.2~9.3-模型量化学习内容

量化简介 量化是将模型浮点数变为定点数运行的过程。通过一个原始float数值range(scale、min、max)&#xff0c;将类似实属域的float数值映射到一个网格比较稀疏的int网络上&#xff0c;中间肯定会产生数值的偏移。 基本概念 &#xff1a;模型量化可以减少模型尺寸&#xff0…

驾驶模拟左拐右拐

目录 根据4个点确定投影变换关系&#xff1a; 驾驶模拟左拐右拐 平移 四个点选 通过3个点定义放射变换&#xff1a;结果不对 根据4个点确定投影变换关系&#xff1a; import cv2 import numpy as npdef apply_perspective_transform(image, src_points, dst_points):# 将选…

spring--小白面试版01

bean 1.Spring框架中的bean是单例的吗? Service Scope("singleton") public class UserServicelmpl implements UserService { } 在Scope中 singleton: bean在每个Spring IOC容器中只有一个实例 prototype:一个bean的定义可以有多个实例 2. Spring框架中的单例bea…

jdk11安装步骤(含安装包)

安装包 通过百度网盘分享的文件&#xff1a;jdk-11.0.15.1_windows-x64_bin.exe 链接&#xff1a;https://pan.baidu.com/s/1IYRnvtPvfgloS8rawtRDvg 提取码&#xff1a;sv1w 一、安装过程 双击安装程序 二、配置环境 右键“此电脑”&#xff0c;点击“属性”&#xff0c;点…

学生管理系统升级(登录注册 + 关联学生管理系统)

新增需求 这是在昨天的基础初代版本上面新增一个登录注册忘记密码的功能 需求分析 注册 登录 忘记密码 user类代码呈现 package StudentSystem;public class User {private String username;private String password;private String personID;private String phoneNumber;pu…

828华为云征文|华为云Flexus X实例docker部署srs6并调优,协议使用webrtc与rtmp

828华为云征文&#xff5c;华为云Flexus X实例docker部署srs6并调优&#xff0c;协议使用webrtc与rtmp 华为云最近正在举办828 B2B企业节&#xff0c;Flexus X实例的促销力度非常大&#xff0c;特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务…

KTH5701 系列低功耗、高精度 3D 霍尔传感器

KTH5701 是一款数字输出的 3D 霍尔芯片&#xff0c;内部 分别集成了 X 轴、 Y 轴和 Z 轴三个独立的霍尔传感器。 信号链采用高精度运放通过 16 bit ADC 将模拟信号 转换成数字输出。外部主机可以采用 SPI 或 I2C 两种 模式读出测量数据。此外&#xff0c;在芯片…

2024第三届大学生算法大赛 真题训练一 解题报告 | 珂学家

前言 题解 这是第三届大学生算法大赛(第二届为清华社杯)的赛前练习赛一. 这是上界比赛的体验报告: 2023第二届“清华社杯”大学生算法大赛 解题报告(流水账版) | 珂学家&#xff0c;个人还是非常推荐这个比赛。 难度分布&#xff1a;4 easy/4 mid-hard/2 hard 赛前练习赛一…

Node.js发票查验接口示例、识别查验接口参数返回

财务、审计等经常与发票打交道的人员常常会遇到虚假发票、错票、重复报销等一系列问题。对于会计审计、代理记账、电子商务等发票查验量多的企业来说&#xff0c;成千上万张发票如果仅依赖于人工来进行核验&#xff0c;速度慢效率低&#xff0c;准确率也没保障&#xff0c;因此…

Tomato靶机通关攻略

步骤一&#xff1a;进行端口扫描&#xff0c;找寻靶机地址 步骤二&#xff1a;访问靶机地址 步骤三&#xff1a;利用dirb进行扫描 得出&#xff1a;/antibot_image/进行访问 步骤四&#xff1a;进入antibots->info.php->右击进入页面源代码->发现存在文件包含漏洞 步…

如何让wave波形信号不显示全路径

Modesim仿真如何让wave信号不显示全路径 问题说明 在使用modesim仿真时&#xff0c;需要利用modesim的wave界面显示调试信号的波形&#xff0c;默认情况下wave栏的左边是显示抓捕信号的全路径的&#xff0c;如下图所示: 这种情况下&#xff0c;区分信号比较麻烦&#xff0c;如…

vulhub xxe靶机渗透测试

1.先用kali的nmap扫描端口 2. 找到靶机地址后用工具扫描目录 3.我们先进入robots.txt中 4.访问xxe文件 5.在登陆时抓包 这里可以看到在我们用户名的位置是有回显的&#xff0c;我们可以在这里做文章 6.因为在 linux 系统中/etc/passwd 文件包含有用户账号信息所以我们可以写一…

开源轻量级进程监控工具monit的使用以及monit进程监控工具常用的监控配置案例示例大全

一、开源轻量级进程监控工具monit的应用 今天在服务器杀进程时&#xff0c;发现有一个进程一直在重启&#xff0c;寻找服务器各种定时任务未发现有定时程序&#xff0c;也没有发现supervisord的进程管理服务&#xff0c;后来才发现服务器上启用了monit这个工具&#xff0c;moni…

上证50ETF期权交易策略有哪些?期权交易时要注意什么?

今天带你了解上证50ETF期权交易策略有哪些&#xff1f;期权交易时要注意什么&#xff1f;上证50ETF期权是一种以华夏50etf基金为标的物的金融衍生品&#xff0c;它允许投资者通过买卖期权合约来对冲风险或进行投机。 期权趋势型策略 趋势型的策略就是我们通常说的追涨杀跌&am…

Anaconda最新安装教程

1 概述 1 介绍 Anaconda是一个专注于数据分析的Python发行版本&#xff0c;它为科学计算和数据科学领域提供了强大的支持。Anaconda是一个开源的Python发行版&#xff0c;包含了conda、Python以及超过190个科学包及其依赖项。这些包涵盖了数据分析、机器学习、深度学习等多个…

自己动手写CPU_step5_移动指令

移动操作指令 define EXE_MOVN 6b001011 //不等于0转移 if rt ! 0 then rs -> rd define EXE_MOVZ 6b001010 //等于0转移 if rt 0 then rs -> rd define EXE_MFHI 6b010000 // hi -> rd define EXE_MFLO 6b010010 // lo…

828华为云征文|华为云Flexus X实例docker部署harbor镜像仓库

828华为云征文&#xff5c;华为云Flexus X实例docker部署harbor镜像仓库 华为云最近正在举办828 B2B企业节&#xff0c;Flexus X实例的促销力度非常大&#xff0c;特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求&#xff0c;一定不要错…