Hook更改为HTML5画布上下文中的lineWidth

时间:2014-08-06 23:06:54

标签: javascript html5 canvas getter-setter

我想在实际像素中强制执行miterLimit,而不是lineWidth的比率。为此,我想将任何更改挂钩到lineWidth,并同时自动设置miterLimit。我以前在对象上使用过自定义setter,但是如果我替换lineWidth setter,我就不知道如何实际传递值来设置实际的画布上下文。

是否有某种方式(在IE9 +上兼容)我可以监听更改对象上的给定键而不更改设置该值的行为

1 个答案:

答案 0 :(得分:0)

你的getter / setter想法很好......

如何只将属性定义添加到上下文对象中?

向您的上下文对象添加myLineWidth属性,然后使用context.myLineWidth而不是context.lineWidth设置线宽。

一些示例代码:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

Object.defineProperty(ctx, 'myLineWidth', {
    get: function() {
        return(this.lineWidth);
    },
    set: function(newWidth) {
        this.lineWidth=newWidth;
        console.log("Executed myLineWidth setter: ",this.lineWidth);        
    }
});

ctx.myLineWidth=5;
ctx.strokeRect(100,100,50,50);

使用封装的替代方法:

JavaScript确实具有真正的继承性,因此无法继承&覆盖lineWidth

下一个最好的事情是封装上下文对象。然后,所有编码器都可以使用标准属性和方法语法(不需要myLineWidth)来使用上下文的封装版本。如果需要,这里有一个操作方法:http://aboutcode.net/2011/10/04/efficient-encapsulation-of-javascript-objects.html

我做了类似的封装以记录上下文绘图。下面,我试图从我的一个项目中截取封装代码。您可以忽略我对drawImage和渐变的特殊处理,因为我需要从这些中获取您不需要抓取的值 - 只需将这些方法添加到returnMethods []数组即可。

您可以从以下开始的一些示例代码:

// Log all context drawings
// Creates a proxy class wrapping canvas context
function LoggedContext(canvas,context) {
    var self = this;
    this.canvas=canvas;
    this.context=context;
    this.imageURLs=[];
    this.log=[];
    this.gradients=[];
    this.patterns=[];
    this.init(self);

}

// maintain urls of images used
LoggedContext.prototype.imageIndex=function(url){
    var i=a.indexOf(url);
    // found
    if(i>-1){ return(i); }
    // not found -- added
    a.push(url);
    return(a.length-1);
}
///////////////////////////////////////////
// These methods require special handling
// (drawImage:need image.src, gradients:need gradDefs & colors)
//
LoggedContext.prototype.drawImage=function(){
    this.context.drawImage.apply(this.context,arguments);
    var args = Array.prototype.slice.call(arguments);
    args[0]=arguments[0].src;
    args.unshift(2,"drawImage");
    var sArgs=JSON.stringify(args);
    this.log.push(sArgs);
    return(this);
}
//
LoggedContext.prototype.createLinearGradient =function(x1,y1,x2,y2){
    var gradient=this.context.createLinearGradient(x1,y1,x2,y2);
    gradient.context=this;
    gradient.gradientID=this.gradients.length;
    this.gradients.push({line:{x1:x1,y1:y1,x2:x2,y2:y2},stops:[]});
    gradient.baseAddColorStop=gradient.addColorStop;
    gradient.addColorStop=function(stop,color){
        this.context.gradients[this.gradientID].stops.push({stop:stop,color:color});
        this.baseAddColorStop(stop,color);
    }
    return(gradient);
}
//
LoggedContext.prototype.createPattern =function(i,r){
    var pattern=this.context.createPattern(i,r);
    pattern.patternID=this.patterns.length;
    this.patterns.push({src:i.src,repeat:r});
    return(pattern);
}
//
LoggedContext.prototype.createRadialGradient =function(sx,sy,sr,ex,ey,er){
    var gradient=this.context.createRadialGradient(sx,sy,sr,ex,ey,er);
    gradient.context=this;
    gradient.gradientID=this.gradients.length;
    this.gradients.push({circles:{sx:sx,sy:sy,sr:sr,ex:ex,ey:ey,er:er},stops:[]});
    gradient.baseAddColorStop=gradient.addColorStop;
    gradient.addColorStop=function(stop,color){
        this.context.gradients[this.gradientID].stops.push({stop:stop,color:color});
        this.baseAddColorStop(stop,color);
    }
    return(gradient);
}

// load the proxy object with all properties & methods of the context
LoggedContext.prototype.init=function(self){

    // define public context properties
    var properties={
        //
        fillStyle:"black",
        strokeStyle:"black",
        lineWidth:1,
        font:"10px sans-serif",
        //
        globalAlpha:1.00,
        globalCompositeOperation:"source-over",
        //
        shadowColor:"black",
        shadowBlur:0,
        shadowOffsetX:0,
        shadowOffsetY:0,
        //
        lineCap:"butt",   // butt,round,square
        lineJoin:"miter", // miter,round,miter
        miterLimit:10,
        //
        textAlign:"start",
        textBaseLine:"alphabetic",
    };

    // encapsulate public properties
    for (var i in properties) {
        (function(i) {
            if(!(i=="fillStyle")){
                Object.defineProperty(self, i, {
                    get: function () {
                        return properties[i];
                    },
                    set: function (val) {
                        this.log.push(JSON.stringify([1,i,val]));
                        properties[i] = val;
                        this.context[i]=val;
                    }
                })
            }else{
                Object.defineProperty(self, i, {
                    get: function () {
                        return properties[i];
                    },
                    set: function (val) {
                        if(typeof val ==="object"){
                            if(val.gradientID>=0){
                                this.log.push(JSON.stringify([1,i,"gradient",val.gradientID]));
                            }else if(val.patternID>=0){
                                this.log.push(JSON.stringify([1,i,"pattern",val.patternID]));
                            }
                        }else{
                            this.log.push(JSON.stringify([1,i,val]));
                        }
                        properties[i] = val;
                        this.context[i]=val;
                    }
                })
            }
        })(i);
    }

    // define public context methods
    var methods = ['arc','beginPath','bezierCurveTo','clearRect','clip',
      'closePath','fill','fillRect','fillText','lineTo','moveTo',
      'quadraticCurveTo','rect','restore','rotate','save','scale','setTransform',
      'stroke','strokeRect','strokeText','transform','translate','putImageData'];

    // encapsulate public methods
    for (var i=0;i<methods.length;i++){   
        var m = methods[i];
        this[m] = (function(m){
            return function () {
                this.context[m].apply(this.context, arguments);
                // "arguments" is not a real array--so convert it
                var args = Array.prototype.slice.call(arguments);
                args.unshift(2,m);
                var sArgs=JSON.stringify(args);
                this.log.push(sArgs);
                return(this);
        };}(m));
    }

    // define context methods that return values
    var returnMethods = ['measureText','getImageData','toDataURL',
      'isPointInPath','isPointInStroke'];

    // encapsulate return methods
    for (var i=0;i<returnMethods.length;i++){   
        var m = returnMethods[i];
        this[m] = (function(m){
            return function () {
                return(this.context[m].apply(this.context, arguments));
        };}(m));
    }

}  // end init()