js手动画平滑曲线,贝塞尔曲线拟合

效果图:

代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>bezier</title><link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"><style>* {margin: 0;padding: 0;}#canvas {background-color: #dcdcdc;margin: 10px;display: block;}.btn {margin-left: 10px;}</style>
</head>
<body><canvas id="canvas" width="800" height="600"></canvas> <button type="button" id="print" class="btn btn-primary">绘制</button><button type="button" id="clear" class="btn btn-primary">清空</button><script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script><script>var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')
var t = 0 //贝塞尔函数涉及的占比比例,0<=t<=1
var clickNodes = [] //点击的控制点对象数组
var bezierNodes = [] //绘制内部控制点的数组
var isPrinted = false //当前存在绘制的曲线
var isPrinting = false //正在绘制中
var num = 0 //控制点数
var isDrag = false //是否进入拖拽行为
var isDragNode = false //是否点击到了控制点
var dragIndex = 0 //被拖拽的点的索引
var clickon = 0 //鼠标按下时间戳
var clickoff = 0 //鼠标抬起
$(canvas).mousedown(function(e){isDrag = trueclickon = new Date().getTime()var diffLeft = $(this).offset().left,diffTop = $(this).offset().top,clientX = e.clientX,clientY = e.clientY,x = clientX - diffLeft,y = clientY - diffTopclickNodes.forEach(function(item, index) {var absX = Math.abs(item.x - x),absY = Math.abs(item.y - y)if(absX < 5 && absY < 5) {isDragNode = truedragIndex = index}})
}).mousemove(function(e) {if(isDrag && isDragNode) {var diffLeft = $(this).offset().left,diffTop = $(this).offset().top,clientX = e.clientX,clientY = e.clientY,x = clientX - diffLeft,y = clientY - diffTopclickNodes[dragIndex] = {x: x,y: y}ctx.clearRect(0, 0, canvas.width, canvas.height)clickNodes.forEach(function(item, index) {var x = item.x,y = item.y,i = parseInt(index, 10) + 1ctx.fillText("p" + i, x, y + 20)ctx.fillText("p" + i + ': ('+ x +', '+ y +')', 10, i * 20)ctx.beginPath()ctx.arc(x, y, 4, 0, Math.PI * 2, false)ctx.fill()ctx.beginPath()ctx.moveTo(startX, startY)ctx.lineTo(x, y)ctx.strokeStyle = '#696969'ctx.stroke()if (index) {var startX = clickNodes[index - 1].x,startY = clickNodes[index - 1].yctx.beginPath()ctx.moveTo(startX, startY)ctx.lineTo(x, y)ctx.stroke()}})if(isPrinted) {var bezierArr = []for(i = 0; i < 1; i+=0.01) {bezierArr.push(bezier(clickNodes, i))}bezierArr.forEach(function(obj, index) {if (index) {var startX = bezierArr[index - 1].x,startY = bezierArr[index - 1].y,x = obj.x,y = obj.yctx.beginPath()ctx.moveTo(startX, startY)ctx.lineTo(x, y)ctx.strokeStyle = 'red'ctx.stroke()}})}}
}).mouseup(function(e) {isDrag = falseisDragNode = falseclickoff = new Date().getTime()if(clickoff - clickon < 200) {var diffLeft = $(this).offset().left,diffTop = $(this).offset().top,clientX = e.clientX,clientY = e.clientYx = clientX - diffLeft,y = clientY - diffTopif(!isPrinted && !isDragNode) {num++var ctx = canvas.getContext('2d')ctx.font = "16px Microsoft YaHei";ctx.fillStyle = '#696969'ctx.fillText("p" + num, x, y + 20);ctx.fillText("p" + num + ': ('+ x +', '+ y +')', 10, num * 20)ctx.beginPath()ctx.arc(x, y, 4, 0, Math.PI * 2, false)ctx.fill()if(clickNodes.length) {var startX = clickNodes[clickNodes.length - 1].x,startY = clickNodes[clickNodes.length - 1].yctx.beginPath() ctx.moveTo(startX, startY)ctx.lineTo(x, y)ctx.strokeStyle = '#696969'ctx.stroke()} clickNodes.push({x: x,y: y})}}
})
$('#print').click(function() {if(!num) returnif(!isPrinting) {isPrinted = truedrawBezier(ctx, clickNodes)}
})
$('#clear').click(function() {if(!isPrinting) {isPrinted = falsectx.clearRect(0, 0, canvas.width, canvas.height)clickNodes = []bezierNodes = []t = 0num = 0}
})function drawBezier(ctx, origin_nodes) {if(t > 1) {isPrinting = falsereturn}isPrinting = truevar nodes = origin_nodest += 0.01ctx.clearRect(0, 0, canvas.width, canvas.height)drawnode(nodes)window.requestAnimationFrame(drawBezier.bind(this, ctx, nodes))
}
function drawnode(nodes) {if(!nodes.length) returnvar _nodes = nodesvar next_nodes = []_nodes.forEach(function(item, index) {var x = item.x,y = item.y    if(_nodes.length === num) {ctx.font = "16px Microsoft YaHei"var i = parseInt(index, 10) + 1ctx.fillText("p" + i, x, y + 20)ctx.fillText("p" + i + ': ('+ x +', '+ y +')', 10, i * 20)}ctx.beginPath()ctx.arc(x, y, 4, 0, Math.PI * 2, false)ctx.fill()if(_nodes.length === 1) {bezierNodes.push(item)if(bezierNodes.length > 1) {bezierNodes.forEach(function (obj, i) {if (i) {var startX = bezierNodes[i - 1].x,startY = bezierNodes[i - 1].y,x = obj.x,y = obj.yctx.beginPath()ctx.moveTo(startX, startY)ctx.lineTo(x, y)ctx.strokeStyle = 'red'ctx.stroke()}})}}if(index) {var startX = _nodes[index - 1].x,startY = _nodes[index - 1].yctx.beginPath()ctx.moveTo(startX, startY)ctx.lineTo(x, y)ctx.strokeStyle = '#696969'ctx.stroke()}})  if(_nodes.length) {for(var i = 0; i < _nodes.length - 1; i++) {var arr = [{x: _nodes[i].x,y: _nodes[i].y}, {x: _nodes[i + 1].x,y: _nodes[i + 1].y }]next_nodes.push(bezier(arr, t))}drawnode(next_nodes)}}
function factorial(num) { //递归阶乘if (num <= 1) {return 1;} else {return num * factorial(num - 1);}
}function bezier(arr, t) { //通过各控制点与占比t计算当前贝塞尔曲线上的点坐标var x = 0,y = 0,n = arr.length - 1arr.forEach(function(item, index) {if(!index) {x += item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) y += item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) } else {x += factorial(n) / factorial(index) / factorial(n - index) * item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) y += factorial(n) / factorial(index) / factorial(n - index) * item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) }})return {x: x,y: y}
}
var getRandomColor = function(){return '#'+Math.floor(Math.random()*16777215).toString(16);
}</script>
</body>
</html>

