2016-04-02 58 views
5

我有一個已使用matrix3d進行轉換的元素,以給它透視。它代表了手持設備的屏幕。獲取已轉換元素的本地座標中的已觸摸位置

有一個背景圖像顯示手持設備本身,這是不會改變。放置該元素的元素被定位,並且屏幕元素完全位於其中,位於left: 0; top: 0;處,然後進行轉換,並在容器的左上角有一個原點。這對我來說是最簡單的方法,可以將它與背景圖像完美對齊(我使用this very handy tool來提供矩陣),並將屏幕元素從角落移開。

我希望能夠通過鼠標和觸摸事件與屏幕進行交互。爲此,在點擊或觸摸事件時,我需要在屏幕元素的本地座標系中找到座標 - 即轉換髮生之前的座標。換句話說,當點擊手持設備屏幕的左上方(而不是頁面上其邊框的左上方!)時,我想要[0, 0],並且在點擊屏幕的右上角時這個轉換的情況實際上是在頁面上以及在右邊,我想要[untransformedWidth, 0]

鼠標事件提供offsetXoffsetY據稱這是做的(下面更多),但觸摸事件沒有這些屬性,所以我需要一種方法來自己計算它們。

使用math.js我可以輸入轉換矩陣並將其反轉。我有some code to loop over the CSS rules得到transform: matrix3d(...)規則(我不想在我的代碼中重複它,如果我不需要),我將跳過 - 我知道它的工作原理是因爲數字匹配CSS。

注意CSS在列順序矩陣元素,所以matrix3d(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)看起來正規矩陣符號是這樣的:

┌   ┐ 
│ a e i m │ 
│ b f j n │ 
│ c g k o │ 
│ d h l p │ 
└   ┘ 

同時,math.js希望其矩陣的行申報行,像[[a, e, i, m], [b, f, j, n]...

於是開始在那裏我有從matrix3d(...)表達式中的一些元素的列表,CSS順序,我建立和反相這樣的矩陣:

var rows = [[], [], [], []]; 
for (var i = 0; i < elements.length; i++) { 
    rows[i % 4][Math.floor(i/4)] = elements[i]; 
} 

var matrixTransform = math.matrix(rows); 

var invertedMatrixTransform = math.inv(matrixTransform); 

我然後設置鼠標屏幕元素事件處理程序:

screen.addEventListener('mousedown', function (event) { 
    var rect = container.getBoundingClientRect(); 
    var x = event.clientX - rect.left; 
    var y = event.clientY - rect.top; 

如果我移動標記(相對於容器)這一點[x, y],它在那裏我點擊顯示準確。所以我知道這很多工作。

var vector = math.matrix([x, y, 0, 1]); 
    var result = math.multiply(inverseMatrixTransform, vector); 

如果我提出另一個標記(這一個相對於屏幕元件),以所得到的矢量的值[result.get([0]), result.get([1])]它移動到大致相同的位置:然後我通過逆變換矩陣相乘這些座標的矢量作爲上一個標記,但它不太正確。似乎離我的起源越遠,錯誤就越多,直到它對右邊和底邊非常不好。

但是如果我檢查offsetXoffsetY怎麼辦?那麼,事實證明,答案取決於瀏覽器。

在Firefox中,使用offset*找到的座標也與所點擊的位置不匹配。它們與我的計算結果並不完全相同,但僅有幾個像素不同。它們與我的計算值相距真正的點擊點。

Sample output in Firefox 45

但在Chrome中發現offset*的座標是完美的。

Sample output in Chrome

這裏有一個jsfiddle

有什麼我做錯了我的計算?有沒有辦法讓我模仿Chrome的結果,但沒有offset*屬性?

+0

我懷疑在Firefox和Chrome'event.offset *'之間的不匹配可能是一個錯誤。我已經[在Firefox跟蹤器上報告過](https://bugzilla.mozilla.org/show_bug.cgi?id=1261645)。但是如果它*是一個Firefox錯誤,我的代碼中存在相同的錯誤,我想找到它。 – tremby

+0

這個錯誤似乎在Firefox 50.0.2版本中得到解決,儘管我仍然對實際的解決方案在這裏感興趣。 – Thomas

+0

更正:我可以確認錯誤仍然存​​在,我的測試是錯誤的。如果這個問題得到解決,會很好。 – Thomas

回答

2

我對這個理論並不完全確定,當我在研究類似的問題時,我讀到了這個問題,但這裏是我發現的。矩陣(三維變換矩陣 - 齊次座標和光標位置)的乘法產生除x和y之外的兩個更多值。第一個是z,另一個是用於在3d平面上投影3d對象的w。

如果您將矢量的x和y值除以w座標,您將得到正確的位置/光標在笛卡爾平面上的映射。

所以,我會替換代碼在你的小提琴,線69-70,這些:

var x = result.get([0]); 
var y = result.get([1]); 
var w = result.get([3]); 
screenCrosshair.style.left = x/w + 'px'; 
screenCrosshair.style.top = y/w + 'px'; 

這裏是更新小提琴: https://jsfiddle.net/x3ruc3tL/1/

然後你不需要offsetXoffsetY瀏覽器的值,以便找到正確的位置。

請閱讀以下文章瞭解更多信息:

https://en.wikipedia.org/wiki/3D_projection#Perspective_projection http://deltaorange.com/2012/03/08/the-truth-behind-homogenous-coordinates/

+0

就是這樣!非常感謝!看起來Mozilla在他們的代碼中有完全相同的錯誤,所以我會引導他們到你的解決方案。 – tremby