@visactor/vseed 0.4.25 → 0.4.27

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.
Files changed (97) hide show
  1. package/dist/cjs/index.cjs +2 -2
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/esm/pipeline/advanced/chart/pipes/config/column.js +1 -0
  4. package/dist/esm/pipeline/advanced/chart/pipes/config/column.js.map +1 -1
  5. package/dist/esm/pipeline/advanced/chart/pipes/config/line.js +1 -0
  6. package/dist/esm/pipeline/advanced/chart/pipes/config/line.js.map +1 -1
  7. package/dist/esm/pipeline/spec/chart/pipeline/area.js +5 -1
  8. package/dist/esm/pipeline/spec/chart/pipeline/area.js.map +1 -1
  9. package/dist/esm/pipeline/spec/chart/pipeline/areaPercent.js +3 -1
  10. package/dist/esm/pipeline/spec/chart/pipeline/areaPercent.js.map +1 -1
  11. package/dist/esm/pipeline/spec/chart/pipeline/bar.js +3 -1
  12. package/dist/esm/pipeline/spec/chart/pipeline/bar.js.map +1 -1
  13. package/dist/esm/pipeline/spec/chart/pipeline/barParallel.js +3 -1
  14. package/dist/esm/pipeline/spec/chart/pipeline/barParallel.js.map +1 -1
  15. package/dist/esm/pipeline/spec/chart/pipeline/barPercent.js +3 -1
  16. package/dist/esm/pipeline/spec/chart/pipeline/barPercent.js.map +1 -1
  17. package/dist/esm/pipeline/spec/chart/pipeline/column.js +3 -1
  18. package/dist/esm/pipeline/spec/chart/pipeline/column.js.map +1 -1
  19. package/dist/esm/pipeline/spec/chart/pipeline/columnParallel.js +3 -1
  20. package/dist/esm/pipeline/spec/chart/pipeline/columnParallel.js.map +1 -1
  21. package/dist/esm/pipeline/spec/chart/pipeline/columnPercent.js +3 -1
  22. package/dist/esm/pipeline/spec/chart/pipeline/columnPercent.js.map +1 -1
  23. package/dist/esm/pipeline/spec/chart/pipeline/line.js +5 -1
  24. package/dist/esm/pipeline/spec/chart/pipeline/line.js.map +1 -1
  25. package/dist/esm/pipeline/spec/chart/pipes/annotation/annotationDifferenceLine.js +220 -73
  26. package/dist/esm/pipeline/spec/chart/pipes/annotation/annotationDifferenceLine.js.map +1 -1
  27. package/dist/esm/pipeline/spec/chart/pipes/annotation/annotationDifferenceLineCommon.d.ts +21 -5
  28. package/dist/esm/pipeline/spec/chart/pipes/annotation/annotationDifferenceLineCommon.js +67 -14
  29. package/dist/esm/pipeline/spec/chart/pipes/annotation/annotationDifferenceLineCommon.js.map +1 -1
  30. package/dist/esm/pipeline/spec/chart/pipes/region/index.d.ts +1 -0
  31. package/dist/esm/pipeline/spec/chart/pipes/region/index.js +1 -0
  32. package/dist/esm/pipeline/spec/chart/pipes/region/regionPadding.d.ts +2 -0
  33. package/dist/esm/pipeline/spec/chart/pipes/region/regionPadding.js +20 -0
  34. package/dist/esm/pipeline/spec/chart/pipes/region/regionPadding.js.map +1 -0
  35. package/dist/esm/types/chartType/area/area.d.ts +11 -1
  36. package/dist/esm/types/chartType/area/zArea.d.ts +309 -0
  37. package/dist/esm/types/chartType/area/zArea.js +3 -1
  38. package/dist/esm/types/chartType/area/zArea.js.map +1 -1
  39. package/dist/esm/types/chartType/areaPercent/areaPercent.d.ts +6 -1
  40. package/dist/esm/types/chartType/areaPercent/zAreaPercent.d.ts +6 -0
  41. package/dist/esm/types/chartType/areaPercent/zAreaPercent.js +2 -1
  42. package/dist/esm/types/chartType/areaPercent/zAreaPercent.js.map +1 -1
  43. package/dist/esm/types/chartType/bar/bar.d.ts +6 -1
  44. package/dist/esm/types/chartType/bar/zBar.d.ts +6 -0
  45. package/dist/esm/types/chartType/bar/zBar.js +2 -1
  46. package/dist/esm/types/chartType/bar/zBar.js.map +1 -1
  47. package/dist/esm/types/chartType/barParallel/barParallel.d.ts +6 -1
  48. package/dist/esm/types/chartType/barParallel/zBarParallel.d.ts +6 -0
  49. package/dist/esm/types/chartType/barParallel/zBarParallel.js +2 -1
  50. package/dist/esm/types/chartType/barParallel/zBarParallel.js.map +1 -1
  51. package/dist/esm/types/chartType/barPercent/barPercent.d.ts +6 -1
  52. package/dist/esm/types/chartType/barPercent/zBarPercent.d.ts +6 -0
  53. package/dist/esm/types/chartType/barPercent/zBarPercent.js +2 -1
  54. package/dist/esm/types/chartType/barPercent/zBarPercent.js.map +1 -1
  55. package/dist/esm/types/chartType/column/column.d.ts +6 -1
  56. package/dist/esm/types/chartType/column/zColumn.d.ts +6 -0
  57. package/dist/esm/types/chartType/column/zColumn.js +2 -1
  58. package/dist/esm/types/chartType/column/zColumn.js.map +1 -1
  59. package/dist/esm/types/chartType/columnParallel/columnParallel.d.ts +6 -1
  60. package/dist/esm/types/chartType/columnParallel/zColumnParallel.d.ts +6 -0
  61. package/dist/esm/types/chartType/columnParallel/zColumnParallel.js +2 -1
  62. package/dist/esm/types/chartType/columnParallel/zColumnParallel.js.map +1 -1
  63. package/dist/esm/types/chartType/columnPercent/columnPercent.d.ts +6 -1
  64. package/dist/esm/types/chartType/columnPercent/zColumnPercent.d.ts +6 -0
  65. package/dist/esm/types/chartType/columnPercent/zColumnPercent.js +2 -1
  66. package/dist/esm/types/chartType/columnPercent/zColumnPercent.js.map +1 -1
  67. package/dist/esm/types/chartType/line/line.d.ts +11 -1
  68. package/dist/esm/types/chartType/line/zLine.d.ts +309 -0
  69. package/dist/esm/types/chartType/line/zLine.js +3 -1
  70. package/dist/esm/types/chartType/line/zLine.js.map +1 -1
  71. package/dist/esm/types/properties/config/area.d.ts +12 -0
  72. package/dist/esm/types/properties/config/area.js +2 -0
  73. package/dist/esm/types/properties/config/area.js.map +1 -1
  74. package/dist/esm/types/properties/config/bar.d.ts +18 -0
  75. package/dist/esm/types/properties/config/bar.js +2 -0
  76. package/dist/esm/types/properties/config/bar.js.map +1 -1
  77. package/dist/esm/types/properties/config/column.d.ts +18 -0
  78. package/dist/esm/types/properties/config/column.js +2 -0
  79. package/dist/esm/types/properties/config/column.js.map +1 -1
  80. package/dist/esm/types/properties/config/config.d.ts +66 -0
  81. package/dist/esm/types/properties/config/line.d.ts +6 -0
  82. package/dist/esm/types/properties/config/line.js +2 -0
  83. package/dist/esm/types/properties/config/line.js.map +1 -1
  84. package/dist/esm/types/properties/config/race.d.ts +12 -0
  85. package/dist/esm/types/properties/index.d.ts +1 -0
  86. package/dist/esm/types/properties/index.js +1 -0
  87. package/dist/esm/types/properties/regionPadding/index.d.ts +2 -0
  88. package/dist/esm/types/properties/regionPadding/index.js +1 -0
  89. package/dist/esm/types/properties/regionPadding/regionPadding.d.ts +6 -0
  90. package/dist/esm/types/properties/regionPadding/regionPadding.js +0 -0
  91. package/dist/esm/types/properties/regionPadding/zRegionPadding.d.ts +7 -0
  92. package/dist/esm/types/properties/regionPadding/zRegionPadding.js +11 -0
  93. package/dist/esm/types/properties/regionPadding/zRegionPadding.js.map +1 -0
  94. package/dist/esm/types/properties/theme/customTheme.d.ts +132 -0
  95. package/dist/umd/index.js +552 -291
  96. package/dist/umd/index.js.map +1 -1
  97. package/package.json +1 -1
