Вот фрагмент, который начнет регистрировать все обращения к любому CanvasRenderingContext2D
.Я отключил фрагмент стека, потому что он выдает кучу ошибок, пытаясь сериализовать вывод console.log()
, поэтому просто проверьте на реальной консоли фактический вывод.
// handler used for intercepting proxy
const handler = {
get (target, key) {
// forward access to underlying property
const value = Reflect.get(target, key)
console.log('get', target, key, value)
// return underlying value as an intercepting proxy
// if value is function, its calling context will be the target
return proxyValue(target, value)
},
set (target, key, value) {
// forward access to underlying property
Reflect.set(target, key, value)
console.log('set', target, key, value)
// return set value as an intercepting proxy
// if value is function, it will not have a calling context
return proxyValue(undefined, value)
},
apply (target, thisArg, args) {
// forward invocation to underlying function
const value = Reflect.apply(target, thisArg, args)
console.log('apply', thisArg, target, args, value)
// return underlying return value as an intercepting proxy
// if value is a function, it will not have a calling context
return proxyValue(undefined, value)
}
}
// wrap all accessed non-primitives in an intercepting proxy
function proxyValue (target, value) {
switch (typeof value) {
case 'function':
// return function bound to target as proxy
return new Proxy(value.bind(target), handler)
case 'object':
// return object as proxy
return new Proxy(value, handler)
default:
// return primitive as normal
return value
}
}
// iterate all descriptors of CanvasRenderingContext2D prototype
const descriptors = Object.getOwnPropertyDescriptors(CanvasRenderingContext2D.prototype)
Object.entries(descriptors).forEach(([key, { value, get, set, configurable, enumerable, writable }]) => {
// if this is an accessor property
const accessor = get || set ? {
get () {
// forward access to underlying getter
const getValue = Reflect.apply(get, this, [])
console.log('get', this, key, getValue)
// return underlying value as an intercepting proxy
return proxyValue(this, getValue)
},
set (setValue) {
// forward access to underlying setter
Reflect.apply(set, this, [setValue])
console.log('set', this, key, setValue)
// return set value as an intercepting proxy
return proxyValue(this, setValue)
},
configurable,
enumerable
} : {
get () {
console.log('get', this, key, value)
// return underlying value as an intercepting proxy
return proxyValue(this, value)
},
set (setValue) {
// assign and return underlying value
value = setValue
console.log('set', this, key, setValue)
// return set value as an intercepting proxy
return proxyValue(this, setValue)
},
configurable,
enumerable
}
// overwrite property with intercepting accessor property
Object.defineProperty(CanvasRenderingContext2D.prototype, key, accessor)
})
const canvas = document.querySelector('canvas')
const context = canvas.getContext('2d')
context.fillStyle = 'red'
context.save()
context.getImageData(0, 0, 100, 100).data
<canvas></canvas>
Список литературы