Created
July 11, 2023 08:22
-
-
Save MrZhouZh/0c64a859ef5fd29ddf7617b92c50f7cf to your computer and use it in GitHub Desktop.
贝塞尔曲线算法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @desc 贝塞尔曲线算法,包含了3阶贝塞尔 | |
*/ | |
class Bezier { | |
/** | |
* @desc 获取点,这里可以设置点的个数 | |
* @param {number} num 点个数 | |
* @param {Array} p1 点坐标 | |
* @param {Array} p2 点坐标 | |
* @param {Array} p3 点坐标 | |
* @param {Array} p4 点坐标 | |
* 如果参数是 num, p1, p2 为一阶贝塞尔 | |
* 如果参数是 num, p1, c1, p2 为二阶贝塞尔 | |
* 如果参数是 num, p1, c1, c2, p2 为三阶贝塞尔 | |
*/ | |
getBezierPoints(num = 100, p1, p2, p3, p4) { | |
let func = null; | |
const points = []; | |
if (!p3 && !p4) { | |
func = this.oneBezier; | |
} else if (p3 && !p4) { | |
func = this.twoBezier; | |
} else if (p3 && p4) { | |
func = this.threeBezier; | |
} | |
for (let i = 0; i < num; i++) { | |
points.push(func(i / num, p1, p2, p3, p4)); | |
} | |
if (p4) { | |
points.push([...p4]); | |
} else if (p3) { | |
points.push([...p3]); | |
} | |
return points; | |
} | |
/** | |
* @desc 一阶贝塞尔 | |
* @param {number} t 当前百分比 | |
* @param {Array} p1 起点坐标 | |
* @param {Array} p2 终点坐标 | |
*/ | |
oneBezier(t, p1, p2) { | |
const [x1, y1] = p1; | |
const [x2, y2] = p2; | |
let x = x1 + (x2 - x1) * t; | |
let y = y1 + (y2 - y1) * t; | |
return [x, y]; | |
} | |
/** | |
* @desc 二阶贝塞尔 | |
* @param {number} t 当前百分比 | |
* @param {Array} p1 起点坐标 | |
* @param {Array} p2 终点坐标 | |
* @param {Array} cp 控制点 | |
*/ | |
twoBezier(t, p1, cp, p2) { | |
const [x1, y1] = p1; | |
const [cx, cy] = cp; | |
const [x2, y2] = p2; | |
let x = (1 - t) * (1 - t) * x1 + 2 * t * (1 - t) * cx + t * t * x2; | |
let y = (1 - t) * (1 - t) * y1 + 2 * t * (1 - t) * cy + t * t * y2; | |
return [x, y]; | |
} | |
/** | |
* @desc 三阶贝塞尔 | |
* @param {number} t 当前百分比 | |
* @param {Array} p1 起点坐标 | |
* @param {Array} p2 终点坐标 | |
* @param {Array} cp1 控制点1 | |
* @param {Array} cp2 控制点2 | |
*/ | |
threeBezier(t, p1, cp1, cp2, p2) { | |
const [x1, y1] = p1; | |
const [x2, y2] = p2; | |
const [cx1, cy1] = cp1; | |
const [cx2, cy2] = cp2; | |
let x = | |
x1 * (1 - t) * (1 - t) * (1 - t) + | |
3 * cx1 * t * (1 - t) * (1 - t) + | |
3 * cx2 * t * t * (1 - t) + | |
x2 * t * t * t; | |
let y = | |
y1 * (1 - t) * (1 - t) * (1 - t) + | |
3 * cy1 * t * (1 - t) * (1 - t) + | |
3 * cy2 * t * t * (1 - t) + | |
y2 * t * t * t; | |
return [x, y]; | |
} | |
} | |
export default new Bezier(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> | |
<style> | |
.box{ | |
border: 1px solid #ccc; | |
height: 600px; | |
width: 1000px; | |
margin: 20px auto; | |
position: relative; | |
} | |
.dot { | |
position: absolute; | |
width: 4px; | |
height: 4px; | |
border-radius: 100px; | |
display: inline-block; | |
background: red; | |
font-size: 12px; | |
color: #ccc; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="box" id="oneBezier"></div> | |
<div class="box" id="twoBezier"></div> | |
<div class="box" id="threeBezier"></div> | |
<script type="module" src="./test.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bezier from './bezier'; | |
(function() { | |
const p1 = [0, 0]; | |
const p2 = [1000, 600]; | |
const c1 = [1000, 0]; | |
const c2 = [0, 600]; | |
function $(selector) { | |
return document.querySelector(selector) | |
} | |
// 一阶贝塞尔 | |
const dotNumber = 50; | |
let shtml = ''; | |
bezier.getBezierPoints(dotNumber, p1, p2).forEach(d => { | |
d = d.map(e => parseInt(e, 10)); | |
shtml += `<span style="left: ${d[0]}px; top: ${d[1]}px;" class="dot">${d.join(',')}</span>`; | |
}); | |
$('#oneBezier').innerHTML = shtml; | |
shtml = ''; | |
bezier.getBezierPoints(dotNumber, p1, c1, p2).forEach(d => { | |
d = d.map(e => parseInt(e, 10)); | |
shtml += `<span style="left: ${d[0]}px; top: ${d[1]}px;" class="dot">${d.join(',')}</span>`; | |
}); | |
$('#twoBezier').innerHTML = shtml; | |
shtml = ''; | |
bezier.getBezierPoints(dotNumber, p1, c1, c2, p2).forEach(d => { | |
d = d.map(e => parseInt(e, 10)); | |
shtml += `<span style="left: ${d[0]}px; top: ${d[1]}px;" class="dot">${d.join(',')}</span>`; | |
}); | |
$('#threeBezier').innerHTML = shtml; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment