I want to be able to:
Get the Font Awesome 5 unicode character for any given Font Awesome class name (fas fa-check-circle, etc...)
Draw that unicode character to an html5 canvas
How would I go about doing this?
To get the correct unicode character and other important data for a Font Awesome 5 icon class and draw it onto an html5 canvas:
// create an icon with the Font Awesome class name you want
const i = document.createElement('i');
i.setAttribute('class', 'fas fa-check-circle');
document.body.appendChild(i);
// get the styles for the icon you just made
const iStyles = window.getComputedStyle(i);
const iBeforeStyles = window.getComputedStyle(i, ':before');
const fontFamily = iStyles.getPropertyValue('font-family');
const fontWeight = iStyles.getPropertyValue('font-weight');
const fontSize = '40px'; // just to make things a little bigger...
const canvasFont = `${fontWeight} ${fontSize} ${fontFamily}`; // should be something like: '900 40px "Font Awesome 5 Pro"'
const icon = String.fromCodePoint(iBeforeStyles.getPropertyValue('content').codePointAt(1)); // codePointAt(1) because the first character is a double quote
const ctx = myCanvas.getContext('2d');
ctx.font = canvasFont;
ctx.fillStyle = 'red';
ctx.textAlign = 'center';
ctx.fillText(icon, myCanvas.width / 2, myCanvas.height / 2);
When you do this, make sure the Font Awesome 5 font has actually loaded when you do the drawing. I made the mistake of only drawing once when I was testing and it resulted in only a box showing up. When the icon has loaded it should appear like this:
Related
I am trying to change the default font style of the canvas text to Press Start 2P
I have imported the url into a css file like so
#import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
.canvasClass{
font-family: 'Press Start 2P';
}
<Box className='canvasClass'>
<Canvas2/>
</Box>
and im trying to draw some text like this:
context.fillStyle = 'rgba(194,213,219,0.8)'
context.font = "42px Press Start 2P";
context.textAlign = 'center'
I can confirm that the font is being applied to the parent div, however I cannot apply my desired font to the canvas that is inside that div. Why would I have trouble applying the font to the canvas if it works with other text components in the same div?
EDIT:
I would like to add that I change font to Roboto (I'm assuming another Google font)
You need to wrap the font family name in quotes like you did in your CSS declaration.
context.fillStyle = 'rgba(194,213,219,0.8)'
context.font = "42px 'Press Start 2P'";
context.textAlign = 'center'
Also, wait for document.fonts.ready to be sure the external font has been loaded before you use it in your canvas.
(async () => {
await document.fonts.ready;
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
context.fillStyle = 'rgba(194,213,219,0.8)'
context.font = "42px 'Press Start 2P'";
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText('Hello world', canvas.width/2, canvas.height/2);
})().catch(console.error);
#import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
.canvasClass{
font-family: 'Press Start 2P';
}
<div class=canvasClass>
<canvas width=500 height=150></canvas>
</div>
I am trying to create a little game in a pixel retro look and I am using a pixelated font. Unfortunately I am unable to render the font with edges as sharp as they are in the source font.
About my mcve:
I am using this font for fonts/pokemon_classic.ttf (I found no way to host that font online, so no jsfiddle), but you can use any pixel font you like.
The example below renders the font like this:
How can I make this text render as sharp as it is in the source font? It should look like this (edited image):
the scale of root may change during runtime to fit the screen
A less elegant solution which would probably work is to fix the alpha of each pixel to be either 0 or 1 depending on some threshold, but I don't know how to do this.
JS:
PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
let scale = 30;
let app = new PIXI.Application();
document.body.appendChild(app.view);
app.renderer.view.style.position = "absolute";
app.renderer.view.style.display = "block";
app.renderer.autoResize = true;
app.renderer.resize(window.innerWidth, window.innerHeight);
let root = new PIXI.Container();
app.stage.addChild(root);
root.scale.set(scale);
document.fonts.load('8pt "pokemon"').then(() => {
let text = new PIXI.Text("Test", {fontFamily: 'pokemon', fontSize: 8, fill: 0xff1010});
root.addChild(text);
});
CSS:
#font-face {
font-family: 'pokemon';
src: url("fonts/pokemon_classic.ttf");
}
* {
padding: 0;
margin: 0;
}
Things that can make text blurry....
SCALE_MODE
Sub-pixel positioning. Turn on roundPixels when creating new PIXI.Application for v4, v5 you can set globally via PIXI.settings.ROUND_PIXELS = true;, or indivudally, displayObject.roundPixels = true;
Scaling
So you're good on #1, but #2 and #3 could be issues.
I resolved it by setting resolution like this:
text.resolution = window.devicePixel * scale
It will re-render the text leading to bad performance, so I just apply it for the last value of scale.
If you don't mind having a double resolution for the whole app...
My Pixi.js text and textures were blurry.
I increased the resolution of the whole Pixi app.
Then your canvas size will double.
You can then you options.autoDensity to fit double resolution in the same canvas. https://pixijs.download/dev/docs/PIXI.Application.html
// Pixi.js API from v6.5.1
import * as PIXI from 'pixi.js';
PIXI.settings.PRECISION_FRAGMENT = PIXI.PRECISION.HIGH; // might help a bit
PIXI.settings.ROUND_PIXELS = true; // might help a bit
PIXI.settings.RESOLUTION = 2;
const app = new PIXI.Application({ width: 750, height: 400, autoDensity: true });
I'm making a whiteboard app just for fun and have tools like the brush tool, eraser, etc and I draw on an HTML5 canvas.
I'm trying to implement custom cursors for my tools (like brush, line, square) and was just going to use the CSS cursor property depending on which tool is selected but I'd like sizes to vary depending on the current line width.
For example, in MS Paint you'll notice with the brush and eraser tool, depending on the size of the line width, the cursor is differently sized when drawing on the canvas.
So I have two questions. The first is if I can use CSS still and somehow alternate the cursor size dynamically from JS.
The second is how you would implement this solution by just deleting the cursor and drawing your own on the canvas that follows the mouse movement. I'm a bit concerned that the latter would be quite glitchy and more complex so am hoping that the first one is possible.
Maintaining the position of your own cursor does not work very well on the browsers. By the time you have handled the mouse move, waited for the next animation frame you are one frame behind. (drawing immediately to canvas in the mouse event does help) The is very off putting, even if you set the cursor to "none" so the two do not overlap, the 1/60th of a second can make a big difference from where you see your rendered cursor to and where the hardware cursor (for want of a better name) is.
But it turns out that the browsers Chrome and Firefox allow you to have full control of the hardware cursor image. I have personally exploited it to the limits and it is a robust and tolerant system.
I started with pre made cursors as DataURLs. But now most of my cursors are dynamic. If a control uses the mouse wheel, I add the wheel indicator on the cursor, when using resize cursor, instead of 8 directions N, NE, E, SE, S, SW, W, NW It is created on demand to line up with whatever I happen to be resizing at what ever angle it is. When drawing the cursor is continuously reorienting to avoid covering pixels I may be working on.
To set a custom cursor, set the elements style.cursor to an image URL, followed by two numbers that are the hotspot (Where the click is focused), and a cursor name. I just use the same name "pointer" and generate the image URL on the fly with toDataURL.
Below is a quick example of changing the cursor dynamically. I am unsure what the limits are in terms of size, but so far I haven't wanted a cursor that it has not given me. Some of them, in games have been very big (lol as cursors go) (128*128 pixels +)
Note a slight bug in code. Will return to fix the first rendered word being clipped soon.
The only issue with this is IE does not support this what of doing cursors, so you will need a fallback
// create an image to use to create cursors
var image = document.createElement("canvas");
image.width = 200;
image.height = 14;
image.ctx = image.getContext("2d");
// some graphic cursors
var cursors = [
"url('data:image/png;base64,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') 0 0, cursor",
"url('data:image/png;base64,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') 0 0, cursor ",
"url('data:image/png;base64,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') 0 0, cursor "
];
// Do the stuff that does the stuff
var el = document.getElementById("customeCurs");
var over = false;
// set up canvas rendering
var c = image.ctx;
// some stuff to say and ABC are graphic flags
var stuff = "A C Hello pointy clicky things are great and easy to use A B C B".split(" ");
var tHandle;
var wordPos=0;
function createCursor(){ // creates cursors from the canvas
// get a word from the word list
var w = stuff[wordPos % stuff.length];
if(w === "A" || w === "B" || w === "C"){ // display graphics cursor
// just for fun. to much time on
// my hands. I really need a job.
var datURL;
switch(w){
case "A":
datURL = cursors[0];
break;
case "B":
datURL = cursors[1];
break;
case "C":
datURL = cursors[2];
}
el.style.cursor = datURL;
}else{ // create a dynamic cursor from canvas image
// get the size. Must do this
var size = c.measureText(w).width + 4;
// resize the canvas
image.width = size;
image.height = 36;
c.font = "28px arial black";
c.textAlign ="center";
c.textBaseline = "middle";
c.lineCap = "round";
c.lineJoin = "round";
// Please always give user a visual guide to the hotspot.
// following draws a little arrow to the hotspot.
// Always outline as single colours can get lost to the background
c.lineWidth = 3;
c.strokeStyle = "white";
c.moveTo(1,5);
c.lineTo(1,1);
c.lineTo(5,1);
c.moveTo(1,1);
c.lineTo(8,8);
c.stroke();
c.strokeStyle = "black";
c.lineWidth = 1;
c.moveTo(1,5);
c.lineTo(1,1);
c.lineTo(5,1);
c.moveTo(1,1);
c.lineTo(8,8);
c.stroke();
c.lineWidth = 5;
c.strokeStyle = "black";
c.fillStyle = "White";
// Draw the text outline
c.strokeText(w, image.width / 2, image.height / 2+2);
// and inside
c.fillText(w, image.width / 2, image.height / 2);
// create a cursor and add it to the element CSS curso property
el.style.cursor = "url('"+image.toDataURL("image/png")+"') 0 0 , pointer"; // last two
// numbers are the
// cursor hot spot.
}
// Next word
wordPos += 1;
// if the mouse still over then do it again in 700 ticks of the tocker.
if(over){
tHandle = setTimeout(createCursor,700);
}
}
// mouse over event to start cursor rendering
el.addEventListener("mouseover",function(){
over = true;
if(tHandle === undefined){
createCursor();
}
});
el.addEventListener("mouseout",function(){
over = false; // clean up if the mouse moves out. But leave the cursor
clearTimeout(tHandle);
tHandle = undefined;
});
<div id="customeCurs" >Move Mouse Over ME.</div>
<!-- Some say don't put style in HTML doc! The standards are indifferent. The author is lazy :P -->
<span style="font-size:small;color:#BBB;">Sorry IE again you miss out.</span>
I'm trying to recreate a Snapchat "snap" with HTML5 Canvas. The part that has me stumped is getting the font to look the same. The font Snapchat uses seems to be Helvetica, but I can't get my text to look the same as that of a real snap.
Here's my attempt of matching the font. I've drawn my text on top of an actual screenshot of a snap so it's easy to compare. You can edit the JavaScript variables to try to match the text (JSFiddle: http://jsfiddle.net/9RB88/1/).
HTML:
<img src='http://i.imgur.com/tivQ8xJ.jpg'>
<canvas width='640' height='1136'></canvas>
CSS:
img {display:none}
JavaScript:
//--- EDIT THESE ----------------
// text styles...
var fontFamily = 'Helvetica';
var fontSize = '35px';
var fontWeight = 'normal';
// http://css-tricks.com/almanac/properties/f/font-weight/
var onTop = false;
// set this to "true" to place our text on top of the real text (for more precise comparing)
var differentColours = false;
// draw our text/background different colours, making it easier to compare (use when "onTop" is "true")
// tweak where the text is drawn
var horOffset = 2;
var vertOffset = 0;
//-------------------------------
var can = document.getElementsByTagName('canvas')[0];
var c = can.getContext('2d');
c.fillStyle = 'white';
c.fillRect(0, 0, can.width, can.height);
var img = document.getElementsByTagName('img')[0];
c.drawImage(img, 0, 0);
var top;
if(onTop) top = 531;
else top = 450;
if(differentColours) c.fillStyle = 'orange';
else c.fillStyle = 'black';
c.globalAlpha = 0.6;
c.fillRect(0, top, can.width, 74);
c.globalAlpha = 1;
var text = 'Template example thingy $&#?! 123';
if(differentColours) c.fillStyle = 'red';
else c.fillStyle = 'white';
c.textAlign = 'center';
c.font = fontWeight + ' ' + fontSize + ' ' + fontFamily;
c.fillText(text, can.width/2 + horOffset, top + 50 + vertOffset);
JSFiddle: http://jsfiddle.net/9RB88/1/
It seems like one of the issues is letter spacing, but that's not possible to change in HTML5 Canvas.
What can I do?
Snapchat may embed a very specific variant or similar font to Helvetica. That doesn't mean the user loading the page (incl. on your own machine) will have that font installed on the system.
If the user doesn't have the font installed the browser will look for similar fonts, for example, it will use Arial on Windows and if that is not available use another sans-serif font. On Mac and Linux the same thing. This mean it will perhaps closely match but will not be the same font. If they don't use a web font the snap could have been taken on a different OS then you are using resulting in a different font being rendered.
Or in other words - when you specify "Helvetica" as font family the system will try to find a font in that family but it isn't given that Helvetica is the font you'll get. The browser will try to find the closest matching font available on the system in use.
You have to embed the very same font they are using as a web font otherwise there is no guarantee that the font will be the same.
To find out which font they are using (if any) open the stylesheets they're using.
My 2 cents..
Is there a way to only change the font size of a canvas context without having to know/write the font family.
var ctx = document.getElementById("canvas").getContext("2d");
ctx.font = '20px Arial'; //Need to speficy both size and family...
Note:
ctx.fontSize = '12px'; //doesn't exist so won't work...
ctx.style.fontSize = '20 px' //doesn't exist so won't work...
//we are changing the ctx, not the canvas itself
Other note: I could do something like: detect where 'px' is, remove what's before 'px' and replace it by my font size. But I'd like something easier than that if possible.
Here is an easier and cleaner way of changing the font size that will work regardless if you are using font-variant or font-weight or not.
First some RegEx to match and return the current font size
const match = /(?<value>\d+\.?\d*)/;
Set an absolute size, assuming your new font size is 12px
ctx.font = ctx.font.replace(match, 12);
Set a relative size, increase by 5:
const newSize = parseFloat(ctx.font.match(match).groups.value + 5);
ctx.font = ctx.font.replace(match, newSize);
Working example:
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
// Match on digit at least once, optional decimal, and optional digits
// Named group `value`
const match = /(?<value>\d+\.?\d*)/;
const setFontSize = (size) => ctx.font = ctx.font.replace(match, size);
const adjustFontSize = (amount) => {
const newSize = parseFloat(ctx.font.match(match).groups.value + amount);
return ctx.font = ctx.font.replace(match, newSize);
}
// Default font is 12px sans-serif
console.log( setFontSize(18) ); // 18px sans-serif
console.log( adjustFontSize(2) ); // 20px sans-serif
console.log( adjustFontSize(-5) ); // 15px sans-serif
<canvas id="canvas"></canvas>
Update: (from comments) There is no way around specifying font. The Canvas' font is modeled after the short-hand version of font in CSS.
However, there is always a font set on the canvas (or a font type) so what you can do is to first extract the current font by using it like this:
var cFont = ctx.font;
Then replace size arguments and set it back (note that there might be a style parameter there as well).
A simple split for the sake of example:
var fontArgs = ctx.font.split(' ');
var newSize = '12px';
ctx.font = newSize + ' ' + fontArgs[fontArgs.length - 1]; /// using the last part
You will need support for style if needed (IIRC it comes first if used).
Notice that font-size is fourth parameter, so this will not work if you will have/not have font-variant(bold,italic,oblique), font-variant(normal, small-caps) and font-weight(bold etc).
A cleaner way to not worry about scraping every other parameter:
canvas.style.font = canvas.getContext("2d").font;
canvas.style.fontSize = newVal + "px";
canvas.getContext("2d").font = canvas.style.font;
Explanation:
As mentioned in the first answer, the canvas context will always have a font. So canvas.getContext("2d").font might return something like "10px sans-serif". To not scrape this string we can use the Canvas DOM element (or any other element) to parse the full font spec and populate the other font fields. Which means that after setting:
canvas.style.font = "10px sans-serif";
canvas.style.fontSize = "26px";
the canvas.style.font will become "26px sans-serif". We can then pass this font spec back to the canvas context.
To correctly answer your question, there is no way to change the font size of a canvas context without having to know/write the font family.
try this (using jquery):
var span = $('<span/>').css('font', context.font).css('visibility', 'hidden');
$('body').append(span);
span[0].style.fontWeight = 'bold';
span[0].style.fontSize = '12px';
//add more style here.
var font = span[0].style.font;
span.remove();
return font;