【问题标题】:How can I implement cloning elements onto canvas如何在画布上实现克隆元素
【发布时间】:2020-04-23 11:05:07
【问题描述】:

我正在努力将可拖动元素克隆到画布上(可放置元素)。到目前为止,我只能拖动一个原始图像,但我需要它的副本才能拖动到。这是它必须如何工作source 以及它现在如何工作source 1 source 2。 所以它不适用于其他图像。

// 1 - wall, 0 - free/street
const map1 = [
  [1, 1, 1, 1],
  [0, 0, 0, 0],
  [1, 0, 1, 1],
  [1, 0, 0, 0]
];

const city = map1;
const size = 41;

window.onload = function() {
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");

  //draw images
  const p = ctx.lineWidth; //padding
  for (let i = 0; i < city.length; i++) {
    for (let j = 0; j < city[i].length; j++) {
      const x = i * size;
      const y = j * size;
      const img = new Image();
      img.onload = function() {
        ctx.drawImage(img, x, y, size + p * 2, size + p * 2);
      };
      img.src = city[i][j] == 0 ? "images/white.png" : "images/black.png";
    }
  }
};

$(document).ready(function() {
  let currentDroppable = null;
  const cam1 = document.getElementById('cam1');

  cam1.onmousedown = function(event) {

    let shiftX = event.clientX - cam1.getBoundingClientRect().left;
    let shiftY = event.clientY - cam1.getBoundingClientRect().top;

    cam1.style.position = 'absolute';
    cam1.style.zIndex = 1000;
    document.body.append(cam1);

    moveAt(event.pageX, event.pageY);

    function moveAt(pageX, pageY) {
      cam1.style.left = pageX - shiftX + 'px';
      cam1.style.top = pageY - shiftY + 'px';
    }

    function onMouseMove(event) {
      moveAt(event.pageX, event.pageY);

      cam1.hidden = true;
      let elemBelow = document.elementFromPoint(event.clientX, event.clientY);
      cam1.hidden = false;

      if (!elemBelow) return;

      let droppableBelow = elemBelow.closest('#canvas');
      if (currentDroppable != droppableBelow) {
        if (currentDroppable) { // null when we were not over a droppable before this event
          leaveDroppable(currentDroppable);
        }
        currentDroppable = droppableBelow;
        if (currentDroppable) { // null if we're not coming over a droppable now
          // (maybe just left the droppable)
          enterDroppable(currentDroppable);
        }
      }
    }

    document.addEventListener('mousemove', onMouseMove);

    cam1.onmouseup = function() {
      document.removeEventListener('mousemove', onMouseMove);
      cam1.onmouseup = null;
    };

  };


  function enterDroppable(elem) {
    elem.style.background = 'blue';
  }

  function leaveDroppable(elem) {
    elem.style.background = '';
  }

  cam1.ondragstart = function() {
    return false;
  };
});
body {
  color: #000;
}

h1,
footer {
  text-align: center;
  margin-top: 10px;
}

#game {
  border: 1px solid #666;
  position: relative;
  width: 600px;
  height: 450px;
  margin: 0 auto;
  z-index: 1;
  background-color: gold;
}

#cam1 {
  cursor: pointer;
}

#canvas {
  cursor: pointer;
}

