|
|
Line 1: |
Line 1: |
- | <html>
| |
- | <body>
| |
| | | |
- | <canvas id="myCanvas" width="1000" height="1000" style="border:1px solid #d3d3d3;">
| |
- | Your browser does not support the HTML5 canvas tag.
| |
- | </canvas>
| |
- |
| |
- |
| |
- |
| |
- | <script>
| |
- |
| |
- | var c=document.getElementById("myCanvas");
| |
- | var ctx=c.getContext("2d");
| |
- |
| |
- |
| |
- |
| |
- | var myPoints = [10,10, 40,30, 300,300]; //minimum two points
| |
- | var tension = 1;
| |
- |
| |
- | drawCurve(ctx, myPoints); //default tension=0.5
| |
- |
| |
- | function drawCurve(ctx, ptsa, tension, isClosed, numOfSegments, showPoints) {
| |
- |
| |
- |
| |
- | showPoints = showPoints ? showPoints : false;
| |
- |
| |
- | ctx.beginPath();
| |
- |
| |
- | drawLines(ctx, getCurvePoints(ptsa, tension, isClosed, numOfSegments));
| |
- |
| |
- | if (showPoints) {
| |
- | ctx.stroke();
| |
- | ctx.beginPath();
| |
- | for(var i=0;i<pts.length-1;i+=2)
| |
- | ctx.rect(pts[i] - 2, pts[i+1] - 2, 4, 4);
| |
- | }
| |
- |
| |
- | }
| |
- |
| |
- | function getCurvePoints(ptsa, tension, isClosed, numOfSegments) {
| |
- |
| |
- |
| |
- | // use input value if provided, or use a default value
| |
- | tension = (typeof tension != 'undefined') ? tension : 0.5;
| |
- | isClosed = isClosed ? isClosed : false;
| |
- | numOfSegments = numOfSegments ? numOfSegments : 16;
| |
- |
| |
- | var _pts = [], res = [], // clone array
| |
- | x, y, // our x,y coords
| |
- | t1x, t2x, t1y, t2y, // tension vectors
| |
- | c1, c2, c3, c4, // cardinal points
| |
- | st, t, i; // steps based on num. of segments
| |
- |
| |
- | // clone array so we don't change the original
| |
- |
| |
- | _pts = ptsa.slice(0);
| |
- |
| |
- | // The algorithm require a previous and next point to the actual point array.
| |
- | // Check if we will draw closed or open curve.
| |
- | // If closed, copy end points to beginning and first points to end
| |
- | // If open, duplicate first points to befinning, end points to end
| |
- | if (isClosed) {
| |
- | _pts.unshift(ptsa[ptsa.length - 1]);
| |
- | _pts.unshift(ptsa[ptsa.length - 2]);
| |
- | _pts.unshift(ptsa[ptsa.length - 1]);
| |
- | _pts.unshift(ptsa[ptsa.length - 2]);
| |
- | _pts.push(_pts[0]);
| |
- | _pts.push(_pts[1]);
| |
- | }
| |
- | else {
| |
- | _pts.unshift(ptsa[1]); //copy 1. point and insert at beginning
| |
- | _pts.unshift(ptsa[0]);
| |
- | _pts.push(ptsa[ptsa.length - 2]); //copy last point and append
| |
- | _pts.push(ptsa[ptsa.length - 1]);
| |
- | }
| |
- |
| |
- | // ok, lets start..
| |
- |
| |
- | // 1. loop goes through point array
| |
- | // 2. loop goes through each segment between the 2 pts + 1e point before and after
| |
- | for (i=2; i < (_pts.length - 4); i+=2) {
| |
- | for (t=0; t <= numOfSegments; t++) {
| |
- |
| |
- | // calc tension vectors
| |
- | t1x = (_pts[i+2] - _pts[i-2]) * tension;
| |
- | t2x = (_pts[i+4] - _pts[i]) * tension;
| |
- |
| |
- | t1y = (_pts[i+3] - _pts[i-1]) * tension;
| |
- | t2y = (_pts[i+5] - _pts[i+1]) * tension;
| |
- |
| |
- | // calc step
| |
- | st = t / numOfSegments;
| |
- |
| |
- | // calc cardinals
| |
- | c1 = 2 * Math.pow(st, 3) - 3 * Math.pow(st, 2) + 1;
| |
- | c2 = -(2 * Math.pow(st, 3)) + 3 * Math.pow(st, 2);
| |
- | c3 = Math.pow(st, 3) - 2 * Math.pow(st, 2) + st;
| |
- | c4 = Math.pow(st, 3) - Math.pow(st, 2);
| |
- |
| |
- | // calc x and y cords with common control vectors
| |
- | x = c1 * _pts[i] + c2 * _pts[i+2] + c3 * t1x + c4 * t2x;
| |
- | y = c1 * _pts[i+1] + c2 * _pts[i+3] + c3 * t1y + c4 * t2y;
| |
- |
| |
- | //store points in array
| |
- | res.push(x);
| |
- | res.push(y);
| |
- |
| |
- | }
| |
- | }
| |
- |
| |
- | return res;
| |
- | }
| |
- |
| |
- | function drawLines(ctx, pts) {
| |
- | ctx.beginPath();
| |
- |
| |
- |
| |
- | ctx.moveTo(pts[0], pts[1]);
| |
- |
| |
- | for(i=2;i<pts.length-1;i+=2)
| |
- | {
| |
- |
| |
- | ctx.lineTo(pts[i], pts[i+1]);
| |
- | }
| |
- | ctx.stroke();
| |
- | }
| |
- |
| |
- |
| |
- | </script>
| |
- |
| |
- | </body>
| |
- | </html>
| |