猿问

如何使用javascript HTML5画布通过N个点绘制平滑曲线?

如何使用javascript HTML5画布通过N个点绘制平滑曲线?

对于绘图应用程序,我将鼠标移动坐标保存到数组,然后使用lineTo绘制它们。生成的线条不平滑。如何在所有聚集点之间生成单条曲线?

我用谷歌搜索但我只找到了3个绘制线的函数:对于2个样本点,只需使用lineTo。对于3个样本点,quadraticCurveTo,对于4个样本点,bezierCurveTo。

(我尝试在阵列中每4个点绘制一个bezierCurveTo,但这会导致每4个采样点扭结,而不是连续的平滑曲线。)

如何编写一个函数来绘制一个包含5个样本点的平滑曲线?


慕丝7291255
浏览 1698回答 3
3回答

千万里不及你

有点晚了,但是为了记录。您可以通过使用基数样条线(也称为规范样条线)绘制穿过点的平滑曲线来实现平滑线条。我为画布制作了这个功能 - 它分为三个功能,以增加多功能性。主包装函数如下所示:function&nbsp;drawCurve(ctx,&nbsp;ptsa,&nbsp;tension,&nbsp;isClosed,&nbsp;numOfSegments,&nbsp;showPoints)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;showPoints&nbsp;&nbsp;=&nbsp;showPoints&nbsp;?&nbsp;showPoints&nbsp;:&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;ctx.beginPath(); &nbsp;&nbsp;&nbsp;&nbsp;drawLines(ctx,&nbsp;getCurvePoints(ptsa,&nbsp;tension,&nbsp;isClosed,&nbsp;numOfSegments)); &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(showPoints)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctx.stroke(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctx.beginPath(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(var&nbsp;i=0;i<ptsa.length-1;i+=2)&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctx.rect(ptsa[i]&nbsp;-&nbsp;2,&nbsp;ptsa[i+1]&nbsp;-&nbsp;2,&nbsp;4,&nbsp;4); &nbsp;&nbsp;&nbsp;&nbsp;}}绘制曲线的数组中包含x,y点的顺序:x1,y1, x2,y2, ...xn,yn。像这样使用它:var&nbsp;myPoints&nbsp;=&nbsp;[10,10,&nbsp;40,30,&nbsp;100,10];&nbsp;//minimum&nbsp;two&nbsp;pointsvar&nbsp;tension&nbsp;=&nbsp;1;drawCurve(ctx,&nbsp;myPoints);&nbsp;//default&nbsp;tension=0.5drawCurve(ctx,&nbsp;myPoints,&nbsp;tension);上面的函数调用两个子函数,一个用于计算平滑点。这将返回一个带有新点的数组 - 这是计算平滑点的核心函数:function&nbsp;getCurvePoints(pts,&nbsp;tension,&nbsp;isClosed,&nbsp;numOfSegments)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;use&nbsp;input&nbsp;value&nbsp;if&nbsp;provided,&nbsp;or&nbsp;use&nbsp;a&nbsp;default&nbsp;value&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;tension&nbsp;=&nbsp;(typeof&nbsp;tension&nbsp;!=&nbsp;'undefined')&nbsp;?&nbsp;tension&nbsp;:&nbsp;0.5; &nbsp;&nbsp;&nbsp;&nbsp;isClosed&nbsp;=&nbsp;isClosed&nbsp;?&nbsp;isClosed&nbsp;:&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;numOfSegments&nbsp;=&nbsp;numOfSegments&nbsp;?&nbsp;numOfSegments&nbsp;:&nbsp;16; &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;_pts&nbsp;=&nbsp;[],&nbsp;res&nbsp;=&nbsp;[],&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;clone&nbsp;array &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x,&nbsp;y,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;our&nbsp;x,y&nbsp;coords &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t1x,&nbsp;t2x,&nbsp;t1y,&nbsp;t2y,&nbsp;//&nbsp;tension&nbsp;vectors &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c1,&nbsp;c2,&nbsp;c3,&nbsp;c4,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;cardinal&nbsp;points &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;st,&nbsp;t,&nbsp;i;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;steps&nbsp;based&nbsp;on&nbsp;num.&nbsp;of&nbsp;segments &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;clone&nbsp;array&nbsp;so&nbsp;we&nbsp;don't&nbsp;change&nbsp;the&nbsp;original &nbsp;&nbsp;&nbsp;&nbsp;// &nbsp;&nbsp;&nbsp;&nbsp;_pts&nbsp;=&nbsp;pts.slice(0); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;The&nbsp;algorithm&nbsp;require&nbsp;a&nbsp;previous&nbsp;and&nbsp;next&nbsp;point&nbsp;to&nbsp;the&nbsp;actual&nbsp;point&nbsp;array. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Check&nbsp;if&nbsp;we&nbsp;will&nbsp;draw&nbsp;closed&nbsp;or&nbsp;open&nbsp;curve. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;If&nbsp;closed,&nbsp;copy&nbsp;end&nbsp;points&nbsp;to&nbsp;beginning&nbsp;and&nbsp;first&nbsp;points&nbsp;to&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;If&nbsp;open,&nbsp;duplicate&nbsp;first&nbsp;points&nbsp;to&nbsp;befinning,&nbsp;end&nbsp;points&nbsp;to&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(isClosed)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[pts.length&nbsp;-&nbsp;1]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[pts.length&nbsp;-&nbsp;2]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[pts.length&nbsp;-&nbsp;1]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[pts.length&nbsp;-&nbsp;2]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.push(pts[0]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.push(pts[1]); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[1]);&nbsp;&nbsp;&nbsp;//copy&nbsp;1.&nbsp;point&nbsp;and&nbsp;insert&nbsp;at&nbsp;beginning &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[0]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.push(pts[pts.length&nbsp;-&nbsp;2]);&nbsp;//copy&nbsp;last&nbsp;point&nbsp;and&nbsp;append &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_pts.push(pts[pts.length&nbsp;-&nbsp;1]); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;ok,&nbsp;lets&nbsp;start.. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1.&nbsp;loop&nbsp;goes&nbsp;through&nbsp;point&nbsp;array &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;2.&nbsp;loop&nbsp;goes&nbsp;through&nbsp;each&nbsp;segment&nbsp;between&nbsp;the&nbsp;2&nbsp;pts&nbsp;+&nbsp;1e&nbsp;point&nbsp;before&nbsp;and&nbsp;after &nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(i=2;&nbsp;i&nbsp;<&nbsp;(_pts.length&nbsp;-&nbsp;4);&nbsp;i+=2)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(t=0;&nbsp;t&nbsp;<=&nbsp;numOfSegments;&nbsp;t++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;calc&nbsp;tension&nbsp;vectors &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t1x&nbsp;=&nbsp;(_pts[i+2]&nbsp;-&nbsp;_pts[i-2])&nbsp;*&nbsp;tension; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t2x&nbsp;=&nbsp;(_pts[i+4]&nbsp;-&nbsp;_pts[i])&nbsp;*&nbsp;tension; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t1y&nbsp;=&nbsp;(_pts[i+3]&nbsp;-&nbsp;_pts[i-1])&nbsp;*&nbsp;tension; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t2y&nbsp;=&nbsp;(_pts[i+5]&nbsp;-&nbsp;_pts[i+1])&nbsp;*&nbsp;tension; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;calc&nbsp;step &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;st&nbsp;=&nbsp;t&nbsp;/&nbsp;numOfSegments; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;calc&nbsp;cardinals &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c1&nbsp;=&nbsp;&nbsp;&nbsp;2&nbsp;*&nbsp;Math.pow(st,&nbsp;3)&nbsp;&nbsp;-&nbsp;3&nbsp;*&nbsp;Math.pow(st,&nbsp;2)&nbsp;+&nbsp;1;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c2&nbsp;=&nbsp;-(2&nbsp;*&nbsp;Math.pow(st,&nbsp;3))&nbsp;+&nbsp;3&nbsp;*&nbsp;Math.pow(st,&nbsp;2);&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c3&nbsp;=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Math.pow(st,&nbsp;3)&nbsp;&nbsp;-&nbsp;2&nbsp;*&nbsp;Math.pow(st,&nbsp;2)&nbsp;+&nbsp;st;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c4&nbsp;=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Math.pow(st,&nbsp;3)&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Math.pow(st,&nbsp;2); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;calc&nbsp;x&nbsp;and&nbsp;y&nbsp;cords&nbsp;with&nbsp;common&nbsp;control&nbsp;vectors &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;c1&nbsp;*&nbsp;_pts[i]&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;c2&nbsp;*&nbsp;_pts[i+2]&nbsp;+&nbsp;c3&nbsp;*&nbsp;t1x&nbsp;+&nbsp;c4&nbsp;*&nbsp;t2x; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;=&nbsp;c1&nbsp;*&nbsp;_pts[i+1]&nbsp;&nbsp;+&nbsp;c2&nbsp;*&nbsp;_pts[i+3]&nbsp;+&nbsp;c3&nbsp;*&nbsp;t1y&nbsp;+&nbsp;c4&nbsp;*&nbsp;t2y; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//store&nbsp;points&nbsp;in&nbsp;array &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.push(x); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.push(y); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;res;}实际绘制点作为平滑曲线(或任何其他分段线,只要你有一个x,y数组):function&nbsp;drawLines(ctx,&nbsp;pts)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;ctx.moveTo(pts[0],&nbsp;pts[1]); &nbsp;&nbsp;&nbsp;&nbsp;for(i=2;i<pts.length-1;i+=2)&nbsp;ctx.lineTo(pts[i],&nbsp;pts[i+1]);}var&nbsp;ctx&nbsp;=&nbsp;document.getElementById("c").getContext("2d");function&nbsp;drawCurve(ctx,&nbsp;ptsa,&nbsp;tension,&nbsp;isClosed,&nbsp;numOfSegments,&nbsp;showPoints)&nbsp;{ &nbsp;&nbsp;ctx.beginPath(); &nbsp;&nbsp;drawLines(ctx,&nbsp;getCurvePoints(ptsa,&nbsp;tension,&nbsp;isClosed,&nbsp;numOfSegments)); &nbsp;&nbsp; &nbsp;&nbsp;if&nbsp;(showPoints)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;ctx.beginPath(); &nbsp;&nbsp;&nbsp;&nbsp;for(var&nbsp;i=0;i<ptsa.length-1;i+=2)&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctx.rect(ptsa[i]&nbsp;-&nbsp;2,&nbsp;ptsa[i+1]&nbsp;-&nbsp;2,&nbsp;4,&nbsp;4); &nbsp;&nbsp;} &nbsp;&nbsp;ctx.stroke();}var&nbsp;myPoints&nbsp;=&nbsp;[10,10,&nbsp;40,30,&nbsp;100,10,&nbsp;200,&nbsp;100,&nbsp;200,&nbsp;50,&nbsp;250,&nbsp;120];&nbsp;//minimum&nbsp;two&nbsp;pointsvar&nbsp;tension&nbsp;=&nbsp;1;drawCurve(ctx,&nbsp;myPoints);&nbsp;//default&nbsp;tension=0.5drawCurve(ctx,&nbsp;myPoints,&nbsp;tension);function&nbsp;getCurvePoints(pts,&nbsp;tension,&nbsp;isClosed,&nbsp;numOfSegments)&nbsp;{ &nbsp;&nbsp;//&nbsp;use&nbsp;input&nbsp;value&nbsp;if&nbsp;provided,&nbsp;or&nbsp;use&nbsp;a&nbsp;default&nbsp;value &nbsp; &nbsp;&nbsp;tension&nbsp;=&nbsp;(typeof&nbsp;tension&nbsp;!=&nbsp;'undefined')&nbsp;?&nbsp;tension&nbsp;:&nbsp;0.5; &nbsp;&nbsp;isClosed&nbsp;=&nbsp;isClosed&nbsp;?&nbsp;isClosed&nbsp;:&nbsp;false; &nbsp;&nbsp;numOfSegments&nbsp;=&nbsp;numOfSegments&nbsp;?&nbsp;numOfSegments&nbsp;:&nbsp;16; &nbsp;&nbsp;var&nbsp;_pts&nbsp;=&nbsp;[],&nbsp;res&nbsp;=&nbsp;[], //&nbsp;clone&nbsp;array &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x,&nbsp;y, //&nbsp;our&nbsp;x,y&nbsp;coords &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t1x,&nbsp;t2x,&nbsp;t1y,&nbsp;t2y, //&nbsp;tension&nbsp;vectors &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c1,&nbsp;c2,&nbsp;c3,&nbsp;c4, //&nbsp;cardinal&nbsp;points &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;st,&nbsp;t,&nbsp;i; //&nbsp;steps&nbsp;based&nbsp;on&nbsp;num.&nbsp;of&nbsp;segments &nbsp;&nbsp;//&nbsp;clone&nbsp;array&nbsp;so&nbsp;we&nbsp;don't&nbsp;change&nbsp;the&nbsp;original &nbsp;&nbsp;// &nbsp;&nbsp;_pts&nbsp;=&nbsp;pts.slice(0); &nbsp;&nbsp;//&nbsp;The&nbsp;algorithm&nbsp;require&nbsp;a&nbsp;previous&nbsp;and&nbsp;next&nbsp;point&nbsp;to&nbsp;the&nbsp;actual&nbsp;point&nbsp;array. &nbsp;&nbsp;//&nbsp;Check&nbsp;if&nbsp;we&nbsp;will&nbsp;draw&nbsp;closed&nbsp;or&nbsp;open&nbsp;curve. &nbsp;&nbsp;//&nbsp;If&nbsp;closed,&nbsp;copy&nbsp;end&nbsp;points&nbsp;to&nbsp;beginning&nbsp;and&nbsp;first&nbsp;points&nbsp;to&nbsp;end &nbsp;&nbsp;//&nbsp;If&nbsp;open,&nbsp;duplicate&nbsp;first&nbsp;points&nbsp;to&nbsp;befinning,&nbsp;end&nbsp;points&nbsp;to&nbsp;end &nbsp;&nbsp;if&nbsp;(isClosed)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[pts.length&nbsp;-&nbsp;1]); &nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[pts.length&nbsp;-&nbsp;2]); &nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[pts.length&nbsp;-&nbsp;1]); &nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[pts.length&nbsp;-&nbsp;2]); &nbsp;&nbsp;&nbsp;&nbsp;_pts.push(pts[0]); &nbsp;&nbsp;&nbsp;&nbsp;_pts.push(pts[1]); &nbsp;&nbsp;} &nbsp;&nbsp;else&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[1]); //copy&nbsp;1.&nbsp;point&nbsp;and&nbsp;insert&nbsp;at&nbsp;beginning &nbsp;&nbsp;&nbsp;&nbsp;_pts.unshift(pts[0]); &nbsp;&nbsp;&nbsp;&nbsp;_pts.push(pts[pts.length&nbsp;-&nbsp;2]); //copy&nbsp;last&nbsp;point&nbsp;and&nbsp;append &nbsp;&nbsp;&nbsp;&nbsp;_pts.push(pts[pts.length&nbsp;-&nbsp;1]); &nbsp;&nbsp;} &nbsp;&nbsp;//&nbsp;ok,&nbsp;lets&nbsp;start.. &nbsp;&nbsp;//&nbsp;1.&nbsp;loop&nbsp;goes&nbsp;through&nbsp;point&nbsp;array &nbsp;&nbsp;//&nbsp;2.&nbsp;loop&nbsp;goes&nbsp;through&nbsp;each&nbsp;segment&nbsp;between&nbsp;the&nbsp;2&nbsp;pts&nbsp;+&nbsp;1e&nbsp;point&nbsp;before&nbsp;and&nbsp;after &nbsp;&nbsp;for&nbsp;(i=2;&nbsp;i&nbsp;<&nbsp;(_pts.length&nbsp;-&nbsp;4);&nbsp;i+=2)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(t=0;&nbsp;t&nbsp;<=&nbsp;numOfSegments;&nbsp;t++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;calc&nbsp;tension&nbsp;vectors &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t1x&nbsp;=&nbsp;(_pts[i+2]&nbsp;-&nbsp;_pts[i-2])&nbsp;*&nbsp;tension; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t2x&nbsp;=&nbsp;(_pts[i+4]&nbsp;-&nbsp;_pts[i])&nbsp;*&nbsp;tension; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t1y&nbsp;=&nbsp;(_pts[i+3]&nbsp;-&nbsp;_pts[i-1])&nbsp;*&nbsp;tension; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t2y&nbsp;=&nbsp;(_pts[i+5]&nbsp;-&nbsp;_pts[i+1])&nbsp;*&nbsp;tension; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;calc&nbsp;step &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;st&nbsp;=&nbsp;t&nbsp;/&nbsp;numOfSegments; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;calc&nbsp;cardinals &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c1&nbsp;=&nbsp;&nbsp;&nbsp;2&nbsp;*&nbsp;Math.pow(st,&nbsp;3)&nbsp; -&nbsp;3&nbsp;*&nbsp;Math.pow(st,&nbsp;2)&nbsp;+&nbsp;1;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c2&nbsp;=&nbsp;-(2&nbsp;*&nbsp;Math.pow(st,&nbsp;3))&nbsp;+&nbsp;3&nbsp;*&nbsp;Math.pow(st,&nbsp;2);&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c3&nbsp;=&nbsp; &nbsp;&nbsp;&nbsp;Math.pow(st,&nbsp;3) -&nbsp;2&nbsp;*&nbsp;Math.pow(st,&nbsp;2)&nbsp;+&nbsp;st;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c4&nbsp;=&nbsp; &nbsp;&nbsp;&nbsp;Math.pow(st,&nbsp;3) -&nbsp; &nbsp;&nbsp;Math.pow(st,&nbsp;2); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;calc&nbsp;x&nbsp;and&nbsp;y&nbsp;cords&nbsp;with&nbsp;common&nbsp;control&nbsp;vectors &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;c1&nbsp;*&nbsp;_pts[i] +&nbsp;c2&nbsp;*&nbsp;_pts[i+2]&nbsp;+&nbsp;c3&nbsp;*&nbsp;t1x&nbsp;+&nbsp;c4&nbsp;*&nbsp;t2x; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;=&nbsp;c1&nbsp;*&nbsp;_pts[i+1] +&nbsp;c2&nbsp;*&nbsp;_pts[i+3]&nbsp;+&nbsp;c3&nbsp;*&nbsp;t1y&nbsp;+&nbsp;c4&nbsp;*&nbsp;t2y; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//store&nbsp;points&nbsp;in&nbsp;array &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.push(x); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.push(y); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;} &nbsp;&nbsp;return&nbsp;res;}function&nbsp;drawLines(ctx,&nbsp;pts)&nbsp;{ &nbsp;&nbsp;ctx.moveTo(pts[0],&nbsp;pts[1]); &nbsp;&nbsp;for(i=2;i<pts.length-1;i+=2)&nbsp;ctx.lineTo(pts[i],&nbsp;pts[i+1]);}canvas&nbsp;{&nbsp;border:&nbsp;1px&nbsp;solid&nbsp;red;&nbsp;}<canvas&nbsp;id="c"><canvas>This results in this:You can easily extend the canvas so you can call it like this instead:ctx.drawCurve(myPoints);Add the following to the javascript:if&nbsp;(CanvasRenderingContext2D&nbsp;!=&nbsp;'undefined')&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;CanvasRenderingContext2D.prototype.drawCurve&nbsp;=&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function(pts,&nbsp;tension,&nbsp;isClosed,&nbsp;numOfSegments,&nbsp;showPoints)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drawCurve(this,&nbsp;pts,&nbsp;tension,&nbsp;isClosed,&nbsp;numOfSegments,&nbsp;showPoints)}}You can find a more optimized version of this on NPM (npm i cardinal-spline-js) or on&nbsp;GitLab.

湖上湖

第一个答案不会通过所有要点。该图将精确地通过所有点,并且将是一个完美的曲线,其中点作为点[[x:,y:}] n这样的点。var&nbsp;points&nbsp;=&nbsp;[{x:1,y:1},{x:2,y:3},{x:3,y:4},{x:4,y:2},{x:5,y:6}]&nbsp;//took&nbsp;5&nbsp;example&nbsp;pointsctx.moveTo((points[0].x),&nbsp;points[0].y);for(var&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;<&nbsp;points.length-1;&nbsp;i&nbsp;++){ &nbsp;&nbsp;var&nbsp;x_mid&nbsp;=&nbsp;(points[i].x&nbsp;+&nbsp;points[i+1].x)&nbsp;/&nbsp;2; &nbsp;&nbsp;var&nbsp;y_mid&nbsp;=&nbsp;(points[i].y&nbsp;+&nbsp;points[i+1].y)&nbsp;/&nbsp;2; &nbsp;&nbsp;var&nbsp;cp_x1&nbsp;=&nbsp;(x_mid&nbsp;+&nbsp;points[i].x)&nbsp;/&nbsp;2; &nbsp;&nbsp;var&nbsp;cp_x2&nbsp;=&nbsp;(x_mid&nbsp;+&nbsp;points[i+1].x)&nbsp;/&nbsp;2; &nbsp;&nbsp;ctx.quadraticCurveTo(cp_x1,points[i].y&nbsp;,x_mid,&nbsp;y_mid); &nbsp;&nbsp;ctx.quadraticCurveTo(cp_x2,points[i+1].y&nbsp;,points[i+1].x,points[i+1].y);}
随时随地看视频慕课网APP
我要回答