halfmagic
8/26/2019 - 5:41 AM

Touch floating navigation study

$(function() {
  let target = document.getElementById('target')
  let testArea = document.getElementById('testArea')
  targetDrag_v02(target, testArea)
})

function targetDrag_v02(target, testArea) {
  // preent the default behavior of mobile browser like body scrolling & zooming
  target.ontouchstart = (e) => {
    e.preventDefault();
  };
  testArea.ontouchstart = (e) => {
    e.preventDefault();
  };
  let targetObj = $(target)
  let testAreaObj = $(testArea)
  let x = 0
  let y = 0
  let targetWidth, targetHeight
  let scaleX, scaleY
  // make it responsive. someone will see this on his/her desktop
  testAreaObj.hammer().bind("touchstart", function(e) {
    // targetObj.text("JUST TOUCHED")
    let touchX, touchY
    touchX = e.originalEvent.touches[0].clientX
    touchY = e.originalEvent.touches[0].clientY
    scaleX = target.getBoundingClientRect().width / target.offsetWidth;
    scaleY = target.getBoundingClientRect().height / target.offsetHeight;
    targetObj.offset({
      left: e.pageX - targetWidth / 2 * scaleX,
      top: e.pageY - targetHeight / 2 * scaleY
    })
  })
  testAreaObj.on("mousedown", function(e) {
    targetWidth = targetObj.outerWidth()
    targetHeight = targetObj.outerHeight()
    scaleX = target.getBoundingClientRect().width / target.offsetWidth;
    scaleY = target.getBoundingClientRect().height / target.offsetHeight;
    targetObj.offset({
      left: e.pageX - targetWidth / 2 * scaleX,
      top: e.pageY - targetHeight / 2 * scaleY
    })
  })
  testAreaObj.hammer().bind("touchstart mousedown panmove panend", function(e) {
    x = target.offsetLeft
    y = target.offsetTop
    targetWidth = targetObj.outerWidth()
    targetHeight = targetObj.outerHeight()
    scaleX = target.getBoundingClientRect().width / target.offsetWidth;
    scaleY = target.getBoundingClientRect().height / target.offsetHeight;
    targetObj.offset({
      left: e.gesture.center.x - targetWidth / 2 * scaleX,
      top: e.gesture.center.y - targetHeight / 2 * scaleY
    })
  })
  testAreaObj.hammer().bind("rotate pinch", function(e) {
    let angle = e.gesture.angle
    targetObj.html(angle)
    targetWidth = targetObj.outerWidth()
    targetHeight = targetObj.outerHeight()
    targetObj.offset({
      left: e.gesture.center.x - targetWidth / 2,
      top: e.gesture.center.y - targetHeight / 2
    })
  })
}
$(function() {
  let nav = document.getElementById('navigation')
  let touchArea = document.getElementById('touchArea')
  let innerNav = document.getElementById('innerNav')
  let debugText = document.getElementById('debugText')
  navDrag_v02(nav, innerNav, touchArea, debugText)
})

function navDrag_v02(nav, innerNav, touchArea, debugText) {
  // preent the default behavior of mobile browser like body scrolling & zooming
  nav.ontouchstart = (e) => {
    e.preventDefault();
  };
  touchArea.ontouchstart = (e) => {
    e.preventDefault();
  };
  let navObj = $(nav)
  let touchAreaObj = $(touchArea)
  let innerNavObj = $(innerNav)
  let debugTextObj = $(debugText)

  let navWidth, navHeight
  let innerNavWidth, innerNavHeight
  let scaleX, scaleY
  let isOn = false
  let dir
  // make it responsive. someone will see this on his/her desktop
  touchAreaObj.hammer().bind("touchstart", function(e) {
    // navObj.text("JUST TOUCHED")
    let touchX, touchY
    touchX = e.originalEvent.touches[0].clientX
    touchY = e.originalEvent.touches[0].clientY
    scaleX = nav.getBoundingClientRect().width / nav.offsetWidth;
    scaleY = nav.getBoundingClientRect().height / nav.offsetHeight;
    navObj.offset({
      left: e.pageX - navWidth / 2 * scaleX,
      top: e.pageY - navHeight / 2 * scaleY
    })
    //TODO find the right initial position of inner navigation
    innerNavObj.position({
      my: "center",
      at: "center",
      of: navObj
    })
  })
  touchAreaObj.on("mousedown", function(e) {
    navWidth = navObj.outerWidth()
    navHeight = navObj.outerHeight()
    scaleX = nav.getBoundingClientRect().width / nav.offsetWidth;
    scaleY = nav.getBoundingClientRect().height / nav.offsetHeight;

    navObj.offset({
      left: e.pageX - navWidth / 2 * scaleX,
      top: e.pageY - navHeight / 2 * scaleY
    })
    innerNavObj.position({
      my: "center",
      at: "center",
      of: navObj
    })
  })
  touchAreaObj.hammer().bind("pan", function(e) {

    navWidth = navObj.outerWidth()
    navHeight = navObj.outerHeight()
    innerNavWidth = innerNavObj.outerWidth()
    innerNavHeight = innerNavObj.outerHeight()
    scaleX = nav.getBoundingClientRect().width / nav.offsetWidth;
    scaleY = nav.getBoundingClientRect().height / nav.offsetHeight;
    // debugMobile(scaleX);

    navObj.offset({
      left: e.gesture.center.x - navWidth / 2 * scaleX - mapRange(e.gesture.deltaX, 0, 100, 0, 95),
      top: e.gesture.center.y - navHeight / 2 * scaleY - mapRange(e.gesture.deltaY, 0, 100, 0, 95)
    })
    innerNavObj.offset({
      left: e.gesture.center.x - innerNavWidth / 2 * scaleX - mapRange(e.gesture.deltaX, 0, 100, 0, 30),
      top: e.gesture.center.y - innerNavHeight / 2 * scaleY - mapRange(e.gesture.deltaY, 0, 100, 0, 30)
    })
    let deltaXmapped = mapRange(Math.abs(e.gesture.deltaX), 0, 250, 0, 1)
    let deltaYmapped = mapRange(Math.abs(e.gesture.deltaY), 0, 250, 0, 1)
    let distanceDeltaXY = pythagorean(deltaXmapped, deltaYmapped)
    if (distanceDeltaXY > 1) {
      distanceDeltaXY = 1
    }
    // innerNavObj.css('opacity', distanceDeltaXY)
    dir = e.gesture.offsetDirection
    // innerNavObj.html(dir)
  })
  touchAreaObj.hammer().bind("panend", function(e) {
    innerNavObj.position({
      my: "center",
      at: "center",
      of: navObj
    })
    switch (dir) {
      case 2:
        debugTextObj.html('<h1>LEFT</h1>')
        break;
      case 4:
        debugTextObj.html('<h1>RIGHT</h1>')
        break;
      case 8:
        debugTextObj.html('<h1>UP</h1>')
        break;
      case 16:
        debugTextObj.html('<h1>DOWN</h1>')
        break;
      default:

    }
  })
}

function mapRange(value, a1, a2, b1, b2) {
  value = (value - a1) / (a2 - a1)
  return b1 + value * (b2 - b1)
}

function pythagorean(deltaX, deltaY) {
  return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
}