Wenn Sie einfach den Text aus Ihrem Bereich in einer Leinwand rendern möchten, können Sie mit der Funktion window.getComputedStyle auf die Stilattribute zugreifen. Um die ursprüngliche Spanne unsichtbar zu machen, setzen Sie ihren Stil auf display: none
.
// get the span element
const span = document.getElementsByClassName('bmcl_evalprompt')[0];
// get the relevant style properties
const font = window.getComputedStyle(span).font;
const color = window.getComputedStyle(span).color;
// get the element's text (if necessary)
const text = span.innerHTML;
// get the canvas element
const canvas = document.getElementById('canvas');
// set the canvas styling
const ctx = canvas.getContext('2d');
ctx.font = font;
ctx.fillStyle = color;
// print the span's content with correct styling
ctx.fillText(text, 35, 110);
#canvas {
width: 300px;
height: 200px;
background: lightgrey;
}
span.bmcl_evalprompt {
display: none; // makes the span invisible
font-family: monospace; // change this value to see the difference
font-size: 32px; // change this value to see the difference
color: rebeccapurple; // change this value to see the difference
}
<span class="bmcl_evalprompt">Hello World!</span>
<canvas id="canvas" width="300" height="200"></canvas>
Passende DOMs-Schriftart im Canvas?
Die einfache Antwort lautet:"Viel zu schwer!!" und "Es wird nie perfekt sein."
Das Beste, was Sie tun können, ist eine Annäherung, die sich im Beispiel unten in der Antwort befindet und die auch zeigt, dass die Übereinstimmung des sichtbaren Stils nichts mit der sichtbaren Qualität zu tun hat.
Erweitern von nur CSS-Regeln.
Wenn Sie möchten, dass die Schriftart so genau wie möglich mit dem Element übereinstimmt, gibt es einige zusätzliche Bedenken, als nur das CSS zu erhalten, wie in der Antwort von Spark Fountain angegeben.
Schriftgröße und CSS-Pixelgröße
-
Die Schriftgröße hängt mit der CSS-Pixelgröße zusammen. Das HTMLCanvasElement
-
Die CSS-Pixelgröße stimmt nicht immer mit den Anzeigepixeln des Geräts überein. ZB HiDPI/Retina-Displays. Sie können über
devicePixelRatio
auf das CSS-Pixelverhältnis des Geräts zugreifen -
Die CSS-Pixelgröße ist keine Konstante und kann sich aus vielen Gründen ändern. Änderungen können über
MediaQueryListEvent
verfolgt werden und höre diechange
Veranstaltung -
Elemente können transformiert werden. Die
CanvasRenderingContext2D
kann keine 3D-Transformationen durchführen, wenn also das Element oder die Leinwand eine 3D-Transformation hat, können Sie die gerenderte Leinwand-Schriftart nicht mit der gerenderten Element-Schriftart abgleichen. -
Die Leinwandauflösung und die Anzeigegröße sind unabhängig.
- Die Leinwandauflösung erhalten Sie über die Eigenschaften
HTMLCanvasElement.width
, undHTMLCanvasElement.height
- Sie können die Anzeigegröße der Leinwand über die Stileigenschaften Breite und Höhe oder über eine Vielzahl anderer Methoden erhalten, siehe Beispiel.
- Der Pixelaspekt der Leinwand stimmt möglicherweise nicht mit dem CSS-Pixelaspekt überein und muss beim Rendern der Schriftart auf der Leinwand berechnet werden.
- Das Rendern von Canvas-Schriftarten bei kleinen Schriftgrößen ist schrecklich. Beispielsweise ist eine 4px-Schriftart, die auf eine Größe von 16px gerendert wird, nicht lesbar.
ctx.font = "4px arial"; ctx.scale(4,4); ctx.fillText("Hello pixels");
Sie sollten eine feste Schriftgröße verwenden, die qualitativ hochwertige Leinwand-Rendering-Ergebnisse liefert, und das Rendering herunterskalieren, wenn Sie kleine Schriftarten verwenden.
- Die Leinwandauflösung erhalten Sie über die Eigenschaften
Schriftfarbe
Der Farbstil der Elemente stellt nur die gerenderte Farbe dar. Es stellt nicht die tatsächliche Farbe dar, wie sie vom Benutzer gesehen wird.
Da dies sowohl für die Leinwand als auch für das Element gilt, von dem Sie die Farbe erhalten, sowie für alle darüber oder darunter liegenden Elemente, ist der Arbeitsaufwand, der erforderlich ist, um die Farbe visuell abzugleichen, enorm und geht weit über den Rahmen einer Stapelüberlaufantwort hinaus (Antworten haben a max. 30 KB Länge)
Schriftwiedergabe
Die Font-Rendering-Engine des Canvas unterscheidet sich von der des DOM. Das DOM kann eine Vielzahl von Rendering-Techniken verwenden, um die sichtbare Qualität der Schriftarten zu verbessern, indem es sich die Anordnung der physischen RGB-Subpixel der Geräte zunutze macht. Zum Beispiel TrueType-Schriftarten und zugehörige Hinweise, die vom Renderer verwendet werden, und das Subpixel des abgeleiteten ClearType mit Hinweis-Rendering.
Diese Font-Rendering-Methoden KÖNNEN auf der Leinwand abgeglichen werden, obwohl Sie für den Echtzeit-Abgleich WebGL verwenden müssen.
Das Problem besteht darin, dass die Darstellung von DOMs-Schriftarten von vielen Faktoren bestimmt wird, einschließlich der Browsereinstellungen. JavaScript kann auf keine der Informationen zugreifen, die erforderlich sind, um zu bestimmen, wie die Schriftart gerendert wird. Bestenfalls können Sie eine fundierte Vermutung anstellen.
Weitere Komplikationen
Es gibt auch andere Faktoren, die sich auf die Schriftart auswirken und wie sich die CSS-Schriftstilregeln auf das visuelle Ergebnis der angezeigten Schriftart beziehen. Zum Beispiel CSS-Einheiten, Animation, Ausrichtung, Richtung, Schrifttransformationen und Quirks-Modus.
Ich persönlich kümmere mich nicht um Rendering und Farbe. Selbst wenn ich eine vollständige Font-Engine mit WebGL geschrieben habe, um alle Font-, Filter-, Compositing- und Rendering-Varianten abzugleichen, sind sie nicht Teil des Standards und können daher ohne Vorankündigung geändert werden. Das Projekt wäre somit immer offen und könnte jederzeit bis zu unlesbaren Ergebnissen scheitern. Es lohnt sich einfach nicht.
Beispiel
Das Beispiel hat eine Render-Leinwand auf der linken Seite. Der Text und die Schriftart zentrieren sich oben. Eine gezoomte Ansicht auf der rechten Seite, die eine vergrößerte Ansicht der linken Leinwand zeigt
Der erste verwendete Stil ist der Seitenstandard. Die Leinwandauflösung beträgt 300 x 150, ist jedoch so skaliert, dass sie auf 500 x 500 CSS-Pixel passt. Dies führt zu Leinwandtext von SEHR schlechter Qualität. Das Durchlaufen der Leinwandauflösung zeigt, wie sich die Leinwandauflösung auf die Qualität auswirkt.
Die Funktionen
-
drawText(text, x, y, fontCSS, sizeCSSpx, colorStyleCSS)
zeichnet den Text mithilfe von CSS-Eigenschaftswerten. Skalieren der Schriftart so, dass sie der visuellen Größe und dem Seitenverhältnis des DOM so gut wie möglich entspricht. -
getFontStyle(element)
gibt die benötigten Schriftstile als Objekt vonelement
zurück
UI-Nutzung
-
KLICKEN Sie auf Schriftart zentrieren, um die Schriftarten zu wechseln.
-
KLICKEN Sie auf die linke Leinwand, um die Leinwandauflösungen zu wechseln.
-
Unten befinden sich die Einstellungen, die zum Rendern des Textes auf der Leinwand verwendet werden.
Sie werden sehen, dass die Qualität des Textes von der Auflösung der Leinwand abhängt.
Um zu sehen, wie sich der DOM-Zoom auf das Rendering auswirkt, müssen Sie die Seite vergrößern oder verkleinern. HiDPI- und Retina-Displays haben eine viel geringere Qualität des Leinwandtexts, da die Leinwand die Hälfte der Auflösung der CSS-Pixel hat.
const ZOOM_SIZE = 16;
canvas1.width = ZOOM_SIZE;
canvas1.height = ZOOM_SIZE;
const ctx = canvas.getContext("2d");
const ctx1 = canvas1.getContext("2d");
const mouse = {x:0, y:0};
const CANVAS_FONT_BASE_SIZE = 32; // the size used to render the canvas font.
const TEXT_ROWS = 12;
var currentFontClass = 0;
const fontClasses = "fontA,fontB,fontC,fontD".split(",");
const canvasResolutions = [[canvas.scrollWidth, canvas.scrollHeight],[300,150],[200,600],[600,600],[1200,1200],[canvas.scrollWidth * devicePixelRatio, canvas.scrollHeight * devicePixelRatio]];
var currentCanvasRes = canvasResolutions.length - 1;
var updateText = true;
var updating = false;
setTimeout(updateDisplay, 0, true);
function drawText(text, x, y, fontCSS, sizeCSSpx, colorStyleCSS) { // Using px as the CSS size unit
ctx.save();
// Set canvas state to default
ctx.globalAlpha = 1;
ctx.filter = "none";
ctx.globalCompositeOperation = "source-over";
const pxSize = Number(sizeCSSpx.toString().trim().replace(/[a-z]/gi,"")) * devicePixelRatio;
const canvasDisplayWidthCSSpx = ctx.canvas.scrollWidth; // these are integers
const canvasDisplayHeightCSSpx = ctx.canvas.scrollHeight;
const canvasResWidth = ctx.canvas.width;
const canvasResHeight = ctx.canvas.height;
const scaleX = canvasResWidth / (canvasDisplayWidthCSSpx * devicePixelRatio);
const scaleY = canvasResHeight / (canvasDisplayHeightCSSpx * devicePixelRatio);
const fontScale = pxSize / CANVAS_FONT_BASE_SIZE
ctx.setTransform(scaleX * fontScale, 0, 0, scaleY * fontScale, x, y); // scale and position rendering
ctx.font = CANVAS_FONT_BASE_SIZE + "px " + fontCSS;
ctx.textBaseline = "hanging";
ctx.fillStyle = colorStyleCSS;
ctx.fillText(text, 0, 0);
ctx.restore();
}
function getFontStyle(element) {
const style = getComputedStyle(element);
const color = style.color;
const family = style.fontFamily;
const size = style.fontSize;
styleView.textContent = `Family: ${family} Size: ${size} Color: ${color} Canvas Resolution: ${canvas.width}px by ${canvas.height}px Canvas CSS size 500px by 500px CSS pixel: ${devicePixelRatio} to 1 device pixels`
return {color, family, size};
}
function drawZoomView(x, y) {
ctx1.clearRect(0, 0, ctx1.canvas.width, ctx1.canvas.height);
//x -= ZOOM_SIZE / 2;
//y -= ZOOM_SIZE / 2;
const canvasDisplayWidthCSSpx = ctx.canvas.scrollWidth; // these are integers
const canvasDisplayHeightCSSpx = ctx.canvas.scrollHeight;
const canvasResWidth = ctx.canvas.width;
const canvasResHeight = ctx.canvas.height;
const scaleX = canvasResWidth / (canvasDisplayWidthCSSpx * devicePixelRatio);
const scaleY = canvasResHeight / (canvasDisplayHeightCSSpx * devicePixelRatio);
x *= scaleX;
y *= scaleY;
x -= ZOOM_SIZE / 2;
y -= ZOOM_SIZE / 2;
ctx1.drawImage(ctx.canvas, -x, -y);
}
displayFont.addEventListener("click", changeFontClass);
function changeFontClass() {
currentFontClass ++;
myFontText.className = fontClasses[currentFontClass % fontClasses.length];
updateDisplay(true);
}
canvas.addEventListener("click", changeCanvasRes);
function changeCanvasRes() {
currentCanvasRes ++;
if (devicePixelRatio === 1 && currentCanvasRes === canvasResolutions.length - 1) {
currentCanvasRes ++;
}
updateDisplay(true);
}
addEventListener("mousemove", mouseEvent);
function mouseEvent(event) {
const bounds = canvas.getBoundingClientRect();
mouse.x = event.pageX - scrollX - bounds.left;
mouse.y = event.pageY - scrollY - bounds.top;
updateDisplay();
}
function updateDisplay(andRender = false) {
if(updating === false) {
updating = true;
requestAnimationFrame(render);
}
updateText = andRender;
}
function drawTextExamples(text, textStyle) {
var i = TEXT_ROWS;
const yStep = ctx.canvas.height / (i + 2);
while (i--) {
drawText(text, 20, 4 + i * yStep, textStyle.family, textStyle.size, textStyle.color);
}
}
function render() {
updating = false;
const res = canvasResolutions[currentCanvasRes % canvasResolutions.length];
if (res[0] !== canvas.width || res[1] !== canvas.height) {
canvas.width = res[0];
canvas.height = res[1];
updateText = true;
}
if (updateText) {
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
updateText = false;
const textStyle = getFontStyle(myFontText);
const text = myFontText.textContent;
drawTextExamples(text, textStyle);
}
drawZoomView(mouse.x, mouse.y)
}
.fontContainer {
position: absolute;
top: 8px;
left: 35%;
background: white;
border: 1px solid black;
width: 30%;
cursor: pointer;
text-align: center;
}
#styleView {
}
.fontA {}
.fontB {
font-family: arial;
font-size: 12px;
color: #F008;
}
.fontC {
font-family: cursive;
font-size: 32px;
color: #0808;
}
.fontD {
font-family: monospace;
font-size: 26px;
color: #000;
}
.layout {
display: flex;
width: 100%;
height: 128px;
}
#container {
border: 1px solid black;
width: 49%;
height: 100%;
overflow-y: scroll;
}
#container canvas {
width: 500px;
height: 500px;
}
#magViewContainer {
border: 1px solid black;
display: flex;
width: 49%;
height: 100%;
}
#magViewContainer canvas {
width: 100%;
height: 100%;
image-rendering: pixelated;
}
<div class="fontContainer" id="displayFont">
<span class="fontA" id="myFontText" title="Click to cycle font styles">Hello Pixels</span>
</div>
<div class="layout">
<div id="container">
<canvas id="canvas" title="Click to cycle canvas resolution"></canvas>
</div>
<div id="magViewContainer">
<canvas id="canvas1"></canvas>
</div>
</div>
<code id="styleView"></code>