多次重用相同的画布上下文是不是很糟糕?

问题描述

我正在使用 HTML5 canvas 编写模拟器。我制作了一个辅助类来包含有关画布的信息。到目前为止看起来像这样:

class Canvas {
    context;
    width;
    height;
    
    constructor(HTMLCanvas) {
        this.context = HTMLCanvas.getContext("2d");
        
        this.width = HTMLCanvas.width;
        this.height = HTMLCanvas.height;
    }
    
    clear() {
        this.context.clearRect(0,this.width,this.height);
    }
}

我所做的是每次在画布上绘图时,我都会重复使用相同的上下文。这是一个坏主意吗?会产生不可预见的后果吗?

解决方法

简单地说:不,那绝对没问题。

,

将相同的画布上下文用于多种用途是可以的(实际上,比销毁和重新创建画布只是为了清除和重绘它更可取),但这似乎与此处所示的类有些对立。

类应该封装数据,但是由于 HTMLCanvas 参数,这里的设置会产生一种错误的封装感。事实上,如果您创建此类的多个实例,它们都共享相同的上下文,当多个 Canvas 实例破坏彼此的状态时,可能会导致类的客户端混淆。

将参数隐藏到画布 clearRect 函数的好处似乎可以忽略不计。当然,您可以添加更多功能以更好地激励它,但仍然存在潜在的数据共享问题以及即使共享已修复,整个企业的收益/回报也不清楚。

这是我的意思的演示:

class Canvas {
  constructor(HTMLCanvas) {
    this.context = HTMLCanvas.getContext("2d");
    this.width = HTMLCanvas.width;
    this.height = HTMLCanvas.height;
  }

  clear() {
    this.context.clearRect(0,this.width,this.height);
  }
}

const canvas = document.createElement("canvas");
document.body.append(canvas);
const canvas1 = new Canvas(canvas);
const canvas2 = new Canvas(canvas);
canvas1.context.fillRect(0,30,30);
canvas2.context.fillRect(30,30);

很难看出这里的好处。作为您班级的客户,我已经分配了 2 个完整的对象,但它们基本上是同一个画布中的视图,导致在一个画布上绘图以影响另一个画布。调用 clear 会擦除两个画布,而且真的没有每个实例的唯一数据可言。我必须明确提供两个单独的画布才能正常使用,而且在看到任何好处之前,我已经把自己挖进了一个额外的冗长和潜在混乱的坑中。

另一个微妙的点是这个类似乎将画布和上下文混为一谈。 clear 确实是一个上下文操作,所以这里的 Canvas 类似乎朝着一个画布和上下文的组合界面的方向发展。由于大多数画布应用程序主要使用上下文并且仅使用画布作为高度/宽度参考,这实际上创建了一个很好的关注点分离,将 DOM/画布从负责的实体类(球、玩家、敌人等)中抽象出来在任意上下文上绘制自己,而无需知道上下文来自的底层 DOM 对象。

长话短说:

  • 你甚至需要这个吗?画布已经是具有良好界面的对象,可能不需要另一层抽象。如果您想抽象常用的绘图函数,不妨考虑一下您应用中的实体(例如,“玩家”实体)并创建使用上下文作为参数的每个实体 draw 函数。
  • 如果您确实觉得您的设计需要它,请考虑使画布本身成为未注入构造函数的“私有”成员。相反,可能传入一个父 DOM 元素,构造函数会将画布附加到该元素。

在没有像 React 这样的框架的情况下在 DOM 上编写抽象是很棘手的!