如何输出canvas 2d context上的所有操作命令
怎么能看一个canvas 2d web应用到底是怎么画出来的呢?webgl我知道可以用浏览器的GL inspector插件,2d的我没有找,而是自己写了几行代码,把所有操作来输出到console里。
只要在getContext
之前执行一下下面的logCanvas2DContextCommand()
就好。
function logCanvas2DContextCommand() {
var tmpcanvas = document.createElement('canvas');
var tmpctx = tmpcanvas.getContext('2d');
var Context2DWrapper = function (ctx) {
this.ctx = ctx;
};
Context2DWrapper.prototype = {};
Object.getOwnPropertyNames(CanvasRenderingContext2D.prototype).forEach(function(p) {
if (typeof tmpctx[p] === 'function') {
Context2DWrapper.prototype[p] = function() {
console.log(p + ' arguments:', arguments);
return this.ctx[p].apply(this.ctx, arguments);
}
} else {
Object.defineProperty(Context2DWrapper.prototype, p, {
get: function() {
console.log('get ' + p);
return this.ctx[p];
},
set: function(value) {
console.log('set ' + p + ' to', value);
this.ctx[p] = value;
}
});
}
});
HTMLCanvasElement.prototype.originalgetContext = HTMLCanvasElement.prototype.getContext
HTMLCanvasElement.prototype.getContext = function(type) {
var ctx = HTMLCanvasElement.prototype.originalgetContext.apply(this, arguments);
if (type === '2d' && ctx) {
return new Context2DWrapper(ctx);
} else {
return ctx;
}
}
};
道理很简单,就是把CanvasRenderingContext2D
对象外面包了一层,所有调用都会经过这个wrapper,我们就可以为所欲为了。方法调用hook起来很容易。属性的读写我们也能用getter和setter来hook。唯一一个麻烦是必须先创建一个临时的CanvasRenderingContext2D
对象才能读取他里面的属性,不能从CanvasRenderingContext2D.prototype
里直接读,不然会报错,比较不爽。。
更新
前面的方法需要提前注入代码,我又写了一个更暴力的方法,直接改了CanvasRenderingContext2D
的prototype
,这样随时打开console把这段代码复制过去执行就可以了。改builtin的对象总感觉不是太好,显示的结果也可能会被搞坏,但其实上面的方法也改了,所以也就无所谓了。
(function () {
var tmpcanvas = document.createElement('canvas');
var tmpctx = tmpcanvas.getContext('2d');
var proto = CanvasRenderingContext2D.prototype;
Object.getOwnPropertyNames(proto).forEach(function(p) {
if (typeof tmpctx[p] === 'function') {
proto['original' + p] = proto[p];
proto[p] = function() {
console.log(p + ' arguments:', arguments);
return proto['original' + p].apply(this, arguments);
}
} else {
Object.defineProperty(proto, p, {
get: function() {
console.log('get ' + p);
return this['original' + p];
},
set: function(value) {
console.log('set ' + p + ' to', value);
this['original' + p] = value;
}
});
}
});
})();