Measure text width according to CSS without rendering it - javascript

I want to measure the theoretical width of some to-be-rendered text.
I like this method for getting text width, because it doesn't mutate the DOM
function getTextWidth(text, font) {
// re-use canvas object for better performance
var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
context.font = font;
var metrics = context.measureText(text);
return metrics.width;
}
I have a CSS description of the font
.dx-widget {
color: #333;
font-weight: 400;
font-size: 14px;
font-family: "Helvetica Neue","Segoe UI",helvetica,verdana,sans-serif;
line-height: 1.35715;
}
How can I get in JavaScript the width that different strings would be according to these CSS rules?
I don't think I can apply this CSS class to the canvas to make it work.

Ok. I created a snippet.
By assigning a dummy element style (or of a real element) to a variable it is much easier to correct the code. In the console in the Developer Tools of any browser you can enter the name of the variable and see all properties.
Test and if it works for you- use it ;)
Or as Stephen P suggested in the comments- create a new empty span and you do not have to risc changing some real visible element :)
Vote his comment. It is great improvement.
var stylee=document.getElementById('test_element').style;
stylee.color="#333";
stylee.fontWeight="400";
stylee.fontSize="14px";
stylee.fontFamily='"Helvetica Neue","Segoe UI",helvetica,verdana,sans-serif';
stylee.lineHeight="1.35715";
function getTextWidth(text, font) {
// re-use canvas object for better performance
var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
context.font = font;
var metrics = context.measureText(text);
return metrics.width;
}
document.getElementById('result').innerText=getTextWidth('some text or variable', stylee);
<span id="test_element"></span>
<div id="result"></div>

By reading https://developer.mozilla.org/en-US/docs/Web/CSS/font I have understood that .font can actually specify all of the information from that CSS.
line-height must immediately follow font-size, preceded by "/", like this: "16px/3"
font-weight must precede font-size
font-family must be the last value specified
So this CSS
font-weight: 400;
font-size: 14px;
font-family: "Helvetica Neue","Segoe UI",helvetica,verdana,sans-serif;
line-height: 1.35715;
can be compressed into
font: 400 14px/1.35715 "Helvetica Neue","Segoe UI",helvetica,verdana,sans-serif;
and that property value can be used in the original canvas getTextWidth function.

Related

HTML text inside Canvas

I need to render an image on which I have put some HTML text on it and then the user to be able to download the image with the text as an image or even better as a pdf.
The certText element is taken from a TinyMCE variable, where the user each time uses different HTML tags within the text.
So it could be
"Hello user, how are you"
or
"Hi there, great that you succeed on the certification".
Starting from the image option I have created below code but Canvas do no translate the HTML tags.
I have read that with Canvas it's not possible to render the HTML tags, but is there any other alternative to succeed this.
The code is used on a Laravel project that I have made.
var p = document.getElementById("certificate");
var ptx = p.getContext("2d");
var imgp = document.getElementById("certificateEmpty");
var txtp = document.getElementById("certText").innerHTML;
imgp.onload = function(){
ptx.drawImage(imgp, 0, 0);
ptx.font = "48px Nunito";
ptx.fillText(txtp, 150, 1000);
};
imgp.src = "{{$attendees[0]->certBLocation}}";
What are you trying to achive when you say "render html tags"?
Do you mean you want to style the text that is drawn on the canvas?
If so, you have to use canvas functions to set what the text will look like.
In the below example using your code, I use "fillStyle" to set the drawing fill colour in which the text will be drawn.
var p = document.getElementById("certificate");
var ptx = p.getContext("2d");
var imgp = document.getElementById("certificateEmpty");
var txt = document.getElementById("certText");
var txtp = txt.innerHTML;
imgp.onload = function(){
ptx.drawImage(imgp, 0, 0, p.width, p.height);
var styles = window.getComputedStyle(txt);
ptx.fillStyle = styles.color;
//ptx.font = styles.font; // Doesn't seem to work in firefox.
ptx.font = styles['font-weight']+" "+styles['font-size']+" "+styles.fontFamily; // Access properties array style because of hyphens.
ptx.fillText(txtp, 0, 100);
};
imgp.src = "https://www.gravatar.com/avatar/7b67c827ee1671ba3b43f4aebf6794fb?s=200";
img, canvas {
width: 200px;
height: 200px;
}
#certText {
color: #ff0000;
font-weight: bold;
font-size: 40px;
}
<img id="certificateEmpty"/>
<canvas id="certificate"></canvas>
<div id="certText">
some text
</div>
Text drawn on the canvas looks squashed on my screen (Ubuntu/Chrome), not sure why.

