是什么使CanvasRenderingContext2D成为CanvasRenderingContext2D? [英] What makes a CanvasRenderingContext2D a CanvasRenderingContext2D?

查看:96
本文介绍了是什么使CanvasRenderingContext2D成为CanvasRenderingContext2D?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下网页.

<html>
    <body>
        <canvas id="canvas" width="300" height="300" style="border:1px solid #000000;">
        </canvas>
    </body>
</html>

我在Firefox中打开此页面,打开JS控制台并输入以下内容.

I open this page in Firefox, open the JS console and type the following.

> document.getElementById("canvas").getContext("2d")

输出如下:

CanvasRenderingContext2D { canvas: canvas#canvas, mozCurrentTransform: (6) […], mozCurrentTransformInverse: (6) […], mozTextStyle: "10px sans-serif", mozImageSmoothingEnabled: true, globalAlpha: 1, globalCompositeOperation: "source-over", strokeStyle: "#000000", fillStyle: "#000000", filter: "none" }

另一方面,如果我自己创建一个对象并复制CanvasRenderingContext2D的所有内容,它仍然只是一个普通对象.

On the other hand, if I create an object myself and copy all of the guts of the CanvasRenderingContext2D, it's still just a plain object.

var realContext = document.getElementById("canvas").getContext("2d")
var myContext = new Object()
for (var property in realContext) {
    myContext[property] = realContext[property];
}

myContext
Object { drawImage: drawImage(), beginPath: beginPath(), fill: fill(), stroke: stroke(), clip: clip(), isPointInPath: isPointInPath(), isPointInStroke: isPointInStroke(), createLinearGradient: createLinearGradient(), createRadialGradient: createRadialGradient(), createPattern: createPattern(), … }

是什么使CanvasRenderingContext2D成为CanvasRenderingContext2D?

作为推论,我该如何将普通的旧对象变成一个CanvasRenderingContext2D?

As a corollary, how can I turn my plain old object into a CanvasRenderingContext2D?

编辑:我不在乎JS控制台说的是什么.我确实担心不能像使用原始上下文那样使用新上下文.

Edit: I don't care about what the JS console says. I do care that I cannot use my new context the same way I use the original one.

myContext.save()
TypeError: 'save' called on an object that does not implement interface CanvasRenderingContext2D

目标是能够像旧对象一样使用新对象并在原始画布上绘制.

The goal is to be able to use the new object exactly like the old one and draw on the original canvas.

编辑:我一直在寻找不需要 使用画布修改网站源代码的解决方案.

I've looked for solutions which do not require modification of the source code of the website using canvas.

推荐答案

这是一个片段,它将开始记录对任何CanvasRenderingContext2D的所有访问.我禁用了堆栈代码片段控制台,因为它会在尝试序列化console.log()输出时引发一些错误,因此只需使用F12检查开发人员控制台的输出即可.

Here's a snippet that will start logging all accesses to any CanvasRenderingContext2D. I disabled the stack snippet console because it throws some errors trying to serialize the console.log() output, so just check the developer console for the output using F12.

function intercept(value) {
  switch (typeof value) {
    case 'function':
    case 'object':
      return new Proxy(value, {
        get(target, key) {
          const value = Reflect.get(target, key);
          console.log('handler.get', target, key, value);
          return intercept(value);
        },
        set(target, key, value) {
          const result = Reflect.set(target, key, value);
          console.log('handler.set', target, key, value);
          return result;
        },
        apply(target, thisArg, args) {
          const value = Reflect.apply(target, thisArg, args);
          console.log('handler.apply', thisArg, target, ...args, value);
          return intercept(value);
        }
      });
    default:
      return value;
  }
}

const ownPropertyDescriptorEntries = Object.entries(
  Object.getOwnPropertyDescriptors(
    CanvasRenderingContext2D.prototype
  )
);
const interceptedPropertyDescriptorEntries = ownPropertyDescriptorEntries.map(
  ([key, { get, set, value, ...descriptor }]) => [
    key, get || set ? {
      ...descriptor,
      get() {
        console.log('descriptor.get', this, key);
        return intercept(Reflect.apply(get, this, []));
      },
      set(value) {
        console.log('descriptor.set', this, key, value);
        return intercept(Reflect.apply(set, this, [value]));
      }
    } : {
      ...descriptor,
      value: intercept(value)
    }
  ]
);

Object.defineProperties(
  CanvasRenderingContext2D.prototype,
  Object.fromEntries(
    interceptedPropertyDescriptorEntries
  )
);

const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');

console.log(context.lineWidth);
context.fillStyle = 'red';
context.getImageData(0, 0, 100, 100).data[0] = 255;

<canvas></canvas>

descriptor.get CanvasRenderingContext2D lineWidth
1
descriptor.set CanvasRenderingContext2D fillStyle red
handler.apply CanvasRenderingContext2D ƒ getImageData() { [native code] } 0 0 100 100 ImageData
handler.get ImageData data Uint8ClampedArray(40000)
handler.set Uint8ClampedArray(40000) 0 255

参考文献

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