GNU/Linux >> Tutoriales Linux >  >> Linux

Cómo usar en un lienzo un elemento de texto con una fuente descrita en CSS

Si simplemente desea representar el texto de su intervalo en un lienzo, puede acceder a los atributos de estilo mediante la función window.getComputedStyle. Para hacer que el tramo original sea invisible, establezca su estilo en 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>

¿Fuente DOM coincidente en el lienzo?

La respuesta simple es:"¡Muy difícil!" y "Nunca será perfecto".

Lo mejor que puede hacer es una aproximación que se encuentra en el ejemplo en la parte inferior de la respuesta, que también mostrará que la coincidencia del estilo visible no está relacionada con la calidad visible.

Ampliar solo las reglas de CSS.

Si desea que la fuente coincida lo más posible con el elemento, existen algunas preocupaciones adicionales además de obtener el CSS como se indica en la respuesta de Spark Fountain.

Tamaño de fuente y tamaño de píxeles CSS

  • El tamaño de fuente está relacionado con el tamaño de píxel de CSS. El HTMLCanvasElement

  • El tamaño de píxel de CSS no siempre coincide con los píxeles de visualización del dispositivo. Por ejemplo, pantallas HiDPI/Retina. Puede acceder a la proporción de píxeles CSS del dispositivo a través de devicePixelRatio

  • El tamaño de píxel de CSS no es una constante y puede cambiar por muchas razones. Los cambios se pueden monitorear a través de MediaQueryListEvent y escuchando el change evento

  • Los elementos se pueden transformar. El CanvasRenderingContext2D no puede hacer transformaciones 3D, por lo tanto, si el elemento o el lienzo tiene una transformación 3D, no podrá hacer coincidir la fuente renderizada del lienzo con la fuente renderizada de los elementos.

  • La resolución del lienzo y el tamaño de la pantalla son independientes.

    • Puede obtener la resolución del lienzo a través de las propiedades HTMLCanvasElement.width y HTMLCanvasElement.height
    • Puede obtener el tamaño de visualización del lienzo a través de las propiedades de estilo ancho y alto, o mediante una variedad de otros métodos, consulte el ejemplo.
    • El aspecto del píxel del lienzo puede no coincidir con el aspecto del píxel CSS y debe calcularse al renderizar la fuente en el lienzo.
    • La representación de fuentes de lienzo en tamaños de fuente pequeños es terrible. Por ejemplo, una fuente de 4 píxeles representada en un tamaño de 16 píxeles es ilegible. ctx.font = "4px arial"; ctx.scale(4,4); ctx.fillText("Hello pixels"); Debe usar un tamaño de fuente fijo que tenga resultados de renderizado de lienzo de buena calidad y escalar el renderizado hacia abajo cuando use fuentes pequeñas.

Color de fuente

El estilo de color de los elementos solo representa el color renderizado. No representa el color real visto por el usuario.

Como esto se aplica tanto al lienzo como al elemento del que obtiene el color y a cualquier elemento que se coloque por encima o por debajo, la cantidad de trabajo necesaria para hacer coincidir visualmente el color es enorme y va mucho más allá del alcance de una respuesta de desbordamiento de pila (las respuestas tienen un longitud máxima de 30K)

Representación de fuentes

El motor de representación de fuentes del lienzo es diferente al del DOM. El DOM puede utilizar una variedad de técnicas de representación para mejorar la calidad aparente de las fuentes aprovechando la forma en que se organizan los subpíxeles RGB físicos de los dispositivos. Por ejemplo, fuentes TrueType y sugerencias relacionadas utilizadas por el renderizador, y el subpíxel ClearType derivado con representación de sugerencias.

Estos métodos de representación de fuentes PUEDEN coincidir en el lienzo, aunque para la coincidencia en tiempo real tendrá que usar WebGL.

El problema es que la representación de fuentes DOM está determinada por muchos factores, incluida la configuración de los navegadores. JavaScript no puede acceder a la información necesaria para determinar cómo se representa la fuente. En el mejor de los casos, puede hacer una conjetura informada.

Otras complicaciones

También hay otros factores que afectan la fuente y cómo las reglas de estilo de fuente CSS se relacionan con el resultado visual de la fuente mostrada. Por ejemplo, unidades CSS, animación, alineación, dirección, transformaciones de fuentes y modo peculiar.

Personalmente para renderizado y color no me molesto. Eventualmente, si escribí un motor de fuente completo usando WebGL para que coincida con cada variante de fuente, filtrado, composición y representación, no son parte del estándar y, por lo tanto, están sujetos a cambios sin previo aviso. Por lo tanto, el proyecto siempre estaría abierto y podría fallar en cualquier momento al nivel de resultados ilegibles. Simplemente no vale la pena el esfuerzo.

Ejemplo

El ejemplo tiene un lienzo de representación a la izquierda. El texto y la fuente en la parte superior central. Una vista ampliada a la derecha, que muestra una vista ampliada del lienzo del lienzo izquierdo

El primer estilo utilizado es el predeterminado de las páginas. La resolución del lienzo es de 300 por 150, pero está escalada para ajustarse a 500 por 500 píxeles CSS. Esto da como resultado un texto de lienzo de MUY mala calidad. Recorrer la resolución del lienzo mostrará cómo el lienzo afecta la calidad.

Las funciones

  • drawText(text, x, y, fontCSS, sizeCSSpx, colorStyleCSS) dibuja el texto utilizando valores de propiedad CSS. Escalar la fuente para que coincida con el tamaño visual DOM y la relación de aspecto lo más cerca posible.

  • getFontStyle(element) devuelve los estilos de fuente necesarios como un objeto de element

Uso de la interfaz de usuario

  • HAGA CLIC en el centro de la fuente para cambiar los estilos de fuente.

  • HAGA CLIC en el lienzo izquierdo para cambiar las resoluciones del lienzo.

  • En la parte inferior está la configuración utilizada para representar el texto en el lienzo.

Verá que la calidad del texto depende de la resolución del lienzo.

Para ver cómo el zoom DOM afecta la representación, debe acercar o alejar la página. Las pantallas HiDPI y retina tendrán un texto de lienzo de calidad mucho menor debido al hecho de que el lienzo tiene la mitad de la resolución de los píxeles CSS.

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>

Linux
  1. Cómo usar la exportación con Python en Linux

  2. ¿Cómo usar expresiones regulares con el comando de búsqueda?

  3. Cómo usar el comando `subproceso` con tuberías

  4. ¿Cómo usar expect con avisos opcionales?

  5. ¿Cómo usar imágenes acoplables locales con Minikube?

Comando alias de Linux:cómo usarlo con ejemplos

Cómo usar el comando rm de Linux con ejemplos

Cómo usar PostgreSQL con la aplicación Ruby on Rails

Cómo usar una clave SSH con usuarios no root

Cómo usar el comando de apagado con ejemplos

Cómo usar Let's Encrypt con Cloudflare