Calculating path length of test [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am trying to solve a problem where i need to know the length of the path of the text typed by the user. Example a user Types "Hello World" i need to check what will be the length of the path of Hello world when typed in a certain font with a certain font size(in pt).
The length that i will get i need to convert it into meters to i can use it in real world to build the Neon.
How should i approach the problem are there any libraries that can help me do this?
Thanks
I don't have any specific libraries to recommend, but here is a snippet of how you might go about doing what you want. The conversion from pixels to centimeters is approximate here, it's just a demo after all.
const getRuler = element => {
const ctx = document.createElement('canvas').getContext('2d');
const style = window.getComputedStyle(element);
const fontSize = style.getPropertyValue('font-size');
const fontFamily = style.getPropertyValue('font-family');
ctx.font = `${fontSize} ${fontFamily}`;
return ctx;
}
const element = document.querySelector('#my-element-with-text');
function updateLength(e) {
const element = e.target
const text = element.innerText;
const ruler = getRuler(element);
const length = ruler.measureText(text).width;
const result = document.querySelector('#length');
result.innerText = (length * 0.026458).toFixed(4) + ' centimeters';
}
element.addEventListener('keyup', updateLength);
body {
height: 100%;
width: 100%;
margin: 0;
}
main {
margin-top: 15vh;
margin-left: 10vw;
width: 85%;
}
#my-element-with-text {
border: 1px solid black;
border-radius: 3px;
height: 2em;
font-size: 5vw;
width: fit-content;
min-width: 200px;
line-height: 2em;
padding: 0 12px;
font-family: 'Helvetica Neue', sans-serif;
}
<main>
<div>Enter text here</div>
<div id='my-element-with-text' contenteditable='true'></div>
<div id='length'></div>
</main>
This is a multistep process, and for now I don't have all the answers.
Load the font to use as a webfont. Normally, this means you go to a provider like Google fonts and get a link to a stylesheet that will do the work for you, including deciding which font format your browser will understand. But in this case, you need the full address of the final font file. If you provide the font file on your own server, this would be trivial.
Since you ultimately need the file content itself, the best strategy is probably to load the font file via an AJAX request and then both insert it into the document font resources and to load it also into a special parser that gives access to the font outline data. This could be opentype.js - note it is a major piece of software with 162kB minified. As soon as the font is loaded, you can start to look for the text you want to measure:
window.fetch(fontUrl).then(response => {
// read response into an ArrayBuffer
return response.arrayBuffer();
}).then(buffer => {
// load into parser
const parsedFont = opentype.parse(buffer);
// load into browser resources, family is the name for CSS reference
const fontFace = new FontFace(family, buffer);
document.fonts.add(fontFace);
// add an event listener to your text input
document.querySelector('#textToMeasure').addEventListener('change', event => {
textToOutline(parsedFont, event.target.value);
});
});
Each time the text input changes, you now render that text to an SVG path. For that, you need to have an (invisible) SVG snippet in your page:
<svg width="0px" height="0px"><path id="outlinePath" d="" /></svg>
You get the path data by providing the text and the font size to the font object and then set them for your SVG <path>:
function textToOutline (font, text) {
// size means font size in pixels
const pathData = font.getPath(text, 0, 0, size).toPathData(4);
// write to path
const path = document.querySelector('#outlinePath');
path.setAttribute('d', pathData);
measureOutline(path);
}
Now the text outline is in a format that the browser can measure with its own API.
function measureOutline (path) {
// length in pixels
const pathLength = path.getTotalLength();
// factor would be the conversion factor to your intended unit,
// and unit the unit name
document.querySelector('#lengthResult').innerText = (pathLength * factor) + unit;
}

