pa_font 0.3.2 → 0.3.3
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 +88 -10
- package/dist/paFont.cjs.map +1 -1
- package/dist/paFont.js +88 -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,10 @@ function normalizeParagraphOptions(fontInstance, options = {}) {
|
|
|
3372
3374
|
width,
|
|
3373
3375
|
height,
|
|
3374
3376
|
gap: gap ?? DEFAULT_PARAGRAPH_GAP,
|
|
3377
|
+
anchor: anchor ?? {
|
|
3378
|
+
x: 0,
|
|
3379
|
+
y: 0
|
|
3380
|
+
},
|
|
3375
3381
|
lineHeight: resolveLineHeight(options.lineHeight, textOptions.size),
|
|
3376
3382
|
align: normalizeEnum(options.align, [
|
|
3377
3383
|
"left",
|
|
@@ -3812,6 +3818,44 @@ function finalizeLayoutBox(layoutBox, options, textHeight) {
|
|
|
3812
3818
|
}
|
|
3813
3819
|
};
|
|
3814
3820
|
}
|
|
3821
|
+
function applyParagraphAnchor(lines, textBBox, layoutBox, anchor) {
|
|
3822
|
+
if (anchor == null || Math.abs(anchor.x) <= JUSTIFY_EPSILON && Math.abs(anchor.y) <= JUSTIFY_EPSILON) return {
|
|
3823
|
+
lines,
|
|
3824
|
+
textBBox,
|
|
3825
|
+
layoutBox
|
|
3826
|
+
};
|
|
3827
|
+
const tx = -layoutBox.contentBox.w * anchor.x;
|
|
3828
|
+
const ty = -layoutBox.contentBox.h * anchor.y;
|
|
3829
|
+
return {
|
|
3830
|
+
lines: translatePositionedLines(lines, tx, ty),
|
|
3831
|
+
textBBox: translateRect(textBBox, tx, ty),
|
|
3832
|
+
layoutBox: translateLayoutBox(layoutBox, tx, ty)
|
|
3833
|
+
};
|
|
3834
|
+
}
|
|
3835
|
+
function translatePositionedLines(lines, tx, ty) {
|
|
3836
|
+
return lines.map((line) => ({
|
|
3837
|
+
...line,
|
|
3838
|
+
x: line.x + tx,
|
|
3839
|
+
y: line.y + ty,
|
|
3840
|
+
baseline: line.baseline + ty,
|
|
3841
|
+
bbox: translateRect(line.bbox, tx, ty),
|
|
3842
|
+
fragments: line.fragments.map((fragment) => ({
|
|
3843
|
+
...fragment,
|
|
3844
|
+
x: fragment.x + tx
|
|
3845
|
+
}))
|
|
3846
|
+
}));
|
|
3847
|
+
}
|
|
3848
|
+
function translateLayoutBox(layoutBox, tx, ty) {
|
|
3849
|
+
return {
|
|
3850
|
+
...layoutBox,
|
|
3851
|
+
contentX: layoutBox.contentX + tx,
|
|
3852
|
+
contentY: layoutBox.contentY + ty,
|
|
3853
|
+
contentBox: translateRect(layoutBox.contentBox, tx, ty),
|
|
3854
|
+
paddingBox: translateRect(layoutBox.paddingBox, tx, ty),
|
|
3855
|
+
marginBox: translateRect(layoutBox.marginBox, tx, ty),
|
|
3856
|
+
clipBox: translateRect(layoutBox.clipBox, tx, ty)
|
|
3857
|
+
};
|
|
3858
|
+
}
|
|
3815
3859
|
function resolveContainerDimension(explicit, fallback) {
|
|
3816
3860
|
if (Number.isFinite(explicit) && explicit > 0) return explicit;
|
|
3817
3861
|
if (Number.isFinite(fallback) && fallback > 0) return fallback;
|
|
@@ -3840,6 +3884,40 @@ function normalizeDimension(value) {
|
|
|
3840
3884
|
function normalizeGap(value) {
|
|
3841
3885
|
return Number.isFinite(value) && value >= 0 ? Number(value) : null;
|
|
3842
3886
|
}
|
|
3887
|
+
function normalizeAnchor(value) {
|
|
3888
|
+
if (value == null) return null;
|
|
3889
|
+
if (Number.isFinite(value)) {
|
|
3890
|
+
const next = Number(value);
|
|
3891
|
+
return {
|
|
3892
|
+
x: next,
|
|
3893
|
+
y: next
|
|
3894
|
+
};
|
|
3895
|
+
}
|
|
3896
|
+
if (Array.isArray(value)) {
|
|
3897
|
+
if (value.length === 1 && Number.isFinite(value[0])) {
|
|
3898
|
+
const next = Number(value[0]);
|
|
3899
|
+
return {
|
|
3900
|
+
x: next,
|
|
3901
|
+
y: next
|
|
3902
|
+
};
|
|
3903
|
+
}
|
|
3904
|
+
if (value.length >= 2 && Number.isFinite(value[0]) && Number.isFinite(value[1])) return {
|
|
3905
|
+
x: Number(value[0]),
|
|
3906
|
+
y: Number(value[1])
|
|
3907
|
+
};
|
|
3908
|
+
return null;
|
|
3909
|
+
}
|
|
3910
|
+
if (typeof value === "object") {
|
|
3911
|
+
const hasX = Number.isFinite(value.x);
|
|
3912
|
+
const hasY = Number.isFinite(value.y);
|
|
3913
|
+
if (!hasX && !hasY) return null;
|
|
3914
|
+
return {
|
|
3915
|
+
x: hasX ? Number(value.x) : 0,
|
|
3916
|
+
y: hasY ? Number(value.y) : 0
|
|
3917
|
+
};
|
|
3918
|
+
}
|
|
3919
|
+
return null;
|
|
3920
|
+
}
|
|
3843
3921
|
function normalizeSpacing(value) {
|
|
3844
3922
|
if (value == null) return zeroSpacing();
|
|
3845
3923
|
if (Number.isFinite(value)) {
|