@simple-mark/canvas 0.3.0 → 0.3.2

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 +28 -5
  2. package/package.json +3 -3
package/index.js CHANGED
@@ -359,9 +359,27 @@ 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
+ ctx.textBaseline = "alphabetic";
369
+ const metrics = ctx.measureText("x");
370
+ const ascent = metrics.fontBoundingBoxAscent;
371
+ const descent = metrics.fontBoundingBoxDescent;
372
+ if (!(ascent > 0) || !(descent >= 0)) return {
373
+ y: run.textTop,
374
+ alphabetic: false
375
+ };
376
+ return {
377
+ y: run.top + (run.height - (ascent + descent)) / 2 + ascent,
378
+ alphabetic: true
379
+ };
380
+ }
362
381
  function paintMarkdown(ctx, layout, sources = {}, color = "#1f2328") {
363
382
  ctx.save();
364
- ctx.textBaseline = "top";
365
383
  ctx.textAlign = "left";
366
384
  for (const line of layout.lines) {
367
385
  if (line.background) {
@@ -375,6 +393,8 @@ function paintMarkdown(ctx, layout, sources = {}, color = "#1f2328") {
375
393
  }
376
394
  for (const run of layout.runs) {
377
395
  ctx.font = run.font;
396
+ const { y, alphabetic } = baseline(ctx, run);
397
+ ctx.textBaseline = alphabetic ? "alphabetic" : "top";
378
398
  if (run.background) {
379
399
  ctx.fillStyle = run.background;
380
400
  ctx.fillRect(run.x, run.textTop - run.fontSize * .1, run.width, run.fontSize * 1.2);
@@ -384,18 +404,21 @@ function paintMarkdown(ctx, layout, sources = {}, color = "#1f2328") {
384
404
  let x = run.x;
385
405
  for (const ch of run.text) {
386
406
  const cell = charWidth(ch.codePointAt(0)) * run.column;
387
- ctx.fillText(ch, x + (cell - ctx.measureText(ch).width) / 2, run.textTop);
407
+ ctx.fillText(ch, x + (cell - ctx.measureText(ch).width) / 2, y);
388
408
  x += cell;
389
409
  }
390
- } else ctx.fillText(run.text, run.x, run.textTop);
410
+ } else ctx.fillText(run.text, run.x, y);
391
411
  if (run.strike || run.underline) {
392
412
  ctx.fillStyle = run.color;
393
413
  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);
414
+ const strikeY = alphabetic ? y - run.fontSize * .3 : run.textTop + run.fontSize * .55;
415
+ const underlineY = alphabetic ? y + run.fontSize * .12 : run.textTop + run.fontSize * 1.02;
416
+ if (run.strike) ctx.fillRect(run.x, strikeY, run.width, thickness);
417
+ if (run.underline) ctx.fillRect(run.x, underlineY, run.width, thickness);
396
418
  }
397
419
  }
398
420
  const message = (text, x, y, fill) => {
421
+ ctx.textBaseline = "top";
399
422
  ctx.font = layout.message.font;
400
423
  ctx.fillStyle = fill;
401
424
  ctx.fillText(text, x, y);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simple-mark/canvas",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
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.3.0",
27
- "@simple-mark/model": "^0.3.0"
26
+ "@simple-mark/math": "^0.3.2",
27
+ "@simple-mark/model": "^0.3.2"
28
28
  }
29
29
  }