Ho un elemento che è stato trasformato con un matrix3d
per fornire una prospettiva. Rappresenta lo schermo di un dispositivo portatile.Ottenere la posizione toccata nelle coordinate locali di un elemento trasformato
C'è un'immagine di sfondo che mostra il dispositivo portatile stesso e questo non viene trasformato. L'elemento che contiene ciò è posizionato e l'elemento dello schermo è posizionato assolutamente al suo interno, a left: 0; top: 0;
e quindi trasformato, con un'origine nella parte in alto a sinistra del contenitore. Questo è stato il modo più semplice per me di allinearlo perfettamente con l'immagine di sfondo (ho usato this very handy tool per inventare la matrice) e sposta l'elemento dello schermo lontano dall'angolo.
Voglio essere in grado di interagire con lo schermo con il mouse e toccare gli eventi. Per fare ciò, in un evento click o touch ho bisogno di trovare le coordinate nel sistema di coordinate locale dell'elemento schermo - cioè, le coordinate prima che la trasformazione abbia avuto luogo. In altre parole, quando si fa clic in alto a sinistra sullo schermo del dispositivo portatile (che è non nella parte in alto a sinistra del riquadro di delimitazione sulla pagina!) Voglio [0, 0]
e quando si fa clic in alto a destra dello schermo, che in il caso di questa trasformazione è in realtà più in alto sulla pagina e sulla destra, voglio [untransformedWidth, 0]
.
Gli eventi del mouse forniscono offsetX
eche presumibilmente fanno esattamente questo (più su quello sotto), ma gli eventi di tocco non hanno queste proprietà, quindi ho bisogno di un modo per calcolarli da solo.
Utilizzo di math.js Posso alimentare la matrice di trasformazione e invertirla. Ho some code to loop over the CSS rules per ottenere la regola transform: matrix3d(...)
(non voglio ripeterlo nel mio codice se non devo), che salterò - So che funziona perché i numeri corrispondono al CSS.
Nota che i CSS ha i suoi elementi di matrice in ordine delle colonne, in modo da matrix3d(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
guarda in regolare forma matriciale come questo:
┌ ┐
│ a e i m │
│ b f j n │
│ c g k o │
│ d h l p │
└ ┘
Nel frattempo, math.js vuole le sue matrici fila dichiarati per riga, come [[a, e, i, m], [b, f, j, n]...
.
Quindi partenza dove ho una lista degli elementi numerici dall'interno del matrix3d(...)
espressione, al fine CSS, sto costruendo e invertendo la matrice in questo modo:
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);
Ho quindi creato un topo gestore di eventi sull'elemento schermo:
screen.addEventListener('mousedown', function (event) {
var rect = container.getBoundingClientRect();
var x = event.clientX - rect.left;
var y = event.clientY - rect.top;
Se mi muovo un marcatore (rispetto al contenitore) a questo punto [x, y]
, sembra esattamente dove ho cliccato. Quindi so che questo sta funzionando. Sono quindi moltiplicare un vettore di queste coordinate per l'inverso matrice di trasformazione:
var vector = math.matrix([x, y, 0, 1]);
var result = math.multiply(inverseMatrixTransform, vector);
Se sposto un altro marcatore (questo rispetto all'elemento schermo) per i valori del vettore risultante [result.get([0]), result.get([1])]
si muove a all'incirca stessa posizione come l'indicatore precedente, ma non è giusto. Sembra che più lontano dall'origine vado, maggiore è l'errore, fino a quando non è davvero molto male verso i bordi destro e inferiore.
Ma allora cosa succede se controllo contro offsetX
e offsetY
? Bene, si scopre che la risposta dipende dal browser.
In Firefox, le coordinate trovate con offset*
non corrispondono nemmeno alla posizione selezionata. Non sono esattamente uguali a quelli calcolati, ma solo diversi di un paio di pixel. Sono tanto lontani dal vero punto cliccato quanto i miei valori calcolati.
Ma in Chrome le coordinate trovati con offset*
sono perfetti.
Ecco un jsfiddle.
C'è qualcosa che sto facendo male con il mio calcolo? C'è un modo per me di imitare il risultato di Chrome, ma senza le proprietà offset*
?
ho il sospetto che la mancata corrispondenza tra '' event.offset * in Firefox e Chrome potrebbe essere un bug. Ho [segnalato sul tracker Firefox] (https://bugzilla.mozilla.org/show_bug.cgi?id=1261645). Ma se * è * un bug di Firefox, lo stesso bug esiste nel mio codice, e voglio trovarlo. – tremby
Questo errore sembra essere risolto in Firefox versione 50.0.2, anche se sono ancora interessato a ciò che la soluzione reale era qui. Correzione – Thomas
: posso confermare che il bug è ancora lì, i miei test erano sbagliati. Sarebbe bello se questo fosse risolto. – Thomas