Search code examples
javascriptgeometrydistanceangle

How to synchronize the ground with the rotation of the wheel?


I want to sync the ground with the rotation of a wheel (pull the ground under with the wheel rotation). The wheel has a dynamic diameter.

In my example bellow the ground should keep moving to the left if I press the right arrow, but it doesn't.

const wheel=$('#wheel')
const plane=$('#plane')
let degree=0
let interval
$(document).on('mousedown','span',event=>{
  let planeX=plane.offset().left
  interval=setInterval(()=>{
    if(event.currentTarget.id==='left')degree-=1 
    else degree+=1
    wheel.css('transform', 'rotate(' + degree + 'deg)')
    const radians=degree * (Math.PI / 180)
    const cos = Math.cos(radians)
    planeX+=cos
    plane.css('left',planeX+'px')
  },10)
})
$(document).on('mouseup','span',event=>clearInterval(interval))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="position:fixed;top:0; font-size:200%;"><span style="cursor:pointer;" id="left">&lt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="cursor:pointer;" id="right">&gt;</span></div>
  <div id="wheelContainer" style="position:fixed;bottom:1em;left:50%;transform:translateX(-50%);"><div id="wheel" style="width:150px;height:150px;border:1px solid;border-radius:50%;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')"></div></div>
  <div id="plane" style="position:fixed;bottom:0;left:-1000vw;right:-1000vw;height:1em;border:1px solid;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')"></div>


Solution

  • The total arc length is equal to the total angle (measured in radians) times the radius. Since the ground is under the wheel, you'll want opposite sign. So instead of

    planeX+=cos
    

    bettwer write

    planeX = planeX0 - radians * radius
    

    where radius would be 75px in your scenario.

    const wheel=$('#wheel')
    const plane=$('#plane')
    const radius=75
    const planeX0=plane.offset().left
    let degree=0
    let interval
    $(document).on('mousedown','span',event=>{
      interval=setInterval(()=>{
        if(event.currentTarget.id==='left')degree-=1 
        else degree+=1
        wheel.css('transform', 'rotate(' + degree + 'deg)')
        const radians=degree * (Math.PI / 180)
        planeX = planeX0 - radians * radius
        plane.css('left',planeX+'px')
      },10)
    })
    $(document).on('mouseup','span',event=>clearInterval(interval))
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div style="position:fixed;top:0; font-size:200%;"><span style="cursor:pointer;" id="left">&lt;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="cursor:pointer;" id="right">&gt;</span></div>
      <div id="wheelContainer" style="position:fixed;bottom:1em;left:50%;transform:translateX(-50%);"><div id="wheel" style="width:150px;height:150px;border:1px solid;border-radius:50%;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')"></div></div>
      <div id="plane" style="position:fixed;bottom:0;left:-1000vw;right:-1000vw;height:1em;border:1px solid;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')"></div>