@lionad/cx-comps-tanstack-charts 0.1.0-alpha.13 → 0.1.0-alpha.15

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/dist/index.mjs CHANGED
@@ -142,16 +142,20 @@ const HOST_PROP_KEYS = [
142
142
  "className"
143
143
  ];
144
144
  /**
145
- * 命名数据集白名单(GenUI 数据顶层化契约):
146
- * rows 恒为主数据集(流式 trigger arrayKey),nodes/links 承载关系型图双数据集;
147
- * 物料 data 顶层与 definition 平级的这三个数组字段分馏进 datasets 表,
148
- * marks 内字符串引用解析。非数组值静默忽略(流式半值防御)。
145
+ * 命名数据集分馏(GenUI 数据顶层化契约):
146
+ * 物料 data 顶层与 definition 平级的数组字段全量进 datasets 表——rows 恒为主
147
+ * 数据集(流式 trigger arrayKey),其余按语义自由命名:关系型图 nodes/links、
148
+ * geo sphere/graticule/land、分层图 innerRows/outerRows、仪表 bandRows 等。
149
+ * 非数组值静默忽略(流式半值防御)。
150
+ * 排除集防串味:宿主 props(class/style Vue 绑定可为数组)、cx 内部键
151
+ * (comp 运行时节点、data-* 编辑标记、_ 前缀编辑器键)不是数据集。
149
152
  */
150
- const DATASET_KEYS = [
151
- "rows",
152
- "nodes",
153
- "links"
154
- ];
153
+ const DATASET_EXCLUDE_KEYS = /* @__PURE__ */ new Set([
154
+ "definition",
155
+ "comp",
156
+ "class",
157
+ "style"
158
+ ]);
155
159
  /**
156
160
  * 分馏 <Chart> 宿主 props:标量白名单 + class/style + ariaLabel 回退。
157
161
  *
@@ -186,9 +190,11 @@ function useChartProps(attrs) {
186
190
  spec: computed(() => attrs.definition ?? { marks: [] }),
187
191
  datasets: computed(() => {
188
192
  const table = {};
189
- for (const key of DATASET_KEYS) {
190
- const value = attrs[key];
191
- if (Array.isArray(value)) table[key] = value;
193
+ for (const [key, value] of Object.entries(attrs)) {
194
+ if (!Array.isArray(value)) continue;
195
+ if (DATASET_EXCLUDE_KEYS.has(key)) continue;
196
+ if (key.startsWith("data-") || key.startsWith("_")) continue;
197
+ table[key] = value;
192
198
  }
193
199
  return table;
194
200
  }),
@@ -613,6 +619,21 @@ function resolveMarkData(data, datasets) {
613
619
  if (typeof data !== "string") return data;
614
620
  return datasets?.[data] ?? [];
615
621
  }
622
+ /** 缺省半径像素上下界(sqrt 面积映射):小值保可见、大值防巨泡覆盖全图 */
623
+ const DEFAULT_R_RANGE = [2.5, 14];
624
+ /**
625
+ * rScale 注入:库缺省 rScale 是恒等映射(字段原始值直接当像素半径,大数据值
626
+ * 渲染为巨泡)——r 为字段名时缺省注入 sqrt 映射(半径∝√值 ⇒ 面积∝值,气泡图
627
+ * 感知编码约定),domain 由库从数据推断(includeZero)。数值常量 r 是显式像素
628
+ * 意图不缩放;spec.rScale.range 覆盖缺省上下界。
629
+ * 工厂形态(无 copy 的函数)让库推断 domain;实例形态库不推断(scale-input 契约)。
630
+ * 返回 undefined 表示不注入(消费方判空挂 options)。
631
+ */
632
+ function resolveRScaleOption(spec) {
633
+ if (typeof spec.r !== "string") return void 0;
634
+ const range = spec.rScale?.range ?? DEFAULT_R_RANGE;
635
+ return { scale: () => scaleSqrt().range([range[0], range[1]]) };
636
+ }
616
637
  /** layout 声明式 → mark layout 工厂(stack/group/dodge 挂 mark.layout 字段) */
