pa_font 0.3.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.
- package/USAGE.md +24 -0
- package/dist/paFont.cjs +34 -4
- package/dist/paFont.cjs.map +1 -1
- package/dist/paFont.js +34 -4
- package/dist/paFont.js.map +1 -1
- package/paFont.d.ts +4 -0
- package/package.json +1 -1
package/USAGE.md
CHANGED
|
@@ -119,6 +119,7 @@ console.log(metrics.width, metrics.bbox);
|
|
|
119
119
|
- `overflowWrap`: `normal | break-word | anywhere`
|
|
120
120
|
- `wordBreak`: `normal | break-all | keep-all`
|
|
121
121
|
- `overflow`: `visible | hidden`
|
|
122
|
+
- `overflowY`: `visible | hidden | scroll`
|
|
122
123
|
- `textOverflow`: `clip | ellipsis`
|
|
123
124
|
- `fontFamily`, `fontWeight`, `fontStyle`, `font`
|
|
124
125
|
- `engine`: `pretext | native`
|
|
@@ -137,6 +138,7 @@ console.log(metrics.width, metrics.bbox);
|
|
|
137
138
|
- `gap`: 문단 사이 간격. `lineHeight` 배수이며 기본값은 `0.5`
|
|
138
139
|
- `whiteSpace: "normal"`이면 문단 안 단일 줄바꿈은 공백으로 정리
|
|
139
140
|
- `whiteSpace: "pre-wrap"`이면 문단 안 단일 줄바꿈 유지
|
|
141
|
+
- `overflowY: "scroll"`을 쓰려면 `height`가 필요
|
|
140
142
|
|
|
141
143
|
## paParagraph API
|
|
142
144
|
|
|
@@ -182,6 +184,28 @@ paragraph.drawText(ctx, {
|
|
|
182
184
|
- `strokeStyle`
|
|
183
185
|
- `fill`
|
|
184
186
|
- `stroke`
|
|
187
|
+
- `scrollTop`
|
|
188
|
+
|
|
189
|
+
스크롤 가능한 viewport를 만들고 싶다면:
|
|
190
|
+
|
|
191
|
+
```js
|
|
192
|
+
const paragraph = font.paragraph(text, {
|
|
193
|
+
width: 320,
|
|
194
|
+
height: 220,
|
|
195
|
+
overflowY: "scroll",
|
|
196
|
+
lineHeight: 1.5,
|
|
197
|
+
gap: 0.5,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
paragraph.drawText(ctx, {
|
|
201
|
+
fillStyle: "#111",
|
|
202
|
+
scrollTop: 48,
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
전체 콘텐츠 높이는 `paragraph.metrics.height`,
|
|
207
|
+
현재 viewport 높이는 `paragraph.metrics.viewportHeight`,
|
|
208
|
+
최대 스크롤 값은 `paragraph.metrics.maxScrollTop`에서 확인할 수 있습니다.
|
|
185
209
|
|
|
186
210
|
### `paragraph.toShape(options?)`
|
|
187
211
|
|
package/dist/paFont.cjs
CHANGED
|
@@ -3332,6 +3332,8 @@ function layoutParagraph(fontInstance, text, options = {}, state = {}) {
|
|
|
3332
3332
|
y: finalLayoutBox.contentBox.y,
|
|
3333
3333
|
width: textWidth,
|
|
3334
3334
|
height: textHeight,
|
|
3335
|
+
viewportHeight: finalLayoutBox.contentBox.h,
|
|
3336
|
+
maxScrollTop: Math.max(0, textHeight - finalLayoutBox.contentBox.h),
|
|
3335
3337
|
lineCount: lines.length,
|
|
3336
3338
|
bbox: textBBox,
|
|
3337
3339
|
contentBox: { ...finalLayoutBox.contentBox },
|
|
@@ -3358,9 +3360,12 @@ function normalizeParagraphOptions(fontInstance, options = {}) {
|
|
|
3358
3360
|
const width = normalizeDimension(options.width);
|
|
3359
3361
|
const height = normalizeDimension(options.height);
|
|
3360
3362
|
const gap = normalizeGap(options.gap);
|
|
3363
|
+
const overflow = normalizeEnum(options.overflow, ["visible", "hidden"], "visible");
|
|
3364
|
+
const overflowY = resolveOverflowY(options.overflowY, overflow);
|
|
3361
3365
|
if (options.width != null && width == null) throw new TypeError("font.paragraph() option \"width\" must be a positive number.");
|
|
3362
3366
|
if (options.height != null && height == null) throw new TypeError("font.paragraph() option \"height\" must be a positive number.");
|
|
3363
3367
|
if (options.gap != null && gap == null) throw new TypeError("font.paragraph() option \"gap\" must be a non-negative number.");
|
|
3368
|
+
if (overflowY === "scroll" && height == null) throw new TypeError("font.paragraph() option \"height\" is required when \"overflowY\" is \"scroll\".");
|
|
3364
3369
|
const font = resolveCanvasFont(fontInstance, textOptions.size, options);
|
|
3365
3370
|
return {
|
|
3366
3371
|
...textOptions,
|
|
@@ -3398,7 +3403,8 @@ function normalizeParagraphOptions(fontInstance, options = {}) {
|
|
|
3398
3403
|
"break-all",
|
|
3399
3404
|
"keep-all"
|
|
3400
3405
|
], wrapDefaults.wordBreak),
|
|
3401
|
-
overflow
|
|
3406
|
+
overflow,
|
|
3407
|
+
overflowY,
|
|
3402
3408
|
textOverflow: normalizeNullableEnum(options.textOverflow, ["clip", "ellipsis"], null),
|
|
3403
3409
|
maxLines: normalizeMaxLines(options.maxLines),
|
|
3404
3410
|
ellipsis: normalizeEllipsis(options.ellipsis),
|
|
@@ -3587,7 +3593,7 @@ function applyOverflowClamping(lines, options, layoutBox, measureWidth) {
|
|
|
3587
3593
|
const contentWidth = layoutBox.contentWidth;
|
|
3588
3594
|
const result = lines.map((line) => ({ ...line }));
|
|
3589
3595
|
let lineLimit = options.maxLines;
|
|
3590
|
-
if (options
|
|
3596
|
+
if (shouldClampLinesToHeight(options) && layoutBox.clipContentHeight != null) {
|
|
3591
3597
|
const visibleLineCount = countVisibleLinesForHeight(result, options, layoutBox.clipContentHeight);
|
|
3592
3598
|
lineLimit = lineLimit == null ? visibleLineCount : Math.min(lineLimit, visibleLineCount);
|
|
3593
3599
|
}
|
|
@@ -3812,7 +3818,7 @@ function finalizeLayoutBox(layoutBox, options, textHeight) {
|
|
|
3812
3818
|
x: layoutBox.contentX,
|
|
3813
3819
|
y: layoutBox.contentY,
|
|
3814
3820
|
w: layoutBox.contentWidth,
|
|
3815
|
-
h: options
|
|
3821
|
+
h: shouldClipToContentHeight(options) ? contentHeight : textHeight
|
|
3816
3822
|
}
|
|
3817
3823
|
};
|
|
3818
3824
|
}
|
|
@@ -3828,6 +3834,19 @@ function normalizeNullableEnum(value, supported, fallback) {
|
|
|
3828
3834
|
if (value == null) return fallback;
|
|
3829
3835
|
return typeof value === "string" && supported.includes(value) ? value : fallback;
|
|
3830
3836
|
}
|
|
3837
|
+
function resolveOverflowY(value, overflow) {
|
|
3838
|
+
return normalizeEnum(value, [
|
|
3839
|
+
"visible",
|
|
3840
|
+
"hidden",
|
|
3841
|
+
"scroll"
|
|
3842
|
+
], overflow === "hidden" ? "hidden" : "visible");
|
|
3843
|
+
}
|
|
3844
|
+
function shouldClampLinesToHeight(options) {
|
|
3845
|
+
return options.overflowY === "hidden";
|
|
3846
|
+
}
|
|
3847
|
+
function shouldClipToContentHeight(options) {
|
|
3848
|
+
return options.overflow === "hidden" || options.overflowY === "hidden" || options.overflowY === "scroll";
|
|
3849
|
+
}
|
|
3831
3850
|
function normalizeEllipsis(value) {
|
|
3832
3851
|
if (value === false) return false;
|
|
3833
3852
|
if (typeof value === "string") return value;
|
|
@@ -4264,6 +4283,7 @@ var paParagraph = class paParagraph {
|
|
|
4264
4283
|
if (!ctx || typeof ctx.fillText !== "function") throw new TypeError("drawText() expects a CanvasRenderingContext2D.");
|
|
4265
4284
|
const fill = options.fill !== false;
|
|
4266
4285
|
const stroke = options.stroke === true;
|
|
4286
|
+
const scrollTop = clampScrollTop(options.scrollTop, this.metrics.maxScrollTop);
|
|
4267
4287
|
if (!fill && !stroke) return;
|
|
4268
4288
|
this._syncLayoutWithContext(ctx);
|
|
4269
4289
|
ctx.save();
|
|
@@ -4272,12 +4292,13 @@ var paParagraph = class paParagraph {
|
|
|
4272
4292
|
ctx.textBaseline = "alphabetic";
|
|
4273
4293
|
if (options.fillStyle != null) ctx.fillStyle = options.fillStyle;
|
|
4274
4294
|
if (options.strokeStyle != null) ctx.strokeStyle = options.strokeStyle;
|
|
4275
|
-
if (this.options
|
|
4295
|
+
if (shouldClipParagraph(this.options) && this._state.layoutBox?.clipBox) {
|
|
4276
4296
|
const clipBox = this._state.layoutBox.clipBox;
|
|
4277
4297
|
ctx.beginPath();
|
|
4278
4298
|
ctx.rect(clipBox.x, clipBox.y, clipBox.w, clipBox.h);
|
|
4279
4299
|
ctx.clip();
|
|
4280
4300
|
}
|
|
4301
|
+
if (scrollTop > 0) ctx.translate(0, -scrollTop);
|
|
4281
4302
|
this._state.lines.forEach((line) => {
|
|
4282
4303
|
line.fragments.forEach((fragment) => {
|
|
4283
4304
|
if (fill) ctx.fillText(fragment.text, fragment.x, line.baseline);
|
|
@@ -4328,6 +4349,8 @@ var paParagraph = class paParagraph {
|
|
|
4328
4349
|
this.metrics = {
|
|
4329
4350
|
...state.metrics,
|
|
4330
4351
|
bbox: { ...state.metrics.bbox },
|
|
4352
|
+
viewportHeight: state.metrics.viewportHeight,
|
|
4353
|
+
maxScrollTop: state.metrics.maxScrollTop,
|
|
4331
4354
|
contentBox: state.metrics.contentBox ? { ...state.metrics.contentBox } : void 0,
|
|
4332
4355
|
paddingBox: state.metrics.paddingBox ? { ...state.metrics.paddingBox } : void 0,
|
|
4333
4356
|
marginBox: state.metrics.marginBox ? { ...state.metrics.marginBox } : void 0,
|
|
@@ -4422,6 +4445,13 @@ function normalizeParagraphPointOptions(options = {}) {
|
|
|
4422
4445
|
layout: options.layout ?? "current"
|
|
4423
4446
|
};
|
|
4424
4447
|
}
|
|
4448
|
+
function shouldClipParagraph(options) {
|
|
4449
|
+
return options.overflow === "hidden" || options.overflowY === "hidden" || options.overflowY === "scroll";
|
|
4450
|
+
}
|
|
4451
|
+
function clampScrollTop(value, maxScrollTop) {
|
|
4452
|
+
if (!Number.isFinite(value) || value <= 0) return 0;
|
|
4453
|
+
return Math.min(Number(value), maxScrollTop ?? 0);
|
|
4454
|
+
}
|
|
4425
4455
|
//#endregion
|
|
4426
4456
|
//#region src/paFont/paFont.js
|
|
4427
4457
|
var browserFontRegistrationId = 0;
|