Can't get a canvas to display a custom font

Canvas.filltext won't render custom font (though body text will, and canvas.filltext will render local fonts)
I want to paint some text on a canvas, using a custom font called jelleebold. Here's an abbreviated version of the function that I hoped would do that:
function paintLinkNameOnCanvas(linkName, canvas){
let context = canvas.getContext('2d');
context.font = "25px jelleebold";
context.fillText(linkName, 50, 50);
return canvas;
}
However, the font that gets used is whatever the browser (Chrome) uses as its fallback (Times New Roman, I think). Here's the html link
<link href="./CSS/stylesheet.css" rel="stylesheet" type="text/css">
and the css, downloaded from fontsquirrel, and modified to suit my local directory structure:
#font-face {
font-family: jelleebold;
src: url('/fonts/jellee-roman-webfont.woff2') format('woff2'),
url('/fonts/jellee-roman-webfont.woff') format('woff');
font-weight: normal;
font-style: normal;
}
I believe that this has worked, and Jelleebold has loaded successfully, because index.php contains:
<body style ="font-size: 50px; font-family: 'jelleebold'">
<div id= "output" >
test
</div>
etc.
and the word 'test' gets printed in jelleebold.
In contrast, if the paintLinkNameOnCanvas function specifies a font that is installed on the local machine (such as context.font = "25px 'Balford Base'"), the linkname does get painted in that font.
So why isn't the custom font being used to paint the linkname on the canvas?
And after a very helpful suggestion from Renato Bibiano, I've now produced an updated version of the function (shown below). The commented lines are a hint about the next problem; how do I get it to work with both woff- and woff2-formatted fonts? It works with either one, but not the other.
function paintLinkNameOnCanvas(linkName, canvas){
let earl = "";
// earl += "url('/fonts/jellee-roman-webfont.woff' ) format('woff' ";
// earl += ", ";
earl += "url('/fonts/jellee-roman-webfont.woff2')format('woff2')";
let f = new FontFace("jelleebold", earl);
f.load().then(function() {
let context = canvas.getContext('2d');
context.font = '23px jelleebold';
context.fillText('Hey, world', 0, 100);
});
return canvas;
}
I feel that taking the comment slashes out should produce something sensible, but if both specifications (woff and woff2) are included, the ouput reverts to the default font, TNR.

Set Font Awesome icons as cursor - is this possible?

