2016-04-02 68 views
5

Mam element, który został przekształcony za pomocą matrix3d, aby nadać mu perspektywę. Przedstawia ekran podręcznego urządzenia.Uzyskiwanie dotkniętej pozycji we współrzędnych lokalnych przekształconego elementu

Na tle urządzenia przenośnego znajduje się obraz tła, który nie jest transformowany. Element, który ją przytrzymuje, jest pozycjonowany, a element ekranu jest umieszczony absolutnie w nim, pod numerem left: 0; top: 0;, a następnie transformowany, ze źródłem w lewym górnym rogu pojemnika. To był najłatwiejszy sposób, aby idealnie go wyrównać z obrazem tła (użyłem this very handy tool do wymyślenia matrycy), i odsuwa element ekranu od rogu.

Chcę mieć możliwość interakcji z ekranem za pomocą myszy i zdarzeń dotykowych. Aby to zrobić, w przypadku kliknięcia lub dotyku, muszę znaleźć współrzędne w lokalnym układzie współrzędnych elementu ekranu - czyli współrzędne przed transformacją. Innymi słowy, po kliknięciu w lewym górnym rogu ekranu urządzenia przenośnego (które jest w lewym górnym rogu obwiedni na stronie!), Chcę [0, 0], i po kliknięciu w prawy górny róg ekranu, który w ten przypadek transformacji jest teraz dalej na stronie, jak również na prawo, chcę [untransformedWidth, 0].

Zdarzenia myszy dostarczają offsetX i offsetY, które rzekomo robią dokładnie to (więcej na tym poniżej), ale zdarzenia dotykowe nie mają tych właściwości, więc potrzebuję sposobu na ich obliczenie.

Używanie math.js Mogę podawać macierz transformacji i odwracać ją. Mam some code to loop over the CSS rules, aby uzyskać regułę transform: matrix3d(...) (nie chcę tego powtarzać w moim kodzie, jeśli nie muszę), którą pomijam - wiem, że działa, ponieważ liczby odpowiadają CSS.

Zauważ, że CSS ma swoje elementy macierzy kolumny w kolejności, więc matrix3d(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) wygląda w zwykłej notacji macierzowej tak:

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

Tymczasem math.js chce jej macierze ogłosił wiersz po wierszu, jak [[a, e, i, m], [b, f, j, n]....

Więc zaczynając gdzie mam listę elementów liczbę od wewnątrz wyrażenia matrix3d(...) w celu CSS, buduję i odwracanie macierzy tak:

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

I następnie skonfigurować mysz obsługi zdarzeń na element ekranu:

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

Gdybym przesunąć znacznik (w stosunku do kontenera) do tego punktu [x, y] wydaje się dokładnie tam, gdzie kliknąłem. Wiem, że to działa. Następnie pomnożyć wektor tych współrzędnych przez odwrotność macierzy transformacji:

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

Jeśli przenieść inny znacznik (tym razem w stosunku do elementu przesiewającego) do wartości Powstały wektor jest [result.get([0]), result.get([1])] porusza się przybliżeniu tę samą pozycję jako poprzedni znacznik, ale nie jest to właściwe. Wygląda na to, że im dalej od początku, tym więcej błędów, dopóki nie jest naprawdę źle na prawą i dolną krawędź.

Ale co jeśli sprawdzę przed offsetX i offsetY? Okazuje się, że odpowiedź zależy od przeglądarki.

W przeglądarce Firefox współrzędne z numerem offset* również nie pasują do pozycji kliknięcia. Nie są one takie same jak moje obliczone, ale różnią się tylko o kilka pikseli. Są tak samo oddalone od prawdziwego klikniętego punktu, jak moje obliczone wartości.

Sample output in Firefox 45

Ale we współrzędnych znalezionych offset* Chrome są doskonałe.

Sample output in Chrome

Oto jsfiddle.

Czy coś jest nie tak z moim obliczeniem? Czy mogę naśladować wynik Chrome, ale bez właściwości offset*?

+0

Podejrzewam niedopasowanie pomiędzy '*' event.offset w Firefoksie i Chrome może być błąd. [Zgłosiłem to na trackerze Firefox] (https://bugzilla.mozilla.org/show_bug.cgi?id=1261645). Ale jeśli to * jest * błędem przeglądarki Firefox, ten sam błąd istnieje w moim kodzie i chcę go znaleźć. – tremby

+0

Ten błąd wydaje się być naprawiony w Firefoksie w wersji 50.0.2, chociaż wciąż jestem zainteresowany tym, co było tutaj. – Thomas

+0

Korekta: mogę potwierdzić, że błąd nadal istnieje, moje testy były błędne. Byłoby wspaniale, gdyby to zostało rozwiązane. – Thomas

Odpowiedz

2

Nie jestem całkowicie pewien teorii, czytałem o tym, gdy pracowałem nad podobnym problemem, ale oto, co znalazłem. Mnożenie macierzy (macierz transformacji 3d - homogeniczne współrzędne i pozycja kursora) daje dwie dodatkowe wartości oprócz x i y. Pierwszy to z, a drugi to w, który służy do wyświetlania obiektu 3d na płaszczyźnie 2d.

Jeśli podzielisz wartości xiy wektora według współrzędnej w, otrzymasz prawidłową pozycję/mapowanie kursora na płaszczyźnie kartezjańskiej.

Tak, chciałbym wymienić kod w swoim skrzypce, wiersze 69-70, z nich:

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

Oto skrzypce zmiana: https://jsfiddle.net/x3ruc3tL/1/

I wtedy nie potrzebne offsetX i offsetY wartości przeglądarki w celu znalezienia właściwej pozycji.

Proszę przeczytać następujące artykuły więcej informacji:

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

+0

To wszystko! Dzięki wielkie! Wygląda na to, że Mozilla ma dokładnie ten sam błąd w swoim kodzie, więc skieruję go do twojego rozwiązania. – tremby