2012-08-30 19 views
5

Sto cercando di trovare il modo migliore per ottenere il riquadro di delimitazione di un elemento SVG arbitrario in pixel dello schermo, in modo da sovrapporre correttamente un elemento HTML. Il mio approccio finora è stato quello di utilizzare .getBBox() e .getCTM() per recuperare il riquadro di delimitazione dell'oggetto e trasformare la matrice, quindi applicare la trasformazione ai punti del riquadro di delimitazione come descritto nella risposta accettata a this question.Ottieni i limiti di un elemento SVG ruotato in pixel dello schermo?

// get the element 
var el = $(selector)[0], 
    pt = $(selector).closest('svg')[0].createSVGPoint(); 

// get the bounding box and matrix 
var bbox = el.getBBox(), 
    matrix = el.getScreenCTM(); 

pt.x = bbox.x; 
pt.y = bbox.y; 
var nw = pt.matrixTransform(matrix); 
pt.x += bbox.width; 
pt.y += bbox.height; 
var se = pt.matrixTransform(matrix); 

// make a div in the screen space around the object 
var $div = $('<div class="bbox"/>').css({ 
     left: nw.x, 
     top: nw.y, 
     width: se.x - nw.x, 
     height: se.y - nw.y 
    }) 
    .appendTo('body'); 

Potete vedere il mio test qui: http://jsfiddle.net/nrabinowitz/zr2jX/

Tuttavia, come gli spettacoli di prova, questo approccio sembra venire a mancare quando c'è una rotazione compresa nel trasformare - sembra che il rettangolo di selezione viene calcolata pre- rotazione, quindi ottenere gli angoli del rettangolo di selezione ruotato non funziona.

Come posso calcolare correttamente il rettangolo di selezione non ruotato degli elementi trasformati?

risposta

4

Dopo alcune ricerche, qui le migliori opzioni che ho trovato:

  • getBoundingClientRect() sembra funzionare bene per gli elementi SVG nei browser moderni, ed è abbastanza veloce, ma i risultati possono variare un po 'da piattaforma per piattaforma (specialmente se si dispone di una larghezza di corsa considerevole). Tuttavia, per il punto @ Sergiu, questo non tiene conto delle modifiche di forma e fornisce i limiti del rettangolo di selezione ruotato, non il percorso o l'oggetto effettivo, quindi può essere piuttosto impreciso - see criticism here. Esempio violino: http://jsfiddle.net/stevenbenner/6M5zf/

  • Il mio obiettivo principale era quello di ottenere angoli di posizione e punti medi del rettangolo, e alla fine ho deciso che usando il rettangolo di selezione ruotata potrebbe anche essere preferibile il "vero" rettangolo di selezione di una ruotata forma. Sono stato in grado di farlo usando l'approccio sopra, e poi facendo girare i punti per avvicinarmi il più possibile alle posizioni N, S, E, W. Si può vedere il mio esempio violino qui: http://jsfiddle.net/nrabinowitz/sPtzV/

3

Non credo che sia possibile, perché inclinazione e la rotazione comportano un cambiamento profilo, o come le proiezioni della forma sui due assi guardano.

È possibile calcolare la matrice di trasformazione che ignorerebbe la parte di rotazione del CTM, ma non si ha alcuna garanzia che il nuovo BBox circonda ancora l'elemento ruotato. Ad esempio, se si dispone di un cerchio, la rotazione non influisce sulle dimensioni del riquadro di delimitazione. Se, d'altra parte, hai un diamante come percorso di base e lo fai ruotare di 45 gradi, così che alla fine è solo un quadrato, il riquadro di delimitazione è diverso: in origine stavi misurando la diagonale, e ora devi ottenere un riquadro di delimitazione che misura la lunghezza del lato. Non importa come usi il marchio comunitario, non puoi tener conto del cambiamento di forma.

Quindi, la rotazione è in realtà abbastanza importante, ignorarla non è un'opzione; ma solo il riquadro di delimitazione locale e la matrice di trasformazione non dicono nulla su come il profilo della forma cambia quando viene ruotato.

+0

Questo è un buon punto, ma a) che sarebbe stato meglio se potessi ottenere i limiti di base del riquadro di delimitazione ruotato, e b) spero c'è qualcosa che non so nell'API SVG che può darmi un nuovo riquadro di delimitazione basato sulla forma trasformata. – nrabinowitz

+0

In teoria si potrebbe usare [checkEnclosure] (http://www.w3.org/TR/SVG11/struct.html#__svg__SVGSVGElement__checkEnclosure) per fare una sorta di ricerca binaria per il rettangolo più piccolo che racchiude completamente l'elemento.Sfortunatamente [non è ancora implementato in Firefox] (https://bugzilla.mozilla.org/show_bug.cgi?id=501421). –

Problemi correlati