Kokkoja as of 2026-10-10: the teacher's requests, the Session window, notices, the QR code, the license
This commit is contained in:
1 parent
95c80d04c9
commit
1d087af633
32 files changed
+4917
-890
No files matched your search
@@ -14,9 +14,10 @@ export const LINE_HEIGHT = 1.25;
|
||||
|
||||
/**
|
||||
* Room between a block's top edge and its first line, as a multiple of
|
||||
* the font size (Andy, 2026-10-03: the text should not sit on the edge).
|
||||
* the font size (Andy, 2026-10-03: the text should not sit on the edge;
|
||||
* halved from 0.3 on 2026-10-09).
|
||||
*/
|
||||
export const TOP_GAP = 0.3;
|
||||
export const TOP_GAP = 0.15;
|
||||
|
||||
/**
|
||||
* Room between a block's left edge (its corner square) and the text, as a
|
||||
@@ -51,6 +52,42 @@ export function textWidth(text, size, family) {
|
||||
return measurer.measureText(text).width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Where the baseline of line `i` of a block lies below the block's top, in
|
||||
* page units, placed as a browser places text in a line box: the gap, then
|
||||
* half the leading (the line height less the font's own ascent and
|
||||
* descent), then the ascent. The text field and the canvas then agree
|
||||
* to the pixel (Andy, 2026-10-09: the text moved when editing ended).
|
||||
* @param {number} size
|
||||
* @param {string} family
|
||||
* @param {number} i
|
||||
* @returns {number}
|
||||
*/
|
||||
export function baselineOf(size, family, i) {
|
||||
const { ascent, descent } = fontMetrics(size, family);
|
||||
const halfLeading = (size * LINE_HEIGHT - ascent - descent) / 2;
|
||||
return size * (TOP_GAP + i * LINE_HEIGHT) + halfLeading + ascent;
|
||||
}
|
||||
|
||||
/**
|
||||
* The font's ascent and descent, in page units, as the browser lays
|
||||
* lines out with them.
|
||||
* @param {number} size
|
||||
* @param {string} family
|
||||
* @returns {{ascent: number, descent: number}}
|
||||
*/
|
||||
export function fontMetrics(size, family) {
|
||||
if (!measurer) {
|
||||
measurer = /** @type {CanvasRenderingContext2D} */ (document.createElement('canvas').getContext('2d'));
|
||||
}
|
||||
measurer.font = fontOf(size, family);
|
||||
const metrics = measurer.measureText('Mg');
|
||||
return {
|
||||
ascent: metrics.fontBoundingBoxAscent ?? size * 0.8,
|
||||
descent: metrics.fontBoundingBoxDescent ?? size * 0.2,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Break one paragraph into lines no wider than `width`. Breaks come at
|
||||
* spaces; a word wider than the width is broken where it must be.
|
||||
|
||||
Reference in new issue
Block a user