@@ -1,5 +1,8 @@
1
+ import { autoFormatter, createFormatter, findAllMeasures } from "../../../../utils/index.js";
2
+ import { isDimensionSelector, isFieldSelector, isMeasureSelector, isPartialDatumSelector } from "../../../../../dataSelector/index.js";
3
+ import { isEmpty } from "remeda";
1
4
  import { ANNOTATION_Z_INDEX } from "../../../../utils/constant.js";
2
- import { buildDifferenceCoordinateDatum, buildDifferenceText, inferDifferenceConnectDirection, isDifferenceLineStacked, resolveDifferenceAnchor } from "./annotationDifferenceLineCommon.js";
5
+ import { buildDifferenceCoordinateDatum, buildDifferenceText, getDifferenceLineStackResolveMode, getRuntimeDifferenceValue, inferDifferenceBracketDirection, inferDifferenceConnectDirection, resolveDifferenceAnchor, usesDifferenceLineElementStackEnd } from "./annotationDifferenceLineCommon.js";
3
6
  const DEFAULT_LINE_COLOR = '#BCC1CB';
4
7
  const DEFAULT_TEXT_COLOR = '#ffffff';
5
8
  const DEFAULT_TEXT_BACKGROUND_COLOR = '#BCC1CB';
@@ -10,7 +13,63 @@ const DEFAULT_CORNER_RADIUS = 4;
10
13
  const DEFAULT_LABEL_PADDING = 4;
11
14
  const DEFAULT_END_SYMBOL_SIZE = 12;
12
15
  const DEFAULT_END_SYMBOL_REF_X = -4;
16
+ const DEFAULT_BRACKET_EXPAND_DISTANCE = 80;
17
+ const DEFAULT_BRACKET_LINE_DASH = [
18
+ 2,
19
+ 2
20
+ ];
21
+ const DEFAULT_PERCENT_DIFFERENCE_FORMAT = {
22
+ type: 'percent',
23
+ fractionDigits: 2
24
+ };
13
25
  const getDifferenceLinePath = (index, total)=>1 === total ? 'annotationDifferenceLine' : `annotationDifferenceLine[${index}]`;
26
+ const toArray = (value)=>{
27
+ if (Array.isArray(value)) return value;
28
+ return null == value ? [] : [
29
+ value
30
+ ];
31
+ };
32
+ const getAxisFormatter = (spec)=>{
33
+ const valueAxisOrient = 'horizontal' === spec.direction ? 'bottom' : 'left';
34
+ const formatMethod = spec.axes?.find((axis)=>axis.orient === valueAxisOrient)?.label?.formatMethod;
35
+ return 'function' == typeof formatMethod ? (value)=>String(formatMethod(value) ?? value) : void 0;
36
+ };
37
+ const getExplicitMeasureFormat = (measure)=>{
38
+ if (measure?.numFormat && !isEmpty(measure.numFormat)) return measure.numFormat;
39
+ if (measure?.format && !isEmpty(measure.format)) return measure.format;
40
+ };
41
+ const inferMeasureIdFromDatum = (anchor, measureIds)=>{
42
+ const candidateValues = [
43
+ anchor.matchedDatum,
44
+ anchor.coordinateDatum
45
+ ];
46
+ for (const datum of candidateValues){
47
+ if (!datum) continue;
48
+ const candidates = measureIds.filter((measureId)=>Number(datum[measureId]) === anchor.value);
49
+ if (1 === candidates.length) return candidates[0];
50
+ }
51
+ };
52
+ const inferMeasureIdFromSelector = (selectorValue, measureIdSet)=>{
53
+ const matchedMeasureIds = new Set();
54
+ for (const currentSelector of toArray(selectorValue)){
55
+ if (isMeasureSelector(currentSelector)) {
56
+ if (measureIdSet.has(currentSelector.field)) matchedMeasureIds.add(currentSelector.field);
57
+ continue;
58
+ }
59
+ if (!(isFieldSelector(currentSelector) || isDimensionSelector(currentSelector))) {
60
+ if (isPartialDatumSelector(currentSelector)) Object.keys(currentSelector).forEach((field)=>{
61
+ if (measureIdSet.has(field)) matchedMeasureIds.add(field);
62
+ });
63
+ }
64
+ }
65
+ return 1 === matchedMeasureIds.size ? Array.from(matchedMeasureIds)[0] : void 0;
66
+ };
67
+ const resolveDifferenceMeasureId = (anchor, selectorValue, measureIds)=>{
68
+ if ('element' !== anchor.mode) return;
69
+ if (1 === measureIds.length) return measureIds[0];
70
+ const measureIdSet = new Set(measureIds);
71
+ return inferMeasureIdFromSelector(selectorValue, measureIdSet) ?? inferMeasureIdFromDatum(anchor, measureIds);
72
+ };
14
73
  const assertDifferenceLineConfig = (value, path)=>{
15
74
  if ('object' != typeof value || null === value || Array.isArray(value)) throw new Error(`${path} must be an object`);
16
75
  const start = value.start;
@@ -29,98 +88,186 @@ const annotationDifferenceLine_annotationDifferenceLine = (spec, context)=>{
29
88
  annotationDifferenceLine
30
89
  ];
31
90
  const dataset = advancedVSeed.dataset.flat();
32
- const barSpec = spec;
33
- const isStacked = isDifferenceLineStacked(vseed, advancedVSeed);
91
+ const chartSpec = spec;
92
+ const stackResolveMode = getDifferenceLineStackResolveMode(vseed, advancedVSeed);
93
+ const useElementStackEnd = usesDifferenceLineElementStackEnd(vseed, advancedVSeed);
94
+ const isBracketChart = 'line' === vseed.chartType || 'area' === vseed.chartType;
95
+ const measures = findAllMeasures(advancedVSeed.measures);
96
+ const measureIds = measures.map((measure)=>measure.id);
97
+ const axisFormatter = getAxisFormatter(chartSpec);
98
+ const percentFormatter = createFormatter(DEFAULT_PERCENT_DIFFERENCE_FORMAT);
34
99
  const markLine = annotationDifferenceLineList.flatMap((annotationDifferenceLine, index)=>{
35
- assertDifferenceLineConfig(annotationDifferenceLine, getDifferenceLinePath(index, annotationDifferenceLineList.length));
36
- const start = resolveDifferenceAnchor({
37
- dataset,
38
- selectorLabel: 'start',
39
- selectorValue: annotationDifferenceLine.start.selector,
40
- spec: barSpec,
41
- isStacked
42
- });
43
- const end = resolveDifferenceAnchor({
44
- dataset,
45
- selectorLabel: 'end',
46
- selectorValue: annotationDifferenceLine.end.selector,
47
- spec: barSpec,
48
- isStacked
49
- });
50
- if (!start || !end) return [];
51
- const lineColor = annotationDifferenceLine.lineColor ?? theme?.lineColor ?? DEFAULT_LINE_COLOR;
52
- const textColor = annotationDifferenceLine.textColor ?? theme?.textColor ?? DEFAULT_TEXT_COLOR;
53
- const textBackgroundColor = annotationDifferenceLine.textBackgroundColor ?? theme?.textBackgroundColor ?? DEFAULT_TEXT_BACKGROUND_COLOR;
54
- const textFontSize = annotationDifferenceLine.textFontSize ?? theme?.textFontSize ?? DEFAULT_TEXT_FONT_SIZE;
55
- return [
56
- {
57
- type: 'type-step',
58
- autoRange: true,
59
- zIndex: ANNOTATION_Z_INDEX,
60
- connectDirection: inferDifferenceConnectDirection(vseed, [
61
- start.value,
62
- end.value
63
- ]),
64
- expandDistance: DEFAULT_EXPAND_DISTANCE,
65
- coordinates: (seriesData, relativeSeries)=>[
66
- buildDifferenceCoordinateDatum({
100
+ try {
101
+ assertDifferenceLineConfig(annotationDifferenceLine, getDifferenceLinePath(index, annotationDifferenceLineList.length));
102
+ const start = resolveDifferenceAnchor({
103
+ dataset,
104
+ selectorLabel: 'start',
105
+ selectorValue: annotationDifferenceLine.start.selector,
106
+ spec: chartSpec,
107
+ stackResolveMode,
108
+ allowSelectorFallback: !useElementStackEnd
109
+ });
110
+ const end = resolveDifferenceAnchor({
111
+ dataset,
112
+ selectorLabel: 'end',
113
+ selectorValue: annotationDifferenceLine.end.selector,
114
+ spec: chartSpec,
115
+ stackResolveMode,
116
+ allowSelectorFallback: !useElementStackEnd
117
+ });
118
+ if (!start || !end) return [];
119
+ if (start.mode !== end.mode) return [];
120
+ const usesRuntimeStackEnd = useElementStackEnd || ('column' === vseed.chartType || 'bar' === vseed.chartType) && 'element' === start.mode && 'auto' === stackResolveMode;
121
+ const useBracketStyle = isBracketChart || ('column' === vseed.chartType || 'bar' === vseed.chartType) && 'element' === start.mode && 'auto' === stackResolveMode;
122
+ const isStackedBarElementBracket = 'bar' === vseed.chartType && 'element' === start.mode && 'auto' === stackResolveMode;
123
+ const connectDirection = useBracketStyle ? isStackedBarElementBracket ? 'top' : inferDifferenceBracketDirection(start, end) : inferDifferenceConnectDirection(vseed, [
124
+ start.value,
125
+ end.value
126
+ ]);
127
+ const lineColor = annotationDifferenceLine.lineColor ?? theme?.lineColor ?? DEFAULT_LINE_COLOR;
128
+ const textColor = annotationDifferenceLine.textColor ?? theme?.textColor ?? DEFAULT_TEXT_COLOR;
129
+ const textBackgroundColor = annotationDifferenceLine.textBackgroundColor ?? theme?.textBackgroundColor ?? DEFAULT_TEXT_BACKGROUND_COLOR;
130
+ const textFontSize = annotationDifferenceLine.textFontSize ?? theme?.textFontSize ?? DEFAULT_TEXT_FONT_SIZE;
131
+ const differenceType = annotationDifferenceLine.differenceType ?? 'absolute';
132
+ const startMeasureId = resolveDifferenceMeasureId(start, annotationDifferenceLine.start.selector, measureIds);
133
+ const endMeasureId = resolveDifferenceMeasureId(end, annotationDifferenceLine.end.selector, measureIds);
134
+ const sameMeasure = void 0 !== startMeasureId && startMeasureId === endMeasureId;
135
+ const explicitMeasureFormat = sameMeasure ? getExplicitMeasureFormat(measures.find((measure)=>measure.id === startMeasureId)) : void 0;
136
+ const differenceFormatter = 'percent' === differenceType ? percentFormatter : explicitMeasureFormat ? createFormatter(explicitMeasureFormat) : axisFormatter ?? autoFormatter;
137
+ const label = usesRuntimeStackEnd ? {
138
+ visible: true,
139
+ position: 'middle',
140
+ refY: 0,
141
+ formatMethod: (_markData, seriesData)=>{
142
+ try {
143
+ return buildDifferenceText(getRuntimeDifferenceValue({
67
144
  anchor: start,
68
145
  seriesData,
69
- relativeSeries
70
- }),
71
- buildDifferenceCoordinateDatum({
146
+ useElementStackEnd: usesRuntimeStackEnd
147
+ }), getRuntimeDifferenceValue({
72
148
  anchor: end,
73
149
  seriesData,
74
- relativeSeries
75
- })
76
- ],
77
- line: {
150
+ useElementStackEnd: usesRuntimeStackEnd
151
+ }), differenceType, differenceFormatter);
152
+ } catch {
153
+ return '';
154
+ }
155
+ },
156
+ style: {
157
+ fill: textColor,
158
+ fontSize: textFontSize
159
+ },
160
+ labelBackground: {
161
+ visible: true,
162
+ padding: DEFAULT_LABEL_PADDING,
78
163
  style: {
79
- visible: true,
164
+ fill: textBackgroundColor,
165
+ fillOpacity: 1,
80
166
  stroke: lineColor,
81
- lineWidth: DEFAULT_LINE_WIDTH,
82
- lineDash: [
83
- 0
84
- ],
167
+ lineWidth: 1,
85
168
  cornerRadius: DEFAULT_CORNER_RADIUS
86
169
  }
170
+ }
171
+ } : {
172
+ visible: true,
173
+ position: 'middle',
174
+ refY: 0,
175
+ text: buildDifferenceText(start.value, end.value, differenceType, differenceFormatter),
176
+ style: {
177
+ fill: textColor,
178
+ fontSize: textFontSize
87
179
  },
88
- label: {
89
- confine: true,
180
+ labelBackground: {
90
181
  visible: true,
91
- position: 'middle',
92
- text: buildDifferenceText(start.value, end.value, annotationDifferenceLine.differenceType ?? 'absolute'),
182
+ padding: DEFAULT_LABEL_PADDING,
93
183
  style: {
94
- fill: textColor,
95
- fontSize: textFontSize
184
+ fill: textBackgroundColor,
185
+ fillOpacity: 1,
186
+ stroke: lineColor,
187
+ lineWidth: 1,
188
+ cornerRadius: DEFAULT_CORNER_RADIUS
189
+ }
190
+ }
191
+ };
192
+ return [
193
+ {
194
+ type: 'type-step',
195
+ autoRange: true,
196
+ zIndex: ANNOTATION_Z_INDEX,
197
+ connectDirection,
198
+ expandDistance: useBracketStyle ? DEFAULT_BRACKET_EXPAND_DISTANCE : DEFAULT_EXPAND_DISTANCE,
199
+ coordinates: (seriesData, relativeSeries)=>{
200
+ try {
201
+ return [
202
+ buildDifferenceCoordinateDatum({
203
+ anchor: start,
204
+ seriesData,
205
+ relativeSeries,
206
+ useElementStackEnd: usesRuntimeStackEnd
207
+ }),
208
+ buildDifferenceCoordinateDatum({
209
+ anchor: end,
210
+ seriesData,
211
+ relativeSeries,
212
+ useElementStackEnd: usesRuntimeStackEnd
213
+ })
214
+ ];
215
+ } catch {
216
+ return [];
217
+ }
96
218
  },
97
- labelBackground: {
98
- visible: true,
99
- padding: DEFAULT_LABEL_PADDING,
219
+ line: useBracketStyle ? {
220
+ multiSegment: true,
221
+ mainSegmentIndex: 1,
222
+ style: [
223
+ {
224
+ visible: true,
225
+ stroke: lineColor,
226
+ lineWidth: DEFAULT_LINE_WIDTH,
227
+ lineDash: DEFAULT_BRACKET_LINE_DASH
228
+ },
229
+ {
230
+ visible: true,
231
+ stroke: lineColor,
232
+ lineWidth: DEFAULT_LINE_WIDTH
233
+ },
234
+ {
235
+ visible: true,
236
+ stroke: lineColor,
237
+ lineWidth: DEFAULT_LINE_WIDTH,
238
+ lineDash: DEFAULT_BRACKET_LINE_DASH
239
+ }
240
+ ]
241
+ } : {
100
242
  style: {
101
- fill: textBackgroundColor,
102
- fillOpacity: 1,
243
+ visible: true,
103
244
  stroke: lineColor,
104
- lineWidth: 1,
245
+ lineWidth: DEFAULT_LINE_WIDTH,
246
+ lineDash: [
247
+ 0
248
+ ],
105
249
  cornerRadius: DEFAULT_CORNER_RADIUS
106
250
  }
107
- }
108
- },
109
- startSymbol: {
110
- visible: false
111
- },
112
- endSymbol: {
113
- visible: true,
114
- size: DEFAULT_END_SYMBOL_SIZE,
115
- refX: DEFAULT_END_SYMBOL_REF_X,
116
- style: {
117
- fill: lineColor
251
+ },
252
+ label,
253
+ startSymbol: {
254
+ visible: false
255
+ },
256
+ endSymbol: {
257
+ visible: true,
258
+ size: DEFAULT_END_SYMBOL_SIZE,
259
+ refX: DEFAULT_END_SYMBOL_REF_X,
260
+ style: {
261
+ fill: lineColor
262
+ }
118
263
  }
119
264
  }
120
- }
121
- ];
265
+ ];
266
+ } catch {
267
+ return [];
268
+ }
122
269
  });
123
- const specMarkLine = barSpec.markLine || [];
270
+ const specMarkLine = chartSpec.markLine || [];
124
271
  return {
125
272
  ...spec,
126
273
  markLine: [
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline/spec/chart/pipes/annotation/annotationDifferenceLine.js","sources":["../../../../../../../src/pipeline/spec/chart/pipes/annotation/annotationDifferenceLine.ts"],"sourcesContent":["import type { IBarChartSpec, ICartesianSeries, IMarkLineSpec } from '@visactor/vchart'\nimport type { AnnotationDifferenceLine, VChartSpecPipe } from 'src/types'\nimport { ANNOTATION_Z_INDEX } from '../../../../utils/constant'\nimport {\n buildDifferenceCoordinateDatum,\n buildDifferenceText,\n inferDifferenceConnectDirection,\n isDifferenceLineStacked,\n resolveDifferenceAnchor,\n} from './annotationDifferenceLineCommon'\n\nconst DEFAULT_LINE_COLOR = '#BCC1CB'\nconst DEFAULT_TEXT_COLOR = '#ffffff'\nconst DEFAULT_TEXT_BACKGROUND_COLOR = '#BCC1CB'\nconst DEFAULT_TEXT_FONT_SIZE = 12\nconst DEFAULT_EXPAND_DISTANCE = 24\nconst DEFAULT_LINE_WIDTH = 2\nconst DEFAULT_CORNER_RADIUS = 4\nconst DEFAULT_LABEL_PADDING = 4\nconst DEFAULT_END_SYMBOL_SIZE = 12\nconst DEFAULT_END_SYMBOL_REF_X = -4\n\nconst getDifferenceLinePath = (index: number, total: number) =>\n total === 1 ? 'annotationDifferenceLine' : `annotationDifferenceLine[${index}]`\n\nconst assertDifferenceLineConfig: (value: unknown, path: string) => asserts value is AnnotationDifferenceLine = (\n value,\n path,\n) => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new Error(`${path} must be an object`)\n }\n\n const start = (value as Record<string, unknown>).start\n if (typeof start !== 'object' || start === null || Array.isArray(start)) {\n throw new Error(`${path}.start is required`)\n }\n if ((start as Record<string, unknown>).selector == null) {\n throw new Error(`${path}.start.selector is required`)\n }\n\n const end = (value as Record<string, unknown>).end\n if (typeof end !== 'object' || end === null || Array.isArray(end)) {\n throw new Error(`${path}.end is required`)\n }\n if ((end as Record<string, unknown>).selector == null) {\n throw new Error(`${path}.end.selector is required`)\n }\n}\n\nexport const annotationDifferenceLine: VChartSpecPipe = (spec, context) => {\n const { advancedVSeed, vseed } = context\n const annotationDifferenceLine = advancedVSeed.annotation?.annotationDifferenceLine\n\n if (!annotationDifferenceLine) {\n return spec\n }\n\n const theme = advancedVSeed.config?.[vseed.chartType as 'column']?.annotation?.annotationDifferenceLine\n const annotationDifferenceLineList = Array.isArray(annotationDifferenceLine)\n ? annotationDifferenceLine\n : [annotationDifferenceLine]\n const dataset = advancedVSeed.dataset.flat()\n const barSpec = spec as IBarChartSpec\n const isStacked = isDifferenceLineStacked(vseed, advancedVSeed)\n\n const markLine = annotationDifferenceLineList.flatMap((annotationDifferenceLine, index) => {\n assertDifferenceLineConfig(\n annotationDifferenceLine,\n getDifferenceLinePath(index, annotationDifferenceLineList.length),\n )\n\n const start = resolveDifferenceAnchor({\n dataset,\n selectorLabel: 'start',\n selectorValue: annotationDifferenceLine.start.selector,\n spec: barSpec,\n isStacked,\n })\n const end = resolveDifferenceAnchor({\n dataset,\n selectorLabel: 'end',\n selectorValue: annotationDifferenceLine.end.selector,\n spec: barSpec,\n isStacked,\n })\n\n if (!start || !end) {\n return []\n }\n\n const lineColor = annotationDifferenceLine.lineColor ?? theme?.lineColor ?? DEFAULT_LINE_COLOR\n const textColor = annotationDifferenceLine.textColor ?? theme?.textColor ?? DEFAULT_TEXT_COLOR\n const textBackgroundColor =\n annotationDifferenceLine.textBackgroundColor ?? theme?.textBackgroundColor ?? DEFAULT_TEXT_BACKGROUND_COLOR\n const textFontSize = annotationDifferenceLine.textFontSize ?? theme?.textFontSize ?? DEFAULT_TEXT_FONT_SIZE\n\n return [\n {\n type: 'type-step',\n autoRange: true,\n zIndex: ANNOTATION_Z_INDEX,\n connectDirection: inferDifferenceConnectDirection(vseed, [start.value, end.value]),\n expandDistance: DEFAULT_EXPAND_DISTANCE,\n coordinates: (seriesData: any[], relativeSeries: ICartesianSeries) => [\n buildDifferenceCoordinateDatum({\n anchor: start,\n seriesData,\n relativeSeries,\n }),\n buildDifferenceCoordinateDatum({\n anchor: end,\n seriesData,\n relativeSeries,\n }),\n ],\n line: {\n style: {\n visible: true,\n stroke: lineColor,\n lineWidth: DEFAULT_LINE_WIDTH,\n lineDash: [0],\n cornerRadius: DEFAULT_CORNER_RADIUS,\n },\n },\n label: {\n confine: true,\n visible: true,\n position: 'middle',\n text: buildDifferenceText(start.value, end.value, annotationDifferenceLine.differenceType ?? 'absolute'),\n style: {\n fill: textColor,\n fontSize: textFontSize,\n },\n labelBackground: {\n visible: true,\n padding: DEFAULT_LABEL_PADDING,\n style: {\n fill: textBackgroundColor,\n fillOpacity: 1,\n stroke: lineColor,\n lineWidth: 1,\n cornerRadius: DEFAULT_CORNER_RADIUS,\n },\n },\n },\n startSymbol: {\n visible: false,\n },\n endSymbol: {\n visible: true,\n size: DEFAULT_END_SYMBOL_SIZE,\n refX: DEFAULT_END_SYMBOL_REF_X,\n style: {\n fill: lineColor,\n },\n },\n } as IMarkLineSpec,\n ]\n })\n\n const specMarkLine = (barSpec.markLine as IMarkLineSpec[]) || []\n\n return {\n ...spec,\n markLine: [...specMarkLine, ...markLine],\n }\n}\n"],"names":["DEFAULT_LINE_COLOR","DEFAULT_TEXT_COLOR","DEFAULT_TEXT_BACKGROUND_COLOR","DEFAULT_TEXT_FONT_SIZE","DEFAULT_EXPAND_DISTANCE","DEFAULT_LINE_WIDTH","DEFAULT_CORNER_RADIUS","DEFAULT_LABEL_PADDING","DEFAULT_END_SYMBOL_SIZE","DEFAULT_END_SYMBOL_REF_X","getDifferenceLinePath","index","total","assertDifferenceLineConfig","value","path","Array","Error","start","end","annotationDifferenceLine","spec","context","advancedVSeed","vseed","theme","annotationDifferenceLineList","dataset","barSpec","isStacked","isDifferenceLineStacked","markLine","resolveDifferenceAnchor","lineColor","textColor","textBackgroundColor","textFontSize","ANNOTATION_Z_INDEX","inferDifferenceConnectDirection","seriesData","relativeSeries","buildDifferenceCoordinateDatum","buildDifferenceText","specMarkLine"],"mappings":"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"}
1
+ {"version":3,"file":"pipeline/spec/chart/pipes/annotation/annotationDifferenceLine.js","sources":["../../../../../../../src/pipeline/spec/chart/pipes/annotation/annotationDifferenceLine.ts"],"sourcesContent":["import type { IAreaChartSpec, IBarChartSpec, ICartesianSeries, ILineChartSpec, IMarkLineSpec } from '@visactor/vchart'\nimport type { AnnotationDifferenceLine, Measure, VChartSpecPipe } from 'src/types'\nimport { createFormatter, findAllMeasures, autoFormatter } from '../../../../utils'\nimport {\n isDimensionSelector,\n isFieldSelector,\n isMeasureSelector,\n isPartialDatumSelector,\n} from '../../../../../dataSelector'\nimport { isEmpty } from 'remeda'\nimport { ANNOTATION_Z_INDEX } from '../../../../utils/constant'\nimport {\n buildDifferenceCoordinateDatum,\n buildDifferenceText,\n getDifferenceLineStackResolveMode,\n getRuntimeDifferenceValue,\n inferDifferenceBracketDirection,\n inferDifferenceConnectDirection,\n type ResolvedDifferenceAnchor,\n usesDifferenceLineElementStackEnd,\n resolveDifferenceAnchor,\n} from './annotationDifferenceLineCommon'\n\nconst DEFAULT_LINE_COLOR = '#BCC1CB'\nconst DEFAULT_TEXT_COLOR = '#ffffff'\nconst DEFAULT_TEXT_BACKGROUND_COLOR = '#BCC1CB'\nconst DEFAULT_TEXT_FONT_SIZE = 12\nconst DEFAULT_EXPAND_DISTANCE = 24\nconst DEFAULT_LINE_WIDTH = 2\nconst DEFAULT_CORNER_RADIUS = 4\nconst DEFAULT_LABEL_PADDING = 4\nconst DEFAULT_END_SYMBOL_SIZE = 12\nconst DEFAULT_END_SYMBOL_REF_X = -4\nconst DEFAULT_BRACKET_EXPAND_DISTANCE = 80\nconst DEFAULT_BRACKET_LINE_DASH: [number, number] = [2, 2]\nconst DEFAULT_PERCENT_DIFFERENCE_FORMAT = {\n type: 'percent' as const,\n fractionDigits: 2,\n}\n\nconst getDifferenceLinePath = (index: number, total: number) =>\n total === 1 ? 'annotationDifferenceLine' : `annotationDifferenceLine[${index}]`\n\nconst toArray = <T>(value: T | T[] | undefined | null): T[] => {\n if (Array.isArray(value)) {\n return value\n }\n\n return value === undefined || value === null ? [] : [value]\n}\n\nconst getAxisFormatter = (spec: IBarChartSpec | ILineChartSpec | IAreaChartSpec) => {\n const valueAxisOrient = spec.direction === 'horizontal' ? 'bottom' : 'left'\n const formatMethod = spec.axes?.find((axis) => axis.orient === valueAxisOrient)?.label?.formatMethod\n\n return typeof formatMethod === 'function'\n ? (value: number) => String(formatMethod(value as never) ?? value)\n : undefined\n}\n\nconst getExplicitMeasureFormat = (measure?: Measure) => {\n if (measure?.numFormat && !isEmpty(measure.numFormat)) {\n return measure.numFormat\n }\n\n if (measure?.format && !isEmpty(measure.format)) {\n return measure.format\n }\n\n return undefined\n}\n\nconst inferMeasureIdFromDatum = (anchor: ResolvedDifferenceAnchor, measureIds: string[]) => {\n const candidateValues = [anchor.matchedDatum, anchor.coordinateDatum]\n\n for (const datum of candidateValues) {\n if (!datum) {\n continue\n }\n\n const candidates = measureIds.filter((measureId) => Number(datum[measureId]) === anchor.value)\n\n if (candidates.length === 1) {\n return candidates[0]\n }\n }\n\n return undefined\n}\n\nconst inferMeasureIdFromSelector = (\n selectorValue: AnnotationDifferenceLine['start']['selector'],\n measureIdSet: Set<string>,\n) => {\n const matchedMeasureIds = new Set<string>()\n\n for (const currentSelector of toArray(selectorValue)) {\n if (isMeasureSelector(currentSelector)) {\n if (measureIdSet.has(currentSelector.field)) {\n matchedMeasureIds.add(currentSelector.field)\n }\n continue\n }\n\n if (isFieldSelector(currentSelector) || isDimensionSelector(currentSelector)) {\n continue\n }\n\n if (isPartialDatumSelector(currentSelector)) {\n Object.keys(currentSelector).forEach((field) => {\n if (measureIdSet.has(field)) {\n matchedMeasureIds.add(field)\n }\n })\n }\n }\n\n return matchedMeasureIds.size === 1 ? Array.from(matchedMeasureIds)[0] : undefined\n}\n\nconst resolveDifferenceMeasureId = (\n anchor: ResolvedDifferenceAnchor,\n selectorValue: AnnotationDifferenceLine['start']['selector'],\n measureIds: string[],\n) => {\n if (anchor.mode !== 'element') {\n return undefined\n }\n\n if (measureIds.length === 1) {\n return measureIds[0]\n }\n\n const measureIdSet = new Set(measureIds)\n return inferMeasureIdFromSelector(selectorValue, measureIdSet) ?? inferMeasureIdFromDatum(anchor, measureIds)\n}\n\nconst assertDifferenceLineConfig: (value: unknown, path: string) => asserts value is AnnotationDifferenceLine = (\n value,\n path,\n) => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new Error(`${path} must be an object`)\n }\n\n const start = (value as Record<string, unknown>).start\n if (typeof start !== 'object' || start === null || Array.isArray(start)) {\n throw new Error(`${path}.start is required`)\n }\n if ((start as Record<string, unknown>).selector == null) {\n throw new Error(`${path}.start.selector is required`)\n }\n\n const end = (value as Record<string, unknown>).end\n if (typeof end !== 'object' || end === null || Array.isArray(end)) {\n throw new Error(`${path}.end is required`)\n }\n if ((end as Record<string, unknown>).selector == null) {\n throw new Error(`${path}.end.selector is required`)\n }\n}\n\nexport const annotationDifferenceLine: VChartSpecPipe = (spec, context) => {\n const { advancedVSeed, vseed } = context\n const annotationDifferenceLine = advancedVSeed.annotation?.annotationDifferenceLine\n\n if (!annotationDifferenceLine) {\n return spec\n }\n\n const theme = advancedVSeed.config?.[vseed.chartType as 'column']?.annotation?.annotationDifferenceLine\n const annotationDifferenceLineList = Array.isArray(annotationDifferenceLine)\n ? annotationDifferenceLine\n : [annotationDifferenceLine]\n const dataset = advancedVSeed.dataset.flat()\n const chartSpec = spec as IBarChartSpec | ILineChartSpec | IAreaChartSpec\n const stackResolveMode = getDifferenceLineStackResolveMode(vseed, advancedVSeed)\n const useElementStackEnd = usesDifferenceLineElementStackEnd(vseed, advancedVSeed)\n const isBracketChart = vseed.chartType === 'line' || vseed.chartType === 'area'\n const measures = findAllMeasures(advancedVSeed.measures)\n const measureIds = measures.map((measure) => measure.id)\n const axisFormatter = getAxisFormatter(chartSpec)\n const percentFormatter = createFormatter(DEFAULT_PERCENT_DIFFERENCE_FORMAT)\n\n const markLine = annotationDifferenceLineList.flatMap((annotationDifferenceLine, index) => {\n try {\n assertDifferenceLineConfig(\n annotationDifferenceLine,\n getDifferenceLinePath(index, annotationDifferenceLineList.length),\n )\n\n const start = resolveDifferenceAnchor({\n dataset,\n selectorLabel: 'start',\n selectorValue: annotationDifferenceLine.start.selector,\n spec: chartSpec,\n stackResolveMode,\n allowSelectorFallback: !useElementStackEnd,\n })\n const end = resolveDifferenceAnchor({\n dataset,\n selectorLabel: 'end',\n selectorValue: annotationDifferenceLine.end.selector,\n spec: chartSpec,\n stackResolveMode,\n allowSelectorFallback: !useElementStackEnd,\n })\n\n if (!start || !end) {\n return []\n }\n\n if (start.mode !== end.mode) {\n return []\n }\n\n const usesRuntimeStackEnd =\n useElementStackEnd ||\n ((vseed.chartType === 'column' || vseed.chartType === 'bar') &&\n start.mode === 'element' &&\n stackResolveMode === 'auto')\n const useBracketStyle =\n isBracketChart ||\n ((vseed.chartType === 'column' || vseed.chartType === 'bar') &&\n start.mode === 'element' &&\n stackResolveMode === 'auto')\n const isStackedBarElementBracket =\n vseed.chartType === 'bar' && start.mode === 'element' && stackResolveMode === 'auto'\n const connectDirection = useBracketStyle\n ? isStackedBarElementBracket\n ? 'top'\n : inferDifferenceBracketDirection(start, end)\n : inferDifferenceConnectDirection(vseed, [start.value, end.value])\n\n const lineColor = annotationDifferenceLine.lineColor ?? theme?.lineColor ?? DEFAULT_LINE_COLOR\n const textColor = annotationDifferenceLine.textColor ?? theme?.textColor ?? DEFAULT_TEXT_COLOR\n const textBackgroundColor =\n annotationDifferenceLine.textBackgroundColor ?? theme?.textBackgroundColor ?? DEFAULT_TEXT_BACKGROUND_COLOR\n const textFontSize = annotationDifferenceLine.textFontSize ?? theme?.textFontSize ?? DEFAULT_TEXT_FONT_SIZE\n const differenceType = annotationDifferenceLine.differenceType ?? 'absolute'\n const startMeasureId = resolveDifferenceMeasureId(start, annotationDifferenceLine.start.selector, measureIds)\n const endMeasureId = resolveDifferenceMeasureId(end, annotationDifferenceLine.end.selector, measureIds)\n const sameMeasure = startMeasureId !== undefined && startMeasureId === endMeasureId\n const explicitMeasureFormat = sameMeasure\n ? getExplicitMeasureFormat(measures.find((measure) => measure.id === startMeasureId))\n : undefined\n const differenceFormatter =\n differenceType === 'percent'\n ? percentFormatter\n : explicitMeasureFormat\n ? createFormatter(explicitMeasureFormat)\n : (axisFormatter ?? autoFormatter)\n\n const label = usesRuntimeStackEnd\n ? {\n visible: true,\n position: 'middle',\n refY: 0,\n formatMethod: (_markData: any[], seriesData: any[]) => {\n try {\n return buildDifferenceText(\n getRuntimeDifferenceValue({\n anchor: start,\n seriesData,\n useElementStackEnd: usesRuntimeStackEnd,\n }),\n getRuntimeDifferenceValue({\n anchor: end,\n seriesData,\n useElementStackEnd: usesRuntimeStackEnd,\n }),\n differenceType,\n differenceFormatter,\n )\n } catch {\n return ''\n }\n },\n style: {\n fill: textColor,\n fontSize: textFontSize,\n },\n labelBackground: {\n visible: true,\n padding: DEFAULT_LABEL_PADDING,\n style: {\n fill: textBackgroundColor,\n fillOpacity: 1,\n stroke: lineColor,\n lineWidth: 1,\n cornerRadius: DEFAULT_CORNER_RADIUS,\n },\n },\n }\n : {\n visible: true,\n position: 'middle',\n refY: 0,\n text: buildDifferenceText(start.value, end.value, differenceType, differenceFormatter),\n style: {\n fill: textColor,\n fontSize: textFontSize,\n },\n labelBackground: {\n visible: true,\n padding: DEFAULT_LABEL_PADDING,\n style: {\n fill: textBackgroundColor,\n fillOpacity: 1,\n stroke: lineColor,\n lineWidth: 1,\n cornerRadius: DEFAULT_CORNER_RADIUS,\n },\n },\n }\n\n return [\n {\n type: 'type-step',\n autoRange: true,\n zIndex: ANNOTATION_Z_INDEX,\n connectDirection,\n expandDistance: useBracketStyle ? DEFAULT_BRACKET_EXPAND_DISTANCE : DEFAULT_EXPAND_DISTANCE,\n coordinates: (seriesData: any[], relativeSeries: ICartesianSeries) => {\n try {\n return [\n buildDifferenceCoordinateDatum({\n anchor: start,\n seriesData,\n relativeSeries,\n useElementStackEnd: usesRuntimeStackEnd,\n }),\n buildDifferenceCoordinateDatum({\n anchor: end,\n seriesData,\n relativeSeries,\n useElementStackEnd: usesRuntimeStackEnd,\n }),\n ]\n } catch {\n return []\n }\n },\n line: useBracketStyle\n ? {\n multiSegment: true,\n mainSegmentIndex: 1,\n style: [\n {\n visible: true,\n stroke: lineColor,\n lineWidth: DEFAULT_LINE_WIDTH,\n lineDash: DEFAULT_BRACKET_LINE_DASH,\n },\n {\n visible: true,\n stroke: lineColor,\n lineWidth: DEFAULT_LINE_WIDTH,\n },\n {\n visible: true,\n stroke: lineColor,\n lineWidth: DEFAULT_LINE_WIDTH,\n lineDash: DEFAULT_BRACKET_LINE_DASH,\n },\n ],\n }\n : {\n style: {\n visible: true,\n stroke: lineColor,\n lineWidth: DEFAULT_LINE_WIDTH,\n lineDash: [0],\n cornerRadius: DEFAULT_CORNER_RADIUS,\n },\n },\n label,\n startSymbol: {\n visible: false,\n },\n endSymbol: {\n visible: true,\n size: DEFAULT_END_SYMBOL_SIZE,\n refX: DEFAULT_END_SYMBOL_REF_X,\n style: {\n fill: lineColor,\n },\n },\n } as IMarkLineSpec,\n ]\n } catch {\n return []\n }\n })\n\n const specMarkLine = (chartSpec.markLine as IMarkLineSpec[]) || []\n\n return {\n ...spec,\n markLine: [...specMarkLine, ...markLine],\n }\n}\n"],"names":["DEFAULT_LINE_COLOR","DEFAULT_TEXT_COLOR","DEFAULT_TEXT_BACKGROUND_COLOR","DEFAULT_TEXT_FONT_SIZE","DEFAULT_EXPAND_DISTANCE","DEFAULT_LINE_WIDTH","DEFAULT_CORNER_RADIUS","DEFAULT_LABEL_PADDING","DEFAULT_END_SYMBOL_SIZE","DEFAULT_END_SYMBOL_REF_X","DEFAULT_BRACKET_EXPAND_DISTANCE","DEFAULT_BRACKET_LINE_DASH","DEFAULT_PERCENT_DIFFERENCE_FORMAT","getDifferenceLinePath","index","total","toArray","value","Array","getAxisFormatter","spec","valueAxisOrient","formatMethod","axis","String","undefined","getExplicitMeasureFormat","measure","isEmpty","inferMeasureIdFromDatum","anchor","measureIds","candidateValues","datum","candidates","measureId","Number","inferMeasureIdFromSelector","selectorValue","measureIdSet","matchedMeasureIds","Set","currentSelector","isMeasureSelector","isFieldSelector","isDimensionSelector","isPartialDatumSelector","Object","field","resolveDifferenceMeasureId","assertDifferenceLineConfig","path","Error","start","end","annotationDifferenceLine","context","advancedVSeed","vseed","theme","annotationDifferenceLineList","dataset","chartSpec","stackResolveMode","getDifferenceLineStackResolveMode","useElementStackEnd","usesDifferenceLineElementStackEnd","isBracketChart","measures","findAllMeasures","axisFormatter","percentFormatter","createFormatter","markLine","resolveDifferenceAnchor","usesRuntimeStackEnd","useBracketStyle","isStackedBarElementBracket","connectDirection","inferDifferenceBracketDirection","inferDifferenceConnectDirection","lineColor","textColor","textBackgroundColor","textFontSize","differenceType","startMeasureId","endMeasureId","sameMeasure","explicitMeasureFormat","differenceFormatter","autoFormatter","label","_markData","seriesData","buildDifferenceText","getRuntimeDifferenceValue","ANNOTATION_Z_INDEX","relativeSeries","buildDifferenceCoordinateDatum","specMarkLine"],"mappings":"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"}
@@ -1,27 +1,43 @@
1
- import type { IBarChartSpec, ICartesianSeries } from '@visactor/vchart';
1
+ import type { IAreaChartSpec, IBarChartSpec, ICartesianSeries, ILineChartSpec } from '@visactor/vchart';
2
2
  import type { AdvancedVSeed, Datum, Selector, Selectors, VSeed } from '../../../../../types';
3
3
  type DifferenceSelectorLabel = 'start' | 'end';
4
+ type DifferenceChartSpec = IBarChartSpec | ILineChartSpec | IAreaChartSpec;
5
+ export type DifferenceStackResolveMode = 'none' | 'stackTotal' | 'auto';
6
+ export type DifferenceAnchorMode = 'element' | 'stackTotal';
4
7
  export type ResolvedDifferenceAnchor = {
8
+ mode: DifferenceAnchorMode;
5
9
  selectorLabel: DifferenceSelectorLabel;
6
10
  coordinateDatum: Datum;
7
11
  matchedDatum?: Datum;
8
12
  stackGroupDatum?: Datum;
13
+ bandDatum: Datum;
14
+ bandIndex?: number;
9
15
  value: number;
10
16
  };
11
- export declare const isDifferenceLineStacked: (vseed: VSeed, advancedVSeed: AdvancedVSeed) => boolean;
17
+ export declare const getDifferenceLineStackResolveMode: (vseed: VSeed, advancedVSeed: AdvancedVSeed) => DifferenceStackResolveMode;
18
+ export declare const usesDifferenceLineElementStackEnd: (vseed: VSeed, advancedVSeed: AdvancedVSeed) => boolean;
12
19
  export declare const resolveDifferenceAnchor: (options: {
13
20
  dataset: Datum[];
14
21
  selectorLabel: DifferenceSelectorLabel;
15
22
  selectorValue: Selector | Selectors;
16
- spec: IBarChartSpec;
17
- isStacked: boolean;
23
+ spec: DifferenceChartSpec;
24
+ stackResolveMode: DifferenceStackResolveMode;
25
+ allowSelectorFallback?: boolean;
18
26
  }) => ResolvedDifferenceAnchor | undefined;
19
27
  export declare const getStackRuntimeTotal: (runtimeMatches: Datum[]) => number | undefined;
20
28
  export declare const buildDifferenceCoordinateDatum: (options: {
21
29
  anchor: ResolvedDifferenceAnchor;
22
30
  seriesData: Datum[];
23
31
  relativeSeries: ICartesianSeries;
32
+ useElementStackEnd?: boolean;
24
33
  }) => Record<string | number, any>;
25
- export declare const buildDifferenceText: (startValue: number, endValue: number, differenceType?: "absolute" | "percent") => string;
34
+ export declare const getRuntimeDifferenceValue: (options: {
35
+ anchor: ResolvedDifferenceAnchor;
36
+ seriesData: Datum[];
37
+ useElementStackEnd?: boolean;
38
+ }) => number;
39
+ export declare const getDifferenceValue: (startValue: number, endValue: number, differenceType?: "absolute" | "percent") => number;
40
+ export declare const buildDifferenceText: (startValue: number, endValue: number, differenceType?: "absolute" | "percent", formatter?: (value: number) => string) => string;
26
41
  export declare const inferDifferenceConnectDirection: (vseed: VSeed, values: [number, number]) => "left" | "top" | "right" | "bottom";
42
+ export declare const inferDifferenceBracketDirection: (start: ResolvedDifferenceAnchor, end: ResolvedDifferenceAnchor) => "left" | "right";
27
43
  export {};
@@ -1,6 +1,7 @@
1
1
  import { isDimensionSelector, isFieldSelector, isMeasureSelector, isPartialDatumSelector, isValueSelector, selector } from "../../../../../dataSelector/index.js";
2
2
  import { hasMultipleMeasureInSingleView, isBarLikeChart } from "../../../../utils/index.js";
3
3
  import { isSubset } from "./utils.js";
4
+ const STACK_END_FIELD = '__VCHART_STACK_END';
4
5
  const toArray = (value)=>{
5
6
  if (Array.isArray(value)) return value;
6
7
  return null == value ? [] : [
@@ -22,6 +23,10 @@ const buildStackGroupDatum = (datum, bandFields)=>Object.fromEntries(bandFields.
22
23
  field,
23
24
  datum[field]
24
25
  ]));
26
+ const resolveBandIndex = (dataset, bandDatum)=>{
27
+ const bandIndex = dataset.findIndex((datum)=>isSubset(bandDatum, datum));
28
+ return bandIndex >= 0 ? bandIndex : void 0;
29
+ };
25
30
  const buildFallbackSelectorDatum = (selectorValue)=>{
26
31
  const selectorList = Array.isArray(selectorValue) ? selectorValue : [
27
32
  selectorValue
@@ -68,7 +73,7 @@ const inferFallbackValue = (fallbackDatum, valueField, bandFields)=>{
68
73
  return fallbackDatum[numericCandidateKeys[0]];
69
74
  };
70
75
  const resolveFallbackAnchor = (options)=>{
71
- const { selectorLabel, selectorValue, valueField, bandFields } = options;
76
+ const { dataset, selectorLabel, selectorValue, valueField, bandFields } = options;
72
77
  const fallbackDatum = buildFallbackSelectorDatum(selectorValue);
73
78
  if (!fallbackDatum) return;
74
79
  const inferredValue = inferFallbackValue(fallbackDatum, valueField, bandFields);
@@ -77,11 +82,15 @@ const resolveFallbackAnchor = (options)=>{
77
82
  ...fallbackDatum,
78
83
  [valueField]: inferredValue
79
84
  };
85
+ const bandDatum = buildStackGroupDatum(coordinateDatum, bandFields);
80
86
  try {
81
87
  return {
88
+ mode: 'element',
82
89
  selectorLabel,
83
90
  coordinateDatum,
84
91
  matchedDatum: fallbackDatum,
92
+ bandDatum,
93
+ bandIndex: resolveBandIndex(dataset, bandDatum),
85
94
  value: normalizeDifferenceValue(inferredValue, selectorLabel, valueField)
86
95
  };
87
96
  } catch {
@@ -92,24 +101,36 @@ const hasMixedSigns = (values)=>{
92
101
  const nonZeroValues = values.filter((value)=>0 !== value);
93
102
  return nonZeroValues.some((value)=>value > 0) && nonZeroValues.some((value)=>value < 0);
94
103
  };
95
- const isDifferenceLineStacked = (vseed, advancedVSeed)=>('column' === vseed.chartType || 'bar' === vseed.chartType) && hasMultipleMeasureInSingleView(advancedVSeed.reshapeMeasures ?? []);
104
+ const getDifferenceLineStackResolveMode = (vseed, advancedVSeed)=>{
105
+ const hasMultipleMeasure = hasMultipleMeasureInSingleView(advancedVSeed.reshapeMeasures ?? []);
106
+ if (!hasMultipleMeasure) return 'none';
107
+ if ('column' === vseed.chartType) return 'auto';
108
+ if ('bar' === vseed.chartType) return 'auto';
109
+ return 'none';
110
+ };
111
+ const usesDifferenceLineElementStackEnd = (vseed, advancedVSeed)=>'area' === vseed.chartType && hasMultipleMeasureInSingleView(advancedVSeed.reshapeMeasures ?? []);
96
112
  const resolveDifferenceAnchor = (options)=>{
97
- const { dataset, selectorLabel, selectorValue, spec, isStacked } = options;
113
+ const { dataset, selectorLabel, selectorValue, spec, stackResolveMode, allowSelectorFallback = true } = options;
98
114
  const matches = dataset.filter((datum)=>selector(datum, selectorValue));
99
115
  const valueField = getDifferenceValueField(spec);
100
116
  const bandFields = getDifferenceBandFields(spec);
101
- if (0 === matches.length) return isStacked ? void 0 : resolveFallbackAnchor({
117
+ if (0 === matches.length) return 'none' === stackResolveMode && allowSelectorFallback ? resolveFallbackAnchor({
118
+ dataset,
102
119
  selectorLabel,
103
120
  selectorValue,
104
121
  valueField,
105
122
  bandFields
106
- });
107
- if (!isStacked) {
123
+ }) : void 0;
124
+ if ('none' === stackResolveMode || 'auto' === stackResolveMode && 1 === matches.length) {
108
125
  if (1 !== matches.length) throw new Error(`annotationDifferenceLine ${selectorLabel} selector must resolve to exactly one datum, got ${matches.length}`);
126
+ const bandDatum = buildStackGroupDatum(matches[0], bandFields);
109
127
  return {
128
+ mode: 'element',
110
129
  selectorLabel,
111
130
  coordinateDatum: matches[0],
112
131
  matchedDatum: matches[0],
132
+ bandDatum,
133
+ bandIndex: resolveBandIndex(dataset, bandDatum),
113
134
  value: normalizeDifferenceValue(matches[0][valueField], selectorLabel, valueField)
114
135
  };
115
136
  }
@@ -121,27 +142,38 @@ const resolveDifferenceAnchor = (options)=>{
121
142
  if (1 !== stackGroups.size) throw new Error(`annotationDifferenceLine ${selectorLabel} selector must resolve to exactly one stack group, got ${stackGroups.size}`);
122
143
  const stackGroupDatum = Array.from(stackGroups.values())[0];
123
144
  const groupRows = dataset.filter((datum)=>isSubset(stackGroupDatum, datum));
145
+ if ('auto' === stackResolveMode && groupRows.length !== matches.length) throw new Error(`annotationDifferenceLine ${selectorLabel} selector must resolve to exactly one stack element or one full stack group`);
124
146
  const groupValues = groupRows.map((datum)=>normalizeDifferenceValue(datum[valueField], selectorLabel, valueField));
125
147
  if (hasMixedSigns(groupValues)) throw new Error('annotationDifferenceLine does not support mixed-sign stack totals in v1');
126
148
  return {
149
+ mode: 'stackTotal',
127
150
  selectorLabel,
128
151
  coordinateDatum: stackGroupDatum,
129
152
  matchedDatum: matches[0],
130
153
  stackGroupDatum,
154
+ bandDatum: stackGroupDatum,
155
+ bandIndex: resolveBandIndex(dataset, stackGroupDatum),
131
156
  value: groupValues.reduce((sum, value)=>sum + value, 0)
132
157
  };
133
158
  };
134
159
  const getStackRuntimeTotal = (runtimeMatches)=>{
135
- const stackEndValues = runtimeMatches.map((datum)=>Number(datum.__VCHART_STACK_END));
136
- if (stackEndValues.some((value)=>Number.isNaN(value))) return;
160
+ if (0 === runtimeMatches.length) return;
161
+ const stackEndValues = runtimeMatches.map((datum)=>Number(datum[STACK_END_FIELD]));
162
+ if (stackEndValues.some((value)=>!Number.isFinite(value))) return;
137
163
  if (hasMixedSigns(stackEndValues)) throw new Error('annotationDifferenceLine does not support mixed-sign runtime stack totals in v1');
138
164
  return stackEndValues.some((value)=>value < 0) ? Math.min(...stackEndValues) : Math.max(...stackEndValues);
139
165
  };
140
166
  const buildDifferenceCoordinateDatum = (options)=>{
141
- const { anchor, seriesData, relativeSeries } = options;
167
+ const { anchor, seriesData, relativeSeries, useElementStackEnd = false } = options;
142
168
  if (!anchor.stackGroupDatum) {
143
169
  const runtimeMatches = anchor.matchedDatum ? seriesData.filter((datum)=>isSubset(anchor.matchedDatum, datum)) : [];
144
- return runtimeMatches[0] ?? anchor.coordinateDatum;
170
+ if (!useElementStackEnd) return runtimeMatches[0] ?? anchor.coordinateDatum;
171
+ const runtimeMatch = runtimeMatches[0];
172
+ const runtimeStackEnd = Number(runtimeMatch?.[STACK_END_FIELD]);
173
+ return {
174
+ ...runtimeMatch ?? anchor.coordinateDatum,
175
+ [relativeSeries.getStackValueField()]: Number.isFinite(runtimeStackEnd) ? runtimeStackEnd : anchor.value
176
+ };
145
177
  }
146
178
  const runtimeMatches = seriesData.filter((datum)=>isSubset(anchor.stackGroupDatum, datum));
147
179
  const runtimeStackTotal = getStackRuntimeTotal(runtimeMatches);
@@ -150,18 +182,39 @@ const buildDifferenceCoordinateDatum = (options)=>{
150
182
  [relativeSeries.getStackValueField()]: runtimeStackTotal ?? anchor.value
151
183
  };
152
184
  };
153
- const buildDifferenceText = (startValue, endValue, differenceType = 'absolute')=>{
185
+ const getRuntimeDifferenceValue = (options)=>{
186
+ const { anchor, seriesData, useElementStackEnd = false } = options;
187
+ if (anchor.stackGroupDatum) {
188
+ const runtimeMatches = seriesData.filter((datum)=>isSubset(anchor.stackGroupDatum, datum));
189
+ return getStackRuntimeTotal(runtimeMatches) ?? anchor.value;
190
+ }
191
+ if (!useElementStackEnd || !anchor.matchedDatum) return anchor.value;
192
+ const runtimeMatch = seriesData.find((datum)=>isSubset(anchor.matchedDatum, datum));
193
+ const runtimeStackEnd = Number(runtimeMatch?.[STACK_END_FIELD]);
194
+ return Number.isFinite(runtimeStackEnd) ? runtimeStackEnd : anchor.value;
195
+ };
196
+ const getDifferenceValue = (startValue, endValue, differenceType = 'absolute')=>{
154
197
  if ('percent' === differenceType) {
155
198
  if (0 === startValue) throw new Error('annotationDifferenceLine percent difference cannot be computed because start value is 0');
156
- return `${((endValue - startValue) / startValue * 100).toFixed(0)}%`;
199
+ return (endValue - startValue) / startValue;
157
200
  }
158
- return `${endValue - startValue}`;
201
+ return endValue - startValue;
202
+ };
203
+ const buildDifferenceText = (startValue, endValue, differenceType = 'absolute', formatter)=>{
204
+ const differenceValue = getDifferenceValue(startValue, endValue, differenceType);
205
+ if (formatter) return formatter(differenceValue);
206
+ if ('percent' === differenceType) return `${(100 * differenceValue).toFixed(2)}%`;
207
+ return `${differenceValue}`;
159
208
  };
160
209
  const inferDifferenceConnectDirection = (vseed, values)=>{
161
210
  const isNegativeSide = values.every((value)=>value < 0);
162
211
  if (isBarLikeChart(vseed)) return isNegativeSide ? 'left' : 'right';
163
212
  return isNegativeSide ? 'bottom' : 'top';
164
213
  };
165
- export { buildDifferenceCoordinateDatum, buildDifferenceText, getStackRuntimeTotal, inferDifferenceConnectDirection, isDifferenceLineStacked, resolveDifferenceAnchor };
214
+ const inferDifferenceBracketDirection = (start, end)=>{
215
+ if (void 0 === start.bandIndex || void 0 === end.bandIndex) return 'right';
216
+ return start.bandIndex <= end.bandIndex ? 'right' : 'left';
217
+ };
218
+ export { buildDifferenceCoordinateDatum, buildDifferenceText, getDifferenceLineStackResolveMode, getDifferenceValue, getRuntimeDifferenceValue, getStackRuntimeTotal, inferDifferenceBracketDirection, inferDifferenceConnectDirection, resolveDifferenceAnchor, usesDifferenceLineElementStackEnd };
166
219
 
167
220
  //# sourceMappingURL=annotationDifferenceLineCommon.js.map