Cách sử dụng trong khung vẽ một phần tử văn bản có phông chữ được mô tả trong CSS


8

Đây là trong dự án Bismon (một phần mềm GPLv3 + được tài trợ bởi các dự án H2020 ở Châu Âu), git commit0e9a8eccc2976f . Báo cáo dự thảo này mô tả phần mềm. Câu hỏi này cung cấp thêm bối cảnh và động lực. Đó là về tệp webroot / jscript / bismon-hwroot.js (được viết bằng tay) , được sử dụng trong một số trang HTML có mã được tạo bởi Bismon (một máy chủ web chuyên dụng trên libonion ).

Tôi đã thêm một số lớp CSS cho span, ví dụ span.bmcl_evalprompt(ví dụ: trong tệp của tôi - theme.css ).

Làm cách nào để mã JavaScript để thêm một đoạn văn bản vào khung vẽ (tốt nhất là sử dụng jcanvas với jquery) có cùng kiểu (cùng phông chữ, màu, v.v ...) như vậy span.bmcl_evalprompt? Tôi có cần tạo phần tử span như vậy trong DOM không? Điều đó thậm chí đơn giản là có thể?

Tôi chỉ quan tâm đến một Firefox gần đây (ít nhất là 68) trên Linux. JQuery là 3,4. Tôi cũng đang sử dụng Jquery UI 1.12.1

Ý tưởng tôi có trong đầu là tạo ra một <span class='bmcl_evalprompt'>yếu tố duy nhất có tọa độ cách xa khung nhìn trình duyệt (hoặc cửa sổ X11), ví dụ tại x= -10000y= -10000 (tính bằng pixel), sau đó thêm phần tử được định vị xấu đó vào DOM tài liệu, sau đó sử dụng truyền thống Kỹ thuật Jquery để có được họ phông chữ, kích thước phông chữ và kích thước phần tử. Nhưng có cách nào tốt hơn không? Hoặc một số thư viện tương thích Jquery làm điều đó?

Câu trả lời:


5

Phù hợp với phông chữ DOM trong vải?

Câu trả lời đơn giản là, "Cách khó !!" "Nó sẽ không bao giờ hoàn hảo."

Điều tốt nhất bạn có thể làm là một phép tính gần đúng trong ví dụ ở cuối câu trả lời cũng sẽ hiển thị phù hợp với kiểu hiển thị không liên quan đến chất lượng hiển thị.

Mở rộng từ chỉ các quy tắc CSS.

Nếu bạn muốn phông chữ phù hợp nhất có thể với phần tử, có một số mối quan tâm bổ sung ngoài việc chỉ lấy CSS như được chỉ ra trong câu trả lời của Spark Fountain .

Cỡ chữ & cỡ pixel CSS

  • Kích thước phông chữ có liên quan đến kích thước pixel CSS. HTMLCanvasEuity
  • Kích thước pixel CSS không phải lúc nào cũng khớp với pixel hiển thị của thiết bị. Ví dụ: màn hình HiDPI / Retina. Bạn có thể truy cập khẩu phần pixel CSS của thiết bị thông quadevicePixelRatio
  • Kích thước pixel CSS không phải là hằng số và có thể thay đổi vì nhiều lý do. Thay đổi có thể được theo dõi thông qua MediaQueryListEventvà lắng nghe changesự kiện
  • Các yếu tố có thể được chuyển đổi. Các CanvasRenderingContext2Dkhông thể làm biến đổi 3D do đó là yếu tố hoặc vải có một 3D chuyển đổi bạn sẽ không thể để phù hợp với vải render phông chữ với các yếu tố phông chữ render.

  • Độ phân giải vải và kích thước hiển thị là độc lập.

    • Bạn có thể nhận được độ phân giải canvas thông qua các thuộc tính HTMLCanvasElement.widthHTMLCanvasElement.height
    • Bạn có thể lấy kích thước hiển thị canvas thông qua chiều rộng và chiều cao của thuộc tính kiểu hoặc thông qua nhiều phương thức khác xem ví dụ.
    • Khía cạnh pixel canvas có thể không khớp với khía cạnh pixel CSS và phải được tính khi hiển thị phông chữ trên canvas.
    • Hiển thị phông chữ vải ở kích thước phông chữ nhỏ là khủng khiếp. Ví dụ, phông chữ 4px được hiển thị có kích thước 16px là không thể đọc được. ctx.font = "4px arial"; ctx.scale(4,4); ctx.fillText("Hello pixels");Bạn nên sử dụng kích thước phông chữ cố định có kết quả hiển thị canvas chất lượng tốt và giảm tỷ lệ kết xuất khi sử dụng phông chữ nhỏ.