转自github: 

beziericon-default.png?t=N6B9https://aaaaaaaty.github.io/bezierMaker.js/playground/playground.html

https://github.com/Aaaaaaaty/blogicon-default.png?t=N6B9https://github.com/Aaaaaaaty/blog 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

postgresql 数据库 重建索引 所需时间测试

postgresql 数据库 重建索引 所需时间测试 文章目录 postgresql 数据库 重建索引 所需时间测试前言测试前准备重建索引前数据库状态测试计划重建索引命令测试开始1.先对表2进行测试2. 表3测试3. 表1测试 &#x1f308;后记 前言 众所周知&#xff0c;postgresql数据库使用久了…

layui入门

layui入门 一.ayui简介1.简单易用2.组件丰富3.高度定制化4.响应式布局5.轻量灵活 2.layui的入门基础操作3.登录实例4.注册实例 一.ayui简介 Layui&#xff08;流行音 “layui”&#xff0c;来自“领域的模块化”&#xff09;是一款前端UI框架&#xff0c;专注于提升 Web 开发效…

解决microsoft windows 恶意软件删除工具 占用内存高

1、winR快捷键&#xff0c;输入regedit&#xff0c;按回车键进入注册表编辑器 2、定位到 \HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\ 并创建新项MRT 3、 新建DWORD(32)值&#xff0c;命名为DontOffer ThroughWUAU,数值数据为1; 4、以管理员身份运行命令提示符&#x…

论文(1)——大家说SCI的一区二区和CCF中A类B类是什么意思?

文章目录 引言问题描述问题解决CCF 和A、B、C类CCF注意事项 SCI和一区、二区如何判定你找的论文所属的会议或期刊是几区或者几类&#xff1f;使用特定的网站查询使用浏览器插件 一年之内的应该投什么刊物&#xff1f; 总结参考 引言 已经研一暑假了&#xff0c;周围很多人已经…

【测试开发】Junit 框架

目录 一. 认识 Junit 二. Junit 的常用注解 1. Test 2. Disabled 3. BeforeAll 4. AfterAll 5. BeforeEach 6. AfterEach 7. 执行测试 三. 参数化 1. 引入依赖 2. 单参数 3. 多参数 3.1 通过CSV实现 3.2 通过方法实现 4. 测试用例的执行顺序 四. 断言 五…

系统架构设计师-项目管理

目录 一、盈亏平衡分析 二、进度管理 1、WBS工作分解结构 2、进度管理流程 &#xff08;1&#xff09;活动定义 &#xff08;2&#xff09;活动排序 &#xff08;3&#xff09;活动资源估算&#xff1a; &#xff08;4&#xff09;活动历时估算&#xff1a; &#xff08;5&…

ASP.NET版本泄露【原理扫描】

如果想屏蔽 Server&#xff0c;X-AspNet-Version&#xff0c;X-AspNetMvc-Version 和 X-Powered-By&#xff0c;需要增加&#xff1a; <httpProtocol><customerHeaders><remove name"Server" /><remove name"X-AspNet-Version" />…

volatile原理剖析和实例讲解

一、是什么 volatile是Java的一个关键字&#xff0c;是Java提供的一种轻量级的同步机制&#xff0c; 二、能做什么 保证了不同线程对这个变量进行操作时的可见性&#xff0c;有序性。 三、可见性 可见性主要是指一个线程修改了共享变量的值&#xff0c;另一个线程可以看见…

PLC远程控制模块的通讯方式有哪些?工业网关ZP4000的功能与特点

在工业场景中&#xff0c;我们PLC通常采用有线的方式进行数据通讯&#xff0c;这种通讯方式距离受到局限&#xff0c;随着科技进步发展&#xff0c;人们更依赖于远程控制&#xff0c;以无线通讯的方式能够以更低成本的方式实现PLC远程控制管理。 在不同区域的PLC场景中&#x…

Django_POST请求的CSRF验证

目录 正常验证CSRF form表单 ajax的POST请求 关闭CSRF验证 源码等资料获取方法 django的POST接口发起请求默认清空下需要进行CSRF验证 正常验证CSRF form表单 如果form表单直接在标签之间添加{{ csrf_token }}就可以完成验证 ajax的POST请求 ajax的post需要在请求的he…

【监控系统】Prometheus监控组件Node-Exporter配置实战

这一节&#xff0c;我们来配置一下Node-Exporter&#xff0c;那么我们先来了解一下什么是Prometheus的Exporter&#xff1f; 任何向Prometheus提供监控样本数据的程序都可以被称为一个Exporter&#xff0c;它是一种用于将不同数据源的指标提供给Prometheus进行收集和监控的工具…

ITIL 4—监控和事态管理实践

1 关于本文 本文为监控和事态管理实践提供了实用指南。它分为五个主要部分&#xff0c;内容包括&#xff1a; 有关实践的一般信息监控和事态管理的流程和活动及其在服务价值链中的角色监控和事态管理中涉及的组织和人员支持监控和事态管理的信息和技术合作伙伴和供应商对监控…