2013-06-13 7 views
20

के साथ किसी ऑब्जेक्ट की एनीमेशन करना चाहता हूं, मुझे पथ पर छोटे आयत को स्थानांतरित करना है। आयताकार कैनवास के अंदर एक क्लिक के बाद चलता है।मैं किसी विशेष पथ

मैं इसे एनिमेट करने में सक्षम नहीं हूं क्योंकि ऑब्जेक्ट बस आवश्यक बिंदु पर कूदता है।

कृपया Fiddle पर कोड पाएं।

एचटीएमएल

<canvas id="myCanvas" width=578 height=200></canvas> 

सीएसएस

#myCanvas { 
    width:578px; 
    height:200px; 
    border:2px thin; 
} 

जावास्क्रिप्ट

var myRectangle = { 
    x: 100, 
    y: 20, 
    width: 25, 
    height: 10, 
    borderWidth: 1 
}; 

$(document).ready(function() { 
    $('#myCanvas').css("border", "2px solid black"); 
    var canvas = document.getElementById('myCanvas'); 
    var context = canvas.getContext('2d'); 
    var cntxt = canvas.getContext('2d'); 
    drawPath(context); 
    drawRect(myRectangle, cntxt); 

    $('#myCanvas').click(function() { 
     function animate(myRectangle, canvas, cntxt, startTime) { 
      var time = (new Date()).getTime() - startTime; 
      var linearSpeed = 10; 
      var newX = Math.round(Math.sqrt((100 * 100) + (160 * 160))); 
      if (newX < canvas.width - myRectangle.width - myRectangle.borderWidth/2) { 

       myRectangle.x = newX; 

      } 


      context.clearRect(0, 0, canvas.width, canvas.height); 
      drawPath(context); 
      drawRect(myRectangle, cntxt); 

      // request new frame 
      requestAnimFrame(function() { 
       animate(myRectangle, canvas, cntxt, startTime); 
      }); 
     } 
     drawRect(myRectangle, cntxt); 
     myRectangle.x = 100; 
     myRectangle.y = 121; 
     setTimeout(function() { 
      var startTime = (new Date()).getTime(); 
      animate(myRectangle, canvas, cntxt, startTime); 
     }, 1000); 

    }); 
}); 

$(document).keypress(function (e) { 
    if (e.which == 13) { 


     $('#myCanvas').click(); 

    } 
}); 

function drawRect(myRectangle, cntxt) { 

    cntxt.beginPath(); 
    cntxt.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height); 
    cntxt.fillStyle = 'cyan'; 
    cntxt.fill(); 

    cntxt.strokeStyle = 'black'; 
    cntxt.stroke(); 
}; 

function drawPath(context) { 

    context.beginPath(); 
    context.moveTo(100, 20); 

    // line 1 
    context.lineTo(200, 160); 
    // quadratic curve 
    context.quadraticCurveTo(230, 200, 250, 120); 

    // bezier curve 
    context.bezierCurveTo(290, -40, 300, 200, 400, 150); 

    // line 2 
    context.lineTo(500, 90); 
    context.lineWidth = 5; 
    context.strokeStyle = 'blue'; 
    context.stroke(); 
}; 
+0

आप विजुअल-जेएस गेम इंजन का उपयोग कर सकते हैं - पेंसिल घटक: https://codepen.io/zlatnaspirala/full/jrzNko, कई अन्य विशेषताएं हैं ... –

उत्तर

49

यहाँ एक विशेष मार्ग

साथ एक वस्तु को स्थानांतरित करने के लिए कैसे है

एनिमेशन में समय के साथ आंदोलन शामिल है। तो आपके एनीमेशन के प्रत्येक "फ्रेम" के लिए आपको XY समन्वय को जानने की आवश्यकता है जहां आपकी चलती वस्तु (आयताकार) खींचना है।

यह कोड प्रतिशत-पूर्ण (0.00 से 1.00) तक लेता है और XY समन्वय देता है जो पथ खंड के साथ प्रतिशत है। उदाहरण के लिए:

  • 0.00 लाइन (या वक्र) की शुरुआत में XY वापस कर देगा।
  • 0.50 लाइन (या वक्र) के बीच में XY वापस कर देगा।
  • 1.00 लाइन (या वक्र) के अंत में XY वापस कर देगा।

    :

    // line: percent is 0-1 
    function getLineXYatPercent(startPt,endPt,percent) { 
        var dx = endPt.x-startPt.x; 
        var dy = endPt.y-startPt.y; 
        var X = startPt.x + dx*percent; 
        var Y = startPt.y + dy*percent; 
        return({x:X,y:Y}); 
    } 
    

    यहाँ एक द्विघात बेज़ियर वक्र साथ निर्धारित प्रतिशत में XY प्राप्त करने के लिए कोड है:

यहाँ एक रेखा के साथ निर्धारित प्रतिशत में XY प्राप्त करने के लिए कोड है

// cubic bezier percent is 0-1 
function getCubicBezierXYatPercent(startPt,controlPt1,controlPt2,endPt,percent){ 
    var x=CubicN(percent,startPt.x,controlPt1.x,controlPt2.x,endPt.x); 
    var y=CubicN(percent,startPt.y,controlPt1.y,controlPt2.y,endPt.y); 
    return({x:x,y:y}); 
} 

// cubic helper formula at percent distance 
function CubicN(pct, a,b,c,d) { 
    var t2 = pct * pct; 
    var t3 = t2 * pct; 
    return a + (-a * 3 + pct * (3 * a - a * pct)) * pct 
    + (3 * b + pct * (-6 * b + b * 3 * pct)) * pct 
    + (c * 3 - c * 3 * pct) * t2 
    + d * t3; 
} 
:
// quadratic bezier: percent is 0-1 
function getQuadraticBezierXYatPercent(startPt,controlPt,endPt,percent) { 
    var x = Math.pow(1-percent,2) * startPt.x + 2 * (1-percent) * percent * controlPt.x + Math.pow(percent,2) * endPt.x; 
    var y = Math.pow(1-percent,2) * startPt.y + 2 * (1-percent) * percent * controlPt.y + Math.pow(percent,2) * endPt.y; 
    return({x:x,y:y}); 
} 

यहाँ एक घन बेज़ियर वक्र साथ निर्दिष्ट प्रतिशत पर XY प्राप्त करने के लिए कोड है

और यहाँ कैसे आप यह सब एक साथ रखा

// calculate the XY where the tracking will be drawn 

if(pathPercent<25){ 
    var line1percent=pathPercent/24; 
    xy=getLineXYatPercent({x:100,y:20},{x:200,y:160},line1percent); 
} 
else if(pathPercent<50){ 
    var quadPercent=(pathPercent-25)/24 
    xy=getQuadraticBezierXYatPercent({x:200,y:160},{x:230,y:200},{x:250,y:120},quadPercent); 
} 
else if(pathPercent<75){ 
    var cubicPercent=(pathPercent-50)/24 
    xy=getCubicBezierXYatPercent({x:250,y:120},{x:290,y:-40},{x:300,y:200},{x:400,y:150},cubicPercent); 
} 
else { 
    var line2percent=(pathPercent-75)/25 
    xy=getLineXYatPercent({x:400,y:150},{x:500,y:90},line2percent); 
} 

// draw the tracking rectangle 
drawRect(xy); 

यहाँ कूट चल रहा है अपने पथ के विभिन्न क्षेत्रों और एक फिडल चेतन करने के लिए है: आप ढांचे से यह चाहते हैं http://jsfiddle.net/m1erickson/LumMX/

<!doctype html> 
<html lang="en"> 
<head> 

    <style> 
     body{ background-color: ivory; } 
     canvas{border:1px solid red;} 
    </style> 

    <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" /> 
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script> 
    <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script> 

    <script> 

    $(function() { 

     var canvas=document.getElementById("canvas"); 
     var ctx=canvas.getContext("2d"); 

     // set starting values 
     var fps = 60; 
     var percent=0 
     var direction=1; 

     // start the animation 
     animate(); 

     function animate() { 

      // set the animation position (0-100) 
      percent+=direction; 
      if(percent<0){ percent=0; direction=1; }; 
      if(percent>100){ percent=100; direction=-1; }; 

      draw(percent); 

      // request another frame 
      setTimeout(function() { 
       requestAnimationFrame(animate); 
      }, 1000/fps); 
     } 


     // draw the current frame based on sliderValue 
     function draw(sliderValue){ 

      // redraw path 
      ctx.clearRect(0,0,canvas.width,canvas.height); 
      ctx.lineWidth = 5; 

      ctx.beginPath(); 
      ctx.moveTo(100, 20); 
      ctx.lineTo(200, 160); 
      ctx.strokeStyle = 'red'; 
      ctx.stroke(); 

      ctx.beginPath(); 
      ctx.moveTo(200, 160); 
      ctx.quadraticCurveTo(230, 200, 250, 120); 
      ctx.strokeStyle = 'green'; 
      ctx.stroke(); 

      ctx.beginPath(); 
      ctx.moveTo(250,120); 
      ctx.bezierCurveTo(290, -40, 300, 200, 400, 150); 
      ctx.strokeStyle = 'blue'; 
      ctx.stroke(); 

      ctx.beginPath(); 
      ctx.moveTo(400, 150); 
      ctx.lineTo(500, 90); 
      ctx.strokeStyle = 'gold'; 
      ctx.stroke(); 

      // draw the tracking rectangle 
      var xy; 

      if(sliderValue<25){ 
       var percent=sliderValue/24; 
       xy=getLineXYatPercent({x:100,y:20},{x:200,y:160},percent); 
      } 
      else if(sliderValue<50){ 
       var percent=(sliderValue-25)/24 
       xy=getQuadraticBezierXYatPercent({x:200,y:160},{x:230,y:200},{x:250,y:120},percent); 
      } 
      else if(sliderValue<75){ 
       var percent=(sliderValue-50)/24 
       xy=getCubicBezierXYatPercent({x:250,y:120},{x:290,y:-40},{x:300,y:200},{x:400,y:150},percent); 
      } 
      else { 
       var percent=(sliderValue-75)/25 
       xy=getLineXYatPercent({x:400,y:150},{x:500,y:90},percent); 
      } 
      drawRect(xy,"red"); 

     } 


     // draw tracking rect at xy 
     function drawRect(point,color){ 
      ctx.fillStyle="cyan"; 
      ctx.strokeStyle="gray"; 
      ctx.lineWidth=3; 
      ctx.beginPath(); 
      ctx.rect(point.x-13,point.y-8,25,15); 
      ctx.fill(); 
      ctx.stroke(); 
     } 

     // draw tracking dot at xy 
     function drawDot(point,color){ 
      ctx.fillStyle=color; 
      ctx.strokeStyle="black"; 
      ctx.lineWidth=3; 
      ctx.beginPath(); 
      ctx.arc(point.x,point.y,8,0,Math.PI*2,false); 
      ctx.closePath(); 
      ctx.fill(); 
      ctx.stroke(); 
     } 

     // line: percent is 0-1 
     function getLineXYatPercent(startPt,endPt,percent) { 
      var dx = endPt.x-startPt.x; 
      var dy = endPt.y-startPt.y; 
      var X = startPt.x + dx*percent; 
      var Y = startPt.y + dy*percent; 
      return({x:X,y:Y}); 
     } 

     // quadratic bezier: percent is 0-1 
     function getQuadraticBezierXYatPercent(startPt,controlPt,endPt,percent) { 
      var x = Math.pow(1-percent,2) * startPt.x + 2 * (1-percent) * percent * controlPt.x + Math.pow(percent,2) * endPt.x; 
      var y = Math.pow(1-percent,2) * startPt.y + 2 * (1-percent) * percent * controlPt.y + Math.pow(percent,2) * endPt.y; 
      return({x:x,y:y}); 
     } 

     // cubic bezier percent is 0-1 
     function getCubicBezierXYatPercent(startPt,controlPt1,controlPt2,endPt,percent){ 
      var x=CubicN(percent,startPt.x,controlPt1.x,controlPt2.x,endPt.x); 
      var y=CubicN(percent,startPt.y,controlPt1.y,controlPt2.y,endPt.y); 
      return({x:x,y:y}); 
     } 

     // cubic helper formula at percent distance 
     function CubicN(pct, a,b,c,d) { 
      var t2 = pct * pct; 
      var t3 = t2 * pct; 
      return a + (-a * 3 + pct * (3 * a - a * pct)) * pct 
      + (3 * b + pct * (-6 * b + b * 3 * pct)) * pct 
      + (c * 3 - c * 3 * pct) * t2 
      + d * t3; 
     } 


    }); // end $(function(){}); 

    </script> 
</head> 
<body> 
    <canvas id="canvas" width=600 height=300></canvas> 
</body> 
</html> 
+0

यह कोड जेएस पहेली पर काम नहीं करता है। – Chandni

+0

ओओपीएस! मैं अनुरोध भूल गया एनीमेशन शिम जो फ़ायरफ़ॉक्स में आवश्यक है। मैंने पहेली तय की और इसे ठीक से काम करना चाहिए। – markE

+0

धन्यवाद! यह अच्छे जवाब के लिए – Chandni

16

आप उपयोग करने वाले हैं तो निर्मित कैनवास के बेजियर वक्र, आपको अभी भी गणित करने की आवश्यकता होगी।

आप cardinal spline के इस कार्यान्वयन का उपयोग कर सकते हैं और आपके लिए पहले से गणना किए गए सभी बिंदुएं हैं।

