如何在画布上实现克隆元素

3
我遇到了一个问题,就是在画布上(可放置元素)制作可拖动元素的克隆。目前我只能拖动一张原始图像,但实际上我需要它的复制品以便能够拖动。这是它的工作方式(原图)和目前的工作方式(源1)(源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>

1个回答

0
根据您的代码,您需要:
  • 在mousedown事件上克隆cam1
  • 将克隆对象的top和left cam1属性添加到其上。
  • 附加到body,然后移动克隆的对象并为其添加相应的事件。

由于此处已包括jQuery,因此我将使用它。

编辑:

以下代码可拖动所有图像而不仅限于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个相机也可以这样做吗?因为我尝试使用相同的逻辑实现了其他相机,但并没有起作用。 - user12657376
1
我本意是不想添加完整的代码,因为它需要更有组织性和重构。请查看更新后的答案。顺便说一下,在上面的代码中我没有发现延迟。也许在添加图像源后,可以根据图像来注意到它。 - Ahed Kabalan
目前它可以与所有相机一起使用,非常感谢。但是,一旦您将其拾起并放置在画布上,并且想要再次移动它以便再次复制,已经放置的相机只能放置一次,这是有意为之吗? - user12657376
好的,所以只需从克隆对象中删除class drag,我刚刚更新了答案。 - Ahed Kabalan
你能否看一下,当相机放置在图像中的编号位置时,将画布上的那些道路变成蓝色?描述中有一个理想的工作示例,我会附上图片链接,谢谢。 - user12657376
这是另一个问题。如果答案已被接受,请关闭此问题并打开新问题在画布上绘制路线。 - Ahed Kabalan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接