使用 js 绘制三次贝塞尔曲线

使用 js 绘制三次贝塞尔曲线

/**
* 生成贝塞尔曲线的点
* @param {Object} point1 
* @param {Object} point2 
* @param {Object} controlPoint1 point1的控制点
* @param {Object} controlPoint2 point2的控制点
* @param {Number} t 取值[0, 1] 设线段point1point2上的某动点p0,t = 线段point1p0长度 / 线段point1point2长度
* @returns 返回曲线上的某个点
*/
function createBezierCurve(startPoint, endPoint, controlPoint1, controlPoint2, t){
	let x = Math.pow(1-t, 3) * startPoint.x + 3 * controlPoint1.x * t * Math.pow(1-t, 2) + 3 * controlPoint2.x * t * t * (1 - t) + endPoint.x * t * t * t
	let y = Math.pow(1-t, 3) * startPoint.y + 3 * controlPoint1.y * t * Math.pow(1-t, 2) + 3 * controlPoint2.y * t * t * (1 - t) + endPoint.y * t * t * t
	return {x, y}
}

/**
* 贝塞尔曲线控制点计算
* @param {Array} pointsArr 贝塞尔曲线所经过的点
* @param {Number} smooth_value 控制曲线丝滑程度 取值[0, 1]
* @returns 
*/
function createBezierCurveControl(pointsArr, smooth_value) {
	let points = [...pointsArr]
	points.unshift({x: points[0].x - 50, y: points[0].y + 50})
	points.push({x: points[points.length - 1].x + 50, y: points[points.length - 1].y + 50})
	let controlPoints = []
	for(let i = 0, len = points.length - 3; i < len; i++){
		let x0 = points[i].x, y0 = points[i].y;
		let x1 = points[i + 1].x, y1 = points[i + 1].y;
		let x2 = points[i + 2].x, y2 = points[i + 2].y;
		let x3 = points[i + 3].x, y3 = points[i + 3].y;
		// 2.求中点
		let xc1 = (x0 + x1) / 2.0;
		let yc1 = (y0 + y1) / 2.0;
		let xc2 = (x1 + x2) / 2.0;
		let yc2 = (y1 + y2) / 2.0;
		let xc3 = (x2 + x3) / 2.0;
		let yc3 = (y2 + y3) / 2.0;

		// 3.求各点连线长度
		let len1 = Math.sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
		let len2 = Math.sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
		let len3 = Math.sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));

		// 4.求连线长度比例(用来确定平移前p2, p3的位置)
		let k1 = len1 / (len1 + len2);
		let k2 = len2 / (len2 + len3);

		// 5.平移点(x1, y1)
		let xm1 = xc1 + (xc2 - xc1) * k1;
		let ym1 = yc1 + (yc2 - yc1) * k1;
		
		// 6.平移点(x2, y2)
		let xm2 = xc2 + (xc3 - xc2) * k2;
		let ym2 = yc2 + (yc3 - yc2) * k2;
		
		// 7.微调控制点与顶点之间的距离,越大曲线越平直
		let ctrl1_x = Math.round(xm1 + (xc2 - xm1) * smooth_value + x1 - xm1) ;
		let ctrl1_y = Math.round(ym1 + (yc2 - ym1) * smooth_value + y1 - ym1);
		
		let ctrl2_x = Math.round(xm2 + (xc2 - xm2) * smooth_value + x2 - xm2);
		let ctrl2_y = Math.round(ym2 + (yc2 - ym2) * smooth_value + y2 - ym2);

		controlPoints.push({x: ctrl1_x, y: ctrl1_y}, {x: ctrl2_x, y: ctrl2_y})
	}
	return controlPoints;
}

/**
* 生成曲线的所有点
* @param {Array} pointsArray 
* @param {Number} smoothValue 控制曲线的丝滑程度, 取值[0, 1]
* @returns 返回曲线的所有点,使用画布绘制即可
*/
function createBezierCurvePoints(pointsArray, smoothValue){
	let controlPoints = createBezierCurveControl(pointsArray, smoothValue);
	let bezierCurvePoints = []
	for (let i = 0; i < pointsArray.length - 1; i++) {
		for(let j = 0; j <= 100; j++){
			bezierCurvePoints.push(createBezierCurve(pointsArray[i], pointsArray[i + 1], controlPoints[2 * i], controlPoints[2 * i + 1], j / 100))
		}
	}
	return bezierCurvePoints
}

使用

let canvas = document.getElementById('myCanvas');
let ctx = canvas.getContext('2d')
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = '#1e1d2b';
ctx.moveTo(200, 200);
let arr = [{x: 200, y: 200}, {x: 300, y: 200}, {x: 200, y: 500}, {x: 500, y: 300}, {x: 600, y: 500}]

let points = createBezierCurvePoints(arr, 0.7)

for(let i = 0; i < points.length; i++){
    ctx.lineTo(points[i].x, points[i].y)
}
ctx.stroke();

效果

在这里插入图片描述
参考文章:http://www.ayqy.net/blog/%E6%B1%82%E4%B8%89%E6%AC%A1%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF%E7%9A%84%E6%8E%A7%E5%88%B6%E7%82%B9/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值