জাভাস্ক্রিপ্ট HTML5 ক্যানভাস ব্যবহার করে এন পয়েন্টগুলির মাধ্যমে মসৃণ বক্ররেখাটি কীভাবে আঁকবেন?


133

একটি অঙ্কন অ্যাপ্লিকেশনটির জন্য, আমি মাউন্টের চলন স্থানাঙ্ককে একটি অ্যারে সংরক্ষণ করছি তারপরে লাইনটো দিয়ে এঁকে দিচ্ছি। ফলাফল লাইন মসৃণ হয় না। আমি কীভাবে সমস্ত জড়ো হওয়া পয়েন্টগুলির মধ্যে একটি একক বাঁক তৈরি করতে পারি?

আমি গুগল করেছি তবে আমি রেখাগুলি আঁকার জন্য কেবল তিনটি ফাংশন পেয়েছি: 2 নমুনা পয়েন্টের জন্য, কেবল ব্যবহার করুন lineTo। 3 নমুনা পয়েন্টের quadraticCurveToজন্য, 4 নমুনা পয়েন্টের জন্য bezierCurveTo,।

(আমি bezierCurveToঅ্যারেতে প্রতি 4 পয়েন্টের জন্য একটি অঙ্কনের চেষ্টা করেছি , তবে এটি অবিচ্ছিন্ন মসৃণ বক্রতার পরিবর্তে প্রতি 4 নমুনা পয়েন্টকে কিঙ্কস করে তোলে))

5 টি নমুনা পয়েন্ট এবং এর বাইরেও একটি মসৃণ বক্ররেখা আঁকার জন্য আমি কীভাবে একটি ফাংশন লিখব?


5
"মসৃণ" বলতে কী বোঝ? অসীম স্বতন্ত্র? দু'বার পার্থক্যযোগ্য? কিউবিক স্প্লাইংগুলি ("বেজিয়ার কার্ভস") এর অনেকগুলি ভাল গুণাবলী রয়েছে এবং এটি দ্বিগুণ পৃথক এবং গণনার পক্ষে যথেষ্ট সহজ।
কেরেক এসবি

7
@ কেরেক এসবি, "মসৃণ" দ্বারা আমার অর্থ দৃশ্যত কোনও কোণ / কুসংস্কার ইত্যাদি সনাক্ত করতে পারে না
হুমান

@ স্কেচফেম্মে, আপনি কি রিয়েল-টাইমে লাইনগুলি উপস্থাপন করছেন, বা একগুচ্ছ পয়েন্ট সংগ্রহের পরে অবধি বিলম্ব করছেন?
ক্র্যাশলোট

@ ক্র্যাশলোট আমি পয়েন্টগুলি একটি অ্যারেতে সংগ্রহ করছি। এই অ্যালগরিদমটি ব্যবহার করতে আপনার কমপক্ষে 4 টি পয়েন্ট দরকার। এর পরে আপনি মাউসউভের প্রতিটি কলের স্ক্রিন সাফ করে ক্যানভাসে রিয়েল টাইমে রেন্ডার করতে পারেন
Homan

1
@ স্কেচফেম্ম: একটি উত্তর গ্রহণ করতে ভুলবেন না। আপনার নিজের হলে এটি ঠিক আছে
টিজে ক্রাউডার

উত্তর:


130

"কার্ভটো" টাইপ ফাংশনগুলির সাথে একত্রে পরবর্তী নমুনা পয়েন্টগুলিতে যোগদানের সমস্যাটি এটিই যেখানে বাঁকগুলি মিলিত হয় তা মসৃণ নয়। এটি কারণ দুটি বক্ররেখাগুলি একটি শেষ পয়েন্ট ভাগ করে নেয় তবে সম্পূর্ণ নিয়ন্ত্রণ পয়েন্ট দ্বারা প্রভাবিত হয়। একটি সমাধান হ'ল পরবর্তী 2 পরবর্তী নমুনা পয়েন্টগুলির মধ্যে মিডপয়েন্টগুলি "বক্ররেখা" করা। এই নতুন আন্তঃবিবাহিত পয়েন্টগুলি ব্যবহার করে বক্ররেখাগুলিতে যোগদান করা শেষ পয়েন্টগুলিতে একটি মসৃণ রূপান্তর দেয় (এক পুনরাবৃত্তির জন্য একটি শেষ বিন্দুটি পরবর্তী পুনরাবৃত্তির জন্য একটি নিয়ন্ত্রণ বিন্দুতে পরিণত হয় )) অন্য কথায় দুটি বিচ্ছিন্ন বক্ররেখা এখন অনেক বেশি প্রচলিত রয়েছে।