617
638
  function translateLayout(spec) {
618
639
  switch (spec.kind) {
@@ -675,7 +696,10 @@ function translateMark(spec, datasets) {
675
696
  if (value === void 0) continue;
676
697
  options[key] = typeof value === "number" ? () => value : value;
677
698
  }
699
+ if (options.key === void 0) options.key = (_datum, { index }) => index;
678
700
  for (const key of CHANNEL_FLEX_KEYS) if (spec[key] !== void 0) options[key] = spec[key];
701
+ const rScale = resolveRScaleOption(spec);
702
+ if (rScale !== void 0) options.rScale = rScale;
679
703
  for (const key of STYLE_KEYS) if (spec[key] !== void 0) options[key] = spec[key];
680
704
  for (const key of SCALAR_KEYS) if (spec[key] !== void 0) options[key] = spec[key];
681
705
  if (spec.id !== void 0) options.id = spec.id;
@@ -861,6 +885,15 @@ function hierarchyOptions(spec, idKey) {
861
885
  };
862
886
  throw new Error(`translateComposite: ${spec.type} 层级数据源必须声明 path 或 nodeId+parentId`);
863
887
  }
888
+ /**
889
+ * 层级布局节点的字段名通道(treemap/sunburst 的 color/z、tree 节点 dot 的 color/r):
890
+ * 库的 channelValues 在布局节点上平查 datum[field],而 flatHierarchyNodeContext 把源行
891
+ * 收纳在 data 下不展开——字段名物化为 data 取值 accessor,保持「字段名引用源数据」契约。
892
+ * sankey 不在此列:其 marks 回调 channel 按设计锁定布局行字段(key/width 等 canonical)。
893
+ */
894
+ function hierarchyFieldChannel(field) {
895
+ return (node) => node?.data?.[field];
896
+ }
864
897
  /** sankey:固化 marks 回调 = link(布局连线) + rect(布局节点),样式取自声明 */
865
898
  function translateSankey(spec, datasets) {
866
899
  const nodes = resolveMarkData(spec.nodes, datasets);
@@ -911,8 +944,8 @@ function translateSunburst(spec, datasets) {
911
944
  value: spec.value
912
945
  };
913
946
  if (spec.id !== void 0) options.id = spec.id;
914
- if (spec.color !== void 0) options.color = spec.color;
915
- if (spec.z !== void 0) options.z = spec.z;
947
+ if (spec.color !== void 0) options.color = hierarchyFieldChannel(spec.color);
948
+ if (spec.z !== void 0) options.z = hierarchyFieldChannel(spec.z);
916
949
  if (spec.visibleDepth !== void 0) options.visibleDepth = spec.visibleDepth;
917
950
  if (spec.ringPadding !== void 0) options.ringPadding = spec.ringPadding;
918
951
  for (const key of [
@@ -942,7 +975,7 @@ function translateTreemap(spec, datasets) {
942
975
  value: spec.value
943
976
  };
944
977
  if (spec.id !== void 0) options.id = spec.id;
945
- if (spec.color !== void 0) options.color = spec.color;
978
+ if (spec.color !== void 0) options.color = hierarchyFieldChannel(spec.color);
946
979
  if (spec.method !== void 0) options.method = spec.method;
947
980
  if (spec.ratio !== void 0) options.ratio = spec.ratio;
948
981
  if (spec.round !== void 0) options.round = spec.round;
@@ -968,6 +1001,7 @@ function translateTree(spec, datasets) {
968
1001
  if (spec.orientation !== void 0) options.orientation = spec.orientation;
969
1002
  if (spec.nodeSize !== void 0) options.nodeSize = spec.nodeSize;
970
1003
  const layout = treeLayout(rows, options);
1004
+ const nodeRScale = resolveRScaleOption(spec);
971
1005
  return [looseLink(layout.links, {
972
1006
  x1: "x1",
973
1007
  y1: "y1",
@@ -981,9 +1015,10 @@ function translateTree(spec, datasets) {
981
1015
  x: "x",
982
1016
  y: "y",
983
1017
  key: "id",
984
- r: spec.r ?? 4.5,
985
- color: spec.color ?? void 0,
986
- strokeWidth: 1.5
1018
+ r: typeof spec.r === "string" ? hierarchyFieldChannel(spec.r) : spec.r ?? 4.5,
1019
+ color: spec.color === void 0 ? void 0 : hierarchyFieldChannel(spec.color),
1020
+ strokeWidth: 1.5,
1021
+ ...nodeRScale !== void 0 ? { rScale: nodeRScale } : {}
987
1022
  })];
988
1023
  }
989
1024
  /** 缺省力集:官方示例常规四力的常量形态(函数 accessor 不可 JSON,由库缺省接管) */
@@ -1023,6 +1058,7 @@ function translateForceGraph(spec, datasets) {
1023
1058
  if (spec.iterations !== void 0) options.iterations = spec.iterations;
1024
1059
  if (spec.domainPadding !== void 0) options.domainPadding = spec.domainPadding;
1025
1060
  const graph = forceLayout(nodes, links, options);
1061
+ const nodeRScale = resolveRScaleOption(spec);
1026
1062
  return {
1027
1063
  marks: [looseLink(graph.links, {
1028
1064
  x1: "x1",
@@ -1038,7 +1074,8 @@ function translateForceGraph(spec, datasets) {
1038
1074
  key: spec.nodeKey,
1039
1075
  color: spec.color ?? void 0,
1040
1076
  r: spec.r ?? 5,
1041
- strokeWidth: 1.5
1077
+ strokeWidth: 1.5,
1078
+ ...nodeRScale !== void 0 ? { rScale: nodeRScale } : {}
1042
1079
  })],
1043
1080
  xDomain: [graph.xDomain[0], graph.xDomain[1]],
1044
1081
  yDomain: [graph.yDomain[0], graph.yDomain[1]]
@@ -1068,6 +1105,8 @@ function translateGeoShape(spec, datasets) {
1068
1105
  if (spec.key !== void 0) options.key = spec.key;
1069
1106
  if (spec.color !== void 0) options.color = spec.color;
1070
1107
  if (spec.r !== void 0) options.r = spec.r;
1108
+ const rScale = resolveRScaleOption(spec);
1109
+ if (rScale !== void 0) options.rScale = rScale;
1071
1110
  for (const key of [
1072
1111
  "fill",
1073
1112
  "fillOpacity",
@@ -1161,6 +1200,8 @@ function translateViewGrid(spec, datasets, hooks) {
1161
1200
  * - transforms 管道先于 marks 执行,产物注册进数据集表副本(marks 字符串引用在此解析)
1162
1201
  * - polar 族(polar/pie/sunburst 全为 polar 容器且无直角 channel)未显式声明 x/y 时
1163
1202
  * 置 null 显式无轴(库对 polar mark 的 scale 类型为 never,缺省 axis 注入会抛错)
1203
+ * - 纯 geoShape 场景同理置 null(geo mark 不物化直角 scale channel,缺省轴只剩
1204
+ * 0-1 无意义刻度;混合直角 channel mark 时保留缺省轴)
1164
1205
  * - tree/forceGraph 展开为多 mark;forceGraph 回传的轴域在 x/y 未显式声明时注入
1165
1206
  * linear scale 实例(仿真坐标以 0 为中心,缺省推断 domain 不包含负半轴余量)
1166
1207
  * - spec.views 存在时分流 viewGrid 多视图组合(views 与 marks 互斥),各子视图以
@@ -1275,6 +1316,7 @@ function buildDefinition(spec, datasets, rowsOverride, mode = "host") {
1275
1316
  let derivedXDomain;
1276
1317
  let derivedYDomain;
1277
1318
  let polarOnly = markSpecs.length > 0;
1319
+ let geoOnly = markSpecs.length > 0;
1278
1320
  const pushMark = (specMark, runtimeMark) => {
1279
1321
  marks.push(specMark.decorative === true ? decorative(runtimeMark) : runtimeMark);
1280
1322
  };
@@ -1284,6 +1326,7 @@ function buildDefinition(spec, datasets, rowsOverride, mode = "host") {
1284
1326
  data: "rows"
1285
1327
  } : mark;
1286
1328
  if (!POLAR_FAMILY_TYPES.has(bound.type)) polarOnly = false;
1329
+ if (bound.type !== "geoShape") geoOnly = false;
1287
1330
  if (bound.type === "polar") pushMark(bound, translatePolar(bound, table));
1288
1331
  else if (bound.type === "pie") pushMark(bound, translatePie(bound, table));
1289
1332
  else if (COMPOSITE_TYPES.has(bound.type)) {
@@ -1302,8 +1345,9 @@ function buildDefinition(spec, datasets, rowsOverride, mode = "host") {
1302
1345
  marks,
1303
1346
  theme
1304
1347
  };
1305
- const xSpec = spec.x === void 0 && polarOnly ? null : spec.x;
1306
- const ySpec = spec.y === void 0 && polarOnly ? null : spec.y;
1348
+ const axisless = polarOnly || geoOnly;
1349
+ const xSpec = spec.x === void 0 && axisless ? null : spec.x;
1350
+ const ySpec = spec.y === void 0 && axisless ? null : spec.y;
1307
1351
  const x = translateAxis(xSpec ?? void 0, "point");
1308
1352
  const y = translateAxis(ySpec ?? void 0, "linear");
1309
1353
  if (xSpec !== null && x) definition.x = x;
@@ -2175,4 +2219,4 @@ const CxTanstackChartsBundle = {
2175
2219
  materials: [...CxTanstackCharts]
2176
2220
  };
2177
2221
  //#endregion
2178
- export { COMPOSITE_TYPES, CX_CHART_CURVE_NAMES, CxTanstackCharts, area_default as CxTanstackChartsArea, bar_default as CxTanstackChartsBar, CxTanstackChartsBundle, chart_default as CxTanstackChartsChart, dot_default as CxTanstackChartsDot, line_default as CxTanstackChartsLine, pie_default as CxTanstackChartsPie, POLAR_FAMILY_TYPES, TANSTACK_CHARTS_STREAM_TRIGGERS, applyTransforms, createTanstackChartsTriggerRegistry, mainArrayOf, resolveMarkData, translateAxis, translateChartSpec, translateCompositeMark, translateCurve, translateMark, translateOutputs, translatePie, translatePolar, translateReduce, translateScale, translateTransform };
2222
+ export { COMPOSITE_TYPES, CX_CHART_CURVE_NAMES, CxTanstackCharts, area_default as CxTanstackChartsArea, bar_default as CxTanstackChartsBar, CxTanstackChartsBundle, chart_default as CxTanstackChartsChart, dot_default as CxTanstackChartsDot, line_default as CxTanstackChartsLine, pie_default as CxTanstackChartsPie, POLAR_FAMILY_TYPES, TANSTACK_CHARTS_STREAM_TRIGGERS, applyTransforms, createTanstackChartsTriggerRegistry, mainArrayOf, resolveMarkData, resolveRScaleOption, translateAxis, translateChartSpec, translateCompositeMark, translateCurve, translateMark, translateOutputs, translatePie, translatePolar, translateReduce, translateScale, translateTransform };
@@ -8,7 +8,7 @@ export type { CxChartAxisSpec, CxChartCurveName, CxChartDatasets, CxChartForceSp
8
8
  export { CX_CHART_CURVE_NAMES, translateCurve } from './curve';
9
9
  export { translateScale } from './scale';
10
10
  export { translateAxis } from './axis';
11
- export { resolveMarkData, translateMark } from './mark';
11
+ export { resolveMarkData, resolveRScaleOption, translateMark } from './mark';
12
12
  export { applyTransforms, translateOutputs, translateReduce, translateTransform } from './transforms';
13
13
  export { POLAR_FAMILY_TYPES, translatePie, translatePolar } from './polar';
14
14
  export { COMPOSITE_TYPES, translateCompositeMark } from './composite';
@@ -7,6 +7,15 @@ import type { CxChartDatasets, CxChartMarkSpec } from './types';
7
7
  * fallback 从简」契约一致);笔误显式化归生成期校验(spec 渲染断言门)。
8
8
  */
9
9
  export declare function resolveMarkData(data: readonly unknown[] | string | undefined, datasets: CxChartDatasets | undefined): readonly unknown[];
10
+ /**
11
+ * rScale 注入:库缺省 rScale 是恒等映射(字段原始值直接当像素半径,大数据值
12
+ * 渲染为巨泡)——r 为字段名时缺省注入 sqrt 映射(半径∝√值 ⇒ 面积∝值,气泡图
13
+ * 感知编码约定),domain 由库从数据推断(includeZero)。数值常量 r 是显式像素
14
+ * 意图不缩放;spec.rScale.range 覆盖缺省上下界。
15
+ * 工厂形态(无 copy 的函数)让库推断 domain;实例形态库不推断(scale-input 契约)。
16
+ * 返回 undefined 表示不注入(消费方判空挂 options)。
17
+ */
18
+ export declare function resolveRScaleOption(spec: CxChartMarkSpec): unknown;
10
19
  /**
11
20
  * 单 mark 声明式 → ChartMark;多余样式键对 mark 工厂无害(按名读取)。
12
21
  * polar/pie/sankey 等容器与复合 type 不在此处(polar.ts / composite.ts 分支处理)。
@@ -126,6 +126,15 @@ export interface CxChartMarkSpec {
126
126
  key?: string;
127
127
  text?: string;
128
128
  r?: string | number;
129
+ /**
130
+ * 半径缩放声明式(仅 r 为字段名时消费;数值常量 r 是显式像素意图,不缩放)。
131
+ * 库缺省 rScale 为恒等映射(原始值直接当像素半径),翻译层对字段名 r 缺省注入
132
+ * sqrt 面积映射(半径∝√值 ⇒ 面积∝值,气泡图感知编码约定),本字段覆盖其
133
+ * range 像素上下界;kind 不收(sqrt 是气泡半径的正确默认,线性半径会平方夸大差异)。
134
+ */
135
+ rScale?: {
136
+ range?: [number, number];
137
+ };
129
138
  angle?: string | number;
130
139
  radius?: string | number;
131
140
  width?: string | number;
@@ -428,7 +437,7 @@ export type CxChartTransformSpec = {
428
437
  startAngle?: number;
429
438
  endAngle?: number;
430
439
  };
431
- /** 命名数据集表:物料 data 顶层除 definition 外的数组字段(GenUI 契约 rows/nodes/links) */
440
+ /** 命名数据集表:物料 data 顶层除 definition 外的数组字段全量分馏(rows 恒为主数据集,其余按语义自由命名:geo 的 sphere/land、分层图 innerRows/outerRows 等) */
432
441
  export type CxChartDatasets = Record<string, readonly unknown[] | undefined>;
433
442
  /** viewGrid 网格轨道:size 固定像素 / grow 按比例分配剩余空间(min/max 钳制) */
434
443
  export type CxChartViewTrack = {
@@ -9,7 +9,7 @@ export interface CxChartHostPartition {
9
9
  export interface CxChartPropsPartition extends CxChartHostPartition {
10
10
  /** 物料 JSON definition(声明式 spec,待翻译层组装) */
11
11
  spec: ComputedRef<CxChartSpec>;
12
- /** 命名数据集表(rows/nodes/links 白名单分馏;marks 字符串引用在此解析) */
12
+ /** 命名数据集表(顶层数组字段全量分馏;marks 字符串引用在此解析) */
13
13
  datasets: ComputedRef<CxChartDatasets>;
14
14
  }
15
15
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lionad/cx-comps-tanstack-charts",
3
- "version": "0.1.0-alpha.13",
3
+ "version": "0.1.0-alpha.15",
4
4
  "description": "cx material components wrapping TanStack Charts (@tanstack/charts/vue)",
5
5
  "keywords": [
6
6
  "charts",