.cameras {
  position: absolute;
  flex-direction: column;
  flex-wrap: wrap;
  right: 0;
  top: 0;
  z-index: 200;
  display: flex;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>cameras of the city</title>
  <link rel="stylesheet" href="js/jquery-ui-1.12.1/jquery-ui.min.css">
  <link rel="stylesheet" href="styles.css">
  <script src="js/jquery-3.4.1.js"></script>
  <script src="js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
</head>

<body>
  <header>
    <h1>cameras of the city</h1>
  </header>
  <div id="game">
    <canvas height="450px" width="450px" id="canvas"></canvas>
    <div class="cameras">
      <img id="cam1" src="images/camera1.png">
      <img id="cam2" src="images/camera2.png">
      <img id="cam3" src="images/camera3.png">
      <img id="cam4" src="images/camera4.png">
    </div>
  </div>
  <footer>
    created:
  </footer>

  <script src="js/core.js"></script>
</body>

</html>

【问题讨论】:

    标签: javascript jquery html css canvas


    【解决方案1】:

    根据您的代码,您必须:

    • 在鼠标按下时克隆 cam1
    • 将顶部和左侧cam1 属性添加到克隆对象。
    • 附加到正文,然后移动克隆的对象并为其添加相应的事件。

    我将使用 jQuery,因为它包含在上面的 sn-p 中。

    编辑:

    下面的代码不仅可以拖动所有图像cam1

    // 1 - wall, 0 - free/street
            const map1 = [
              [1, 1, 1, 1],
              [0, 0, 0, 0],
              [1, 0, 1, 1],
              [1, 0, 0, 0]
            ];
    
            const city = map1;
            const size = 41;
    
            window.onload = function() {
              const canvas = document.getElementById("canvas");
              const ctx = canvas.getContext("2d");
    
              //draw images
              const p = ctx.lineWidth; //padding
              for (let i = 0; i < city.length; i++) {
                for (let j = 0; j < city[i].length; j++) {
                  const x = i * size;
                  const y = j * size;
                  const img = new Image();
                  img.onload = function() {
                    ctx.drawImage(img, x, y, size + p * 2, size + p * 2);
                  };
                  img.src = city[i][j] == 0 ? "images/white.png" : "images/black.png";
                }
              }
            };
    
            $(document).ready(function() {
              let currentDroppable = null, clone;
    
              function moveAt(pageX, pageY, shiftX, shiftY) {
                  clone.style.left = pageX - shiftX + 'px';
                  clone.style.top = pageY - shiftY + 'px';
                }
    
                function onMouseMove(event) {
                  moveAt(event.pageX, event.pageY, 0, 0);
    
                  clone.hidden = true;
                  let elemBelow = document.elementFromPoint(event.clientX, event.clientY);
                  clone.hidden = false;
    
                  if (!elemBelow) return;
    
                  let droppableBelow = elemBelow.closest('#canvas');
                  if (currentDroppable != droppableBelow) {
                    if (currentDroppable) { // null when we were not over a droppable before this event
                      leaveDroppable(currentDroppable);
                    }
                    currentDroppable = droppableBelow;
                    if (currentDroppable) { // null if we're not coming over a droppable now
                      // (maybe just left the droppable)
                      enterDroppable(currentDroppable);
                    }
                  }
                }
    
              $(document).on('mousedown', '.drag', function(e){
    
                var tmp = $(this).clone().removeClass("drag");
                $(tmp).css({position: 'absolute', top: $(this).offset().top + "px", left: $(this).offset().left + "px", opacity: 1, 'z-index': 1000});
                $('body').append($(tmp));
    
                clone = $(tmp)[0];
    
                let shiftX = event.clientX - clone.getBoundingClientRect().left;
                let shiftY = event.clientY - clone.getBoundingClientRect().top;
    
                moveAt(event.pageX, event.pageY, shiftX, shiftY);
    
                document.addEventListener('mousemove', onMouseMove);
    
                clone.onmouseup = function() {
                  document.removeEventListener('mousemove', onMouseMove);
                  clone.onmouseup = null;
                };
    
              });
    
    
              function enterDroppable(elem) {
                elem.style.background = 'blue';
              }
    
              function leaveDroppable(elem) {
                elem.style.background = '';
              }
    
              cam1.ondragstart = function() {
                return false;
              };
            });
    body {
      color: #000;
    }
    
    h1,
    footer {
      text-align: center;
      margin-top: 10px;
    }
    
    #game {
      border: 1px solid #666;
      position: relative;
      width: 600px;
      height: 450px;
      margin: 0 auto;
      z-index: 1;
      background-color: gold;
    }
    
    .drag {
      cursor: pointer;
    }
    
    #canvas {
      cursor: pointer;
    }
    
    .cameras {
      position: absolute;
      flex-direction: column;
      flex-wrap: wrap;
      right: 0;
      top: 0;
      z-index: 200;
      display: flex;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8">
      <title>cameras of the city</title>
      <link rel="stylesheet" href="js/jquery-ui-1.12.1/jquery-ui.min.css">
      <link rel="stylesheet" href="styles.css">
      <script src="js/jquery-3.4.1.js"></script>
      <script src="js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
    </head>
    
    <body>
      <header>
        <h1>cameras of the city</h1>
      </header>
      <div id="game">
        <canvas height="450px" width="450px" id="canvas"></canvas>
        <div class="cameras">
          <img id="cam1" class="drag" src="images/camera1.png">
          <img id="cam2" class="drag" src="images/camera2.png">
          <img id="cam3" class="drag" src="images/camera3.png">
          <img id="cam4" class="drag" src="images/camera4.png">
        </div>
      </div>
      <footer>
        created:
      </footer>
    
      <script src="js/core.js"></script>
    </body>
    
    </html>

    【讨论】:

    • 感谢您的解决方案,一旦您选择了第一台相机,它会出现一些延迟,但没关系。其他 3 个也可以这样做,因为我尝试为其他相机实现相同的逻辑但它不起作用?
    • 我打算不添加完整的代码,因为它需要更有条理和重构。请找到更新的答案。顺便说一句,我在上面的代码中没有发现延迟。可能在添加图片 src 后可以根据图片注意到。
    • 它现在适用于所有相机,非常感谢,但是,一旦你拿起它并将它放在画布上并想再次移动它,它就会再次复制并且只能放置已经放置的相机有一次,是打算这样吗?
    • 好的,所以只需从克隆对象中删除类拖动,我刚刚更新了答案。
    • 你能看看根据相机图像中的数字放置相机后,将画布上的那些道路变成蓝色吗?描述中有一个理想的工作示例,我会附上图片的链接,谢谢。
    猜你喜欢
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 2016-10-26
    • 2020-11-20
    • 2016-02-01
    相关资源
    最近更新 更多