屏幕坐标和窗口通信

最近有个海外的大牛做的量子球在浏览器窗口之间的交互很是惊艳,在前端圈子非常火爆。和朋友探讨涉及到的技术细节,其中主要还是利用到了窗口之间的通信,同时需要专递的信息就是量子球在使用canvas绘制时的各种坐标数据信息。下面是自己实现的一个非常简单的demo。

实现效果

源码

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body {
      position: relative;
      margin: 0;
      padding: 0;
      overflow: hidden;
    }
    .rocket {
      position: absolute;
      top: 0;
      left: 0;
      cursor: pointer;
    }
  </style>
</head>
<img>
  <img class="rocket" src="./rocket.png"></img>
  <script src="index.js"></script>
</body>
</html>

index.js

; (function () {
  // 获取火箭图片dom
  const rocket = document.querySelector('.rocket')
  let isDragging = false // 是否处于拖拽状态
  let dx = 0 // 点击位置距火箭图片左边缘的距离
  let dy = 0 // 点击位置距火箭图片上边缘的距离
  const channel = new BroadcastChannel('rocket') // 窗口信息交互广播事件
  channel.onmessage = (e) => {
    const [clientX, clientY] = screenToClient(e.data)
    rocket.style.left = clientX + 'px'
    rocket.style.top = clientY + 'px'
  }

  /**
   * 视口坐标转屏幕坐标
   * @param {*} param0 
   * @returns 
   */
  function clientToScreen([clientX, clientY]) {
    const barHeight = window.outerHeight - window.innerHeight // 浏览器工具栏高度
    const screenX = window.screenX + clientX
    const screenY = window.screenY + clientY + barHeight
    return [screenX, screenY]
  }

  /**
   * 屏幕坐标转视口坐标
   * @param {*} param0 
   * @returns 
   */
  function screenToClient([screenX, screenY]) {
    const barHeight = window.outerHeight - window.innerHeight // 浏览器工具栏高度
    const clientX = screenX - window.screenX
    const clientY = screenY - window.screenY - barHeight
    return [clientX, clientY]
  }

  /**
   * 火箭图片点下事件
   * @param {*} e 
   */
  rocket.onmousedown = (e) => {
    e.preventDefault()
    isDragging = true
    dx = e.pageX - rocket.offsetLeft
    dy = e.pageY - rocket.offsetTop
  }

  /**
   * 火箭图片在视口中移动事件
   * @param {*} e 
   * @returns 
   */
  window.onmousemove = (e) => {
    if (!isDragging) {
      return
    }
    const targetX = e.pageX - dx
    const targetY = e.pageY - dy
    rocket.style.left = targetX + 'px'
    rocket.style.top = targetY + 'px'
    const screentPoints = clientToScreen([targetX, targetY])
    channel.postMessage(screentPoints)
  }

  /**
   * 火箭图片点击取消事件
   */
  rocket.onmouseup = () => {
    isDragging = false
  }
})()

rocket.png

ON THIS PAGE
浙ICP备2023004975号-2
浙公网安备33011002017713号