उपयोग का एक उदाहरण इस छोटे सॉसेज मोबाइल ढलान के साथ आगे बढ़ (ऊपर कार्डिनल पट्टी के साथ उत्पन्न) है:

Slope demo

Full demo here (कट-और-प्रति आप के रूप में करें)।

मुख्य चीजों की आपको आवश्यकता होती है जब आपके पास बिंदु सरणी होती है जिसे आप ऑब्जेक्ट के लिए उपयोग करने के लिए दो बिंदुओं को ढूंढना चाहते हैं। यह हमें वस्तु के कोण दे देंगे:

cPoints = quantX(pointsFromCardinalSpline); //see below 

//get points from array (dx = current array position) 
x1 = cPoints[dx]; 
y1 = cPoints[dx + 1]; 

//get end-points from array (dlt=length, must be an even number) 
x2 = cPoints[dx + dlt]; 
y2 = cPoints[dx + dlt + 1]; 

ढलान ढलानों हम कोण पर आधारित लंबाई पुनर्गणना में खींच से बचने के लिए।

var dg = getLineAngle(x1, y1, x2, y2); 
var l = ((((lineToAngle(x1, y2, dlt, dg).x - x1)/2) |0) * 2); 

x2 = cPoints[dx + l]; 
y2 = cPoints[dx + l + 1]; 

अब हम "कार" प्लॉट कर सकते हैं साथ: एक अनुमानित कोण हम मूल अंत बिंदु का उपयोग एक कोण पाने के लिए प्राप्त करने के लिए, तो हम वांछित लंबाई के आधार पर लाइन की एक नई लंबाई और इस कोण की गणना वाई पदों से इसकी ऊर्ध्वाधर ऊंचाई घटाकर ढलान।

आपको यह देखने के लिए क्या होगा कि "कार" चर गति पर चलता है। यह कार्डिनल स्पलीन के इंटरपोलेशन के कारण है।

हम इसे चिकनी बना सकते हैं ताकि गति एक्स अक्ष को मापकर भी अधिक दिखाई दे। यह अभी भी सही ढलानों में बिल्कुल सही नहीं होगा क्योंकि बिंदुओं के बीच वाई-दूरी एक सपाट सतह से अधिक होगी - हमें वास्तव में एक वर्गिक मात्रा की आवश्यकता होगी, लेकिन इस उद्देश्य के लिए हम केवल एक्स-अक्ष करते हैं।

यह हमें प्रत्येक एक्स-पद के लिए नए अंक के साथ एक नई सरणी देता है:

function quantX(pts) { 

    var min = 99999999, 
     max = -99999999, 
     x, y, i, p = pts.length, 
     res = []; 

    //find min and max of x axis 
    for (i = 0; i < pts.length - 1; i += 2) { 
     if (pts[i] > max) max = pts[i]; 
     if (pts[i] < min) min = pts[i]; 
    } 
    max = max - min; 

    //this will quantize non-existng points 
    function _getY(x) { 

     var t = p, 
      ptX1, ptX2, ptY1, ptY2, f, y; 

     for (; t >= 0; t -= 2) { 
      ptX1 = pts[t]; 
      ptY1 = pts[t + 1]; 

      if (x >= ptX1) { 
       //p = t + 2; 

       ptX2 = pts[t + 2]; 
       ptY2 = pts[t + 3]; 

       f = (ptY2 - ptY1)/(ptX2 - ptX1); 
       y = (ptX1 - x) * f; 

       return ptY1 - y; 
      } 
     } 
    } 

    //generate new array per-pixel on the x-axis 
    //note: will not work if curve suddenly goes backwards 
    for (i = 0; i < max; i++) { 
     res.push(i); 
     res.push(_getY(i)); 
    } 
    return res; 
} 

अन्य दो कार्यों हम जरूरत है एक लाइन के लिए कोण की गणना एक है, और एक की गणना के अंत अंक आधारित कोण और लंबाई पर:

function getLineAngle(x1, y1, x2, y2) { 
    var dx = x2 - x1, 
     dy = y2 - y1, 
     th = Math.atan2(dy, dx); 

    return th * 180/Math.PI; 
} 

function lineToAngle(x1, y1, length, angle) { 

    angle *= Math.PI/180; 

    var x2 = x1 + length * Math.cos(angle), 
     y2 = y1 + length * Math.sin(angle); 

    return {x: x2, y: y2}; 
} 
+0

+1 मुझे कार के कोणीय रोटेशन पसंद है। – markE

+0

जावा में इसका एहसास कैसे करें? –

संबंधित मुद्दे