@retikz/core 0.2.0-rc.1 → 0.3.0-alpha.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/README.md +41 -0
- package/dist/es/compile/node.d.ts.map +1 -1
- package/dist/es/compile/node.js +9 -6
- package/dist/es/compile/path/label.d.ts.map +1 -1
- package/dist/es/compile/path/label.js +5 -3
- package/dist/es/compile/text-baseline.d.ts +28 -0
- package/dist/es/compile/text-baseline.d.ts.map +1 -0
- package/dist/es/compile/text-baseline.js +40 -0
- package/dist/es/compile/text-metrics.d.ts +1 -1
- package/dist/es/index.d.ts +1 -1
- package/dist/lib/compile/node.cjs +9 -6
- package/dist/lib/compile/node.d.ts.map +1 -1
- package/dist/lib/compile/path/label.cjs +5 -3
- package/dist/lib/compile/path/label.d.ts.map +1 -1
- package/dist/lib/compile/text-baseline.cjs +40 -0
- package/dist/lib/compile/text-baseline.d.ts +28 -0
- package/dist/lib/compile/text-baseline.d.ts.map +1 -0
- package/dist/lib/compile/text-metrics.d.ts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @retikz/core
|
|
2
|
+
|
|
3
|
+
Framework-agnostic core of [retikz](https://pionpill.github.io/retikz/) — a TikZ-inspired diagramming library. Provides the zod-typed **IR**, the **`compileToScene`** compiler, pure **parsers**, geometry helpers, and the shape / arrow / pattern / path-generator registries.
|
|
4
|
+
|
|
5
|
+
零框架核心:retikz 的中间表示(IR)、`compileToScene` 编译器、纯解析器、几何工具与形状 / 箭头 / 图案 / 路径生成器注册面。**零 React、零 DOM**,运行时依赖只有 `zod`,IR 100% 可 JSON 序列化。
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @retikz/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
`@retikz/core` is renderer-agnostic: it turns an IR into a serializable `Scene`. A backend (`@retikz/render`) or runtime (`@retikz/react` / `@retikz/vanilla`) then renders that Scene.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { compileToScene } from '@retikz/core';
|
|
19
|
+
|
|
20
|
+
const scene = compileToScene(ir);
|
|
21
|
+
// optional: compileToScene(ir, { measureText, shapes, arrows, padding, ... })
|
|
22
|
+
// hand `scene` to @retikz/render/svg, @retikz/render/canvas, or a runtime
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Most users consume core indirectly through [`@retikz/react`](https://www.npmjs.com/package/@retikz/react) or [`@retikz/vanilla`](https://www.npmjs.com/package/@retikz/vanilla). Use core directly when you build IR programmatically, persist/transport scenes, or write a custom renderer.
|
|
26
|
+
|
|
27
|
+
## Exports
|
|
28
|
+
|
|
29
|
+
- `compileToScene` / `computeLayout` / `fallbackMeasurer` — IR → `Scene`
|
|
30
|
+
- IR & `Scene` zod schemas + inferred types
|
|
31
|
+
- `parseWay` / `parseNodeTarget` / `parseTargetSugar` — pure parsers
|
|
32
|
+
- `point` / `rect` / `circle` / `ellipse` / `diamond` / `polar` — geometry
|
|
33
|
+
- `BUILTIN_SHAPES` / `BUILTIN_ARROWS` / `BUILTIN_PATTERNS` + `ShapeDefinition` / `ArrowDefinition` / `PatternDefinition` / `definePathGenerator` — registries
|
|
34
|
+
|
|
35
|
+
## Docs
|
|
36
|
+
|
|
37
|
+
<https://pionpill.github.io/retikz/>
|
|
38
|
+
|
|
39
|
+
## License
|
|
40
|
+
|
|
41
|
+
MIT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAc,MAAM,EAAe,WAAW,EAAE,MAAM,OAAO,CAAC;AACvG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAa,cAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnF,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,WAAW,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,KAAK,oBAAoB,EAAmB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"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"}
|
package/dist/es/compile/node.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BUILTIN_SHAPES } from "../shapes/index.js";
|
|
2
2
|
import { resolvePosition } from "./position.js";
|
|
3
|
+
import { toAlphabeticBaselineY } from "./text-baseline.js";
|
|
3
4
|
//#region src/compile/node.ts
|
|
4
5
|
var DEFAULT_FONT_SIZE = 14;
|
|
5
6
|
var DEFAULT_PADDING = 8;
|
|
@@ -383,18 +384,19 @@ var emitNodePrimitives = (layout, round, resolveFill) => {
|
|
|
383
384
|
if (layout.lines) {
|
|
384
385
|
const halfBlockW = layout.textWidth / 2;
|
|
385
386
|
const xOffset = layout.align === "start" ? -halfBlockW : layout.align === "end" ? halfBlockW : 0;
|
|
387
|
+
const lineHeight = round(layout.lineHeight);
|
|
386
388
|
inner.push({
|
|
387
389
|
type: "text",
|
|
388
390
|
x: round(layout.rect.x + xOffset),
|
|
389
|
-
y: round(layout.rect.y),
|
|
391
|
+
y: round(toAlphabeticBaselineY(layout.rect.y, "middle", layout.lines.length, lineHeight, layout.fontSize)),
|
|
390
392
|
lines: layout.lines,
|
|
391
393
|
fontSize: layout.fontSize,
|
|
392
394
|
fontFamily: layout.fontFamily,
|
|
393
395
|
fontWeight: layout.fontWeight,
|
|
394
396
|
fontStyle: layout.fontStyle,
|
|
395
397
|
align: layout.align,
|
|
396
|
-
baseline: "
|
|
397
|
-
lineHeight
|
|
398
|
+
baseline: "alphabetic",
|
|
399
|
+
lineHeight,
|
|
398
400
|
fill: layout.textColor ?? "currentColor",
|
|
399
401
|
opacity: layout.opacity,
|
|
400
402
|
measuredWidth: round(layout.textWidth),
|
|
@@ -426,18 +428,19 @@ var emitNodePrimitives = (layout, round, resolveFill) => {
|
|
|
426
428
|
opacity: lab.opacity ?? layout.opacity
|
|
427
429
|
});
|
|
428
430
|
}
|
|
431
|
+
const labLineHeight = round(lab.fontSize * DEFAULT_LINE_HEIGHT_FACTOR);
|
|
429
432
|
const textPrim = {
|
|
430
433
|
type: "text",
|
|
431
434
|
x: round(lx),
|
|
432
|
-
y: round(ly),
|
|
435
|
+
y: round(toAlphabeticBaselineY(ly, "middle", 1, labLineHeight, lab.fontSize)),
|
|
433
436
|
lines: [{ text: lab.text }],
|
|
434
437
|
fontSize: lab.fontSize,
|
|
435
438
|
fontFamily: lab.fontFamily,
|
|
436
439
|
fontWeight: lab.fontWeight,
|
|
437
440
|
fontStyle: lab.fontStyle,
|
|
438
441
|
align: "middle",
|
|
439
|
-
baseline: "
|
|
440
|
-
lineHeight:
|
|
442
|
+
baseline: "alphabetic",
|
|
443
|
+
lineHeight: labLineHeight,
|
|
441
444
|
fill: lab.textColor ?? "currentColor",
|
|
442
445
|
opacity: lab.opacity ?? layout.opacity,
|
|
443
446
|
measuredWidth: 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/label.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAY,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/label.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAY,MAAM,iBAAiB,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAmBpD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,KAAK,WAAW,CAAC,UAAU,CAAC,KAAG,MAIhE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,WAAW,EAClB,QAAQ,aAAa,EACrB,aAAa,YAAY,EACzB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAC5B,cAAc,MAAM,KACnB;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;CAmGxD,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toAlphabeticBaselineY } from "../text-baseline.js";
|
|
1
2
|
//#region src/compile/path/label.ts
|
|
2
3
|
/** 边标注默认字号 / 偏移量 */
|
|
3
4
|
var LABEL_FONT_SIZE = 14;
|
|
@@ -60,15 +61,16 @@ var emitLabelPrimitive = (label, sample, measureText, round, hostOpacity) => {
|
|
|
60
61
|
x += LABEL_SIDE_OFFSET;
|
|
61
62
|
align = "start";
|
|
62
63
|
} else baseline = "bottom";
|
|
64
|
+
const emittedLineHeight = round(lineHeight);
|
|
63
65
|
const text = {
|
|
64
66
|
type: "text",
|
|
65
67
|
x: round(x),
|
|
66
|
-
y: round(y),
|
|
68
|
+
y: round(toAlphabeticBaselineY(y, baseline, 1, emittedLineHeight, fontSize)),
|
|
67
69
|
lines: [{ text: label.text }],
|
|
68
70
|
fontSize,
|
|
69
71
|
align,
|
|
70
|
-
baseline,
|
|
71
|
-
lineHeight:
|
|
72
|
+
baseline: "alphabetic",
|
|
73
|
+
lineHeight: emittedLineHeight,
|
|
72
74
|
measuredWidth: round(measuredWidth),
|
|
73
75
|
measuredHeight: round(measuredHeight),
|
|
74
76
|
fill: label.textColor ?? "currentColor"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文本垂直定位归一:任意 baseline 锚点 → 首行 alphabetic 基线 y
|
|
3
|
+
* @description canvas 的 `textBaseline` 与 SVG 的 `dominant-baseline` 是两套同名异义的关键字
|
|
4
|
+
* (`top/middle/bottom` 各按「em 方块」与「字体 ascent/descent」两种不同参照线解释),
|
|
5
|
+
* 只有 `alphabetic`(拉丁字母坐的底线)在两套模型、各浏览器里定义一致。故 core 在编译期把
|
|
6
|
+
* 所有文本的垂直锚点统一折算成首行 alphabetic 基线、emit `baseline: 'alphabetic'`,让 adapter
|
|
7
|
+
* 只渲染这一条无歧义的基线 —— 跨后端像素一致,垂直定位逻辑收口到 renderer-agnostic 的 core。
|
|
8
|
+
*
|
|
9
|
+
* 无字体测量器时用下方 ascent/descent 近似(占一个 em,asc 8 : desc 2 拆分),renderer-agnostic
|
|
10
|
+
* 且两后端一致;接入精确测量器后只需替换 asc/desc 来源,折算公式不变。
|
|
11
|
+
*/
|
|
12
|
+
/** ascent 近似占 fontSize 比例(基线之上) */
|
|
13
|
+
export declare const ASCENT_FACTOR = 0.8;
|
|
14
|
+
/** descent 近似占 fontSize 比例(基线之下) */
|
|
15
|
+
export declare const DESCENT_FACTOR = 0.2;
|
|
16
|
+
/**
|
|
17
|
+
* 把按 `baseline` 解释的垂直锚点 `y` 折算成首行 alphabetic 基线 y
|
|
18
|
+
* @description 多行文本首行基线在上、后续行按 lineHeight 向下堆叠;折算保持「关键字所指的块边界
|
|
19
|
+
* (top=块顶 ascent 线 / bottom=块底 descent 线 / middle=视觉中心 / alphabetic=首行基线)落在 y」。
|
|
20
|
+
* @param y - 原垂直锚点(含义由 baseline 决定)
|
|
21
|
+
* @param baseline - 锚点语义
|
|
22
|
+
* @param lineCount - 文本行数(≥1)
|
|
23
|
+
* @param lineHeight - 行高(相邻行基线间距)
|
|
24
|
+
* @param fontSize - 字号(算 ascent/descent 用)
|
|
25
|
+
* @returns 首行 alphabetic 基线 y
|
|
26
|
+
*/
|
|
27
|
+
export declare const toAlphabeticBaselineY: (y: number, baseline: "top" | "middle" | "bottom" | "alphabetic", lineCount: number, lineHeight: number, fontSize: number) => number;
|
|
28
|
+
//# sourceMappingURL=text-baseline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-baseline.d.ts","sourceRoot":"","sources":["../../../src/compile/text-baseline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,mCAAmC;AACnC,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,oCAAoC;AACpC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAChC,GAAG,MAAM,EACT,UAAU,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,EACpD,WAAW,MAAM,EACjB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,MAcF,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/compile/text-baseline.ts
|
|
2
|
+
/**
|
|
3
|
+
* 文本垂直定位归一:任意 baseline 锚点 → 首行 alphabetic 基线 y
|
|
4
|
+
* @description canvas 的 `textBaseline` 与 SVG 的 `dominant-baseline` 是两套同名异义的关键字
|
|
5
|
+
* (`top/middle/bottom` 各按「em 方块」与「字体 ascent/descent」两种不同参照线解释),
|
|
6
|
+
* 只有 `alphabetic`(拉丁字母坐的底线)在两套模型、各浏览器里定义一致。故 core 在编译期把
|
|
7
|
+
* 所有文本的垂直锚点统一折算成首行 alphabetic 基线、emit `baseline: 'alphabetic'`,让 adapter
|
|
8
|
+
* 只渲染这一条无歧义的基线 —— 跨后端像素一致,垂直定位逻辑收口到 renderer-agnostic 的 core。
|
|
9
|
+
*
|
|
10
|
+
* 无字体测量器时用下方 ascent/descent 近似(占一个 em,asc 8 : desc 2 拆分),renderer-agnostic
|
|
11
|
+
* 且两后端一致;接入精确测量器后只需替换 asc/desc 来源,折算公式不变。
|
|
12
|
+
*/
|
|
13
|
+
/** ascent 近似占 fontSize 比例(基线之上) */
|
|
14
|
+
var ASCENT_FACTOR = .8;
|
|
15
|
+
/** descent 近似占 fontSize 比例(基线之下) */
|
|
16
|
+
var DESCENT_FACTOR = .2;
|
|
17
|
+
/**
|
|
18
|
+
* 把按 `baseline` 解释的垂直锚点 `y` 折算成首行 alphabetic 基线 y
|
|
19
|
+
* @description 多行文本首行基线在上、后续行按 lineHeight 向下堆叠;折算保持「关键字所指的块边界
|
|
20
|
+
* (top=块顶 ascent 线 / bottom=块底 descent 线 / middle=视觉中心 / alphabetic=首行基线)落在 y」。
|
|
21
|
+
* @param y - 原垂直锚点(含义由 baseline 决定)
|
|
22
|
+
* @param baseline - 锚点语义
|
|
23
|
+
* @param lineCount - 文本行数(≥1)
|
|
24
|
+
* @param lineHeight - 行高(相邻行基线间距)
|
|
25
|
+
* @param fontSize - 字号(算 ascent/descent 用)
|
|
26
|
+
* @returns 首行 alphabetic 基线 y
|
|
27
|
+
*/
|
|
28
|
+
var toAlphabeticBaselineY = (y, baseline, lineCount, lineHeight, fontSize) => {
|
|
29
|
+
const asc = fontSize * ASCENT_FACTOR;
|
|
30
|
+
const desc = fontSize * DESCENT_FACTOR;
|
|
31
|
+
const span = (lineCount - 1) * lineHeight;
|
|
32
|
+
switch (baseline) {
|
|
33
|
+
case "top": return y + asc;
|
|
34
|
+
case "bottom": return y - span - desc;
|
|
35
|
+
case "middle": return y - span / 2 + (asc - desc) / 2;
|
|
36
|
+
case "alphabetic": return y;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { toAlphabeticBaselineY };
|
|
@@ -22,7 +22,7 @@ export type TextMetrics = {
|
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
24
|
* 文字度量函数接口(编译期由 adapter 注入)
|
|
25
|
-
* @description @retikz/react: canvas measureText;@retikz/ssr: opentype.js/fontkit;@retikz/canvas: ctx.measureText
|
|
25
|
+
* @description @retikz/react: canvas measureText;@retikz/ssr: opentype.js/fontkit;@retikz/render/canvas: ctx.measureText
|
|
26
26
|
*/
|
|
27
27
|
export type TextMeasurer = (text: string, font: FontSpec) => TextMetrics;
|
|
28
28
|
/**
|
package/dist/es/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @retikz/core 公开 API
|
|
3
|
-
* @description 任何 framework adapter(@retikz/react、@retikz/vue、@retikz/canvas、@retikz/ssr)只能 import 本文件导出内容,不准走子路径。本包零 React/零 DOM 依赖
|
|
3
|
+
* @description 任何 framework adapter(@retikz/react、@retikz/vue、@retikz/render/canvas、@retikz/ssr)只能 import 本文件导出内容,不准走子路径。本包零 React/零 DOM 依赖
|
|
4
4
|
*/
|
|
5
5
|
export { PositionSchema, PolarPositionSchema, AtPositionSchema, OffsetPositionSchema, AT_DIRECTIONS, TargetSchema, AnchorRefSchema, NodeTargetSchema, RelativeTargetSchema, RelativeAccumulateTargetSchema, AbsoluteTargetSchema, BetweenPositionSchema, MoveStepSchema, LineStepSchema, FoldStepSchema, CycleStepSchema, CurveStepSchema, CubicStepSchema, BendStepSchema, ArcStepSchema, CirclePathStepSchema, EllipsePathStepSchema, RectangleStepSchema, GeneratorStepSchema, ControlPointSchema, StepLabelSchema, StepSchema, NodeSchema, NodeLabelSchema, CoordinateSchema, FontSchema, TextBlockSchema, LineSpecSchema, PathSchema, ArrowDetailSchema, ArrowEndDetailSchema, ScopeSchema, NodeDefaultSchema, PathDefaultSchema, LabelDefaultSchema, ArrowDefaultSchema, TransformSchema, ChildSchema, SceneSchema, CURRENT_IR_VERSION, PaintSpecSchema, GradientStopSchema, JsonValueSchema, JsonObjectSchema, ClipSpecSchema, ViewBoxSchema, } from './ir';
|
|
6
6
|
export type { IRPosition, IRAtPosition, IROffsetPosition, AtDirection, IRTarget, IRAnchorRef, IRNodeTarget, IRRelativeTarget, IRRelativeAccumulateTarget, IRAbsoluteTarget, IRBetweenPosition, IRMoveStep, IRLineStep, IRFoldStep, IRCycleStep, IRCurveStep, IRCubicStep, IRBendStep, IRArcStep, IRCirclePathStep, IREllipsePathStep, IRRectangleStep, IRGeneratorStep, IRControlPoint, IRStepLabel, IRStep, IRNode, IRNodeLabel, IRCoordinate, IRFont, IRLineSpec, IRTextBlock, IRPath, IRScope, IRNodeDefault, IRPathDefault, IRLabelDefault, IRArrowDefault, StyleChannel, IRTransform, IRTranslateTransform, IRPolarTranslateTransform, IRAtTranslateTransform, IROffsetTranslateTransform, IRRotateTransform, IRScaleTransform, IRChild, IR, ArrowShape, BuiltinArrowName, ArrowShapeName, IRArrowDetail, IRArrowEndDetail, NodeShape, BuiltinShapeName, NodeTextAlign, PatternShapeName, BuiltinPatternName, IRPaintSpec, IRGradientStop, JsonValue, IRJsonObject, IRClipSpec, IRViewBox, } from './ir';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const require_index = require("../shapes/index.cjs");
|
|
2
2
|
const require_position = require("./position.cjs");
|
|
3
|
+
const require_text_baseline = require("./text-baseline.cjs");
|
|
3
4
|
//#region src/compile/node.ts
|
|
4
5
|
var DEFAULT_FONT_SIZE = 14;
|
|
5
6
|
var DEFAULT_PADDING = 8;
|
|
@@ -383,18 +384,19 @@ var emitNodePrimitives = (layout, round, resolveFill) => {
|
|
|
383
384
|
if (layout.lines) {
|
|
384
385
|
const halfBlockW = layout.textWidth / 2;
|
|
385
386
|
const xOffset = layout.align === "start" ? -halfBlockW : layout.align === "end" ? halfBlockW : 0;
|
|
387
|
+
const lineHeight = round(layout.lineHeight);
|
|
386
388
|
inner.push({
|
|
387
389
|
type: "text",
|
|
388
390
|
x: round(layout.rect.x + xOffset),
|
|
389
|
-
y: round(layout.rect.y),
|
|
391
|
+
y: round(require_text_baseline.toAlphabeticBaselineY(layout.rect.y, "middle", layout.lines.length, lineHeight, layout.fontSize)),
|
|
390
392
|
lines: layout.lines,
|
|
391
393
|
fontSize: layout.fontSize,
|
|
392
394
|
fontFamily: layout.fontFamily,
|
|
393
395
|
fontWeight: layout.fontWeight,
|
|
394
396
|
fontStyle: layout.fontStyle,
|
|
395
397
|
align: layout.align,
|
|
396
|
-
baseline: "
|
|
397
|
-
lineHeight
|
|
398
|
+
baseline: "alphabetic",
|
|
399
|
+
lineHeight,
|
|
398
400
|
fill: layout.textColor ?? "currentColor",
|
|
399
401
|
opacity: layout.opacity,
|
|
400
402
|
measuredWidth: round(layout.textWidth),
|
|
@@ -426,18 +428,19 @@ var emitNodePrimitives = (layout, round, resolveFill) => {
|
|
|
426
428
|
opacity: lab.opacity ?? layout.opacity
|
|
427
429
|
});
|
|
428
430
|
}
|
|
431
|
+
const labLineHeight = round(lab.fontSize * DEFAULT_LINE_HEIGHT_FACTOR);
|
|
429
432
|
const textPrim = {
|
|
430
433
|
type: "text",
|
|
431
434
|
x: round(lx),
|
|
432
|
-
y: round(ly),
|
|
435
|
+
y: round(require_text_baseline.toAlphabeticBaselineY(ly, "middle", 1, labLineHeight, lab.fontSize)),
|
|
433
436
|
lines: [{ text: lab.text }],
|
|
434
437
|
fontSize: lab.fontSize,
|
|
435
438
|
fontFamily: lab.fontFamily,
|
|
436
439
|
fontWeight: lab.fontWeight,
|
|
437
440
|
fontStyle: lab.fontStyle,
|
|
438
441
|
align: "middle",
|
|
439
|
-
baseline: "
|
|
440
|
-
lineHeight:
|
|
442
|
+
baseline: "alphabetic",
|
|
443
|
+
lineHeight: labLineHeight,
|
|
441
444
|
fill: lab.textColor ?? "currentColor",
|
|
442
445
|
opacity: lab.opacity ?? layout.opacity,
|
|
443
446
|
measuredWidth: 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAc,MAAM,EAAe,WAAW,EAAE,MAAM,OAAO,CAAC;AACvG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAa,cAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnF,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,WAAW,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,KAAK,oBAAoB,EAAmB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const require_text_baseline = require("../text-baseline.cjs");
|
|
1
2
|
//#region src/compile/path/label.ts
|
|
2
3
|
/** 边标注默认字号 / 偏移量 */
|
|
3
4
|
var LABEL_FONT_SIZE = 14;
|
|
@@ -60,15 +61,16 @@ var emitLabelPrimitive = (label, sample, measureText, round, hostOpacity) => {
|
|
|
60
61
|
x += LABEL_SIDE_OFFSET;
|
|
61
62
|
align = "start";
|
|
62
63
|
} else baseline = "bottom";
|
|
64
|
+
const emittedLineHeight = round(lineHeight);
|
|
63
65
|
const text = {
|
|
64
66
|
type: "text",
|
|
65
67
|
x: round(x),
|
|
66
|
-
y: round(y),
|
|
68
|
+
y: round(require_text_baseline.toAlphabeticBaselineY(y, baseline, 1, emittedLineHeight, fontSize)),
|
|
67
69
|
lines: [{ text: label.text }],
|
|
68
70
|
fontSize,
|
|
69
71
|
align,
|
|
70
|
-
baseline,
|
|
71
|
-
lineHeight:
|
|
72
|
+
baseline: "alphabetic",
|
|
73
|
+
lineHeight: emittedLineHeight,
|
|
72
74
|
measuredWidth: round(measuredWidth),
|
|
73
75
|
measuredHeight: round(measuredHeight),
|
|
74
76
|
fill: label.textColor ?? "currentColor"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/label.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAY,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/label.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAY,MAAM,iBAAiB,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAmBpD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,KAAK,WAAW,CAAC,UAAU,CAAC,KAAG,MAIhE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,WAAW,EAClB,QAAQ,aAAa,EACrB,aAAa,YAAY,EACzB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAC5B,cAAc,MAAM,KACnB;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;CAmGxD,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/compile/text-baseline.ts
|
|
2
|
+
/**
|
|
3
|
+
* 文本垂直定位归一:任意 baseline 锚点 → 首行 alphabetic 基线 y
|
|
4
|
+
* @description canvas 的 `textBaseline` 与 SVG 的 `dominant-baseline` 是两套同名异义的关键字
|
|
5
|
+
* (`top/middle/bottom` 各按「em 方块」与「字体 ascent/descent」两种不同参照线解释),
|
|
6
|
+
* 只有 `alphabetic`(拉丁字母坐的底线)在两套模型、各浏览器里定义一致。故 core 在编译期把
|
|
7
|
+
* 所有文本的垂直锚点统一折算成首行 alphabetic 基线、emit `baseline: 'alphabetic'`,让 adapter
|
|
8
|
+
* 只渲染这一条无歧义的基线 —— 跨后端像素一致,垂直定位逻辑收口到 renderer-agnostic 的 core。
|
|
9
|
+
*
|
|
10
|
+
* 无字体测量器时用下方 ascent/descent 近似(占一个 em,asc 8 : desc 2 拆分),renderer-agnostic
|
|
11
|
+
* 且两后端一致;接入精确测量器后只需替换 asc/desc 来源,折算公式不变。
|
|
12
|
+
*/
|
|
13
|
+
/** ascent 近似占 fontSize 比例(基线之上) */
|
|
14
|
+
var ASCENT_FACTOR = .8;
|
|
15
|
+
/** descent 近似占 fontSize 比例(基线之下) */
|
|
16
|
+
var DESCENT_FACTOR = .2;
|
|
17
|
+
/**
|
|
18
|
+
* 把按 `baseline` 解释的垂直锚点 `y` 折算成首行 alphabetic 基线 y
|
|
19
|
+
* @description 多行文本首行基线在上、后续行按 lineHeight 向下堆叠;折算保持「关键字所指的块边界
|
|
20
|
+
* (top=块顶 ascent 线 / bottom=块底 descent 线 / middle=视觉中心 / alphabetic=首行基线)落在 y」。
|
|
21
|
+
* @param y - 原垂直锚点(含义由 baseline 决定)
|
|
22
|
+
* @param baseline - 锚点语义
|
|
23
|
+
* @param lineCount - 文本行数(≥1)
|
|
24
|
+
* @param lineHeight - 行高(相邻行基线间距)
|
|
25
|
+
* @param fontSize - 字号(算 ascent/descent 用)
|
|
26
|
+
* @returns 首行 alphabetic 基线 y
|
|
27
|
+
*/
|
|
28
|
+
var toAlphabeticBaselineY = (y, baseline, lineCount, lineHeight, fontSize) => {
|
|
29
|
+
const asc = fontSize * ASCENT_FACTOR;
|
|
30
|
+
const desc = fontSize * DESCENT_FACTOR;
|
|
31
|
+
const span = (lineCount - 1) * lineHeight;
|
|
32
|
+
switch (baseline) {
|
|
33
|
+
case "top": return y + asc;
|
|
34
|
+
case "bottom": return y - span - desc;
|
|
35
|
+
case "middle": return y - span / 2 + (asc - desc) / 2;
|
|
36
|
+
case "alphabetic": return y;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
exports.toAlphabeticBaselineY = toAlphabeticBaselineY;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文本垂直定位归一:任意 baseline 锚点 → 首行 alphabetic 基线 y
|
|
3
|
+
* @description canvas 的 `textBaseline` 与 SVG 的 `dominant-baseline` 是两套同名异义的关键字
|
|
4
|
+
* (`top/middle/bottom` 各按「em 方块」与「字体 ascent/descent」两种不同参照线解释),
|
|
5
|
+
* 只有 `alphabetic`(拉丁字母坐的底线)在两套模型、各浏览器里定义一致。故 core 在编译期把
|
|
6
|
+
* 所有文本的垂直锚点统一折算成首行 alphabetic 基线、emit `baseline: 'alphabetic'`,让 adapter
|
|
7
|
+
* 只渲染这一条无歧义的基线 —— 跨后端像素一致,垂直定位逻辑收口到 renderer-agnostic 的 core。
|
|
8
|
+
*
|
|
9
|
+
* 无字体测量器时用下方 ascent/descent 近似(占一个 em,asc 8 : desc 2 拆分),renderer-agnostic
|
|
10
|
+
* 且两后端一致;接入精确测量器后只需替换 asc/desc 来源,折算公式不变。
|
|
11
|
+
*/
|
|
12
|
+
/** ascent 近似占 fontSize 比例(基线之上) */
|
|
13
|
+
export declare const ASCENT_FACTOR = 0.8;
|
|
14
|
+
/** descent 近似占 fontSize 比例(基线之下) */
|
|
15
|
+
export declare const DESCENT_FACTOR = 0.2;
|
|
16
|
+
/**
|
|
17
|
+
* 把按 `baseline` 解释的垂直锚点 `y` 折算成首行 alphabetic 基线 y
|
|
18
|
+
* @description 多行文本首行基线在上、后续行按 lineHeight 向下堆叠;折算保持「关键字所指的块边界
|
|
19
|
+
* (top=块顶 ascent 线 / bottom=块底 descent 线 / middle=视觉中心 / alphabetic=首行基线)落在 y」。
|
|
20
|
+
* @param y - 原垂直锚点(含义由 baseline 决定)
|
|
21
|
+
* @param baseline - 锚点语义
|
|
22
|
+
* @param lineCount - 文本行数(≥1)
|
|
23
|
+
* @param lineHeight - 行高(相邻行基线间距)
|
|
24
|
+
* @param fontSize - 字号(算 ascent/descent 用)
|
|
25
|
+
* @returns 首行 alphabetic 基线 y
|
|
26
|
+
*/
|
|
27
|
+
export declare const toAlphabeticBaselineY: (y: number, baseline: "top" | "middle" | "bottom" | "alphabetic", lineCount: number, lineHeight: number, fontSize: number) => number;
|
|
28
|
+
//# sourceMappingURL=text-baseline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-baseline.d.ts","sourceRoot":"","sources":["../../../src/compile/text-baseline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,mCAAmC;AACnC,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,oCAAoC;AACpC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAChC,GAAG,MAAM,EACT,UAAU,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,EACpD,WAAW,MAAM,EACjB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,MAcF,CAAC"}
|
|
@@ -22,7 +22,7 @@ export type TextMetrics = {
|
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
24
|
* 文字度量函数接口(编译期由 adapter 注入)
|
|
25
|
-
* @description @retikz/react: canvas measureText;@retikz/ssr: opentype.js/fontkit;@retikz/canvas: ctx.measureText
|
|
25
|
+
* @description @retikz/react: canvas measureText;@retikz/ssr: opentype.js/fontkit;@retikz/render/canvas: ctx.measureText
|
|
26
26
|
*/
|
|
27
27
|
export type TextMeasurer = (text: string, font: FontSpec) => TextMetrics;
|
|
28
28
|
/**
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @retikz/core 公开 API
|
|
3
|
-
* @description 任何 framework adapter(@retikz/react、@retikz/vue、@retikz/canvas、@retikz/ssr)只能 import 本文件导出内容,不准走子路径。本包零 React/零 DOM 依赖
|
|
3
|
+
* @description 任何 framework adapter(@retikz/react、@retikz/vue、@retikz/render/canvas、@retikz/ssr)只能 import 本文件导出内容,不准走子路径。本包零 React/零 DOM 依赖
|
|
4
4
|
*/
|
|
5
5
|
export { PositionSchema, PolarPositionSchema, AtPositionSchema, OffsetPositionSchema, AT_DIRECTIONS, TargetSchema, AnchorRefSchema, NodeTargetSchema, RelativeTargetSchema, RelativeAccumulateTargetSchema, AbsoluteTargetSchema, BetweenPositionSchema, MoveStepSchema, LineStepSchema, FoldStepSchema, CycleStepSchema, CurveStepSchema, CubicStepSchema, BendStepSchema, ArcStepSchema, CirclePathStepSchema, EllipsePathStepSchema, RectangleStepSchema, GeneratorStepSchema, ControlPointSchema, StepLabelSchema, StepSchema, NodeSchema, NodeLabelSchema, CoordinateSchema, FontSchema, TextBlockSchema, LineSpecSchema, PathSchema, ArrowDetailSchema, ArrowEndDetailSchema, ScopeSchema, NodeDefaultSchema, PathDefaultSchema, LabelDefaultSchema, ArrowDefaultSchema, TransformSchema, ChildSchema, SceneSchema, CURRENT_IR_VERSION, PaintSpecSchema, GradientStopSchema, JsonValueSchema, JsonObjectSchema, ClipSpecSchema, ViewBoxSchema, } from './ir';
|
|
6
6
|
export type { IRPosition, IRAtPosition, IROffsetPosition, AtDirection, IRTarget, IRAnchorRef, IRNodeTarget, IRRelativeTarget, IRRelativeAccumulateTarget, IRAbsoluteTarget, IRBetweenPosition, IRMoveStep, IRLineStep, IRFoldStep, IRCycleStep, IRCurveStep, IRCubicStep, IRBendStep, IRArcStep, IRCirclePathStep, IREllipsePathStep, IRRectangleStep, IRGeneratorStep, IRControlPoint, IRStepLabel, IRStep, IRNode, IRNodeLabel, IRCoordinate, IRFont, IRLineSpec, IRTextBlock, IRPath, IRScope, IRNodeDefault, IRPathDefault, IRLabelDefault, IRArrowDefault, StyleChannel, IRTransform, IRTranslateTransform, IRPolarTranslateTransform, IRAtTranslateTransform, IROffsetTranslateTransform, IRRotateTransform, IRScaleTransform, IRChild, IR, ArrowShape, BuiltinArrowName, ArrowShapeName, IRArrowDetail, IRArrowEndDetail, NodeShape, BuiltinShapeName, NodeTextAlign, PatternShapeName, BuiltinPatternName, IRPaintSpec, IRGradientStop, JsonValue, IRJsonObject, IRClipSpec, IRViewBox, } from './ir';
|