簡體   English   中英

在 Canvas、JavaScript 上關閉窗口

[英]Closing windows on Canvas, JavaScript

我試圖想出一個解決這個問題的方法。 我需要檢測鼠標點擊小紅色矩形以關閉窗口。 只有當沒有其他窗口“在它上面”時,點擊的窗口才應該關閉。

我想檢測紅色的點擊,但這並不能很好地工作。

附注。 我不能使用彈出窗口,他們需要這樣做。

有人可以幫我弄這個嗎? 謝謝!

 <!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, y, width, 30); ctx.fillStyle = "gray"; ctx.fillRect(x, y, width, 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, y, 30, 30); ctx.fillStyle = "red"; ctx.fillRect(new_x, y, 30, 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, y, width, height); ctx.fillStyle = 'gray'; ctx.fillRect(x, y, width, 30); ctx.strokeStyle = 'black'; ctx.strokeRect(x, y, width, 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, y, 30, 30); ctx.strokeStyle = 'black'; ctx.strokeRect(new_x, y, 30, 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, 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 被構建為一棵樹,例如桌面包含窗口,窗口包含標題欄,標題欄包含關閉圖標。

在下面的示例中,我實現了一個非常基本的樹結構和各種類型的元素。 由於所有元素都有很多相同的行為,而且我個人不會使用類語法(直到它被正確修復),元素被構建添加 hock。

行為

  • click 事件在根元素樹中搜索被點擊的項目。

  • 項目通過頂部的聚焦窗口直觀地排序。

  • 如果單擊一個窗口元素並且它不在焦點上,則該窗口將被聚焦。

  • 如果一個窗口元素被點擊並且它處於焦點並且被點擊的項目是一個關閉按鈕,該窗口將被關閉並且下一個視覺順序將獲得焦點。

  • 如果單擊最頂部的項目(畫布),則會創建一個新窗口。

  • 最頂層的元素(根)稱為desktopCanvas 正是通過這個元素,您可以打開、關閉、聚焦和查詢點擊事件。

通常所有的動作都會驅動一個事件隊列,但在這個例子中我沒有實現。

所有項目都是從CanvasElement構建的,並且為CanvasElement分配了屬性和方法來實現樹結構、基本渲染。 您傳遞希望元素成為的對象類型。 例如const element = new CanvasElement(new Area(0, 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, undefined, "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, y, 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, 0, this.w, this.h); ctx.stroke(); }, transform(ctx) { ctx.transform(1, 0, 0, 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, 0, 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, 0, this.w, 18); this.add(new CanvasElement(bar, MenuBar, undefined, 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,0,1, 0, 0) this.ctx.clearRect(0, 0, this.w, 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, 0, canvas.width, canvas.width), Desktop, "desktop", ctx); desktopCanvas.open(new CanvasElement(new Area(10 , 10, 200, 200), CanvasWindow, undefined, "Example window"));
 <canvas id="canvas" width="600" height="600" style="border: 1px solid black"></canvas>

單擊畫布以創建窗口。 單擊窗口以聚焦窗口。 單擊焦點窗口上的關閉以關閉。 在獲得焦點之前,您無法關閉窗口。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM