如何输出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里直接读,不然会报错,比较不爽。。


更新

前面的方法需要提前注入代码,我又写了一个更暴力的方法,直接改了CanvasRenderingContext2Dprototype,这样随时打开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;
                }
            });
        }
    });
})();
posted @ 2017-02-17 17:52  kilobtye  阅读(870)  评论(0编辑  收藏  举报