Màu phông chữ

Các kiểu phần tử màu chỉ đại diện cho màu kết xuất. Nó không đại diện cho màu sắc thực tế mà người dùng nhìn thấy.

Vì điều này áp dụng cho cả khung vẽ và thành phần mà bạn đang lấy màu và bất kỳ yếu tố đặt hoặc dưới nào, nên số lượng công việc cần thiết để khớp màu trực quan là rất lớn và vượt ra ngoài phạm vi của câu trả lời tràn ngăn xếp (câu trả lời có chiều dài tối đa 30K)

Phông chữ kết xuất

Công cụ kết xuất phông chữ của khung vẽ khác với DOM. DOM có thể sử dụng nhiều kỹ thuật kết xuất khác nhau để cải thiện chất lượng phông chữ rõ ràng bằng cách tận dụng cách bố trí các pixel phụ vật lý RGB của thiết bị. Ví dụ: phông chữ TrueType và gợi ý liên quan được sử dụng bởi trình kết xuất và pixel phụ của ClearType có kết xuất với gợi ý.

Các phương thức kết xuất phông chữ này CÓ THỂ được khớp trên khung vẽ , mặc dù để khớp thời gian thực, bạn sẽ phải sử dụng WebGL.

Vấn đề là kết xuất phông chữ DOM được xác định bởi nhiều yếu tố, bao gồm cả cài đặt trình duyệt. JavaScript không thể truy cập bất kỳ thông tin cần thiết nào để xác định cách hiển thị phông chữ. Tốt nhất bạn có thể đoán.

Biến chứng thêm

Ngoài ra còn có các yếu tố khác ảnh hưởng đến phông chữ và cách các quy tắc kiểu phông chữ CSS liên quan đến kết quả trực quan của phông chữ được hiển thị. Ví dụ: các đơn vị CSS, hình động, căn chỉnh, hướng, biến đổi phông chữ và chế độ quirks.

Cá nhân để kết xuất và màu sắc tôi không bận tâm. Sự kiện nếu tôi đã viết một công cụ phông chữ đầy đủ bằng WebGL để khớp với mọi biến thể phông chữ, lọc, tổng hợp và kết xuất, chúng không phải là một phần của tiêu chuẩn và do đó có thể thay đổi mà không cần thông báo trước. Do đó, dự án sẽ luôn mở và bất kỳ lúc nào cũng không thể đạt được kết quả không thể đọc được. Chỉ là không đáng nỗ lực.


Thí dụ

Ví dụ này có một khung vẽ ở bên trái. Các văn bản và phông chữ trung tâm hàng đầu. Chế độ xem được phóng to ở bên phải, hiển thị chế độ xem được phóng to của khung vẽ bên trái

Kiểu đầu tiên được sử dụng là các trang mặc định. Độ phân giải canvas là 300by150 nhưng được chia tỷ lệ để phù hợp với 500 x 500 pixel CSS. Điều này dẫn đến văn bản vải RẤT kém chất lượng. Đi xe đạp độ phân giải vải sẽ cho thấy làm thế nào độ phân giải vải ảnh hưởng đến chất lượng.

Chức năng

  • drawText(text, x, y, fontCSS, sizeCSSpx, colorStyleCSS)vẽ văn bản bằng các giá trị thuộc tính CSS. Thu nhỏ phông chữ để phù hợp với kích thước hình ảnh DOM và tỷ lệ khung hình càng gần càng tốt.

  • getFontStyle(element) trả về các kiểu phông chữ cần thiết như một đối tượng từ element

Sử dụng giao diện người dùng

  • NHẤP phông chữ trung tâm để chu kỳ các kiểu phông chữ.

  • BẤM trái vải để chu kỳ độ phân giải vải.

  • Ở phía dưới là cài đặt được sử dụng để hiển thị văn bản trong khung vẽ.

Bạn sẽ thấy rằng chất lượng của văn bản phụ thuộc vào độ phân giải của khung vẽ.

Để xem cách thu phóng DOM ảnh hưởng đến kết xuất, bạn phải phóng to hoặc thu nhỏ trang. Màn hình HiDPI và retina sẽ có văn bản canvas chất lượng thấp hơn nhiều do thực tế là canvas có một nửa độ phân giải của các pixel 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>


3

Nếu bạn chỉ đơn giản muốn hiển thị văn bản từ khoảng của mình trong một khung vẽ, bạn có thể truy cập các thuộc tính kiểu dáng bằng cách sử dụng hàm window.getComputingStyle . Để làm cho nhịp ban đầu vô hình, đặt kiểu của nó thành 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>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.