画布视图框窗口内的可单击对象或形状

问题描述

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>

<style>
body {
  font-family: "Lato",sans-serif;
}

.sidenav {
  height: 100%;
  width: 0;
  position: fixed;
  z-index: 1;
  top: 0;
  left: 0;
  background-color: #111;
  overflow-x: hidden;
  transition: 0.5s;
  padding-top: 60px;
}

.sidenav a {
  padding: 8px 8px 8px 32px;
  text-decoration: none;
  font-size: 25px;
  color: #818181;
  display: block;
  transition: 0.3s;
}

.sidenav a:hover {
  color: #f1f1f1;
}

.sidenav .closebtn {
  position: absolute;
  top: 0;
  right: 25px;
  font-size: 36px;
  margin-left: 50px;
}

#main {
  transition: margin-left .5s;
  padding: 16px;
}

@media screen and (max-height: 450px) {
  .sidenav {padding-top: 15px;}
  .sidenav a {font-size: 18px;}
}
</style>
</head>
<body>

<div id="mySidenav" class="sidenav">
  <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a> 
  <a href="#">About</a>
  <a href="#">Services</a>
  <a href="#">Clients</a>
  <a href="#">Contact</a>
    
</div>
<div id="main">
  <span style="font-size:30px;cursor:pointer" onclick="openNav()">&#9776; Menu</span>
<canvas id="canvas" width="600" height="350" style="border:2px solid #d3d3d3;">></canvas>
</div>

<script>

var zoomIntensity = 0.1;
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = 90;
var height = 50;
var scale = 1;
var originx = 0;
var originy = 0;
var visibleWidth = width;
var visibleHeight = height;


var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

function draw(){

    context.fillStyle = "white";
    context.fillRect(originx,originy,1000/scale,800/scale);

    context.fillStyle = "blue";
    context.fillRect(170,50,50);
    context.fillStyle = "white";
    context.fillText('click here',175,70);   
}

setInterval(draw,1000/60);
canvas.onwheel = function (event){
    event.preventDefault();
    var mousex = event.clientX - canvas.offsetLeft;
    var mousey = event.clientY - canvas.offsetTop;
    var wheel = event.deltaY < 0 ? 1 : -1;
    var zoom = Math.exp(wheel*zoomIntensity);
    
    context.translate(originx,originy);
    originx -= mousex/(scale*zoom) - mousex/scale;
    originy -= mousey/(scale*zoom) - mousey/scale;
    context.scale(zoom,zoom);
    context.translate(-originx,-originy);
    scale *= zoom;
    visibleWidth = width / scale;
    visibleHeight = height / scale;
}
function openNav() {
  document.getElementById("mySidenav").style.width = "200px";
  document.getElementById("main").style.marginLeft = "200px";
}

function closeNav() {
  document.getElementById("mySidenav").style.width = "0";
  document.getElementById("main").style.marginLeft= "0";
}
</script>

</body>
</html>
即使在放大或缩小时,

仍然可以在画布框架或视图框上使形状或对象可单击,因为我看到的所有示例只是一个固定的可单击位置。例如,当我放大时,谷歌地图位置可以单击更多对象。 有没有办法使形状或对象在画布框架或视图框上可单击,即使当我放大或缩小时,由于我看到的所有示例只是一个固定的可单击位置。例如,当我放大时,谷歌地图位置可以单击更多对象。

解决方法

您必须考虑两个空间,实际的画布空间和翻译的空间。这意味着您需要平移鼠标坐标才能知道对象实际在空间中的位置,并将其映射回画布坐标,以便知道是否单击它。这可以通过跟踪var originx中提供的偏移值来实现,但是问题是,如果使用{{1 }}如果同时缩放和平移对象空间。

我已经编写了自己的转换函数,从而无需使用转换功能就重写了代码,使您可以在画布空间和对象空间之间进行转换,以便在对象上注册单击事件,而无需考虑平移或放大位置。

此功能还具有单击和平移功能,因此您可以单击对象屏幕并将其拖动到要定位对象的任何位置。

context.translate(originx,originy)
/*jshint esversion: 8 */

(function() {
  const canvas = document.querySelector("canvas");
  const context = canvas.getContext("2d");
  let canvasWidth = 600;
  let canvasHeight = 600;
  let offset = {
    x: 0,y: 0
  };
  let pan = {
    x: 0,y: 0
  };
  var zoomIntensity = 0.1;
  let scale = 1;
  let mouse = {
    x: 0,y: 0
  };
  let dragging = false;
  let square;

  let shapes = [{
      x: 170,y: 50,w: 50,h: 50,color: "blue"
    },{
      x: 85,y: 25,color: "red"
    },{
      x: 50,y: 100,color: "green"
    },];

  function init() {
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;

    renderCanvas();
  }

  function drawSquare(x,y,width,height,color) {
    context.fillStyle = color;
    context.fillRect(x,height);
  }

  function objectsToCanvasScreen(x,y) {
    const canvasScreenX = Math.floor((x - offset.x) * scale);
    const canvasScreenY = Math.floor((y - offset.y) * scale);

    return {
      x: canvasScreenX,y: canvasScreenY
    };
  }

  function canvasToObjectsScreen(x,y) {
    return {
      x: x / scale + offset.x,y: y / scale + offset.y
    };
  }

  function renderCanvas() {
    context.clearRect(0,canvas.width,canvas.height);

    shapes.forEach(({
      x,w,h,color
    },index) => {
      const {
        x: csx,y: csy
      } = objectsToCanvasScreen(x,y);
      shapes[index]._x = csx;
      shapes[index]._y = csy;
      shapes[index]._w = w * scale;
      shapes[index]._h = h * scale;
      drawSquare(csx,csy,w * scale,h * scale,color);
    });

  }

  canvas.onwheel = function(e) {
    const zoom = Math.exp((e.deltaY < 0 ? 1 : -1) * zoomIntensity);
    const beforeZoom = canvasToObjectsScreen(mouse.x,mouse.y);
    scale *= zoom;
    const afterZoom = canvasToObjectsScreen(mouse.x,mouse.y);
    offset.x += beforeZoom.x - afterZoom.x;
    offset.y += beforeZoom.y - afterZoom.y;

    renderCanvas();
  };
  canvas.onmousedown = function(e) {
    if (e.button === 0) {
      pan.x = mouse.x;
      pan.y = mouse.y;
      dragging = true;
    }
  };
  canvas.onmouseup = (e) => (dragging = false);
  canvas.onmousemove = function(e) {
    mouse.x = e.offsetX;
    mouse.y = e.offsetY;
    if (dragging) {
      offset.x -= (mouse.x - pan.x) / scale;
      offset.y -= (mouse.y - pan.y) / scale;

      pan.x = mouse.x;
      pan.y = mouse.y;
      renderCanvas();
    }
  };
  canvas.onclick = function(e) {
    shapes.forEach(({
      _x,_y,_w,_h,color
    }) => {
      const {
        x: mousex,y: mousey
      } = canvasToObjectsScreen(mouse.x,mouse.y);
      const {
        x: squarex,y: squarey
      } = canvasToObjectsScreen(_x,_y);
      if (
        mousex >= squarex &&
        mousex <= _w / scale + squarex &&
        mousey >= squarey &&
        mousey <= _h / scale + squarey
      ) {
        alert(`${color} clicked!`);
      }
    });

  };

  init();
})();
body {
  font-family: "Lato",sans-serif;
}

#canvas {
  background: #E1BC8B;
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...