canvas 视图框 window 内的可点击对象或形状
clickable object or shape inside a canvas viewbox window
<!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()">×</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()">☰ 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,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>
是否可以在 canvas 框架或视图框上制作可点击的形状或对象,即使我放大或缩小,因为我看到的所有示例都只是一个固定的可点击位置。例如 google 地图位置,当我放大时我可以点击更多对象。
是否可以使 canvas 框架或视图框上的形状或对象可点击,即使当我放大或缩小时,因为我看到的所有示例都只是一个固定的可点击位置。例如 google 地图位置,当我放大时我可以点击更多对象。
您必须考虑两个 space,实际的 canvas space 和翻译后的 space。这意味着您需要平移鼠标坐标才能知道对象在 space 中的实际位置并将其映射回 canvas 坐标,这样您就可以知道您是否正在单击它。这是通过跟踪您在 var originx
中提供的偏移值来实现的,但问题是,如果您使用 [=14],至少根据我的轨迹,您无法平移鼠标单击位置=] 如果同时缩放和平移对象 space.
我在不使用翻译函数的情况下重写了代码,方法是制作我自己的翻译函数,使您能够在 canvas space 和对象 space 之间进行翻译,以便无论平移或放大位置如何,在对象上注册一个点击事件。
此功能还具有点击平移功能,因此您可以点击对象屏幕并将其拖动到您想要放置对象的位置。
/*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,
w: 50,
h: 50,
color: "red"
},
{
x: 50,
y: 100,
w: 50,
h: 50,
color: "green"
},
];
function init() {
canvas.width = canvasWidth;
canvas.height = canvasHeight;
renderCanvas();
}
function drawSquare(x, y, width, height, color) {
context.fillStyle = color;
context.fillRect(x, y, width, 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, 0, canvas.width, canvas.height);
shapes.forEach(({
x,
y,
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;
}
<body>
<div id="main">
<canvas id="canvas" width="300" height="350"></canvas>
</div>
</body>
<!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()">×</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()">☰ 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,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>
是否可以在 canvas 框架或视图框上制作可点击的形状或对象,即使我放大或缩小,因为我看到的所有示例都只是一个固定的可点击位置。例如 google 地图位置,当我放大时我可以点击更多对象。 是否可以使 canvas 框架或视图框上的形状或对象可点击,即使当我放大或缩小时,因为我看到的所有示例都只是一个固定的可点击位置。例如 google 地图位置,当我放大时我可以点击更多对象。
您必须考虑两个 space,实际的 canvas space 和翻译后的 space。这意味着您需要平移鼠标坐标才能知道对象在 space 中的实际位置并将其映射回 canvas 坐标,这样您就可以知道您是否正在单击它。这是通过跟踪您在 var originx
中提供的偏移值来实现的,但问题是,如果您使用 [=14],至少根据我的轨迹,您无法平移鼠标单击位置=] 如果同时缩放和平移对象 space.
我在不使用翻译函数的情况下重写了代码,方法是制作我自己的翻译函数,使您能够在 canvas space 和对象 space 之间进行翻译,以便无论平移或放大位置如何,在对象上注册一个点击事件。
此功能还具有点击平移功能,因此您可以点击对象屏幕并将其拖动到您想要放置对象的位置。
/*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,
w: 50,
h: 50,
color: "red"
},
{
x: 50,
y: 100,
w: 50,
h: 50,
color: "green"
},
];
function init() {
canvas.width = canvasWidth;
canvas.height = canvasHeight;
renderCanvas();
}
function drawSquare(x, y, width, height, color) {
context.fillStyle = color;
context.fillRect(x, y, width, 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, 0, canvas.width, canvas.height);
shapes.forEach(({
x,
y,
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;
}
<body>
<div id="main">
<canvas id="canvas" width="300" height="350"></canvas>
</div>
</body>