通过使用鼠标旋转圆来平移平面

时间:2018-09-23 19:45:32

标签: javascript html geometry angle

我有两个按钮(箭头),当按下它们时,一切都会按预期进行。

不起作用的是用鼠标移动地面(将鼠标悬停在方向盘上以查看),它不断跳回先前的值(由飞机上的数字显示)。

如何通过鼠标旋转圆来平移平面?

const plane = $('#plane')
const planeX = plane.offset().left
const wheel = $('.wheel>div')
const radius = wheel.width() / 2
let degrees = 0

// buttons
let interval
$(document).on('mousedown', 'span', event => {
  $('.interactive').css('background', 'rgba(172, 255, 47, 0.25)')
  interval = setInterval(() => {
    if (event.currentTarget.id === 'left') degrees -= 2
    else degrees += 2
    wheel.css('transform', 'rotate(' + degrees + 'deg)').data('degree', degrees)
    plane.css('left', planeX - degrees * (Math.PI / 180) * radius + 'px')
  }, 10)
})
$(document).on('mouseup', 'span', () => {
  $('.interactive').css('background', '')
  clearInterval(interval)
})

// mouse
const offset = wheel.parent().offset()
$(document).on('mouseenter', '.interactive', event => {
  $('.interactive').css('background', 'rgba(172, 255, 47, 0.25)')
  const degreeOffset =
    Math.atan2(
      event.pageX - (offset.left + radius),
      event.pageY - (offset.top + radius)
    ) *
      (180 / Math.PI) *
      -1 -
    degrees
  $(document).on('mousemove', event2 => {
    const radians = Math.atan2(
      event2.pageX - (offset.left + radius),
      event2.pageY - (offset.top + radius)
    )
    degrees = radians * (180 / Math.PI) * -1 - degreeOffset
    wheel.css('transform', 'rotate(' + degrees + 'deg)').data('degree', degrees)
    plane.css('left', planeX - degrees * (Math.PI / 180) * radius + 'px')
  })
})
$(document).on('mouseleave', '.interactive', () => {
  $('.interactive').css('background', '')
  $(document).off('mousemove')
})
<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;<span
      style="cursor:pointer;" id="right">&gt;</span></div>
  <div class="wheel" style="position:fixed;bottom:1em;left:50%;transform:translateX(-50%);">
    <div 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 class="interactive" style="border-radius:50%;position:absolute;top:0;left:0;bottom:0;right:0"></div>
      <div style="border:1px solid;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:white;width:25%;height:25%;display: flex;justify-content: center;align-items: center;">X</div>
    </div>
  </div>
  <div id="plane" style="position:fixed;bottom:0;left:-100vw;width:300vw;height:1em;border:1px solid;display:flex;justify-content:space-around;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')"><b>1</b><b>2</b><b>3</b><b>4</b><b>5</b><b>6</b><b>7</b><b>8</b><b>9</b></div>

1 个答案:

答案 0 :(得分:2)

mousemove的处理程序未考虑超过0度标记的问题。我已经更新了代码,以计算鼠标位置的变化(例如newMousePos - mousePos),并说明了0度的移动。

const plane = $('#plane')
const planeX = plane.offset().left
const wheel = $('.wheel>div')
const radius = wheel.width() / 2
let degrees = 0

// buttons
let interval
$(document).on('mousedown', 'span', event => {
  $('.interactive').css('background', 'rgba(172, 255, 47, 0.25)')
  interval = setInterval(() => {
    if (event.currentTarget.id === 'left') degrees -= 2
    else degrees += 2
    wheel.css('transform', 'rotate(' + degrees + 'deg)').data('degree', degrees)
    plane.css('left', planeX - degrees * (Math.PI / 180) * radius + 'px')
  }, 10)
})
$(document).on('mouseup', 'span', () => {
  $('.interactive').css('background', '')
  clearInterval(interval)
})

// mouse
const offset = wheel.parent().offset()
let mousePos = 0
$(document).on('mouseenter', '.interactive', event => {
  $('.interactive').css('background', 'rgba(172, 255, 47, 0.25)')
  const degreeOffset =
  Math.atan2(
    event.pageX - (offset.left + radius),
    event.pageY - (offset.top + radius)
  ) *
    (180 / Math.PI) *
    -1 -
    degrees
  $(document).on('mousemove', event2 => {
    const radians = Math.atan2(
      event2.pageX - (offset.left + radius),
      event2.pageY - (offset.top + radius)
    )

    const newMousePos = radians * (180 / Math.PI) * -1 - degreeOffset
    let change = newMousePos - mousePos

    // adjust for moving over 0 deg.
    if (change < -180) change += 360
    else if (change > 180) change -= 360
    mousePos = newMousePos
    degrees += change

    wheel.css('transform', 'rotate(' + degrees + 'deg)').data('degree', degrees)
    plane.css('left', planeX - degrees * (Math.PI / 180) * radius + 'px')
  })
})

$(document).on('mouseleave', '.interactive', () => {
  $('.interactive').css('background', '')
  $(document).off('mousemove')
})
<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;<span
      style="cursor:pointer;" id="right">&gt;</span></div>
  <div class="wheel" style="position:fixed;bottom:1em;left:50%;transform:translateX(-50%);">
    <div 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 class="interactive" style="border-radius:50%;position:absolute;top:0;left:0;bottom:0;right:0"></div>
      <div style="border:1px solid;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:white;width:25%;height:25%;display: flex;justify-content: center;align-items: center;">X</div>
    </div>
  </div>
  <div id="plane" style="position:fixed;bottom:0;left:-100vw;width:300vw;height:1em;border:1px solid;display:flex;justify-content:space-around;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAAAAAA7suyFAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAFuSURBVDjLfdRBa8IwGMbxx7cjEklIiVQqjsoCnvb9P8FACBQKngQHXpTJhJx2mRDZoXUmqfW9WX68f5tAR1tEw3jD5/EjUPKT1e/68NRQvil/X1MUGSbXeno9LRMUGmJ1NbsgSxHFIXEBeoiSENBHlITayc4hojTUTbiJbiGrulC36WT+UWuI28U82BIjakNNlccEwPGWIwCUWy16BNm520QAk+tydsWD6f44gUSzmF6AYUSU11oNkO6cRl92cAsA+PLgX+ybfEKQHVacijOejZc/R1qJHXtChLDf5Iza0SDhvK4mBGf0ng0R3RRjEOCWeiCn1Ech27twS7V9kPOM2WqC7k6d0Xvqh1RTjnEzcEZ9JjkvxFpPcDdwRsdv5zmrK4nQwBkV5jxXmzYUGDij7kfghbBdKDRw5v52nNWlRN/cD9MztSkneGTgjNoxwAtV64DE34T27gSzhcSQgTNqz1kUAjBKvmN6h4uQ8bM/WtmCgAk7YV0AAAAASUVORK5CYII=')"><b>1</b><b>2</b><b>3</b><b>4</b><b>5</b><b>6</b><b>7</b><b>8</b><b>9</b></div>