এই সমাধানটি "ফাউন্ডেশন অ্যাকশনস্ক্রিপ্ট 3.0 অ্যানিমেশন: জিনিসগুলি সরানো" বইটি থেকে বের করা হয়েছিল। p.95 - রেন্ডারিং কৌশল: একাধিক বক্ররেখা তৈরি।

দ্রষ্টব্য: এই সমাধানটি আসলে প্রতিটি পয়েন্টের মাধ্যমে অঙ্কিত হয় না, যা আমার প্রশ্নের শিরোনাম ছিল (বরং এটি নমুনা পয়েন্টগুলির মাধ্যমে বক্ররেখাকে প্রায় সরিয়ে দেয় তবে কখনও নমুনা পয়েন্টগুলির মধ্য দিয়ে যায় না), তবে আমার উদ্দেশ্যে (একটি অঙ্কন অ্যাপ্লিকেশন), এটি আমার পক্ষে যথেষ্ট এবং দৃষ্টিভঙ্গি আপনি পার্থক্য বলতে পারবেন না। সেখানে হয় সব নমুনা পয়েন্ট মধ্য দিয়ে যেতে একটি সমাধান, কিন্তু এটা অনেক বেশি জটিল (দেখুন http://www.cartogrammar.com/blog/actionscript-curves-update/ )

আনুমানিক পদ্ধতির জন্য অঙ্কন কোডটি এখানে:

// move to the first point
   ctx.moveTo(points[0].x, points[0].y);


   for (i = 1; i < points.length - 2; i ++)
   {
      var xc = (points[i].x + points[i + 1].x) / 2;
      var yc = (points[i].y + points[i + 1].y) / 2;
      ctx.quadraticCurveTo(points[i].x, points[i].y, xc, yc);
   }
 // curve through the last two points
 ctx.quadraticCurveTo(points[i].x, points[i].y, points[i+1].x,points[i+1].y);

+1 এটি আমি যে জাভাস্ক্রিপ্ট / ক্যানভাস প্রকল্পে কাজ করছি তার পক্ষে দুর্দান্ত কাজ করেছে
ম্যাট

1
সাহায্য করার জন্য খুশি। এফওয়াইআই, আমি একটি ওপেন সোর্স এইচটিএমএল 5 ক্যানভাস অঙ্কন প্যাড শুরু করেছি যা একটি জিকুয়েরি প্লাগইন। এটি একটি কার্যকর প্রারম্ভিক পয়েন্ট হওয়া উচিত। github.com/homanchou/sketchyPad
হোমান

4
এটি ভাল, তবে আপনি কীভাবে বক্ররেখা তৈরি করবেন যাতে এটি সমস্ত পয়েন্টের মধ্য দিয়ে যায়?
রিচার্ড

এই অ্যালগরিদমের সাথে প্রতিটি ক্রমাগত বক্ররেখাটি কি পূর্ববর্তী কার্ভের শেষ বিন্দু থেকে শুরু করতে বোঝানো হয়?
লি ব্রিন্ডলে

তোমাকে অনেক ধন্যবাদ হোমান! এটি কাজ করে! আমি এর সমাধানের জন্য অনেক দিন অতিবাহিত করেছি। এবং হাই ডেলফি অ্যান্ড্রয়েড / আইওএস সম্প্রদায় থেকে!
অলিট্রুন

104

কিছুটা দেরি হলেও রেকর্ডের জন্য।

আপনি বিন্দুগুলির মধ্য দিয়ে যায় এমন মসৃণ বক্ররেখা আঁকতে কার্ডিনাল স্প্লিংস (ওরফে ক্যানোনিকাল স্প্লাইন) ব্যবহার করে মসৃণ রেখাগুলি অর্জন করতে পারেন ।

আমি ক্যানভাসের জন্য এই ফাংশনটি তৈরি করেছিলাম - বহুমুখিতা বাড়াতে এটি তিনটি ফাংশনে বিভক্ত। মূল মোড়ক ফাংশনটি দেখতে এরকম দেখাচ্ছে:

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<ptsa.length-1;i+=2) 
                ctx.rect(ptsa[i] - 2, ptsa[i+1] - 2, 4, 4);
    }
}

