[英]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.