1

Ich habe versucht, eine responsive Website zu machen, die eine Leinwand enthält.2D Canvas: Spezifizieren `arc()` Radius Einheiten

Während eine kreisförmige Fortschrittsbalken zeichnen, am Aufruf der arc() Funktion, aber seine radius Argument, sieht aus wie es in Pixel sein muss, aber ich würde es als Prozente brauchen, vw, vh, em oder jede andere Einheit, css schlägt vor.

Natürlich könnte ich es in Pixel rendern und es mit CSS strecken, aber es wird entweder hochskaliert und pixelig, herunterskaliert und eine Verschwendung von Ressourcen oder sonst verzerrt.

Wie soll ich das machen?

Antwort

1

Nach einigem Suchen stolperte ich auf this question, die mir half, das Problem zu lösen.

Hier ist, wie ich es tat:

var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); 
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); 

var vw = w/100; 
var vh = h/100; 

var pxradius = 50; 
var vwradius = pxradius*vw; 

leider, ich habe immer noch keine Lösung für Prozent- und ems

+0

Es scheint mir, dass Ihr Code genau Prozentwert von 'pxradius' in Pixelwert umwandelt. Es ist also eine Lösung für Prozente. Fehle ich etwas? –

+1

Nun, nicht wirklich, da Prozente relativ zu dem Container sind, in dem das Element platziert wird (afaik) und hier ist es nur relativ zu der Fensterhöhe/-breite – Magix

1

ich bin in diesem Augenblick auf etwas arbeiten, wo ich das lösen musste genau dasselbe Problem (dh Einstellradiuswerte für CanvasRenderingContext2D.arc() in Prozent oder ems).


Hier ist JavaScript-Code meiner Lösung:

function percentToPixelParentBased(percent, element, width_based=true) { 
    return percentToPixelElementRelative(percent, element.parentElement, width_based); 
} 


function emToPixelParentBased(em_value, element) { 
    return emToPixelElementRelative(em_value, element.parentElement); 
} 


function percentToPixelElementRelative(percent, element=false, width_based=true) { 
    if (element) { 
    if (width_based) { 
     var dimension = element.style.width || element.offsetWidth; 
    } else { 
     var dimension = element.style.height || element.offsetHeight; 
    } 
    } else { 
    if (width_based) { 
     var dimension = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); 
    } else { 
     var dimension = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); 
    } 
    } 

    var pixels_in_percent = dimension/100; 

    return pixels_in_percent * percent; 
} 


function emToPixelElementRelative(em_value, element=false) { 
    var font_size = getFontSize(element); 
    var ppi = getPPI(); 
    var px_in_pt = 72/ppi; /* 1pt is 1/72 of an inch */ 
    var value_in_pt = em_value * font_size; 

    return value_in_pt * px_in_pt; 
} 


function getFontSize(element=false) { 

    if (element) { 
    return parseFloat(getComputedStyle(element).fontSize); 
    } else { 
    /* getting font size from body */ 
    return parseFloat(getComputedStyle(document.body).fontSize); 
    } 
} 


function getPPI() { 
    var inch_div_html = "<div id='inch-div' style='height: 1in; left: -100%; position: absolute; top: -100%; width: 1in;'></div>"; 
    document.body.insertAdjacentHTML('afterbegin', inch_div_html); 

    var device_pixel_ratio = window.devicePixelRatio || 1; 
    var ppi_test_div = document.getElementById('inch-div'); 
    var ppi = ppi_test_div.offsetWidth * devicePixelRatio; 

    document.body.removeChild(ppi_test_div); 

    return ppi; 
} 

Ich habe es auch als gist veröffentlicht. Um es ein wenig zu stecken, gibt es demo on JSFiddle.


Nun wird ein wenig Erklärung/Bemerkungen: emToPixelElementRelative und percentToPixelElementRelative jeweils wandelt Wert als erstes Argument an sie übergeben und em=>px%=>px sind. Zweites Argument für beide Funktionen (element) ist ein Element, basierend auf dem Dimensionen, Werte in px berechnet werden (NB: Denken Sie daran, dass Sie Radius, nicht Durchmesser an die arc() übergeben, was für Prozente bedeutet, dass wenn Sie Übergeben Sie eine 50 (%) und Berechnungen auf Basis canvas Element - Durchmesser des Kreises wird 100% und füllt die ganze canvas (im Falle von quadratischen Leinwand)), wenn das Argument nicht übergeben wird - Werte werden berechnet, basierend in den Abmessungen eines Ansichtsfensters. Das dritte Argument (width_based) gibt an, ob die berechneten Werte relativ zur Breite sein sollten (wenn sie auf true (Standardeinstellung) oder Höhe (wenn auf false gesetzt) ​​eingestellt sind.

percentToPixelParentBased und emToPixelParentBased sind Wrapper nur für percentToPixelElementRelative und emToPixelElementRelative, welche Basisumwandlung auf der übergeordneten des übergebenen element.

getFontSize gibt Schriftgröße für das element übergeben oder für <body> Element, wenn ohne Argumente aufgerufen.

getPPI erhält Strom über PPI, Art, hack mentioned in this answer, es nimmt ein einziges Argument (width_based) angibt, ob es sich um Berechnungen auf Breite (wenn true - Standard) zu stützen oder Höhe (wenn false).

Beachten Sie auch, dass ich em=>px Berechnungen auf die folgenden Annahmen zugrunde haben:

  • Schriftgröße in pt gemessen wird (basierend auf this article)
  • 1em auf die Größe der aktuellen Schriftart in pt gleich ist (basierend auf pxtoem.com und this answer)
  • Formel für pt=>px1pt = 72/ppi konvertiert (basierend auf this answer)
  • 012.

Fragen (und Antworten auf sie, natürlich)/Ressourcen, die mir geholfen, diese Lösung zusammen:

  1. Erste aktuelle PPI:
  2. Erste aktuelle Schriftgröße:
  3. Prozent auf Pixelumwandlung:
  4. Em Pixelumwandlung:
  5. Sonstiges: