创建我的画布并获得var context = can.getContext('2d')
后,我的所有画布工作都是通过设置属性或在context.
我创建了一个多监视器截图工具,在单个监视器上运行良好。但是现在,我正在处理多个显示器,因此不同的屏幕顶部/左侧和刻度。有时候(比如在具有自定义DPI级别的Windows平台上)我必须扩展积分。因此,我希望通过覆盖函数传递属性和方法的所有设置,以便在调用真实context.BLAH
之前,它将首先将坐标转换为缩放并偏移当前屏幕坐标。
我可以缩放上下文,但这确实会导致抗锯齿的视觉问题。
这可能吗?
我尝试覆盖context.lineWidth和context.fillRect,但我遇到了原生访问错误。
我想避免用:
包装它function lineWidth(a) {
doConvesionOnA(a)
ctx.lineWidth = a;
}
然后每次通过函数换行调用。但如果这是唯一的方法,我会把它包裹起来。在我为每个属性和方法创建一个包装然后用我的包裹替换所有context.
调用之前,我只想先问一下。
答案 0 :(得分:2)
有可能使用方法,但不能使用属性,因为这些通过验证,如果不是有效类型,则简单地拒绝该值,即无法将函数设置为替换它(并且它也不能更新内部设置如果可以)。
我建议改为使用包装器对象。您可以通过绑定方法和包装属性使其与普通上下文兼容:
function MyContext(ctx) {
// Methods
this.moveTo = ctx.moveTo.bind(ctx);
this.lineTo = ctx.lineTo.bind(ctx);
// etc.
// Properties
Object.defineProperty(this, "lineWidth", {
get: function() {return ctx.lineWidth},
set: function(value) {
// do something magic with value
ctx.lineWidth = value
}
});
// etc.
}
如果您想更改方法的值:
this.moveTo = function(x, y) {
// alter here
ctx.moveTo(x, y);
};
您也可以使用apply()
,它比传递实际参数更灵活但更慢:
this.arc = function() {
ctx.arc.apply(ctx, arguments)
};
这可能有点乏味,但让你完全控制传递到真实环境的内容。然后简单地创建一个对象的实例,并将其用作2D上下文:
var myCtx = new MyContext(ctx);
myCtx.lineTo(100, 100);
myCtx.lineWidth = 20;
...
答案 1 :(得分:1)
同意@ K3N的建议以包装上下文。
这是我从CanvasRendingContext2D记录器中获取的一些代码,显示了您开始包装CanvasRendingContext2D
的速度:
function LoggedContext(canvas) {
var self = this;
this.canvas=canvas;
this.context=canvas.getContext('2d');
this.imageURLs=[];
this.fillStyles=[];
this.logs=[];
this.commands=[];
this.funcs={};
this.init(self);
}
在LoggedContext.prototype.init
方法中,为每个属性创建get / set块,并通过将所有收到的参数传递给" real"来镜像每个上下文方法。上下文使用.apply
。
LoggedContext.prototype.init=function(self){
// create get/sets for properties
var properties=['strokeStyle','lineWidth','font','globalAlpha',
'globalCompositeOperation','shadowColor','shadowBlur',
'shadowOffsetX','shadowOffsetY','lineCap','lineJoin',
'miterLimit','textAlign','textBaseline'];
for(var i=0;i<properties.length;i++){
(function(i) {
Object.defineProperty(self, i, {
get: function () {
return this.context[i];
},
set: function (val) {
this.log(i,val,true);
this.context[i]=val;
}
})
})(properties[i]);
}
// create mirror methods that pipe arguments to the real context
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'];
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);
this.log(m,arguments);
return(this);
};}(m));
}
// mirror methods that have return values
var returnMethods = ['measureText','getImageData','toDataURL',
'isPointInPath','isPointInStroke','createImageData'];
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));
}
// In this example code ...
// These Properties & Methods requiring special handling have
// been removed for brevity & clarity
//
// .fillStyle
// .strokeStyle
// .drawImage
// .createLinearGradient
// .createRadialGradient
// .createPattern
} // end init()
所有属性获取/设置,所有方法调用都通过LoggedContext.prototype.log
方法引导。
出于您的目的,您可以在get / set块中进行调整,也可以在.log
方法中方便地进行调整,因为所有内容都是通过.log
方法传输的。
LoggedContext.prototype.log=function(command,Args,isProperty){
var commandIndex=this.commands.indexOf(command);
if(commandIndex<0){
this.commands.push(command);
commandIndex=this.commands.length-1
}
if(isProperty){
this.logs.push([commandIndex,Args]);
}else{
this.logs.push([commandIndex,Array.prototype.slice.call(Args)]);
}
}