2016-04-02 15 views
5

Tôi có một phần tử đã được chuyển đổi với một số matrix3d để cho phối cảnh đó. Nó đại diện cho màn hình của một thiết bị cầm tay.Lấy vị trí chạm vào trong các tọa độ cục bộ của một phần tử được chuyển đổi

Có hình nền hiển thị chính thiết bị cầm tay và điều này không được chuyển đổi. Phần tử giữ vị trí này được định vị và phần tử màn hình được đặt hoàn toàn bên trong nó, tại left: 0; top: 0; và sau đó được chuyển đổi, có nguồn gốc ở trên cùng bên trái của vùng chứa. Đây là cách dễ nhất để tôi xếp hàng hoàn hảo với hình nền (tôi đã sử dụng this very handy tool để tìm ra ma trận) và nó di chuyển phần tử màn hình ra khỏi góc.

Tôi muốn có thể tương tác với màn hình bằng chuột và các sự kiện chạm. Để thực hiện điều này, trên một sự kiện nhấp hoặc chạm, tôi cần phải tìm tọa độ trong hệ tọa độ cục bộ của phần tử màn hình - tức là tọa độ trước khi biến đổi diễn ra. Nói cách khác, khi nhấp vào phía trên cùng bên trái của màn hình thiết bị cầm tay (là không phải là ở trên cùng bên trái của hộp giới hạn trên trang!) Tôi muốn [0, 0] và khi nhấp vào phía trên bên phải của màn hình, trường hợp của biến đổi này thực sự là tiếp tục lên trên trang cũng như bên phải, tôi muốn [untransformedWidth, 0].

Sự kiện chuột cung cấp offsetXoffsetY mà thực sự làm chính xác điều này (nhiều hơn ở bên dưới), nhưng sự kiện chạm không có các thuộc tính này, vì vậy tôi cần một cách để tự tính chúng.

Sử dụng math.js Tôi có thể nạp vào ma trận chuyển đổi và đảo ngược. Tôi có some code to loop over the CSS rules để nhận quy tắc transform: matrix3d(...) (Tôi không muốn lặp lại quy tắc này trong mã của mình nếu tôi không phải), tôi sẽ bỏ qua - Tôi biết nó hoạt động vì các con số khớp với CSS.

Lưu ý rằng CSS có yếu tố ma trận của nó để cột, vì vậy matrix3d(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) trông trong ký hiệu ma trận thường xuyên như thế này:

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

Trong khi đó, math.js muốn ma trận của nó tuyên bố từng hàng, như [[a, e, i, m], [b, f, j, n]....

Vì vậy, bắt đầu từ nơi tôi có một danh sách các yếu tố số lượng từ bên trong biểu matrix3d(...), để CSS, Tôi đang xây dựng và đảo ngược những ma trận như thế này:

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); 

sau đó tôi thiết lập một con chuột xử lý sự kiện trên các yếu tố màn hình:

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

Nếu tôi di chuyển một đánh dấu (liên quan đến container) đến thời điểm này [x, y], nó xuất hiện chính xác nơi tôi nhấp. Vì vậy, tôi biết điều này nhiều đang làm việc. sau đó tôi nhân một vector của các tọa độ của các ma trận biến đổi nghịch đảo:

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

Nếu tôi chuyển điểm đánh dấu khác (điều này một tương đối so với các yếu tố màn hình) với các giá trị vector kết quả của [result.get([0]), result.get([1])] nó di chuyển để khoảng vị trí tương đương như điểm đánh dấu trước, nhưng nó không hoàn toàn đúng. Có vẻ như là xa hơn từ nguồn gốc tôi đi, càng có nhiều lỗi, cho đến khi nó thực sự khá xấu về phía bên phải và dưới cùng.

Nhưng sau đó nếu tôi kiểm tra lại offsetXoffsetY thì sao? Vâng, nó chỉ ra rằng câu trả lời phụ thuộc vào trình duyệt.

Trong Firefox, các tọa độ được tìm thấy với offset* không khớp với vị trí được nhấp. Chúng không hoàn toàn giống với tính toán của tôi, nhưng chỉ khác nhau một vài pixel. Chúng chỉ cách xa điểm được nhấn đúng như các giá trị tính toán của tôi.

Sample output in Firefox 45

Nhưng trong Chrome tọa độ tìm thấy với offset* là hoàn hảo.

Sample output in Chrome

Dưới đây là một jsfiddle.

Có bất kỳ điều gì tôi đang làm sai với tính toán của tôi không? Có cách nào để tôi bắt chước kết quả của Chrome không, nhưng không có thuộc tính offset*?

+0

tôi nghi ngờ sự không phù hợp giữa 'event.offset * 'trong Firefox và Chrome có thể là một lỗi. Tôi đã [báo cáo nó trên trình theo dõi Firefox] (https://bugzilla.mozilla.org/show_bug.cgi?id=1261645). Nhưng nếu nó * là * một lỗi Firefox, cùng một lỗi tồn tại trong mã của tôi, và tôi muốn tìm nó. – tremby

+0

Lỗi này dường như được sửa trong phiên bản Firefox 50.0.2, mặc dù tôi vẫn quan tâm đến giải pháp thực tế ở đây. – Thomas

+0

Hiệu chỉnh: tôi có thể xác nhận lỗi vẫn còn đó, thử nghiệm của tôi đã sai. Sẽ là tuyệt vời nếu điều này được giải quyết. – Thomas

Trả lời

2

Tôi không hoàn toàn chắc chắn về lý thuyết, tôi đọc về điều này trong khi tôi đang làm việc trên một vấn đề tương tự, nhưng đây là những gì tôi tìm thấy. Phép nhân của các ma trận (ma trận của phép biến đổi 3d - các tọa độ đồng nhất và vị trí của con trỏ) tạo ra hai giá trị khác ngoài x và y. Đầu tiên là z và cái còn lại là w được sử dụng để chiếu đối tượng 3D trên mặt phẳng 2d.

Nếu bạn chia giá trị x và y của vectơ theo tọa độ w, bạn sẽ có được vị trí/ánh xạ chính xác của con trỏ trên mặt phẳng Descartes.

Vì vậy, tôi sẽ thay thế mã trong fiddle của bạn, dòng 69-70, với những:

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'; 

Dưới đây là bản cập nhật fiddle: https://jsfiddle.net/x3ruc3tL/1/

Và sau đó bạn không cần offsetXoffsetY giá trị của trình duyệt để tìm vị trí chính xác.

Vui lòng đọc bài viết sau để biết thêm chi tiết:

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

+0

Đúng rồi! Cám ơn rất nhiều! Có vẻ như Mozilla có cùng một lỗi trong mã của họ, vì vậy tôi sẽ hướng dẫn họ đến giải pháp của bạn. – tremby

Các vấn đề liên quan