如何解决在Canvas,JavaScript上关闭窗口
我正在尝试解决此问题。 我需要检测鼠标单击红色小矩形以关闭窗口。 只有在“顶部”没有其他窗口时,该单击的窗口才应关闭。
我曾想过要检测到红色的点击,但这并不是很好。
PS。我无法使用弹出式窗口,需要这样做。
有人可以帮我吗? 谢谢!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
</head>
<body>
<input type="radio" name="choice" id="open">
Open new window:
Height = <input type="text" id="txt_height">,width =
<input type="text" id="txt_width"> <br>
<input type="radio" name="choice" id="close"> Closing window
<br> <br>
<canvas id="canvas" width="600" height="600" style="border: 1px solid black"></canvas> <br> <br>
Currently,there are <span id="details_1"></span> windows open. <br>
<span id="details_2"></span>
<script>
var A = 0;
var i = 0;
$("#details_1").text(i);
$('input[type=radio]').click(function(e) {
var value = $(this).val();
if(this.id === 'open') A=1;
if(this.id === 'close') A=2;
});
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
function mouse_position(canvas,event){
const rect = canvas.getBoundingClientRect();
const x = Math.floor(event.clientX - rect.left);
const y = Math.floor(event.clientY - rect.top);
if ( A === 1 ) open(x,y);
if ( A === 2 ) close();
}
$('#canvas').click(function(e){ mouse_position(canvas,event);})
function open(x,y){
i++;
var width = $("#txt_width").val();
var height = $("#txt_height").val();
var new_x = x + (width - 30);
if( !width.match(/^\d+$/) || !height.match(/^\d+$/)) alert('Natural numbers only!');
if ( height < 30) alert('Must be greater than 30!');
ctx.restore();
ctx.rect(x,y,width,height);
ctx.stroke();
ctx.save();
ctx.rect(x,30);
ctx.fillStyle = "gray";
ctx.fillRect(x,30);
ctx.font = "15px Arial";
ctx.fillStyle = "black";
ctx.fillText("Window no. " + i,x + 10,y + 20);
ctx.stroke();
ctx.save();
ctx.rect(new_x,30,30);
ctx.fillStyle = "red";
ctx.fillRect(new_x,30);
ctx.font = "15px Arial";
ctx.fillStyle = "black";
ctx.fillText("X",new_x + 10,y + 20);
ctx.stroke();
ctx.save();
$("#details_1").text(i);
$("#details_2").text('Those are: ');
for (var j = 0; j < i; j++)
$("#details_2").append('Window ' + (j+1) + ' ');
}
function close(){
//need help here
}
</script>
</body>
</html>
解决方法
这是一个更简单的示例:
var canvas,ctx;
var win_list = [];
var A = 0;
var cnt = 0,i = 0;
function win (width,height) {
var x = 0,y = 0;
return {'id':++i,'name':"Window no. "+i,'open':open,'show':show,'isInside':isInside,'isInsideClose':isInsideClose};
function open (xx,yy) {
x = xx; y = yy;
this.show();
return this;
}
function show () {
ctx.save();
ctx.fillStyle = 'white';
ctx.fillRect(x,y,width,height);
ctx.strokeStyle = 'black';
ctx.strokeRect(x,height);
ctx.fillStyle = 'gray';
ctx.fillRect(x,30);
ctx.strokeStyle = 'black';
ctx.strokeRect(x,30);
ctx.font = '15px Arial';
ctx.fillStyle = 'black';
ctx.fillText(this.name,x+10,y+20);
var new_x = x + (width - 30);
ctx.fillStyle = 'red';
ctx.fillRect(new_x,30,30);
ctx.strokeStyle = 'black';
ctx.strokeRect(new_x,30);
ctx.font = '15px Arial';
ctx.fillStyle = 'black';
ctx.fillText('X',new_x+10,y+20);
ctx.restore();
return this;
}
function isInside (xx,yy) {
return x <= xx && xx < x+width && y <= yy && yy < y+width;
}
function isInsideClose (xx,yy) {
var new_x = x + (width - 30);
return new_x <= xx && xx < x+width && y <= yy && yy < y+width;
}
}
function mouse_position (event) {
const rect = canvas.getBoundingClientRect();
const x = Math.floor(event.clientX - rect.left);
const y = Math.floor(event.clientY - rect.top);
if ( A === 1 ) create_win(x,y);
if ( A === 2 ) close(x,y);
}
function create_win (x,y) {
var width = $('#txt_width').val();
var height = $('#txt_height').val();
if (! width.match(/^\d+$/) || !height.match(/^\d+$/))
alert("Natural numbers only!");
if (height < 30)
alert("Must be greater than 30!");
var w = win(width,height).open(x,y);
win_list.push(w);
$("#details_1").text(win_list.length);
$("#details_2").append(' '+w.name);
}
function close (x,y) {
//need help here
var j;
for (j = win_list.length - 1; j >= 0 ; --j) {
let w = win_list[j];
if (w.isInside(x,y)) {
if (w.isInsideClose(x,y)) {
break;
}
return;
}
}
if (j < 0) return;
for (; j < win_list.length-1 ; ++j) {
win_list[j] = win_list[j+1];
}
win_list.pop();
redraw_all();
}
function redraw_all () {
ctx.fillStyle = 'white';
ctx.fillRect(0,600,600);
win_list.forEach(function (w) {w.show();});
$("#details_1").text(win_list.length);
$("#details_2").text("Those are: ");
win_list.forEach(function (w) {
$("#details_2").append(' '+w.name);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
Height = <input type="text" id="txt_height" value="100"><br>
Width = <input type="text" id="txt_width" value="200"><br>
<input type="radio" name="choice" id="open"> Open new window <br>
<input type="radio" name="choice" id="close"> Closing window <br>
<br>
<canvas id="canvas" width="600" height="600" style="border: 1px solid black"></canvas>
<br>
Currently,there are <span id="details_1"></span> windows open. <br>
<span id="details_2"></span>
<script>
canvas = document.getElementById('canvas');
ctx = canvas.getContext("2d");
$("#details_1").text(0);
$("#details_2").text("Those are: ");
$('input[type=radio]').click(function(e) {
if (this.id === 'open') A=1;
if (this.id === 'close') A=2;
});
$('#canvas').click(function(e){
mouse_position(e);
});
</script>
,
Windows GUI,焦点和树
我想说简单。无论您如何实现窗口系统,它都会变得非常复杂。
像DOM这样的Windows GUI都是以树的形式构建的,例如,桌面包含窗口,窗口包含标题栏,而标题栏包含关闭图标。
在下面的示例中,我实现了非常基本的树结构和各种类型的元素。由于所有元素都具有许多相同的行为,而且由于我个人不会使用类语法(直到正确修复),所以这些元素将被添加。
行为
-
单击事件在根元素树中搜索单击的项目。
-
项目以可视化方式排序,顶部的焦点窗口位于
。 -
如果单击了窗口元素,但窗口焦点未对准,则该窗口将被聚焦。
-
如果单击一个窗口元素并且它处于焦点位置,并且单击的项目是一个关闭按钮,则该窗口将被关闭,而下一个可视顺序将获得焦点。
-
如果单击最上面的项目(画布),则会创建一个新窗口。
-
最上面的元素(根)称为
desktopCanvas
。通过此元素,您可以打开,关闭,聚焦和查询点击事件。
通常所有动作都会驱动事件队列,但是在示例中我没有实现。
所有项目都是从CanvasElement
构建的,并且向CanvasElement
分配了用于实现树结构(基本呈现)的属性和方法。您传递希望元素成为的Object类型。例如,const element = new CanvasElement(new Area(0,this.w,30),MenuBar,undefined,name)
创建类型为MenuBar
的元素。您通过cWindow.add(element)
更多信息请参见示例。
示例
单击画布创建窗口。单击窗口以聚焦窗口。单击聚焦窗口上的关闭以关闭。您必须先获得焦点,然后才能关闭窗口。
const ctx = canvas.getContext("2d");
const canBounds = canvas.getBoundingClientRect();
canvas.addEventListener("click",mouseEvent);
function mouseEvent(event) {
const x = event.offsetX;
const y = event.offsetY;
const found = desktopCanvas.findClicked(x,y);
if (found === desktopCanvas) {
const wx = x < canvas.width - 200 ? x : canvas.width - 200;
const wy = y < canvas.height - 200 ? y : canvas.height - 200;
desktopCanvas.open(new CanvasElement(new Area(wx,wy,200,200),CanvasWindow,"Window"));
} else if (found) {
const top = found.topParent();
if (found.name === "close" && top.focused) { desktopCanvas.close(top) }
else { desktopCanvas.focus(top) }
}
}
const tree = {
get children() { return [] },add(child,top = false) {
child.parent = this;
if (top) { this.children.unshift(child) }
else { this.children.push(child) }
},remove(child) {
const idx = this.children.indexOf(child);
if (idx > -1) {
this.children.splice(idx,1);
return true;
}
for (const c of this.children) {
if (c.remove(child)) { return true }
}
},eachChild(cb,...data) {
if (typeof cb === "string") {
for (const c of this.children) {c[cb](...data) }
return;
}
for (const c of this.children) { cb(c) }
},topParent() {
var top = this;
while (top.top !== true) { top = top.parent }
return top;
},}
function Area(x,w,h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
function CanvasElement(area,type = {},name,...data) {
Object.assign(this,type);
name !== undefined && (this.name = name);
Object.assign(this,area);
Object.assign(this,tree);
this.init(...data);
}
CanvasElement.prototype = {
init() {},draw(ctx) {
ctx.save();
this.transform(ctx);
this.drawBorder(ctx);
if (this.drawContent) { this.drawContent(ctx) }
this.eachChild("draw",ctx);
ctx.restore();
},drawBorder(ctx) {
ctx.strokeStyle = "#000";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.rect(0,this.h);
ctx.stroke();
},transform(ctx) { ctx.transform(1,1,this.x,this.y) },isInside(x,y) { return x > this.x && x < this.x + this.w && y > this.y && y < this.y + this.h },findClicked(x,y) {
var idx = this.children.length;
if (this.isInside(x,y)) {
while (idx-- > 0) { // from top to bottom visually
const child = this.children[idx];
const found = child.findClicked(x - this.x,y - this.y);
if (found) { return found }
}
return this;
}
},}
const CloseIcon = {
name : "close",drawContent(ctx) {
const {w,h} = this;
ctx.fillStyle = "#f00";
ctx.fill();
ctx.font = "16px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = this.parent.parent.focused ? "#FFF" : "#000";
ctx.fillText("X",w / 2,h / 2);
},}
const MenuBar = {
name : "menuBar",init(text) {
this.text = text;
const bar = new Area(this.w - 18,18,18);
this.add(new CanvasElement(bar,CloseIcon));
},drawContent() {
ctx.fillStyle = this.parent.focused ? "#CCC" : "#999";
ctx.fill();
ctx.font = "16px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "#000";
ctx.fillText(this.text,this.w / 2,this.h / 2 + 2);
},}
const CanvasWindow = {
name: "window",top: true,init(name) {
this.name = name;
const bar = new Area(0,name))
},drawContent() {
ctx.fillStyle = this.focused ? "#FFF" : "#EEE";
ctx.fill();
},}
const Desktop = {
name: "desk",focuse: undefined,init(ctx) {
this.w = ctx.canvas.width;
this.h = ctx.canvas.height;
this.ctx = ctx;
},draw() {
this.ctx.setTransform(1,0)
this.ctx.clearRect(0,this.h);
if (this.drawContent) { this.drawContent(this.ctx) }
this.eachChild("draw",this.ctx);
},close(item) {
this.remove(item);
if(this.focuse && this.focuse === item) {
if (this.children.length) { this.focus(this.children[this.children.length - 1]) }
else { this.focuse = undefined }
}
desktopCanvas.draw();
},open(item) { this.focus(item) },focus(item) {
this.remove(item);
this.add(item);
if(this.focuse) {
this.focuse.focused = false;
this.focuse = undefined;
}
item.focused = true;
this.focuse = item;
this.draw();
}
}
const desktopCanvas = new CanvasElement(new Area( 0,canvas.width,canvas.width),Desktop,"desktop",ctx);
desktopCanvas.open(new CanvasElement(new Area(10,10,"Example window"));
<canvas id="canvas" width="600" height="600" style="border: 1px solid black"></canvas>
单击画布创建窗口。单击窗口以聚焦窗口。单击聚焦窗口上的关闭以关闭。您必须先获得焦点,然后才能关闭窗口。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。