HTML5 Javascript:如何确保绘制的对象不能离开画布
HTML5 Javascript: How to Make Sure a Drawn Object Cannot Leave the Canvas
我有以下分配问题,我正在努力解决:
- 编写一个应用程序,使用canvas元素在画布的两个不同部分创建两个圆圈(颜色不同)。圆圈应该能够在画布内拖动,当它到达边缘时应该停止。换句话说,圆的边缘不应该超过画布的边缘。每个圆应该单独拖动。当你松开鼠标按钮时,圆圈应该停止。
到目前为止,我已经创建了两个圆圈,然而,我有麻烦的部分,我必须使它,使两个圆圈可以被拖动,但不能离开画布。我很确定这应该是一个事件监听器,但我不知道如何编码。如果您能提供帮助或见解,我将不胜感激。
目前为止我有什么:
<!DOCTYPE html>
<html>
<head>
<script>
window.onload = draw;
function draw(){
var canvas = document.getElementById("circleCanvas");
var ctx = canvas.getContext("2d");
ctx.arc(100,75,50,0,2*Math.PI);
ctx.fillStyle = "green";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.arc(100,200,50,0,2*Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.stroke();
ctx.closePath();
}
</script>
</head>
<body>
<canvas id="circleCanvas" width="500" height="500"></canvas>
</body>
</html>
简单的画布拖放操作。
-
创建一个鼠标对象,通过监听鼠标事件设置鼠标位置和按钮状态
-
创建一个圆数组,描述每个圆的位置和大小。
-
创建一个函数来绘制一个圆。在这个函数中,你可以检查圆圈是否超出了界限,如果超出了界限,就移动它。
-
创建一个位置搜索功能,检查每个圆以及它离点的距离。如果圆在点(dist <</p>
-
创建一个动画循环,每1/60秒重新绘制画布。检查一下鼠标是否按下。如果是,并且没有拖动任何东西看看鼠标是否在一个圆上。如果是,选择那个圆圈进行拖动。当鼠标向上时,放下圆圈
因为这是一个作业,我们不应该直接给你答案。但是学校是我们一生中唯一不被允许寻求帮助的时候,是我们最需要帮助的时候。我认为你对学习很感兴趣,在很多情况下,以身作则是最好的方法。
如果你有任何问题,请问
"use strict";
const canvas = document.createElement("canvas");
canvas.height = innerHeight;
canvas.width = innerWidth;
canvas.style.position = "absolute";
canvas.style.top = canvas.style.left = "0px";
const ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
ctx.font = "48px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
var w = canvas.width;
var h = canvas.height;
var renderUpdate = true; // flags if there is a need to render
var globalTime = 0;
const mouse = {
x:0,y:0,button:false
};
const circles = [{
x : 100,
y : 100,
radius : 40,
col : "red",
lineWidth : 4,
highlight : false,
},{
x : 200,
y : 100,
radius : 40,
col : "green",
lineWidth : 4,
highlight : false,
},
];
var closestCircle; // holds result of function findClosestCircle2Point
const drag = { // if dragging this holds the circle being dragged
circle : null,
offsetX : 0, // distance from mouse to circle center when drag started
offsetY : 0,
}
const message = { // a message to inform of problems.
time : 120, // 60 ticks per second
text: "Click drag circles",
}
// adds mouse events listeners
canvas.addEventListener("mousemove",mouseEvent)
canvas.addEventListener("mousedown",mouseEvent)
canvas.addEventListener("mouseup",mouseEvent)
// function to handle all mouse events
function mouseEvent(e){
var m = mouse;
var bounds = canvas.getBoundingClientRect();
m.x = e.clientX - bounds.left;
m.y = e.clientY - bounds.top;
if(e.type === "mousedown"){
m.button = true;
}else if(e.type === "mouseup"){
m.button = false;
}
renderUpdate = true; // flag that there could be a render change.
}
// this finds the closest circle under x,y if nothing under the point then retVal.circle = null
function findClosestCircle2Point(x, y, retVal){
if(retVal === undefined){
retVal = {};
}
var minDist = Infinity;
var dist;
var xx,yy;
retVal.circle = null;
for(var i = 0; i < circles.length; i ++){
xx = x - circles[i].x;
yy = y - circles[i].y;
dist = Math.sqrt(xx*xx+yy*yy);
if(dist < minDist && dist <= circles[i].radius){
minDist = dist;
retVal.circle = circles[i];
}
}
return retVal;
}
// this draws a circle, adds highlight if needed and makes sure the circle does not go outside the canvas
function drawCircle(circle){
var c = circle;
var rad = c.radius + c.lineWidth / 2; // get radius plus half line width
// keep circle inside canvas
c.x = c.x - rad < 0 ? c.x = rad : c.x + rad >= w ? c.x = w-rad : c.x;
c.y = c.y - rad < 0 ? c.y = rad : c.y + rad >= h ? c.y = h-rad : c.y;
ctx.lineWidth = 4;
if(c.highlight){ // highlight the circle if needed
ctx.strokeStyle = "#0F0";
ctx.globalAlpha = 0.5;
ctx.beginPath();
ctx.arc(c.x,c.y,c.radius + c.lineWidth,0,Math.PI * 2);
ctx.stroke();
c.highlight = false;
}
// draw the circle
ctx.fillStyle = c.col;
ctx.strokeStyle = c.col;
ctx.globalAlpha = 0.5;
ctx.beginPath();
ctx.arc(c.x,c.y,c.radius,0,Math.PI * 2);
ctx.fill();
ctx.globalAlpha = 1;
ctx.stroke();
}
// main update function
function update(time){
globalTime = time;
requestAnimationFrame(update); // get the next animation frame.
if(!renderUpdate ){ // don't render if there is no need
return;
}
renderUpdate = false;
ctx.clearRect(0,0,w,h);
// when not dragging look for the closest circle under the mouse and highlight it
if(drag.circle === null){
closestCircle = findClosestCircle2Point(mouse.x,mouse.y,closestCircle);
if(closestCircle.circle !== null){
closestCircle.circle.highlight = true;
}
}
if(mouse.button){ // if the mouse is down start dragging if circle is under mouse
if(drag.circle === null){
if(closestCircle.circle !== null){
drag.circle = closestCircle.circle;
drag.offsetX = mouse.x - drag.circle.x;
drag.offsetY = mouse.y - drag.circle.y;
}else{
mouse.button = false;
}
}else{
drag.circle.x = mouse.x - drag.offsetX;
drag.circle.y = mouse.y - drag.offsetY;
}
}else{ // drop circle
drag.circle = null;
}
for(var i = 0; i < circles.length; i ++){ // draw all circles
drawCircle(circles[i]);
}
// display any messages if needed.
if(message.time > 0){
message.time -= 1;
ctx.fillStyle = "black";
ctx.fillText(message.text,w/2,h/2);
renderUpdate = true; // while message is up need to render.
}
}
requestAnimationFrame(update); // start the whole thing going.
HTML5 canvas没有针对您绘制的对象的事件监听器。一旦它们被栅格化(绘制),它们就只是图像上的像素。
这意味着你必须独立处理对画布的点击,然后通过javascript对象处理屏幕上的事件,然后重新绘制画布。像fabric.js这样的框架可以让这个过程变得非常轻松。http://fabricjs.com/
还有其他框架,但如果你不想要一个框架,它将要求你管理自己的场景,执行点击检测对象事件处理等。
相关文章:
- 使用fabric.js从矩形区域获取对象,并将该区域绘制到画布上
- 用图像而不是颜色填充对象(将图像绘制到画布上)
- 在画布中绘制对象的阴影
- 使用 jQuery animate 时绘制一个又一个对象的线条
- 如何在画布上绘制(使用鼠标/触摸)、保存绘制的对象、存储、加载和操作
- 未捕获的类型错误:对象#<HTML对象元素>没有方法'重新绘制工作流'
- 画布对象总是在其他对象后面绘制
- 动力学.js“对象没有方法批处理绘制”
- D3 - 在两个不与其他对象相交的对象之间绘制一条线
- 我正在尝试从可绘制对象中获取位图
- 如何使用google.maps.Rectangle对象在谷歌地图上绘制选择/边界框/矩形,并检查标记是否落在其中
- 从对象数组数组绘制 D3 图表
- 如何在表格中绘制对象 sapui5.
- HTML5 画布擦除绘制的对象
- 在 Fabric.js 中同时绘制两个对象
- 制作主干.js视图以在画布上绘制对象
- 在Javascript中,为什么我不能绘制对象的多个实例
- 如何使用矢量作为坐标在画布上绘制对象
- 当对象来自jQuery选择时,如何将图像对象绘制到画布
- 为数组中的每个对象绘制画布笔画文本,但只绘制一个图像