2013-07-16 17 views
6

Mi stavo chiedendo se è possibile e fattibile convertire valori CSS assoluti in valori relativi mantenendo le proporzioni utilizzando Javascript. La soluzione deve funzionare con HTML e markup SVG.Converti valori assoluti in CSS relativi utilizzando Javascript

dici che hai questo:

<div style="width:100%;height:800px"> 
    <svg width="1000" height="500"> 
    <rect width="30" height="50" x="34" y="24"/> 
    </svg> 
</div> 

Come si raggiungere questo obiettivo?

<div style="width:100%;height:100%"> 
    <svg width="83%" height="62.5%"> 
    <rect width="3%" height="10%" x="3.4% y="4.8%"/> 
    </svg> 
</div> 

avrei

  1. Inizia l'elemento radice (div)
  2. ottenere .width() e .height() di this e l'elemento genitore
  3. calcolare proporzione (this_height/parent_height*100) Larghezza
  4. set e altezza di conseguenza
  5. iterare sui bambini, impostare child come root, iniziare da 1.

Quali sono le insidie ​​più comuni che possono accadere? Ci sono probabilmente tag che non hanno una larghezza o altezza impostata, come svg:g. Poi ci sono definizioni di dimensioni non standard come in svg:circle o attributi a cui non si pensa inizialmente, come svg:text s dy. C'è un modo per fare un'ipotesi plausibile sul successo della performance a causa dei massicci riflessi? Cos'altro?

Grazie mille!

+0

Questo sarà molto difficile per diversi motivi. Pensa all''attributo '' di SVG e' trasforma' e alle trasformazioni CSS. – user123444555621

+0

Se sto capendo correttamente, il tuo ridimensionamento SVG dovrebbe essere risolto dalla proprietà 'viewBox'. – Duopixel

+0

Qual è lo scopo alla base di questo? – screenmutt

risposta

1

Ok. Quindi ecco quello che capisco che tu vuoi fare con le mie parole.

loop attraverso tutti gli elementi DOM conversione dimensioni assolute (cioè altezza/larghezza in termini di pixel) in dimensioni relative (cioè altezza/larghezza in termini di percentuali). Questo dovrebbe essere fatto con la sensibilità per stabilire se la dimensione è impostata usando gli attributi CSS o HTML in modo da essere utilizzabile per gli elementi SVG.

Detto questo, v'è un vincolo importante: Se si desidera convertire dimensioni assolute di dimensioni relative utilizzando <x> come l'elemento radice, quindi <x> deve avere dimensioni assolute. In caso contrario, le dimensioni relative all'interno del contenitore cambieranno le dimensioni in base al loro contenuto anziché alla dimensione complessiva del genitore <x>.

Con questa clausola, quello che stai chiedendo è abbastanza facile. Questo è l'algoritmo che deve essere usato.

  1. Inizia dai <body>
  2. Dare <body> dimensioni fisse
  3. piedi dell'albero DOM per <body> fare quanto segue per ogni elemento
    1. Prendi le dimensioni dell'elemento
    2. Ricevi le dimensioni del genitore
    3. Convert alle dimensioni relative (cioè larghezza/larghezza genitore).
    4. Applicare dimensioni relative

Per testare il mio codice che ho usato il seguente codice HTML. Ha sia il codice che includi sia un'istanza in cui un elemento figlio è più grande di quello genitore. Questo è un caso che ho identificato come condizione al contorno da testare.

<div style="width:100%;height:800px"> 
    <svg width="150" height="200" style="background: red;"> 
    <rect width="30" height="50" x="34" y="24"/> 
    </svg> 

    <div style="background: green; width: 50px; height: 50px;"> 
     <p style="background: teal; width: 100px; height: 20px;">Content</p> 
    </div> 
</div> 

Questo è il codice JavaScript. È abbastanza ben commentato e fornisce un'uscita console decente. Per il codice di produzione suggerirei di raccomandare di rimuovere la registrazione della console.

Si prega di tenere presente che il codice non viene eseguito immediatamente, ma con un ritardo di 2 secondi. In questo modo puoi vedere come appare il DOM prima che venga modificato.

Per coloro che non conoscono il seguente codice restituirà a se è presente e non falso e b in caso contrario.

foo = a || b; 

Potremmo riscrivere come uno dei due sotto, ma questo è più sintetico.

foo = a ? a : b; 

if(a) 
    foo = a 
else 
    foo = b 

Ecco uno jsFiddle.

E il codice!

/** convertToRelative 
* Convert absolute width/height to relative. Should work for 
* Both HTML and SVG objects. Tries to use CSS attributes, falls 
* back on HTML attributes. 
*/ 
function convertToRelative(element) { 
    // Get Element and Parent 
    element = $(element); 
    parent = element.parent(); 

    // If there is no valid with, we need to use attributes 
    var useAttr = !element.width(); 

    // Get dimensions from css or attributes 
    var width  = element.width() || element.attr('width'); 
    var height = element.height() || element.attr('height'); 
    var pWidth = parent.width() || parent.attr('width'); 
    var pHeight = parent.height() || parent.attr('height'); 

    // Find relative dimensions 
    var relWidth = (width/pWidth) * 100.0; 
    var relHeight = (height/pHeight) * 100.0; 

    // Log info 
    console.log(element); 
    console.log("1: "+ parent.height() +", 2: "+ parent.attr('height')); 
    console.log("Width: "+ width +", Height: "+ height); 
    console.log("PWidth: "+ pWidth +", pHeight: "+ pHeight); 
    console.log("relWidth: "+ relWidth +", relHeight: "+ relHeight); 

    // Clear current stylings 
    element.removeAttr('width'); 
    element.removeAttr('height'); 

    // Apply relative dimensions 
    if (useAttr) { 
     element.attr('width', relWidth +'%'); 
     element.attr('height', relHeight +'%'); 
    } else { 
     element.width(relWidth +"%"); 
     element.height(relHeight +"%"); 
    } 
} 

/** walk 
* Walk through a DOM element and all its sub elements running 
* the convertToRelative function to convert absolute positions 
* to relative positions. 
* DOES NOT CONVERT THE FIRST ELEMENT, ONLY CHILDREN. 
*/ 
function walk(element) { 
    $(element).children().each(function() { 
     convertToRelative(this); 
     walk(this); 
    }); 
} 

/** fixBody 
* In order to play with relative dimensions for children of the 
* body, we need to fix the dimensions of the body. Otherwise it 
* will resize as we begin to use relative dimensions. 
*/ 
function fixBody() { 
    $('body').css('width', $('body').width() +"px"); 
    $('body').css('height', $('body').height() +"px"); 
} 

// Walk the body and all children on a 2 second delay. 
setTimeout(function() { 
    console.log('Running Conversion'); 
    fixBody() 
    walk('body'); 
    console.log('Conversion Finished'); 
}, 2000); 

Fammi sapere se questo non è quello che volevi o ti imbatti in un problema!

Per le vostre domande

Quali sono gli errori più comuni che possono probabilmente accadrà?

La trappola più comune sarà una conversione errata. Qualcosa andrà storto nella trasformazione e il DOM risultante non assomiglierà all'input.

Probabilmente ci sono tag che non hanno una larghezza o altezza impostata, come svg: g. Poi ci sono definizioni di dimensioni non standard come in svg: circle o attributi a cui non si pensa inizialmente, come svg: testi dy.

Ci sono tag che non hanno un elemento width/height. Tuttavia, l'utilizzo di jQuery dovrebbe darci un po 'più di robustezza in questo reparto.Non ho lavorato molto con jQuery e SVG, ma è disponibile un plug-in per il supporto in caso di problemi con gli elementi più oscuri.

C'è un modo per fare un'ipotesi plausibile sul successo in termini di prestazioni a causa di enormi riflessi?

credo che questo codice verrà eseguito in O(m * n) Dove m = delay for a single reflow e n = number of nodes. I Reflows dovrebbero avere un cambiamento abbastanza consistente perché stiamo convertendo gli elementi più grandi prima del più piccolo. MA Posso essere smentito in quest'ultima affermazione.

Cos'altro?

Success!

+0

Grazie per lo sforzo! Pensi che il nostro algoritmo di base possa essere esteso per gestire l'intera specifica SVG? Sto parlando di cose come clipPaths, polilinee, trasformazioni (tradurre e ridimensionare soprattutto perché le rotazioni dovrebbero essere indipendenti) e così via. – prayerslayer

+0

Sono sicuro che potrebbe. Non sono così familiare con questo. – screenmutt

Problemi correlati