একটি বক্ররেখা আঁকতে এক্স, যাতে Y পয়েন্ট সঙ্গে একটি অ্যারের আছে: x1,y1, x2,y2, ...xn,yn

এটি এর মতো ব্যবহার করুন:

var myPoints = [10,10, 40,30, 100,10]; //minimum two points
var tension = 1;

drawCurve(ctx, myPoints); //default tension=0.5
drawCurve(ctx, myPoints, tension);

উপরের ফাংশনটি দুটি উপ-ফাংশন কল করে, একটি স্মুথড পয়েন্টগুলি গণনা করার জন্য। এটি নতুন পয়েন্ট সহ একটি অ্যারে প্রদান করে - এটি মূল ফাংশন যা স্মুথড পয়েন্টগুলি গণনা করে:

function getCurvePoints(pts, 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 = pts.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(pts[pts.length - 1]);
        _pts.unshift(pts[pts.length - 2]);
        _pts.unshift(pts[pts.length - 1]);
        _pts.unshift(pts[pts.length - 2]);
        _pts.push(pts[0]);
        _pts.push(pts[1]);
    }
    else {
        _pts.unshift(pts[1]);   //copy 1. point and insert at beginning
        _pts.unshift(pts[0]);
        _pts.push(pts[pts.length - 2]); //copy last point and append
        _pts.push(pts[pts.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.moveTo(pts[0], pts[1]);
    for(i=2;i<pts.length-1;i+=2) ctx.lineTo(pts[i], pts[i+1]);
}

এর ফলাফল:

উদাহরণ পিক্স

আপনি সহজেই ক্যানভাস প্রসারিত করতে পারেন যাতে আপনি এর পরিবর্তে এটিকে কল করতে পারেন:

ctx.drawCurve(myPoints);

জাভাস্ক্রিপ্টে নিম্নলিখিতগুলি যুক্ত করুন:

if (CanvasRenderingContext2D != 'undefined') {
    CanvasRenderingContext2D.prototype.drawCurve = 
        function(pts, tension, isClosed, numOfSegments, showPoints) {
       drawCurve(this, pts, tension, isClosed, numOfSegments, showPoints)}
}

আপনি এনপিএম ( npm i cardinal-spline-js) বা গিটল্যাবে এটির একটি আরও অনুকূলিত সংস্করণ খুঁজে পেতে পারেন ।


3
প্রথম বন্ধ: এটি দারুণ। :-) তবে সেই চিত্রটির দিকে তাকালে, এটি কি (বিভ্রান্তিকর) ধারণাটি দেয় না যে মানগুলি # 9 এবং # 10 এর মধ্যে পথে # 10 এর নীচে চলে গেছে? (আমি দেখতে পাচ্ছি সত্যিকারের বিন্দুগুলি থেকে আমি গণনা করছি, সুতরাং # 1 হ'ল প্রাথমিক নিম্নগামী ট্র্যাজেক্টোরির শীর্ষের নিকটবর্তী একটি, # 2 একেবারে নীচের অংশে [গ্রাফের সর্বনিম্ন পয়েন্ট], এবং আরও ... )
টিজে ক্রাউডার

6
শুধু বলতে চাই যে অনুসন্ধানের দিন পরে, এই ছিল চান শুধুমাত্র util যে আসলে কাজ ঠিক যেমন আমি চেয়েছিলাম। অনেক অনেক ধন্যবাদ
সিএনপি

4
হ্যাঁ হ্যাঁ হ্যাঁ আপনাকে ধন্যবাদ! আমি লাফিয়ে উঠে আনন্দে নেচে উঠলাম।
জেফরি সান 21

1
আপনার কোডে একটি ধরণের ত্রুটি রয়েছে। প্যারামিটারটি ptsaহওয়া উচিত pts, অন্যথায় এটি এরো ছুঁড়ে ফেলবে।
নির্লজ্জ

2
অনেক আগে আপনি এই সমাধান পোস্ট করেছেন এবং আপনি আজ আমাকে একটি বড় সমস্যা সমাধানে সহায়তা করেছেন। আপনাকে অনেক ধন্যবাদ!
Â্লেক্সবে

19

প্রথম উত্তরটি সমস্ত পয়েন্টের মধ্য দিয়ে যাবে না। এই গ্রাফটি ঠিক সমস্ত পয়েন্টের মধ্য দিয়ে যাবে এবং [{x:, y:}] n এর মতো পয়েন্টগুলির সাথে একটি নিখুঁত বক্ররেখা হবে।

var points = [{x:1,y:1},{x:2,y:3},{x:3,y:4},{x:4,y:2},{x:5,y:6}] //took 5 example points
ctx.moveTo((points[0].x), points[0].y);

for(var i = 0; i < points.length-1; i ++)
{

  var x_mid = (points[i].x + points[i+1].x) / 2;
  var y_mid = (points[i].y + points[i+1].y) / 2;
  var cp_x1 = (x_mid + points[i].x) / 2;
  var cp_x2 = (x_mid + points[i+1].x) / 2;
  ctx.quadraticCurveTo(cp_x1,points[i].y ,x_mid, y_mid);
  ctx.quadraticCurveTo(cp_x2,points[i+1].y ,points[i+1].x,points[i+1].y);
}

1
এটি এখন পর্যন্ত সবচেয়ে সহজ এবং সঠিক পদ্ধতির।
হাইমেজ

10

ড্যানিয়েল হাওয়ার্ড যেমন উল্লেখ করেছেন , রব স্পেন্সার http://scaledinnovation.com/analytics/splines/aboutSplines.html এ আপনি কী চান তা বর্ণনা করে ।

একটি ইন্টারেক্টিভ ডেমো এখানে: http://jsbin.com/ApitIxo/2/

জেসবিন ডাউন হবার ক্ষেত্রে এটি স্নিপেট হিসাবে রয়েছে।

<!DOCTYPE html>
    <html>
      <head>
        <meta charset=utf-8 />
        <title>Demo smooth connection</title>
      </head>
      <body>
        <div id="display">
          Click to build a smooth path. 
          (See Rob Spencer's <a href="http://scaledinnovation.com/analytics/splines/aboutSplines.html">article</a>)
          <br><label><input type="checkbox" id="showPoints" checked> Show points</label>
          <br><label><input type="checkbox" id="showControlLines" checked> Show control lines</label>
          <br>
          <label>
            <input type="range" id="tension" min="-1" max="2" step=".1" value=".5" > Tension <span id="tensionvalue">(0.5)</span>
          </label>
        <div id="mouse"></div>
        </div>
        <canvas id="canvas"></canvas>
        <style>
          html { position: relative; height: 100%; width: 100%; }
          body { position: absolute; left: 0; right: 0; top: 0; bottom: 0; } 
          canvas { outline: 1px solid red; }
          #display { position: fixed; margin: 8px; background: white; z-index: 1; }
        </style>
        <script>
          function update() {
            $("tensionvalue").innerHTML="("+$("tension").value+")";
            drawSplines();
          }
          $("showPoints").onchange = $("showControlLines").onchange = $("tension").onchange = update;
      
          // utility function
          function $(id){ return document.getElementById(id); }
          var canvas=$("canvas"), ctx=canvas.getContext("2d");

          function setCanvasSize() {
            canvas.width = parseInt(window.getComputedStyle(document.body).width);
            canvas.height = parseInt(window.getComputedStyle(document.body).height);
          }
          window.onload = window.onresize = setCanvasSize();
      
          function mousePositionOnCanvas(e) {
            var el=e.target, c=el;
            var scaleX = c.width/c.offsetWidth || 1;
            var scaleY = c.height/c.offsetHeight || 1;
          
            if (!isNaN(e.offsetX)) 
              return { x:e.offsetX*scaleX, y:e.offsetY*scaleY };
          
            var x=e.pageX, y=e.pageY;
            do {
              x -= el.offsetLeft;
              y -= el.offsetTop;
              el = el.offsetParent;
            } while (el);
            return { x: x*scaleX, y: y*scaleY };
          }
      
          canvas.onclick = function(e){
            var p = mousePositionOnCanvas(e);
            addSplinePoint(p.x, p.y);
          };
      
          function drawPoint(x,y,color){
            ctx.save();
            ctx.fillStyle=color;
            ctx.beginPath();
            ctx.arc(x,y,3,0,2*Math.PI);
            ctx.fill()
            ctx.restore();
          }
          canvas.onmousemove = function(e) {
            var p = mousePositionOnCanvas(e);
            $("mouse").innerHTML = p.x+","+p.y;
          };
      
          var pts=[]; // a list of x and ys

          // given an array of x,y's, return distance between any two,
          // note that i and j are indexes to the points, not directly into the array.
          function dista(arr, i, j) {
            return Math.sqrt(Math.pow(arr[2*i]-arr[2*j], 2) + Math.pow(arr[2*i+1]-arr[2*j+1], 2));
          }

          // return vector from i to j where i and j are indexes pointing into an array of points.
          function va(arr, i, j){
            return [arr[2*j]-arr[2*i], arr[2*j+1]-arr[2*i+1]]
          }
      
          function ctlpts(x1,y1,x2,y2,x3,y3) {
            var t = $("tension").value;
            var v = va(arguments, 0, 2);
            var d01 = dista(arguments, 0, 1);
            var d12 = dista(arguments, 1, 2);
            var d012 = d01 + d12;
            return [x2 - v[0] * t * d01 / d012, y2 - v[1] * t * d01 / d012,
                    x2 + v[0] * t * d12 / d012, y2 + v[1] * t * d12 / d012 ];
          }

          function addSplinePoint(x, y){
            pts.push(x); pts.push(y);
            drawSplines();
          }
          function drawSplines() {
            clear();
            cps = []; // There will be two control points for each "middle" point, 1 ... len-2e
            for (var i = 0; i < pts.length - 2; i += 1) {
              cps = cps.concat(ctlpts(pts[2*i], pts[2*i+1], 
                                      pts[2*i+2], pts[2*i+3], 
                                      pts[2*i+4], pts[2*i+5]));
            }
            if ($("showControlLines").checked) drawControlPoints(cps);
            if ($("showPoints").checked) drawPoints(pts);
    
            drawCurvedPath(cps, pts);
 
          }
          function drawControlPoints(cps) {
            for (var i = 0; i < cps.length; i += 4) {
              showPt(cps[i], cps[i+1], "pink");
              showPt(cps[i+2], cps[i+3], "pink");
              drawLine(cps[i], cps[i+1], cps[i+2], cps[i+3], "pink");
            } 
          }
      
          function drawPoints(pts) {
            for (var i = 0; i < pts.length; i += 2) {
              showPt(pts[i], pts[i+1], "black");
            } 
          }
      
          function drawCurvedPath(cps, pts){
            var len = pts.length / 2; // number of points
            if (len < 2) return;
            if (len == 2) {
              ctx.beginPath();
              ctx.moveTo(pts[0], pts[1]);
              ctx.lineTo(pts[2], pts[3]);
              ctx.stroke();
            }
            else {
              ctx.beginPath();
              ctx.moveTo(pts[0], pts[1]);
              // from point 0 to point 1 is a quadratic
              ctx.quadraticCurveTo(cps[0], cps[1], pts[2], pts[3]);
              // for all middle points, connect with bezier
              for (var i = 2; i < len-1; i += 1) {
                // console.log("to", pts[2*i], pts[2*i+1]);
                ctx.bezierCurveTo(
                  cps[(2*(i-1)-1)*2], cps[(2*(i-1)-1)*2+1],
                  cps[(2*(i-1))*2], cps[(2*(i-1))*2+1],
                  pts[i*2], pts[i*2+1]);
              }
              ctx.quadraticCurveTo(
                cps[(2*(i-1)-1)*2], cps[(2*(i-1)-1)*2+1],
                pts[i*2], pts[i*2+1]);
              ctx.stroke();
            }
          }
          function clear() {
            ctx.save();
            // use alpha to fade out
            ctx.fillStyle = "rgba(255,255,255,.7)"; // clear screen
            ctx.fillRect(0,0,canvas.width,canvas.height);
            ctx.restore();
          }
      
          function showPt(x,y,fillStyle) {
            ctx.save();
            ctx.beginPath();
            if (fillStyle) {
              ctx.fillStyle = fillStyle;
            }
            ctx.arc(x, y, 5, 0, 2*Math.PI);
            ctx.fill();
            ctx.restore();
          }

          function drawLine(x1, y1, x2, y2, strokeStyle){
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            if (strokeStyle) {
              ctx.save();
              ctx.strokeStyle = strokeStyle;
              ctx.stroke();
              ctx.restore();
            }
            else {
              ctx.save();
              ctx.strokeStyle = "pink";
              ctx.stroke();
              ctx.restore();
            }
          }

        </script>


      </body>
    </html>


7

আমি এটি সুন্দরভাবে কাজ করতে পেলাম

function drawCurve(points, tension) {
    ctx.beginPath();
    ctx.moveTo(points[0].x, points[0].y);

    var t = (tension != null) ? tension : 1;
    for (var i = 0; i < points.length - 1; i++) {
        var p0 = (i > 0) ? points[i - 1] : points[0];
        var p1 = points[i];
        var p2 = points[i + 1];
        var p3 = (i != points.length - 2) ? points[i + 2] : p2;

        var cp1x = p1.x + (p2.x - p0.x) / 6 * t;
        var cp1y = p1.y + (p2.y - p0.y) / 6 * t;

        var cp2x = p2.x - (p3.x - p1.x) / 6 * t;
        var cp2y = p2.y - (p3.y - p1.y) / 6 * t;

        ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2.x, p2.y);
    }
    ctx.stroke();
}

6

আমার সমাধানটি অন্য পোস্টে পোস্ট করার চেয়ে আমি যুক্ত করার সিদ্ধান্ত নিয়েছি। নীচে আমি যে সমাধানটি তৈরি করি তা নিখুঁত নাও হতে পারে তবে এখন পর্যন্ত আউটপুটটি ভাল।

গুরুত্বপূর্ণ: এটি সমস্ত পয়েন্টের মধ্য দিয়ে যাবে!

এটিকে আরও ভাল করার জন্য আপনার যদি কিছু ধারণা থাকে তবে দয়া করে আমার সাথে শেয়ার করুন। ধন্যবাদ।

এখানে আগের তুলনা এখানে:

এখানে চিত্র বর্ণনা লিখুন

এটি পরীক্ষা করার জন্য এই কোডটি এইচটিএমএল এ সংরক্ষণ করুন।

    <!DOCTYPE html>
    <html>
    <body>
    	<canvas id="myCanvas" width="1200" height="700" style="border:1px solid #d3d3d3;">Your browser does not support the HTML5 canvas tag.</canvas>
    	<script>
    		var cv = document.getElementById("myCanvas");
    		var ctx = cv.getContext("2d");
    
    		function gradient(a, b) {
    			return (b.y-a.y)/(b.x-a.x);
    		}
    
    		function bzCurve(points, f, t) {
    			//f = 0, will be straight line
    			//t suppose to be 1, but changing the value can control the smoothness too
    			if (typeof(f) == 'undefined') f = 0.3;
    			if (typeof(t) == 'undefined') t = 0.6;
    
    			ctx.beginPath();
    			ctx.moveTo(points[0].x, points[0].y);
    
    			var m = 0;
    			var dx1 = 0;
    			var dy1 = 0;
    
    			var preP = points[0];
    			for (var i = 1; i < points.length; i++) {
    				var curP = points[i];
    				nexP = points[i + 1];
    				if (nexP) {
    					m = gradient(preP, nexP);
    					dx2 = (nexP.x - curP.x) * -f;
    					dy2 = dx2 * m * t;
    				} else {
    					dx2 = 0;
    					dy2 = 0;
    				}
    				ctx.bezierCurveTo(preP.x - dx1, preP.y - dy1, curP.x + dx2, curP.y + dy2, curP.x, curP.y);
    				dx1 = dx2;
    				dy1 = dy2;
    				preP = curP;
    			}
    			ctx.stroke();
    		}
    
    		// Generate random data
    		var lines = [];
    		var X = 10;
    		var t = 40; //to control width of X
    		for (var i = 0; i < 100; i++ ) {
    			Y = Math.floor((Math.random() * 300) + 50);
    			p = { x: X, y: Y };
    			lines.push(p);
    			X = X + t;
    		}
    
    		//draw straight line
    		ctx.beginPath();
    		ctx.setLineDash([5]);
    		ctx.lineWidth = 1;
    		bzCurve(lines, 0, 1);
    
    		//draw smooth line
    		ctx.setLineDash([0]);
    		ctx.lineWidth = 2;
    		ctx.strokeStyle = "blue";
    		bzCurve(lines, 0.3, 1);
    	</script>
    </body>
    </html>


5

কিনেটিকজেএস ব্যবহার করে দেখুন - আপনি পয়েন্টের অ্যারে দিয়ে একটি স্প্লাইন সংজ্ঞায়িত করতে পারেন। এখানে একটি উদাহরণ:

পুরাতন ইউআরএল: http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-spline-tutorial/

সংরক্ষণাগারটি ইউআরএল দেখুন: https://web.archive.org/web/20141204030628/http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-spline-tutorial/


আশ্চর্যজনক! কাজের জন্য সেরা এক!
ডিজিয়াড বোরোয়

হ্যাঁ!! সমস্ত পয়েন্টের মধ্য দিয়ে যায় এমন একটি বদ্ধ আকার তৈরি করতে আমার ব্লব () ফাংশন প্রয়োজন।
জেগে উঠছেন wo

7
404 পৃষ্ঠা খুঁজে পাওয়া যায়নি.
ডাইটার

আসল লিঙ্ক - 404 ডট পাওয়া যায় নি - দেখুন web.archive.org/web/20141204030628/http://…
স্যাটেলস

1

অবিশ্বাস্যরূপে দেরী হলেও হোমানের উজ্জ্বল সহজ উত্তর থেকে অনুপ্রাণিত হয়ে আমাকে আরও একটি সাধারণ সমাধান পোস্ট করার অনুমতি দেয় (সাধারণভাবে এই অর্থে যে হুমনের দ্রবণটি 3 টিরও কম অংশের সাথে পয়েন্টের অ্যারেতে ক্র্যাশ হয়ে গেছে):

function smooth(ctx, points)
{
    if(points == undefined || points.length == 0)
    {
        return true;
    }
    if(points.length == 1)
    {
        ctx.moveTo(points[0].x, points[0].y);
        ctx.lineTo(points[0].x, points[0].y);
        return true;
    }
    if(points.length == 2)
    {
        ctx.moveTo(points[0].x, points[0].y);
        ctx.lineTo(points[1].x, points[1].y);
        return true;
    }
    ctx.moveTo(points[0].x, points[0].y);
    for (var i = 1; i < points.length - 2; i ++)
    {
        var xc = (points[i].x + points[i + 1].x) / 2;
        var yc = (points[i].y + points[i + 1].y) / 2;
        ctx.quadraticCurveTo(points[i].x, points[i].y, xc, yc);
    }
    ctx.quadraticCurveTo(points[i].x, points[i].y, points[i+1].x, points[i+1].y);
}

0

কে 3 এন এর কার্ডিনাল স্প্লাইজ পদ্ধতিতে যুক্ত করতে এবং টিজে ক্রাউডারকে বিভ্রান্তিকর জায়গায় 'ডুবানো' সম্পর্কে উদ্বেগ প্রকাশ করার জন্য, আমি getCurvePoints()ঠিক আগে ফাংশনে নীচের কোডটি sertedোকালামres.push(x);

if ((y < _pts[i+1] && y < _pts[i+3]) || (y > _pts[i+1] && y > _pts[i+3])) {
    y = (_pts[i+1] + _pts[i+3]) / 2;
}
if ((x < _pts[i] && x < _pts[i+2]) || (x > _pts[i] && x > _pts[i+2])) {
    x = (_pts[i] + _pts[i+2]) / 2;
}

এটি কার্যকরভাবে প্রতিটি জোড় পয়েন্টের মধ্যে একটি (অদৃশ্য) সীমানা বাক্স তৈরি করে এবং বক্ররেখার বাক্সের মধ্যে বক্ররেখাকে নিশ্চিত করে - যেমন। যদি বক্ররেখার কোনও বিন্দু উভয় পয়েন্টের উপরে / নীচে / বাম / ডান হয় তবে এটি বাক্সের মধ্যে অবস্থানে পরিবর্তিত হয়। এখানে মিডপয়েন্ট ব্যবহার করা হয়েছে, তবে সম্ভবত এটি লিনিয়ার ইন্টারপোলেশন ব্যবহার করে এটি উন্নত করা যেতে পারে।


0

আপনি যদি এন পয়েন্টগুলির মাধ্যমে বক্রের সমীকরণ নির্ধারণ করতে চান তবে নীচের কোডটি ডিগ্রি এন -1 এর বহুবর্ষের সহগগুলি দেবে এবং এই সহগগুলি coefficients[]অ্যারেতে (ধ্রুবক শব্দ থেকে শুরু করে) সংরক্ষণ করবে। এক্স স্থানাঙ্ক ক্রমযুক্ত হতে হবে না। এটি একটি ল্যাঞ্জরেঞ্জ বহুপদী উদাহরণ ।

var xPoints=[2,4,3,6,7,10]; //example coordinates
var yPoints=[2,5,-2,0,2,8];
var coefficients=[];
for (var m=0; m<xPoints.length; m++) coefficients[m]=0;
    for (var m=0; m<xPoints.length; m++) {
        var newCoefficients=[];
        for (var nc=0; nc<xPoints.length; nc++) newCoefficients[nc]=0;
        if (m>0) {
            newCoefficients[0]=-xPoints[0]/(xPoints[m]-xPoints[0]);
            newCoefficients[1]=1/(xPoints[m]-xPoints[0]);
    } else {
        newCoefficients[0]=-xPoints[1]/(xPoints[m]-xPoints[1]);
        newCoefficients[1]=1/(xPoints[m]-xPoints[1]);
    }
    var startIndex=1; 
    if (m==0) startIndex=2; 
    for (var n=startIndex; n<xPoints.length; n++) {
        if (m==n) continue;
        for (var nc=xPoints.length-1; nc>=1; nc--) {
        newCoefficients[nc]=newCoefficients[nc]*(-xPoints[n]/(xPoints[m]-xPoints[n]))+newCoefficients[nc-1]/(xPoints[m]-xPoints[n]);
        }
        newCoefficients[0]=newCoefficients[0]*(-xPoints[n]/(xPoints[m]-xPoints[n]));
    }    
    for (var nc=0; nc<xPoints.length; nc++) coefficients[nc]+=yPoints[m]*newCoefficients[nc];
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.