@simple-mark/canvas 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +27 -5
  2. package/package.json +3 -3
package/index.js CHANGED
@@ -359,9 +359,26 @@ function createMathImages(onReady) {
359
359
  //#endregion
360
360
  //#region packages/canvas/src/paint.ts
361
361
  const PLACEHOLDER = "rgba(129, 139, 152, 0.15)";
362
+ /**
363
+ * Where text sits in its line, as a browser places it: the line's extra height (half-leading)
364
+ * split above and below the font's ascent + descent, the glyphs on the baseline. Falls back to
365
+ * the layout's estimate where a browser doesn't give font metrics.
366
+ */
367
+ function baseline(ctx, run) {
368
+ const metrics = ctx.measureText("x");
369
+ const ascent = metrics.fontBoundingBoxAscent;
370
+ const descent = metrics.fontBoundingBoxDescent;
371
+ if (!(ascent > 0) || !(descent >= 0)) return {
372
+ y: run.textTop,
373
+ alphabetic: false
374
+ };
375
+ return {
376
+ y: run.top + (run.height - (ascent + descent)) / 2 + ascent,
377
+ alphabetic: true
378
+ };
379
+ }
362
380
  function paintMarkdown(ctx, layout, sources = {}, color = "#1f2328") {
363
381
  ctx.save();
364
- ctx.textBaseline = "top";
365
382
  ctx.textAlign = "left";
366
383
  for (const line of layout.lines) {
367
384
  if (line.background) {
@@ -375,6 +392,8 @@ function paintMarkdown(ctx, layout, sources = {}, color = "#1f2328") {
375
392
  }
376
393
  for (const run of layout.runs) {
377
394
  ctx.font = run.font;
395
+ const { y, alphabetic } = baseline(ctx, run);
396
+ ctx.textBaseline = alphabetic ? "alphabetic" : "top";
378
397
  if (run.background) {
379
398
  ctx.fillStyle = run.background;
380
399
  ctx.fillRect(run.x, run.textTop - run.fontSize * .1, run.width, run.fontSize * 1.2);
@@ -384,18 +403,21 @@ function paintMarkdown(ctx, layout, sources = {}, color = "#1f2328") {
384
403
  let x = run.x;
385
404
  for (const ch of run.text) {
386
405
  const cell = charWidth(ch.codePointAt(0)) * run.column;
387
- ctx.fillText(ch, x + (cell - ctx.measureText(ch).width) / 2, run.textTop);
406
+ ctx.fillText(ch, x + (cell - ctx.measureText(ch).width) / 2, y);
388
407
  x += cell;
389
408
  }
390
- } else ctx.fillText(run.text, run.x, run.textTop);
409
+ } else ctx.fillText(run.text, run.x, y);
391
410
  if (run.strike || run.underline) {
392
411
  ctx.fillStyle = run.color;
393
412
  const thickness = Math.max(run.fontSize / 15, .5);
394
- if (run.strike) ctx.fillRect(run.x, run.textTop + run.fontSize * .55, run.width, thickness);
395
- if (run.underline) ctx.fillRect(run.x, run.textTop + run.fontSize * 1.02, run.width, thickness);
413
+ const strikeY = alphabetic ? y - run.fontSize * .3 : run.textTop + run.fontSize * .55;
414
+ const underlineY = alphabetic ? y + run.fontSize * .12 : run.textTop + run.fontSize * 1.02;
415
+ if (run.strike) ctx.fillRect(run.x, strikeY, run.width, thickness);
416
+ if (run.underline) ctx.fillRect(run.x, underlineY, run.width, thickness);
396
417
  }
397
418
  }
398
419
  const message = (text, x, y, fill) => {
420
+ ctx.textBaseline = "top";
399
421
  ctx.font = layout.message.font;
400
422
  ctx.fillStyle = fill;
401
423
  ctx.fillText(text, x, y);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simple-mark/canvas",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Draws Markdown on a <canvas> without hiding its syntax: layout (no DOM) and Canvas 2D painting.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,7 +23,7 @@
23
23
  }
24
24
  },
25
25
  "dependencies": {
26
- "@simple-mark/math": "^0.2.0",
27
- "@simple-mark/model": "^0.2.0"
26
+ "@simple-mark/math": "^0.3.1",
27
+ "@simple-mark/model": "^0.3.1"
28
28
  }
29
29
  }