pa_font 0.3.2 → 0.3.4
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.
- package/USAGE.md +21 -1
- package/dist/paFont.cjs +85 -10
- package/dist/paFont.cjs.map +1 -1
- package/dist/paFont.js +85 -10
- package/dist/paFont.js.map +1 -1
- package/paFont.d.ts +8 -0
- package/package.json +1 -1
package/dist/paFont.js
CHANGED
|
@@ -3317,28 +3317,28 @@ function layoutParagraph(fontInstance, text, options = {}, state = {}) {
|
|
|
3317
3317
|
const textBBox = combineRects(lines.map((line) => line.bbox)) ?? emptyRect();
|
|
3318
3318
|
const textWidth = lines.reduce((max, line) => Math.max(max, line.width), 0);
|
|
3319
3319
|
const textHeight = resolvePositionedTextHeight(lines, layoutBox.contentY);
|
|
3320
|
-
const
|
|
3320
|
+
const anchoredLayout = applyParagraphAnchor(lines, textBBox, finalizeLayoutBox(layoutBox, normalized, textHeight), normalized.anchor);
|
|
3321
3321
|
const cachedPrepared = pretextState?.prepared ?? retainedPreparedState.prepared ?? null;
|
|
3322
3322
|
const cachedPreparedWhiteSpace = pretextState?.preparedWhiteSpace ?? retainedPreparedState.preparedWhiteSpace ?? null;
|
|
3323
3323
|
return {
|
|
3324
3324
|
options: normalized,
|
|
3325
|
-
lines,
|
|
3325
|
+
lines: anchoredLayout.lines,
|
|
3326
3326
|
metrics: {
|
|
3327
|
-
x:
|
|
3328
|
-
y:
|
|
3327
|
+
x: anchoredLayout.layoutBox.contentBox.x,
|
|
3328
|
+
y: anchoredLayout.layoutBox.contentBox.y,
|
|
3329
3329
|
width: textWidth,
|
|
3330
3330
|
height: textHeight,
|
|
3331
3331
|
lineCount: lines.length,
|
|
3332
|
-
bbox: textBBox,
|
|
3333
|
-
contentBox: { ...
|
|
3334
|
-
paddingBox: { ...
|
|
3335
|
-
marginBox: { ...
|
|
3336
|
-
clipBox: { ...
|
|
3332
|
+
bbox: anchoredLayout.textBBox,
|
|
3333
|
+
contentBox: { ...anchoredLayout.layoutBox.contentBox },
|
|
3334
|
+
paddingBox: { ...anchoredLayout.layoutBox.paddingBox },
|
|
3335
|
+
marginBox: { ...anchoredLayout.layoutBox.marginBox },
|
|
3336
|
+
clipBox: { ...anchoredLayout.layoutBox.clipBox }
|
|
3337
3337
|
},
|
|
3338
3338
|
prepared: cachedPrepared,
|
|
3339
3339
|
preparedWhiteSpace: cachedPreparedWhiteSpace,
|
|
3340
3340
|
layoutEngine: layoutState.layoutEngine,
|
|
3341
|
-
layoutBox:
|
|
3341
|
+
layoutBox: anchoredLayout.layoutBox,
|
|
3342
3342
|
containerWidth: layoutBox.containerWidth,
|
|
3343
3343
|
containerHeight: layoutBox.containerHeight
|
|
3344
3344
|
};
|
|
@@ -3354,9 +3354,11 @@ function normalizeParagraphOptions(fontInstance, options = {}) {
|
|
|
3354
3354
|
const width = normalizeDimension(options.width);
|
|
3355
3355
|
const height = normalizeDimension(options.height);
|
|
3356
3356
|
const gap = normalizeGap(options.gap);
|
|
3357
|
+
const anchor = normalizeAnchor(options.anchor);
|
|
3357
3358
|
if (options.width != null && width == null) throw new TypeError("font.paragraph() option \"width\" must be a positive number.");
|
|
3358
3359
|
if (options.height != null && height == null) throw new TypeError("font.paragraph() option \"height\" must be a positive number.");
|
|
3359
3360
|
if (options.gap != null && gap == null) throw new TypeError("font.paragraph() option \"gap\" must be a non-negative number.");
|
|
3361
|
+
if (options.anchor != null && anchor == null) throw new TypeError("font.paragraph() option \"anchor\" must be a number, [x, y], or { x, y }.");
|
|
3360
3362
|
const font = resolveCanvasFont(fontInstance, textOptions.size, options);
|
|
3361
3363
|
return {
|
|
3362
3364
|
...textOptions,
|
|
@@ -3372,6 +3374,7 @@ function normalizeParagraphOptions(fontInstance, options = {}) {
|
|
|
3372
3374
|
width,
|
|
3373
3375
|
height,
|
|
3374
3376
|
gap: gap ?? DEFAULT_PARAGRAPH_GAP,
|
|
3377
|
+
anchor,
|
|
3375
3378
|
lineHeight: resolveLineHeight(options.lineHeight, textOptions.size),
|
|
3376
3379
|
align: normalizeEnum(options.align, [
|
|
3377
3380
|
"left",
|
|
@@ -3812,6 +3815,44 @@ function finalizeLayoutBox(layoutBox, options, textHeight) {
|
|
|
3812
3815
|
}
|
|
3813
3816
|
};
|
|
3814
3817
|
}
|
|
3818
|
+
function applyParagraphAnchor(lines, textBBox, layoutBox, anchor) {
|
|
3819
|
+
if (anchor == null) return {
|
|
3820
|
+
lines,
|
|
3821
|
+
textBBox,
|
|
3822
|
+
layoutBox
|
|
3823
|
+
};
|
|
3824
|
+
const tx = layoutBox.contentX - (textBBox.x + textBBox.w * anchor.x);
|
|
3825
|
+
const ty = layoutBox.contentY - (textBBox.y + textBBox.h * anchor.y);
|
|
3826
|
+
return {
|
|
3827
|
+
lines: translatePositionedLines(lines, tx, ty),
|
|
3828
|
+
textBBox: translateRect(textBBox, tx, ty),
|
|
3829
|
+
layoutBox: translateLayoutBox(layoutBox, tx, ty)
|
|
3830
|
+
};
|
|
3831
|
+
}
|
|
3832
|
+
function translatePositionedLines(lines, tx, ty) {
|
|
3833
|
+
return lines.map((line) => ({
|
|
3834
|
+
...line,
|
|
3835
|
+
x: line.x + tx,
|
|
3836
|
+
y: line.y + ty,
|
|
3837
|
+
baseline: line.baseline + ty,
|
|
3838
|
+
bbox: translateRect(line.bbox, tx, ty),
|
|
3839
|
+
fragments: line.fragments.map((fragment) => ({
|
|
3840
|
+
...fragment,
|
|
3841
|
+
x: fragment.x + tx
|
|
3842
|
+
}))
|
|
3843
|
+
}));
|
|
3844
|
+
}
|
|
3845
|
+
function translateLayoutBox(layoutBox, tx, ty) {
|
|
3846
|
+
return {
|
|
3847
|
+
...layoutBox,
|
|
3848
|
+
contentX: layoutBox.contentX + tx,
|
|
3849
|
+
contentY: layoutBox.contentY + ty,
|
|
3850
|
+
contentBox: translateRect(layoutBox.contentBox, tx, ty),
|
|
3851
|
+
paddingBox: translateRect(layoutBox.paddingBox, tx, ty),
|
|
3852
|
+
marginBox: translateRect(layoutBox.marginBox, tx, ty),
|
|
3853
|
+
clipBox: translateRect(layoutBox.clipBox, tx, ty)
|
|
3854
|
+
};
|
|
3855
|
+
}
|
|
3815
3856
|
function resolveContainerDimension(explicit, fallback) {
|
|
3816
3857
|
if (Number.isFinite(explicit) && explicit > 0) return explicit;
|
|
3817
3858
|
if (Number.isFinite(fallback) && fallback > 0) return fallback;
|
|
@@ -3840,6 +3881,40 @@ function normalizeDimension(value) {
|
|
|
3840
3881
|
function normalizeGap(value) {
|
|
3841
3882
|
return Number.isFinite(value) && value >= 0 ? Number(value) : null;
|
|
3842
3883
|
}
|
|
3884
|
+
function normalizeAnchor(value) {
|
|
3885
|
+
if (value == null) return null;
|
|
3886
|
+
if (Number.isFinite(value)) {
|
|
3887
|
+
const next = Number(value);
|
|
3888
|
+
return {
|
|
3889
|
+
x: next,
|
|
3890
|
+
y: next
|
|
3891
|
+
};
|
|
3892
|
+
}
|
|
3893
|
+
if (Array.isArray(value)) {
|
|
3894
|
+
if (value.length === 1 && Number.isFinite(value[0])) {
|
|
3895
|
+
const next = Number(value[0]);
|
|
3896
|
+
return {
|
|
3897
|
+
x: next,
|
|
3898
|
+
y: next
|
|
3899
|
+
};
|
|
3900
|
+
}
|
|
3901
|
+
if (value.length >= 2 && Number.isFinite(value[0]) && Number.isFinite(value[1])) return {
|
|
3902
|
+
x: Number(value[0]),
|
|
3903
|
+
y: Number(value[1])
|
|
3904
|
+
};
|
|
3905
|
+
return null;
|
|
3906
|
+
}
|
|
3907
|
+
if (typeof value === "object") {
|
|
3908
|
+
const hasX = Number.isFinite(value.x);
|
|
3909
|
+
const hasY = Number.isFinite(value.y);
|
|
3910
|
+
if (!hasX && !hasY) return null;
|
|
3911
|
+
return {
|
|
3912
|
+
x: hasX ? Number(value.x) : 0,
|
|
3913
|
+
y: hasY ? Number(value.y) : 0
|
|
3914
|
+
};
|
|
3915
|
+
}
|
|
3916
|
+
return null;
|
|
3917
|
+
}
|
|
3843
3918
|
function normalizeSpacing(value) {
|
|
3844
3919
|
if (value == null) return zeroSpacing();
|
|
3845
3920
|
if (Number.isFinite(value)) {
|