Skip to content

Commit

Permalink
Pre-calculate line height for fonts (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
LucaScorpion authored Jan 3, 2024
1 parent f30f7e8 commit 6f5efa7
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 17 deletions.
4 changes: 2 additions & 2 deletions src/badge/badgeElements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { PackageInfo } from '../packageInfo';
import { formatNumber } from '../utils/formatNumber';
import { COLORS } from './colors';
import { timeAgo } from '../utils/timeAgo';
import { FONTS } from './fonts';
import { Font, FONTS } from './fonts';
import { InstallMode } from '../installMode';

export interface BadgeElements {
Expand All @@ -16,7 +16,7 @@ export interface BadgeElements {

export interface TextElement {
text: string;
font: string;
font: Font;
color: string;
}

Expand Down
9 changes: 3 additions & 6 deletions src/badge/drawBadge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Canvas, CanvasRenderingContext2D, PNGStream } from 'canvas';
import { PackageInfo } from '../packageInfo';
import { initFonts } from './fonts';
import { getBadgeElements } from './badgeElements';
import { drawText, getTextSizes } from './text';
import { COLORS } from './colors';
Expand All @@ -10,13 +9,11 @@ const BORDER_WIDTH = 2;
const PADDING = 9;
const LINE_SPACING = 2;
const LOGO_SPACING_RIGHT = 14;
const PKG_INFO_Y = 7;
const INSTALL_CMD_Y = 7;
const PKG_INFO_COL_SPACING = 14;
const NPM_LOGO_Y = 1;
const NPM_LOGO_X = BORDER_WIDTH + PADDING;

initFonts();

/*
+---------------------------------------------------+
| N npm install package |
Expand All @@ -41,7 +38,7 @@ export function drawBadge(
Math.max(sizes.dependencyCount.width, sizes.weeklyDownload.width) +
PKG_INFO_COL_SPACING;
const pkgInfoRowOneY =
PKG_INFO_Y + sizes.installCommand.height + LINE_SPACING;
INSTALL_CMD_Y + sizes.installCommand.height + LINE_SPACING;
const pkgInfoRowTwoY =
pkgInfoRowOneY +
Math.max(sizes.dependencyCount.height, sizes.version.height) +
Expand All @@ -62,7 +59,7 @@ export function drawBadge(

drawBorder(ctx, canvas.width, canvas.height);
drawText(ctx, elems.npmLogo, NPM_LOGO_X, NPM_LOGO_Y);
drawText(ctx, elems.installCommand, pkgInfoX, PKG_INFO_Y);
drawText(ctx, elems.installCommand, pkgInfoX, INSTALL_CMD_Y);
drawText(ctx, elems.dependencyCount, pkgInfoX, pkgInfoRowOneY);
drawText(ctx, elems.weeklyDownload, pkgInfoX, pkgInfoRowTwoY);
drawText(ctx, elems.version, pkgInfoRightColX, pkgInfoRowOneY);
Expand Down
42 changes: 36 additions & 6 deletions src/badge/fonts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import path from 'path';
import { registerFont } from 'canvas';
import { Canvas, registerFont } from 'canvas';

// All characters that we use in the badge, used to calculate font heights.
const allCharacters = `abcdefghijklmnopqrstuvwxyz0123456789.,:-_/@`;

const fontFiles = [
{
Expand All @@ -17,22 +20,49 @@ const fontFiles = [
},
];

export const FONTS = {
npm: '50px gubblebum',
bold: 'bold 14px "Ubuntu Mono"',
regular: '13px "Ubuntu Mono"',
export interface Font {
name: string;
lineHeight: number;
}

export const FONTS: Record<string, Font> = {
npm: {
name: '50px gubblebum',
lineHeight: 0,
},
bold: {
name: 'bold 14px "Ubuntu Mono"',
lineHeight: 0,
},
regular: {
name: '13px "Ubuntu Mono"',
lineHeight: 0,
},
};

export function initFonts(): void {
for (const font of fontFiles) {
console.debug(`Registering font: ${font.family}`);
registerFont(font.file, {
family: font.family,
weight: font.weight || undefined,
weight: font.weight ?? undefined,
});
}

for (const font of Object.values(FONTS)) {
font.lineHeight = calculateFontLineHeight(font.name);
}
}

function fontPath(file: string): string {
return path.join(__dirname, '../../fonts', file);
}

function calculateFontLineHeight(font: string): number {
const canvas = new Canvas(0, 0);
const ctx = canvas.getContext('2d');
ctx.antialias = 'subpixel';
ctx.font = font;
const metrics = ctx.measureText(allCharacters);
return metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
}
6 changes: 3 additions & 3 deletions src/badge/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function drawText(
x: number,
y: number
): void {
ctx.font = elem.font;
ctx.font = elem.font.name;
ctx.fillStyle = elem.color;
ctx.fillText(elem.text, x, y);
}
Expand All @@ -21,12 +21,12 @@ export function getTextSize(
ctx: CanvasRenderingContext2D,
elem: TextElement
): TextSize {
ctx.font = elem.font;
ctx.font = elem.font.name;
const metrics = ctx.measureText(elem.text);

return {
width: metrics.width,
height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent,
height: elem.font.lineHeight,
};
}

Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { getPackageInfo } from './packageInfo';
import { drawBadge } from './badge/drawBadge';
import { packageNameMiddleware } from './packageNameMiddleware';
import { parseInstallMode } from './installMode';
import { initFonts } from './badge/fonts';

initFonts();

const app = express();
app.use(express.static('_site'));
Expand Down

0 comments on commit 6f5efa7

Please sign in to comment.