2016-04-24 3 views
2

После создания моего холста, и получать var context = can.getContext('2d'), всю мой холст работы выполняются путем установки свойств или вызова метода на context.Переопределить контекст. свойства и функции

Я создал мульти инструмент скриншот монитор работает прекрасно на одном мониторе. Однако теперь я имею дело с несколькими мониторами, поэтому разные верхние/левые и масштабные экраны. Иногда (например, на платформе Windows с пользовательским уровнем DPI) я должен масштабировать точки. Поэтому я хотел передать всю настройку свойств и методов с помощью функции переопределения, так что перед вызовом реального context.BLAH он сначала преобразует координаты для масштабирования и смещения по текущим координатам экрана.

Я могу масштабировать контекст, однако это действительно вызывает визуальные проблемы с анти-сглаживанием.

Возможно ли это?

Я попытался переопределить context.lineWidth и context.fillRect, но у меня появились ошибки внутреннего доступа.

Я хотел избежать окружив его с:

function lineWidth(a) { 
doConvesionOnA(a) 
ctx.lineWidth = a; 
} 

А затем вызвать с помощью функции завернуть каждый раз. Но если это единственный способ заразиться, оберните его. Я просто хотел спросить, пожалуйста, прежде чем создавать обертку для каждого свойства и метода, а затем заменить все мои вызовы context. моей оболочкой.

ответ

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; 
... 
+0

Большое спасибо за начало! Я пойду в этом направлении. – Noitidart

+0

Большое спасибо за эту заметку от 'apply' Я не знал, что это было медленнее. Я обязательно сделаю это. – Noitidart

+0

Большое спасибо, его работа отлично !! https://github.com/Noitidart/NativeShot/blob/editor-revamp/resources/scripts/editor.js#L4423-L4544 – Noitidart

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 создайте получить/набор блоки для каждого из свойств и зеркало каждого контекстных методов путем передачи всех полученных аргументов в «реальный» контекст с использованием .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)]); 
    } 
} 
+0

Большое спасибо за помощь в начале кода! Я сделаю обертывание, как вы оба порекомендуете. – Noitidart

+1

Большое спасибо за это, это действительно помогло мне посоветовать тонну! https://github.com/Noitidart/NativeShot/blob/editor-revamp/resources/scripts/editor.js#L4423-L4544 – Noitidart

Смежные вопросы