GNU/Linux >> Znalost Linux >  >> Linux

Jak použít na plátně textový prvek s fontem popsaným v CSS

Pokud chcete jednoduše vykreslit text z vašeho rozsahu na plátno, můžete přistupovat k atributům stylů pomocí funkce window.getComputedStyle. Aby byl původní rozsah neviditelný, nastavte jeho styl na 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>

Odpovídá písmu DOM na plátně?

Jednoduchá odpověď zní:"To je těžké!!" a „Nikdy to nebude dokonalé.“

Nejlepší, co můžete udělat, je přiblížení, které je v příkladu ve spodní části odpovědi, který také ukáže, že shoda viditelného stylu nesouvisí s viditelnou kvalitou.

Rozšiřování pouze z pravidel CSS.

Pokud chcete, aby písmo co nejpřesněji odpovídalo prvku, existují další starosti, než jen získání CSS, jak je uvedeno v odpovědi Spark Fountain.

Velikost písma a velikost pixelů CSS

  • Velikost písma souvisí s velikostí pixelů CSS. HTMLCanvasElement

  • Velikost pixelů CSS nemusí vždy odpovídat pixelům na displeji zařízení. Např. HiDPI/Retina displeje. K poměru pixelů CSS zařízení se dostanete přes devicePixelRatio

  • Velikost pixelů CSS není konstantní a může se z mnoha důvodů měnit. Změny lze sledovat pomocí MediaQueryListEvent a poslech change událost

  • Prvky lze transformovat. CanvasRenderingContext2D nemůže provádět 3D transformace, takže je prvek nebo plátno má 3D transformaci, nebudete moci porovnat písmo vykreslené na plátně s vykresleným písmem prvků.

  • Rozlišení plátna a velikost zobrazení jsou nezávislé.

    • Rozlišení plátna můžete získat pomocí vlastností HTMLCanvasElement.width a HTMLCanvasElement.height
    • Velikost zobrazení na plátně můžete získat pomocí vlastností stylu width a height nebo pomocí řady dalších metod, viz příklad.
    • Poměr pixelů na plátně se nemusí shodovat s pixely CSS a musí se vypočítat při vykreslování písma na plátně.
    • Vykreslování písma na plátně při malých velikostech písma je hrozné. Například 4px písmo vykreslené na velikost 16px je nečitelné. ctx.font = "4px arial"; ctx.scale(4,4); ctx.fillText("Hello pixels"); Měli byste použít pevnou velikost písma, která poskytuje kvalitní výsledky vykreslování plátna, a při použití malých písem zmenšit vykreslování.

Barva písma

Styl barev prvků představuje pouze vykreslenou barvu. Nepředstavuje skutečnou barvu, jak ji vidí uživatel.

Vzhledem k tomu, že se to týká jak plátna, tak prvku, ze kterého získáváte barvu, a všech prvků nad nebo pod položením, je množství práce potřebné k vizuálnímu sladění barvy obrovské a značně přesahuje rozsah odpovědi přetečení zásobníku (odpovědi mají max. délka 30 kB)

Vykreslování písma

Vykreslovací modul fontu plátna se liší od modulu DOM. DOM může používat různé techniky vykreslování ke zlepšení zdánlivé kvality písem tím, že využije toho, jak jsou fyzické subpixely RGB zařízení uspořádány. Například písma TrueType a související hinting používaný vykreslovacím modulem a odvozený dílčí pixel ClearType s vykreslováním hintingu.

Tyto metody vykreslování písem LZE porovnat na plátně, ačkoli pro shodu v reálném čase budete muset použít WebGL.

Problém je v tom, že vykreslování písem DOM je určeno mnoha faktory, včetně nastavení prohlížeče. JavaScript nemá přístup k žádným informacím potřebným k určení způsobu vykreslení písma. V nejlepším případě můžete kvalifikovaně odhadnout.

Další komplikace

Existují také další faktory, které ovlivňují písmo a jak pravidla stylu písma CSS souvisí s vizuálním výsledkem zobrazeného písma. Například jednotky CSS, animace, zarovnání, směr, transformace písem a režim vtipů.

Osobně si s vykreslováním a barvou hlavu nelámu. Pokud jsem napsal úplný fontový engine pomocí WebGL, aby odpovídal každému fontu, variantě filtrování, skládání a vykreslování, nejsou součástí standardu, a proto se mohou bez upozornění změnit. Projekt by tak byl vždy otevřený a mohl by kdykoli selhat do úrovně nečitelných výsledků. Prostě to nestojí za námahu.

Příklad

V příkladu je vlevo vykreslovací plátno. Text a písmo uprostřed nahoře. Přiblížený pohled vpravo, který ukazuje zvětšený pohled na levé plátno

První použitý styl je výchozí stránka. Rozlišení plátna je 300 x 150, ale je upraveno tak, aby se vešlo na 500 x 500 pixelů CSS. To má za následek VELMI špatnou kvalitu textu na plátně. Cyklováním rozlišení plátna se ukáže, jak rozlišení plátna ovlivňuje kvalitu.

Funkce

  • drawText(text, x, y, fontCSS, sizeCSSpx, colorStyleCSS) kreslí text pomocí hodnot vlastností CSS. Měřítko písma tak, aby co nejvíce odpovídalo velikosti vizuálu DOM a poměru stran.

  • getFontStyle(element) vrátí potřebné styly písem jako objekt z element

Použití uživatelského rozhraní

  • KLIKNĚTE na střed písma pro přepínání stylů písma.

  • KLIKNĚTE na levé plátno pro cyklování rozlišení plátna.

  • V dolní části jsou nastavení používaná k vykreslení textu na plátně.

Uvidíte, že kvalita textu závisí na rozlišení plátna.

Chcete-li vidět, jak zoom DOM ovlivňuje vykreslování, musíte stránku přiblížit nebo oddálit. Displeje HiDPI a retina budou mít mnohem nižší kvalitu textu na plátně, protože plátno má poloviční rozlišení než pixely 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. Jak používat příkaz ethtool s příklady

  2. Jak používat příkaz Grep k vyhledání textu v souborech

  3. Jak použít Sed nebo Ex k nahrazení bloku (víceřádkového kódu) novým blokem textu (kódu)?

  1. Jak používat regex s příkazem find?

  2. Jak používat očekávat s volitelnými výzvami?

  3. Jak mohu použít SSH s proxy SOCKS 5?

  1. Jak používat export s Pythonem na Linuxu

  2. Jak používat sdílenou paměť s Linuxem v C

  3. Jak používat příkaz `subprocess` s rourami