在Canvas,JavaScript上关闭窗口

如何解决在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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-