Font Awesome has a very good collection of icons to be used in web projects. I want to use one of those icons as cursor (custom cursor).
In my understanding, Custom Cursors need an image url, but I am unable to find the image urls for Font Awesome icons.
Got it!
Create a canvas
Draw the fa icon on it
Change it into a base-64 image url
Apply the image on the cursor css style
And I made a demo: http://jsfiddle.net/rqq8B/2/
// http://stackoverflow.com/questions/13761472/how-to-render-glyphs-from-fontawesome-on-a-canvas-element
// http://stackoverflow.com/questions/13932291/css-cursor-using-data-uri
$(function() {
var canvas = document.createElement("canvas");
canvas.width = 24;
canvas.height = 24;
//document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#000000";
ctx.font = "24px FontAwesome";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("\uf002", 12, 12);
var dataURL = canvas.toDataURL('image/png')
$('body').css('cursor', 'url('+dataURL+'), auto');
});
body {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
In the end, I couldn't get #fish_ball's code working reliably, so I just downloaded the images, used gimp to crop and edit them to 32×32px, and used them like this:
.myClass { cursor: url('/static/img/pencil30_32x32.png') 1 30, crosshair }
The 1 30 part sets the mouse pointer 'hotspot' 1px from the left and 30px from the top of the image.
There is jQuery Awesome Cursor, where you can add font-awesome icons to your cursor by calling only one simple code:
$('body').awesomeCursor('pencil');
Or passing it some options:
$('body').awesomeCursor('pencil', {
/* your options here */
size: 22,
color: 'orange',
flip: 'horizontal'
});
Disclaimer: I am NOT the author of this library I have just found it.
The canvas method mentioned results in blurry cursors.
Using SVG offers better results:
Download the SVG for the icon you want to use from Encharm's Font-Awesome-SVG-PNG.
Edit the SVG using a text editor and specify the width and height you'd like to use
e.g.: 24 x 24.
Keep in mind there's usually a maximum size in the browser (128 x 128 in Firefox.)
Declare the cursor in CSS, e.g.: cursor: url( '/assets/img/volume-up.svg' ), pointer;
For anyone using Vue.js, there is an easier approach:
Importing font awesome icon as a component:
import { library } from '#fortawesome/fontawesome-svg-core';
import { fas } from '#fortawesome/free-solid-svg-icons';
import { fab } from '#fortawesome/free-brands-svg-icons';
import { far } from '#fortawesome/free-regular-svg-icons';
import { FontAwesomeIcon } from '#fortawesome/vue-fontawesome';
library.add(fas);
library.add(fab);
library.add(far);
Vue.component('fa-icon', FontAwesomeIcon);
and using it directly in the HTML of a page:
<fa-icon icon="copy" #click="yourFunction"/>
and surrounding your tag with <span>:
<span class="hover"><fa-icon icon="copy" #click="yourFunction"/></span>
and adding to your css:
span.hover {
cursor: pointer;
}
This will add a pointer on all <span> tags with class hover in your code (and thus your font awesome icons !)

Javascript Clock output text style

I have a clock on my website written in javascript which I got from the internet and modified it slightly to fit my needs better and it looks great on firefox using a mac, but when I use it in other browsers on a PC or Mac it looks terrible and I have no idea how to change it, I'm fairly new to javascript. The code i'm using is below:
var alternate=0
var standardbrowser=!document.all&&!document.getElementById
if (standardbrowser)
document.write('')
function show(){
if (!standardbrowser)
var clockobj=document.getElementById? document.getElementById("digitalclock") : document.all.digitalclock
var Digital=new Date()
var hours=Digital.getHours()
var minutes=Digital.getMinutes()
var dn="AM"
if (hours==12) dn="PM"
if (hours>12){
dn="PM"
}
if (hours==0) hours=0
if (hours.toString().length==1)
hours="0"+hours
if (minutes<=9)
minutes="0"+minutes
if (standardbrowser){
if (alternate==0)
document.tick.tock.value=hours+" : "+minutes+" "+dn
else
document.tick.tock.value=hours+" "+minutes+" "+dn
}
else{
if (alternate==0)
clockobj.innerHTML=hours+" : "+minutes
else
clockobj.innerHTML=hours+" : "+minutes
}
alternate=(alternate==0)? 1 : 0
setTimeout("show()",1000)
}
window.onload=show
I am looking to be able to set the font and size of the clock to be uniform across most browsers if not all, i'm not too bothered about IE because to site is terrible in ie anyway and will get round to sorting that out in the future.
You can use CSS to do this. Your clock is being displayed in a container with an ID of digitalclock. That means you can define style rules in an external stylesheet, inline or in the <head> of your .html file:
#digitalclock {
font-size: 1em;
font-family: arial, helvetica, sans-serif;
font-weight: normal;
color: red;
/* and whatever other rules you want */
}
why don't you just style the containing html element (#digitalclock) via css?

Categories

Resources