简体   繁体   English

JS Proxying HTML5画布上下文

[英]JS Proxying HTML5 canvas context

I'm hoping to proxy the canvas API so I can test that abstracted methods do actually draw to the canvas, however I'm hitting issues where after proxing I get an error: 我希望代理画布API,以便我可以测试抽象方法实际绘制到画布,但是我遇到问题,在代理后我得到一个错误:

'strokeStyle' setter called on an object that does not implement interface CanvasRenderingContext2D

This code is simplified but throws the same error: 此代码已简化但引发相同的错误:

 /** !NB: This snippet will probably only run in Firefox */ var canvas = document.createElement("canvas"); canvas.width = 100; canvas.height = 100; canvas.style.backgroundColor = '#FF0000'; var ctx = canvas.getContext("2d"); var calls = []; var handler = { get( target, property, receiver ) { if ( typeof ctx[property] === 'function' ){ return function( ...args ){ calls.push( { call: property, args: args } ) return ctx[property]( ...args ); }; } return ctx[property]; } }; try { document.body.appendChild(canvas); var proxy = new Proxy( ctx, handler ); proxy.scale( 1, 1 ); proxy.strokeStyle = '#000000'; canvas.getContext = function(){ return proxy; }; } catch( e ) { document.getElementById('message').innerHTML = 'Error: ' + e.message; } 
 <div id="message"></div> 

Any thoughts? 有什么想法吗?

You can fix this erro by defining a set method on your handler: 您可以通过在处理程序上定义set方法来修复此错误:

set(target, property, value, receiver) {
    target[property] = value;
}

The reason for this error might seem a bit strange. 这个错误的原因可能看起来有点奇怪。 CanvasRenderingContext2D instances don't have their own strokeStyle property. CanvasRenderingContext2D实例没有自己的strokeStyle属性。 Instead, the CanvasRenderingContext2DPrototype (the prototype of every CanvasRenderingContext2D instance) has an accessor property whose set / get components will set and get the stroke-style value for the instance: 相反, CanvasRenderingContext2DPrototype (每个CanvasRenderingContext2D实例的原型)都有一个访问器属性,其set / get组件将设置并获取实例的笔触样式值:

> ctx.hasOwnProperty("strokeStyle")
false

> Object.getOwnPropertyDescriptor(ctx.__proto__, "strokeStyle")
Object { get: strokeStyle(), set: strokeStyle(), enumerable: true, configurable: true }

(If you're interested in learning more about this pattern, have a look at my answer on JSON.parse not erroring on cyclic objects .) (如果您有兴趣了解有关此模式的更多信息,请查看我对JSON.parse的回答, 而不是在循环对象出错 。)

The problem here is that the this supplied to the CanvasRenderingContext2DPrototype.strokeStyle setter is the proxy object, not the actual ctx object. 这里的问题是, this提供给CanvasRenderingContext2DPrototype.strokeStyle二传手是proxy对象,而不是实际的ctx对象。 That is, when we set a property on the proxy only: 也就是说,当我们仅在代理上设置属性时:

proxy.isAFake = true;

and test for it in a redefined setter: 并在重新定义的setter中测试它:

Object.defineProperty(ctx.__proto__, "strokeStyle", {
    set: function() {
        console.log("strokeStyle setter called for proxy?", this.isAFake);
    }
});

We see the setter logs the proxy-only property: strokeStyle setter called for proxy? true 我们看到setter记录了仅代理属性: strokeStyle setter called for proxy? true strokeStyle setter called for proxy? true . strokeStyle setter called for proxy? true

For whatever reason, the setter on CanvasRenderingContext2DPrototype.strokeStyle will accept only a genuine CanvasRenderingContext2D instance, not a proxied one. 无论出于何种原因, CanvasRenderingContext2DPrototype.strokeStyle上的setter只接受真正的CanvasRenderingContext2D实例,而不是代理实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM