The names of fonts are rendered using the corresponding font.
Each font's name is rendered to an OffscreenCanvas, and that image is cached in OPFS. There's a list of links to download font files in the preview.
This commit is contained in:
parent
51d57259b0
commit
a4b046a784
3 changed files with 165 additions and 15 deletions
84
script.js
84
script.js
|
@ -79,7 +79,8 @@ const css_template = (info,range,weight,style,variable_info) => {
|
|||
if(axes.includes('slnt')) {
|
||||
extras.push(` font-style: oblique ${variable_info.axes.slnt.min}deg ${variable_info.axes.slnt.max}deg;`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(info.variable) {
|
||||
return `
|
||||
|
@ -113,6 +114,52 @@ async function fetch_json(url) {
|
|||
}
|
||||
|
||||
|
||||
async function draw_font_preview(f) {
|
||||
const d = await navigator.storage.getDirectory();
|
||||
const filename = `${f.family}.png`;
|
||||
let fh;
|
||||
try {
|
||||
fh = await d.getFileHandle(filename);
|
||||
} catch(e) {
|
||||
const style = document.createElement('style');
|
||||
try {
|
||||
document.head.append(style);
|
||||
const info = await fetch_json(font_info_url(f.id));
|
||||
const variable_info = info.variable ? await fetch_json(variable_info_url(info.id)) : {};
|
||||
const css = css_template(info,info.defSubset,info.weights[0],'normal',variable_info);
|
||||
style.textContent += css;
|
||||
await new Promise((resolve,reject) => {
|
||||
setTimeout(async () => {
|
||||
const ffs = Array.from(document.fonts).filter(ff=>ff.family == `"${f.family}"`);
|
||||
await Promise.all(ffs.map(ff => ff.load())).catch(reject)
|
||||
resolve();
|
||||
},1);
|
||||
});
|
||||
} catch(e) {
|
||||
return;
|
||||
}
|
||||
const cv = new OffscreenCanvas(1,1);
|
||||
const ctx = cv.getContext('2d');
|
||||
const font_style = `100px "${f.family}"`;
|
||||
ctx.font = font_style;
|
||||
const {width, fontBoundingBoxAscent, fontBoundingBoxDescent} = ctx.measureText(f.family);
|
||||
cv.width = width;
|
||||
cv.height = fontBoundingBoxAscent + fontBoundingBoxDescent;
|
||||
ctx.font = font_style;
|
||||
ctx.fillText(f.family,0,fontBoundingBoxAscent);
|
||||
const blob = await cv.toBlob();
|
||||
fh = await d.getFileHandle(filename,{create:true});
|
||||
const w = await fh.createWritable();
|
||||
await w.write(blob);
|
||||
await w.close();
|
||||
window.blob = blob;
|
||||
style.parentElement.removeChild(style);
|
||||
}
|
||||
const file = await fh.getFile();
|
||||
return URL.createObjectURL(file);
|
||||
|
||||
}
|
||||
|
||||
|
||||
async function go() {
|
||||
let [fonts, axes_info] = await Promise.all([
|
||||
|
@ -120,14 +167,20 @@ async function go() {
|
|||
fetch_json('https://api.fontsource.org/v1/axis-registry')
|
||||
]);
|
||||
|
||||
window.available_fonts = fonts;
|
||||
|
||||
axes_info = Object.fromEntries(Object.entries(axes_info).map(([k,v]) => [k.toLowerCase(), v]));
|
||||
|
||||
async function use_font() {
|
||||
const name = select.value;
|
||||
console.log(name);
|
||||
const info = await fetch_json(font_info_url(name));
|
||||
const variable_info = info.variable ? await fetch_json(variable_info_url(info.id)) : {};
|
||||
console.log(info);
|
||||
|
||||
const preview = document.querySelector(`[data-font="${name}"]`);
|
||||
if(preview) {
|
||||
preview.scrollIntoView({block: 'center'});
|
||||
document.body.scrollTop = 0;
|
||||
}
|
||||
|
||||
document.body.style.setProperty('--family',info.family);
|
||||
|
||||
|
@ -153,7 +206,6 @@ async function go() {
|
|||
if(info.variable) {
|
||||
const variable_axes = document.getElementById('variable-axes');
|
||||
variable_axes.innerHTML = '';
|
||||
console.log(variable_info);
|
||||
|
||||
const ranges = {};
|
||||
|
||||
|
@ -208,7 +260,6 @@ async function go() {
|
|||
document.body.style['font-variation-settings'] = settings;
|
||||
}
|
||||
update_variables();
|
||||
|
||||
}
|
||||
|
||||
const css_declarations = [];
|
||||
|
@ -240,7 +291,7 @@ async function go() {
|
|||
}
|
||||
|
||||
|
||||
fonts = fonts.filter(f=>!f.id.includes('noto'));
|
||||
fonts = fonts.filter(f=>!f.id.match(/noto|playwrite/i));
|
||||
select.innerHTML = '';
|
||||
for(let font of fonts) {
|
||||
const option = document.createElement('option');
|
||||
|
@ -260,6 +311,27 @@ async function go() {
|
|||
document.getElementById('random-font').addEventListener('click', random_font);
|
||||
|
||||
random_font();
|
||||
|
||||
const fl = document.getElementById('font-list');
|
||||
const step = 10;
|
||||
for(let i=0;i<fonts.length;i+=step) {
|
||||
await Promise.all(fonts.slice(i+0,i+step).map(async f => {
|
||||
const li = document.createElement('li');
|
||||
fl.append(li);
|
||||
const a = document.createElement('a');
|
||||
li.append(a);
|
||||
a.addEventListener('click', () => {
|
||||
select.value = f.id;
|
||||
use_font();
|
||||
})
|
||||
const img = document.createElement('img');
|
||||
img.dataset.font = f.id;
|
||||
a.append(img);
|
||||
img.src = await draw_font_preview(f);
|
||||
img.style.height = '1em';
|
||||
img.alt = f.family;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
go();
|
Loading…
Add table
Add a link
Reference in a new issue