2015-02-10 208 views
0

當我有大量編輯這個問題提供更多的細節大小限制繪製CanvasRenderingContext2D

通過EaselJS框架繪製CanvasRenderingContext2D,當我遇到的限制來了。我的對象是這樣的:

enter image description here

但是當這些物體的位置超過幾百萬像素的圖紙開始崩潰分開。這是與x位置58524928相同的對象。(父容器移動到-58524928,以便我們可以在舞臺上看到該對象。)偏移對象越多,它將崩潰越多。另外,當我嘗試移動物體時 - 用鼠標拖動它 - 它會像跳躍一樣受到大網格的影響。

enter image description here

這是EaseJS框架和形狀最終吸引到通過的drawImage()方法CanvasRenderingContext2D。下面是從代碼段:

ctx.drawImage(cacheCanvas,this._cacheOffsetX + this._filterOffsetX,this._cacheOffsetY + this._filterOffsetY,cacheCanvas.width /秤,cacheCanvas.height /刻度);

我想這事做實數的JavaScript中的有限數量:

注意,有無窮多個實數,但只有有限的 數人(18437736874454810627,是精確)可以完全用JavaScript浮點格式表示 。這意味着當您在使用JavaScript中的實數時, 的數字通常是實際數字的近似值。

來源:JavaScript: The Definitive Guide

有人可以證實/拒絕我的假設? 5800萬(58524928)對我來說似乎並不那麼重要,它是EaselJS的一些低效率還是Canvas的限制?

PS: 縮放無效。我已經把所有東西縮小了1000倍,並且縮小了1000倍,而沒有任何效果。同樣,如果您將對象縮放1000倍,而x仍爲5800萬,則它看起來不會崩潰。但把它移到500億,你就是你開始的地方。細節基本上偏移除以大小是不變的限制。

EDIT

下面是示例jsfiddle.net/wzbsbtgc/2。基本上有兩個獨立的問題

  1. 如果我使用巨大的數字作爲繪圖本身的參數(紅色曲線)它將被扭曲。這可以通過使用較小的數字並移動DisplayObject(藍色曲線)來避免。
  2. 在這兩種情況下,都不可能將DisplayObject移動1px。我認爲這是在GameAlchemist的文章中解釋的。

對於第二個問題的任何建議/解決方法是值得歡迎的。

+0

縮放沒有效果。我已經把所有東西縮小了1000倍,並且縮小了1000倍,而沒有任何效果。同樣,如果您將對象縮放1000倍,而x仍爲5800萬,則不會顯得崩潰。把它移到500億,你就是你開始的地方。基本上偏移量*的大小是不變的限制細節。 – 2015-02-13 21:42:25

+0

您能否確認正在繪製的Shape實例是否被緩存(通過'cache()'方法)?從你提供的圖像看,它看起來像是一個矢量繪製,其值越來越混亂,但是你張貼來自EaselJS的緩存內容繪製例程的代碼。我想確認你在做什麼,以便我可以嘗試重現。 – gskinner 2015-02-17 17:32:36

+0

嗨格蘭特,沒有圖紙沒有被緩存,你說什麼意味着我通過張貼在這裏被裁剪了一個錯誤。這就是爲什麼我需要在如此大的畫布上繪製如此多的細節http://wikibudgets.org/w/uk/london/greenwich/2015/。順便說一句,我是你從Flash時代的樂趣:) – 2015-02-17 17:38:11

回答

2

看來,Context2D使用低精度號碼變換。我還沒有確認精度,但我的猜測是它使用花車而不是雙打。因此,在較高的值下,EaselJS依賴的方法(以及其他類似的C2D方法)失去了精確性,類似於GameAlchemist描述的那樣。您可以在此處看到使用純粹的C2D調用複製的此問題: http://jsfiddle.net/9fLff2we/

我能想到的最佳解決方法是預先計算轉換方法外部的「最終」值。正常的JS數字比C2D使用的要高,所以這應該可以解決這個問題。真正粗略的例子來說明: http://jsfiddle.net/wzbsbtgc/3/

+0

Context2D規範將變換參數列爲浮點數,這意味着它使用32b浮點數而不是用於普通JS數字實例的64b雙精度浮點數。 void變換(在float m11中,在float m12中,在float m21中,在float m22中,在float dx中,在float dy中);' – gskinner 2015-02-17 22:33:08

+0

我認爲你我是對的,這就是解決方法。我可以在DO的updateContext函數中看到3個ctx.transform()實例,我將嘗試通過你的代碼破解我的方式:)。我想知道在JS中進行轉換會有什麼性能損失。 PS:我希望你在TypeScript中編寫CreateJS。 – 2015-02-18 10:50:09

+0

有CreateJS在那裏體面的TypeScript定義文件。例如:https://github.com/elsassph/createjs-def 雖然我真的很喜歡TS,但用JS編寫並擁有def文件使得圖書館可以訪問更廣闊的市場。 – gskinner 2015-02-18 16:20:43

1

您可以使用任意大小的繪圖座標。

畫布會將您的圖形剪輯到畫布元素的顯示區域。

例如,下面是一個從x = -50000000開始繪製直線並在畫布上完成的演示。只有線的可見部分被渲染。所有不可見(非畫布)點都被裁剪。

var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 
var cw=canvas.width; 
 
var ch=canvas.height; 
 

 
ctx.beginPath(); 
 
ctx.moveTo(-50000000,100); 
 
ctx.lineTo(150,100); 
 
ctx.stroke();
body{ background-color: ivory; padding:10px; } 
 
#canvas{border:1px solid red;}
<h4>This line starts at x = negative 50 million!</h4> 
 
<canvas id="canvas" width=300 height=300></canvas>

+0

hi @markE,我大量重新編輯了這個問題,你現在怎麼看? – 2015-02-13 21:17:10

1

請記住,目標受衆爲W3C標準主要是瀏覽器廠商。無符號長整型值(或2 )更多地處理了瀏覽器創建位圖的基礎系統。該標準表示這個範圍內的值是有效的,但不能保證底層系統能夠提供大的位圖(大多數瀏覽器今天將位圖限制爲比這更小的尺寸)。你說過,你不是指畫布元素本身,而是鏈接引用是元素的接口定義,所以我只是想指出數字範圍。

從事情的JavaScript方面來說,我們開發人員通常都是這樣,除了類型化數組之外,沒有像ulong等這樣的東西。只有Number(又名unrestricted double),它被簽名並以64位,格式爲IEEE-754。

的有效範圍爲Number是:

Number.MIN_VALUE = 5e-324 
Number.MAX_VALUE = 1.7976931348623157e+308 

您可以在此範圍內使用任何值與畫布的矢量路徑。當路徑被光柵化時,Canvas會根據當前的變換矩陣將它們剪切到位圖上。

如果您通過繪製意味着另一個位圖(即圖像,畫布,視頻),那麼它們將受到與目標畫布本身相同的系統和瀏覽器功能/限制。定位(直接或通過轉換)受數字範圍的限制(總和)。

+0

嗨@ken,我大量重新編輯了這個問題,你現在怎麼看? – 2015-02-13 21:17:25

+0

我認爲這個答案可能在問題發生變化後呈現爲無關緊要:)雖然我可以將其作爲一般參考。 – K3N 2015-02-18 21:42:21

2

您看到的行爲與數字在IEEE 754標準中表示的方式有關。

雖然Javascript使用64位浮點數,但WebGL僅使用32位浮點數,並且由於大多數(?all?)畫布都是webGL加速的,所以您的所有數字都將在繪製之前進行(下)轉換。

IEEE 754 32位標準使用32位來表示一個數字:1位爲符號,8位指數位,然後尾數爲23位。

讓我們呼籲IEEE_754_32max:

IEEE_754_32max = (1 << 23) -1 = 8.388.6071 (8+ millions) 

我們可以有充分的精度只能在[-IEEE_754_32max, IEEE_754_32max]範圍內的整數。
除此之外,指數將被使用,並且我們將丟掉尾數的弱點。

例如(10百萬+1)= 10.000。001是太大,無法放入23位,所以它會被存儲爲

10.000.001 = 10.000.00• * 10 = 1e7 = 10.000.000 

- 我們失去了最後的「1」 -

網格,你看到的是鏈接的效果正在使用的指數/正在丟失的精度:使用58524928等數字時,我們需要26位來表示數字。因此,3位都丟了,我們有,例如:使用這個數字是從附近的58524928當

58524928 + 7 == 58524928 

所以,它要麼被四捨五入到58524928,或「跳」到最近的可能的數字:您有你的網格效果。

解決方案?
- >>更改您在應用中使用的單位,以獲得更小的數字。也許你正在使用mm - >使用米或公里。
請注意,您使用的精度是一種錯覺:顯示分辨率是第一個限制,而鼠標最多隻有1像素精度,所以即使使用4K顯示器,32位浮點也無法成爲極限。

選擇正確的測量單位,以適應您的所有座標在一個較小的範圍內,你就可以解決你的問題。

更清楚:你需要必須更改你使用的單位。這並不意味着您必須交易準確性:在繪圖之前,您只需自己做翻譯+縮放:這樣您仍然可以使用Javascript IEEE 64位準確性,而且您不再有那些32位舍入問題。

(您可能會覆蓋的x,y屬性的getter/setter方法

Object.defineProperty(targetObject, 'x', { get : function() { return view.pixelWidth*(this.rx-view.left)/view.width ; } } 

+0

Upvote爲一個很好的接收! – markE 2015-02-15 14:54:19

+0

@GameAlchemist我想你已經明白了。不幸的是,我不能簡單地改變單位,我真的需要爲帆布畫出許多細節。見http://wikibudgets.org/w/uk/london/greenwich/2015/。我試圖找到合理的解決方法。也許我會在當前視圖偏離中心時虛假移動或僞造當前視圖,但以這種方式進行時,圖表在每個縮放級別保持一致是非常棘手的。任何想法是受歡迎的。 – 2015-02-16 12:10:13