@antv/gpt-vis 1.0.1 → 1.0.2

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.
@@ -38,9 +38,12 @@ var DualAxes = (options) => {
38
38
  const { container, width, height, theme: chartTheme = "default" } = options;
39
39
  let chart = null;
40
40
  let hasRendered = false;
41
+ let cleanupCrosshairAxisLabels = null;
41
42
  const render = (config) => {
42
43
  const { categories, series, theme = chartTheme, title, axisXTitle, style = {} } = config;
43
44
  if (chart) {
45
+ cleanupCrosshairAxisLabels == null ? void 0 : cleanupCrosshairAxisLabels();
46
+ cleanupCrosshairAxisLabels = null;
44
47
  chart.destroy();
45
48
  }
46
49
  const { startAtZero = false } = style;
@@ -181,11 +184,26 @@ var DualAxes = (options) => {
181
184
  theme: (0, import_util.getThemeObject)(theme)
182
185
  };
183
186
  chart.options(chartOptions);
187
+ const lineYFields = seriesMeta.filter(({ item }) => item.type === "line").map(({ yField }) => yField);
188
+ if (lineYFields.length) {
189
+ const currentChart = chart;
190
+ const cleanups = lineYFields.map(
191
+ (yField, index) => (0, import_util.bindCrosshairAxisLabels)(currentChart, theme, {
192
+ showXLabel: index === 0,
193
+ useStandaloneYLabel: true,
194
+ yAxisPosition: "right",
195
+ yField
196
+ })
197
+ );
198
+ cleanupCrosshairAxisLabels = () => cleanups.forEach((cleanup) => cleanup());
199
+ }
184
200
  chart.render();
185
201
  hasRendered = true;
186
202
  };
187
203
  const destroy = () => {
188
204
  if (chart) {
205
+ cleanupCrosshairAxisLabels == null ? void 0 : cleanupCrosshairAxisLabels();
206
+ cleanupCrosshairAxisLabels = null;
189
207
  chart.destroy();
190
208
  chart = null;
191
209
  }
@@ -14,7 +14,6 @@ export interface FunnelConfig {
14
14
  data: FunnelDataItem[];
15
15
  theme?: VisualizationTheme;
16
16
  title?: string;
17
- locale?: string;
18
17
  conversionRateLabel?: string;
19
18
  style?: {
20
19
  backgroundColor?: string;
@@ -52,15 +52,8 @@ var Funnel = (options) => {
52
52
  const { container, width, height, locale, theme: chartTheme = "default" } = options;
53
53
  let chart = null;
54
54
  const render = (config) => {
55
- const {
56
- data = [],
57
- theme = chartTheme,
58
- title,
59
- locale: renderLocale = locale,
60
- conversionRateLabel,
61
- style = {}
62
- } = config;
63
- const chartLocale = (0, import_util.resolveChartLocale)(renderLocale);
55
+ const { data = [], theme = chartTheme, title, conversionRateLabel, style = {} } = config;
56
+ const chartLocale = (0, import_util.resolveChartLocale)(locale);
64
57
  const labels = FUNNEL_LABELS[chartLocale];
65
58
  const numberFormatter = new Intl.NumberFormat(chartLocale);
66
59
  const stageConversionRateLabel = conversionRateLabel ?? labels.conversionRate;
@@ -72,6 +65,7 @@ var Funnel = (options) => {
72
65
  const backgroundColor = style.backgroundColor || (0, import_util.getBackgroundColor)(theme);
73
66
  const tokens = (0, import_util.getChartVisualTokens)(theme);
74
67
  const formatValue = (value) => Number.isFinite(value) ? numberFormatter.format(value) : "—";
68
+ const isInverted = data.length > 1 && data[0].value < data[data.length - 1].value;
75
69
  const metricsByCategory = new Map(
76
70
  data.map((item, index) => {
77
71
  const previous = data[index - 1];
@@ -153,12 +147,12 @@ ${formatValue(d.value)}`,
153
147
  }
154
148
  },
155
149
  {
156
- text: (_d, index) => index === 0 ? "" : "———",
157
- position: "top-right",
150
+ text: (_d, index, items) => (isInverted ? index < items.length - 1 : index > 0) ? "———" : "",
151
+ position: isInverted ? "bottom-right" : "top-right",
158
152
  fill: tokens.textSecondary,
159
153
  fillOpacity: 0.72,
160
- dx: 18,
161
- dy: -6,
154
+ dx: 8,
155
+ dy: isInverted ? 6 : -6,
162
156
  style: {
163
157
  fontFamily: import_util.CHART_FONT_FAMILY,
164
158
  fontSize: 8,
@@ -167,16 +161,20 @@ ${formatValue(d.value)}`,
167
161
  }
168
162
  },
169
163
  {
170
- text: (_d, index, items) => index === 0 ? "" : formatMetricLabel(
171
- stageConversionRateLabel,
172
- formatConversionRate(items[index - 1].value, items[index].value),
173
- chartLocale
174
- ),
175
- position: "top-right",
164
+ text: (_d, index, items) => {
165
+ const from = isInverted ? items[index] : items[index - 1];
166
+ const to = isInverted ? items[index + 1] : items[index];
167
+ return from && to ? formatMetricLabel(
168
+ stageConversionRateLabel,
169
+ formatConversionRate(from.value, to.value),
170
+ chartLocale
171
+ ) : "";
172
+ },
173
+ position: isInverted ? "bottom-right" : "top-right",
176
174
  textAlign: "left",
177
175
  textBaseline: "middle",
178
176
  fill: tokens.textPrimary,
179
- dx: 44,
177
+ dx: 26,
180
178
  style: {
181
179
  fontFamily: import_util.CHART_FONT_FAMILY,
182
180
  fontSize: 11,
@@ -204,10 +202,10 @@ ${formatValue(d.value)}`,
204
202
  type: "connector",
205
203
  data: [
206
204
  {
207
- startX: data[0].category,
208
- startY: data[data.length - 1].category,
205
+ startX: isInverted ? data[data.length - 1].category : data[0].category,
206
+ startY: isInverted ? data[0].category : data[data.length - 1].category,
209
207
  endX: 0,
210
- endY: (data[0].value - data[data.length - 1].value) / 2
208
+ endY: Math.abs(data[0].value - data[data.length - 1].value) / 2
211
209
  }
212
210
  ],
213
211
  encode: { x: "startX", x1: "startY", y: "endX", y1: "endY" },
@@ -24,6 +24,7 @@ __export(table_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(table_exports);
26
26
  var import_measury = require("measury");
27
+ var import_html = require("../../util/html");
27
28
  var SCOPE_ID = "__gpt-vis-table__";
28
29
  var FONT_FAMILY = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
29
30
  var CELL_PADDING = 16;
@@ -43,6 +44,12 @@ var TABLE_STYLES = `
43
44
  color: #1d2129;
44
45
  }
45
46
 
47
+ .${SCOPE_ID} .table-empty {
48
+ padding: 20px;
49
+ text-align: center;
50
+ color: #999;
51
+ }
52
+
46
53
  .${SCOPE_ID} table {
47
54
  border-collapse: separate;
48
55
  border-spacing: 0;
@@ -167,10 +174,11 @@ var Table = (options) => {
167
174
  if (theme === "dark") {
168
175
  tableWrapper.setAttribute("data-theme", "dark");
169
176
  }
177
+ const titleHTML = title ? `<div class="table-title">${(0, import_html.escapeHtml)(title)}</div>` : "";
170
178
  if (data.length === 0) {
171
179
  tableWrapper.innerHTML = `
172
- ${title ? `<div class="table-title">${title}</div>` : ""}
173
- <div style="padding: 20px; text-align: center; color: #999;">No data available</div>
180
+ ${titleHTML}
181
+ <div class="table-empty">No data available</div>
174
182
  `;
175
183
  container.appendChild(tableWrapper);
176
184
  return;
@@ -178,12 +186,12 @@ var Table = (options) => {
178
186
  const columns = Object.keys(data[0]);
179
187
  let minWidth = calculateTableMinWidth(data, columns);
180
188
  minWidth = Math.max(minWidth, columns.length * 100);
181
- const headerHTML = columns.map((col) => `<th>${col}</th>`).join("");
189
+ const headerHTML = columns.map((column) => `<th>${(0, import_html.escapeHtml)(column)}</th>`).join("");
182
190
  const bodyHTML = data.map(
183
- (row) => `<tr>${columns.map((col) => `<td>${row[col] != null ? row[col] : ""}</td>`).join("")}</tr>`
191
+ (row) => `<tr>${columns.map((column) => `<td>${(0, import_html.escapeHtml)(row[column])}</td>`).join("")}</tr>`
184
192
  ).join("");
185
193
  tableWrapper.innerHTML = `
186
- ${title ? `<div class="table-title">${title}</div>` : ""}
194
+ ${titleHTML}
187
195
  <table style="min-width: ${minWidth}px;">
188
196
  <thead><tr>${headerHTML}</tr></thead>
189
197
  <tbody>${bodyHTML}</tbody>
@@ -1,9 +1,15 @@
1
1
  import { type Chart } from '@antv/g2';
2
2
  import type { VisualizationTheme } from '../types';
3
+ export type CrosshairAxisLabelsOptions = {
4
+ showXLabel?: boolean;
5
+ useStandaloneYLabel?: boolean;
6
+ yAxisPosition?: 'left' | 'right';
7
+ yField?: string;
8
+ };
3
9
  /**
4
10
  * Bridges G2 tooltip crosshairs to axis value tags.
5
11
  *
6
12
  * G2 does not currently expose axis tags for tooltip crosshairs, so this adapter
7
13
  * reads the rule geometry created by G2 5.4 and renders labels with LineCrosshair.
8
14
  */
9
- export declare const bindCrosshairAxisLabels: (chart: Chart, theme: VisualizationTheme) => (() => void);
15
+ export declare const bindCrosshairAxisLabels: (chart: Chart, theme: VisualizationTheme, { showXLabel, useStandaloneYLabel, yAxisPosition, yField, }?: CrosshairAxisLabelsOptions) => (() => void);
@@ -11,27 +11,38 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
11
11
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
12
12
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
13
13
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
14
- import { LineCrosshair } from '@antv/component';
14
+ import { LineCrosshair, Tag } from '@antv/component';
15
15
  import { selectPlotArea } from '@antv/g2';
16
16
  import { CHART_FONT_FAMILY, getChartVisualTokens } from "./tokens";
17
+ var MAX_CROSSHAIR_DECIMAL_PLACES = 6;
17
18
  var formatCrosshairAxisValue = function formatCrosshairAxisValue(value, formatter, precision) {
18
19
  if (value === undefined || value === null || value === '') return '';
20
+ var displayValue = value;
19
21
  try {
20
22
  var formatted = formatter === null || formatter === void 0 ? void 0 : formatter(value);
21
- if (formatted !== undefined && formatted !== null) return String(formatted);
23
+ if (formatted !== undefined && formatted !== null) {
24
+ var numericFormatted = typeof formatted === 'number' || typeof formatted === 'string' && formatted.trim() !== '' && Number.isFinite(Number(formatted)) ? Number(formatted) : undefined;
25
+ if (numericFormatted === undefined) return String(formatted);
26
+ displayValue = numericFormatted;
27
+ }
22
28
  } catch (_unused) {
23
29
  // Fall back to the original value when a scale formatter rejects it.
24
30
  }
25
- if (value instanceof Date) return value.toLocaleString();
26
- if (typeof value === 'number' && Number.isFinite(value) && precision !== undefined) {
27
- return value.toFixed(precision);
31
+ if (displayValue instanceof Date) return displayValue.toLocaleString();
32
+ if (typeof displayValue === 'number' && Number.isFinite(displayValue)) {
33
+ if (displayValue !== 0 && Math.abs(displayValue) < Math.pow(10, -MAX_CROSSHAIR_DECIMAL_PLACES)) {
34
+ return Number(displayValue.toPrecision(4)).toString();
35
+ }
36
+ var decimalPlaces = Math.min(Math.max(precision !== null && precision !== void 0 ? precision : MAX_CROSSHAIR_DECIMAL_PLACES, 0), MAX_CROSSHAIR_DECIMAL_PLACES);
37
+ return Number(displayValue.toFixed(decimalPlaces)).toString();
28
38
  }
29
- return String(value);
39
+ return String(displayValue);
30
40
  };
31
41
  var getNumberPrecision = function getNumberPrecision(value) {
32
42
  var _coefficient$split$;
33
43
  if (!Number.isFinite(value) || value === 0) return 0;
34
- var _Math$abs$toExponenti = Math.abs(value).toExponential().split('e'),
44
+ var normalizedValue = Number(value.toPrecision(12));
45
+ var _Math$abs$toExponenti = Math.abs(normalizedValue).toExponential().split('e'),
35
46
  _Math$abs$toExponenti2 = _slicedToArray(_Math$abs$toExponenti, 2),
36
47
  coefficient = _Math$abs$toExponenti2[0],
37
48
  _Math$abs$toExponenti3 = _Math$abs$toExponenti2[1],
@@ -51,7 +62,7 @@ var getCrosshairScalePrecision = function getCrosshairScalePrecision(scale) {
51
62
  if (Number.isFinite(difference) && difference > 0) interval = Math.min(interval, difference);
52
63
  }
53
64
  if (!Number.isFinite(interval)) return undefined;
54
- return Math.min(getNumberPrecision(interval) + 2, 20);
65
+ return Math.min(getNumberPrecision(interval) + 2, MAX_CROSSHAIR_DECIMAL_PLACES);
55
66
  };
56
67
  var getCrosshairTagStyle = function getCrosshairTagStyle(theme, tokens) {
57
68
  return {
@@ -75,6 +86,27 @@ var getCrosshairTagStyle = function getCrosshairTagStyle(theme, tokens) {
75
86
  tagPointerEvents: 'none'
76
87
  };
77
88
  };
89
+ var getStandaloneTagStyle = function getStandaloneTagStyle(theme, tokens) {
90
+ return {
91
+ align: 'start',
92
+ verticalAlign: 'middle',
93
+ padding: [4, 7],
94
+ radius: 6,
95
+ backgroundFill: tokens.textPrimary,
96
+ backgroundStroke: 'transparent',
97
+ backgroundLineWidth: 0,
98
+ backgroundShadowColor: theme === 'dark' ? 'rgba(0, 0, 0, 0.38)' : 'rgba(15, 23, 42, 0.18)',
99
+ backgroundShadowBlur: 8,
100
+ backgroundShadowOffsetY: 2,
101
+ labelFill: tokens.background,
102
+ labelFillOpacity: 1,
103
+ labelFontFamily: CHART_FONT_FAMILY,
104
+ labelFontSize: 11,
105
+ labelFontWeight: 500,
106
+ labelLineWidth: 0,
107
+ pointerEvents: 'none'
108
+ };
109
+ };
78
110
  var clamp = function clamp(value, min, max) {
79
111
  return Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max));
80
112
  };
@@ -124,13 +156,49 @@ var getTooltipPlot = function getTooltipPlot(context) {
124
156
  // detail isolated here while using the public plot selector for discovery.
125
157
  return selectPlotArea(root);
126
158
  };
127
- var getCartesianView = function getCartesianView(context) {
159
+ var getScaleField = function getScaleField(scale) {
160
+ var _scale$getOptions2;
161
+ return scale === null || scale === void 0 || (_scale$getOptions2 = scale.getOptions) === null || _scale$getOptions2 === void 0 || (_scale$getOptions2 = _scale$getOptions2.call(scale)) === null || _scale$getOptions2 === void 0 ? void 0 : _scale$getOptions2.field;
162
+ };
163
+ var findYScaleByField = function findYScaleByField(view, yField) {
164
+ var _Object$entries$find;
165
+ return (_Object$entries$find = Object.entries(view.scale).find(function (_ref) {
166
+ var _ref2 = _slicedToArray(_ref, 2),
167
+ scaleName = _ref2[0],
168
+ scale = _ref2[1];
169
+ return /^y\d*$/.test(scaleName) && getScaleField(scale) === yField;
170
+ })) === null || _Object$entries$find === void 0 ? void 0 : _Object$entries$find[1];
171
+ };
172
+ var getYScale = function getYScale(view, yField) {
173
+ return yField ? findYScaleByField(view, yField) : view.scale.y;
174
+ };
175
+ var getCartesianView = function getCartesianView(context, yField) {
128
176
  var _context$views;
129
- return (_context$views = context.views) === null || _context$views === void 0 ? void 0 : _context$views.find(function (_ref) {
130
- var coordinate = _ref.coordinate,
131
- scale = _ref.scale;
132
- return Boolean((scale === null || scale === void 0 ? void 0 : scale.x) && (scale === null || scale === void 0 ? void 0 : scale.y)) && typeof (coordinate === null || coordinate === void 0 ? void 0 : coordinate.invert) === 'function';
177
+ return (_context$views = context.views) === null || _context$views === void 0 ? void 0 : _context$views.find(function (view) {
178
+ var _view$scale, _view$coordinate;
179
+ return Boolean(((_view$scale = view.scale) === null || _view$scale === void 0 ? void 0 : _view$scale.x) && getYScale(view, yField)) && typeof ((_view$coordinate = view.coordinate) === null || _view$coordinate === void 0 ? void 0 : _view$coordinate.invert) === 'function';
180
+ });
181
+ };
182
+ var hasAxisField = function hasAxisField(field, yField) {
183
+ return Array.isArray(field) ? field.includes(yField) : field === yField;
184
+ };
185
+ var getYAxisLinePosition = function getYAxisLinePosition(view, yField, position, fallback, plotX) {
186
+ var _view$components;
187
+ if (!yField) return fallback;
188
+ var axis = (_view$components = view.components) === null || _view$components === void 0 ? void 0 : _view$components.find(function (_ref3) {
189
+ var bbox = _ref3.bbox,
190
+ axisPosition = _ref3.position,
191
+ scales = _ref3.scales,
192
+ type = _ref3.type;
193
+ return type === 'axisY' && axisPosition === position && Number.isFinite(Number(bbox === null || bbox === void 0 ? void 0 : bbox.x)) && (scales === null || scales === void 0 ? void 0 : scales.some(function (scale) {
194
+ return hasAxisField(scale.field, yField);
195
+ }));
133
196
  });
197
+ if (!(axis !== null && axis !== void 0 && axis.bbox)) return fallback;
198
+ var x = Number(axis.bbox.x);
199
+ var width = Number(axis.bbox.width);
200
+ var axisX = position === 'right' || !Number.isFinite(width) ? x : x + width;
201
+ return axisX - plotX;
134
202
  };
135
203
  var getRuleLine = function getRuleLine(rule) {
136
204
  var _rule$style, _rule$style2, _rule$style3, _rule$style4;
@@ -148,12 +216,12 @@ var getRuleLine = function getRuleLine(rule) {
148
216
  };
149
217
  var getPlotOffset = function getPlotOffset(plot) {
150
218
  var _plot$getLocalPositio;
151
- var _ref2 = ((_plot$getLocalPositio = plot.getLocalPosition) === null || _plot$getLocalPositio === void 0 ? void 0 : _plot$getLocalPositio.call(plot)) || [],
152
- _ref3 = _slicedToArray(_ref2, 2),
153
- _ref3$ = _ref3[0],
154
- x = _ref3$ === void 0 ? 0 : _ref3$,
155
- _ref3$2 = _ref3[1],
156
- y = _ref3$2 === void 0 ? 0 : _ref3$2;
219
+ var _ref4 = ((_plot$getLocalPositio = plot.getLocalPosition) === null || _plot$getLocalPositio === void 0 ? void 0 : _plot$getLocalPositio.call(plot)) || [],
220
+ _ref5 = _slicedToArray(_ref4, 2),
221
+ _ref5$ = _ref5[0],
222
+ x = _ref5$ === void 0 ? 0 : _ref5$,
223
+ _ref5$2 = _ref5[1],
224
+ y = _ref5$2 === void 0 ? 0 : _ref5$2;
157
225
  return [Number.isFinite(Number(x)) ? Number(x) : 0, Number.isFinite(Number(y)) ? Number(y) : 0];
158
226
  };
159
227
  var invertCoordinate = function invertCoordinate(view, point) {
@@ -175,25 +243,37 @@ var invertCoordinate = function invertCoordinate(view, point) {
175
243
  * reads the rule geometry created by G2 5.4 and renders labels with LineCrosshair.
176
244
  */
177
245
  export var bindCrosshairAxisLabels = function bindCrosshairAxisLabels(chart, theme) {
246
+ var _ref6 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
247
+ _ref6$showXLabel = _ref6.showXLabel,
248
+ showXLabel = _ref6$showXLabel === void 0 ? true : _ref6$showXLabel,
249
+ _ref6$useStandaloneYL = _ref6.useStandaloneYLabel,
250
+ useStandaloneYLabel = _ref6$useStandaloneYL === void 0 ? false : _ref6$useStandaloneYL,
251
+ _ref6$yAxisPosition = _ref6.yAxisPosition,
252
+ yAxisPosition = _ref6$yAxisPosition === void 0 ? 'left' : _ref6$yAxisPosition,
253
+ yField = _ref6.yField;
178
254
  if (!chart || typeof chart.on !== 'function') return function () {
179
255
  return undefined;
180
256
  };
181
257
  var tagStyle = getCrosshairTagStyle(theme, getChartVisualTokens(theme));
258
+ var standaloneTagStyle = getStandaloneTagStyle(theme, getChartVisualTokens(theme));
182
259
  var boundPlot = null;
183
260
  var xCrosshair = null;
184
261
  var yCrosshair = null;
262
+ var standaloneYTag = null;
185
263
  var latestPointerY = null;
186
264
  var latestXValue;
187
265
  var destroyCrosshairs = function destroyCrosshairs() {
188
- var _xCrosshair, _yCrosshair;
266
+ var _xCrosshair, _yCrosshair, _standaloneYTag;
189
267
  (_xCrosshair = xCrosshair) === null || _xCrosshair === void 0 || _xCrosshair.destroy();
190
268
  (_yCrosshair = yCrosshair) === null || _yCrosshair === void 0 || _yCrosshair.destroy();
269
+ (_standaloneYTag = standaloneYTag) === null || _standaloneYTag === void 0 || _standaloneYTag.destroy();
191
270
  xCrosshair = null;
192
271
  yCrosshair = null;
272
+ standaloneYTag = null;
193
273
  boundPlot = null;
194
274
  };
195
275
  var hideCrosshairs = function hideCrosshairs() {
196
- for (var _i = 0, _arr = [xCrosshair, yCrosshair]; _i < _arr.length; _i++) {
276
+ for (var _i = 0, _arr = [xCrosshair, yCrosshair, standaloneYTag]; _i < _arr.length; _i++) {
197
277
  var crosshair = _arr[_i];
198
278
  if (crosshair) crosshair.style.visibility = 'hidden';
199
279
  }
@@ -215,7 +295,7 @@ export var bindCrosshairAxisLabels = function bindCrosshairAxisLabels(chart, the
215
295
  var xEnd = [xLine.x2 + plotX, xLine.y2 + plotY];
216
296
  var yStart = [yLine.x1 + plotX, yLine.y1 + plotY];
217
297
  var yEnd = [yLine.x2 + plotX, yLine.y2 + plotY];
218
- if (!xCrosshair) {
298
+ if (showXLabel && !xCrosshair) {
219
299
  xCrosshair = new LineCrosshair({
220
300
  style: _objectSpread(_objectSpread({}, tagStyle), {}, {
221
301
  startPos: xStart,
@@ -228,30 +308,41 @@ export var bindCrosshairAxisLabels = function bindCrosshairAxisLabels(chart, the
228
308
  xCrosshair.style.pointerEvents = 'none';
229
309
  layer.appendChild(xCrosshair);
230
310
  }
231
- if (!yCrosshair) {
311
+ if (showXLabel && !useStandaloneYLabel && !yCrosshair) {
232
312
  yCrosshair = new LineCrosshair({
233
313
  style: _objectSpread(_objectSpread({}, tagStyle), {}, {
234
314
  startPos: yStart,
235
315
  endPos: yEnd,
236
316
  tagText: yText,
237
- tagPosition: 'start'
317
+ tagPosition: yAxisPosition === 'right' ? 'end' : 'start'
238
318
  })
239
319
  });
240
320
  yCrosshair.style.zIndex = 7;
241
321
  yCrosshair.style.pointerEvents = 'none';
242
322
  layer.appendChild(yCrosshair);
243
323
  }
324
+ if ((useStandaloneYLabel || !showXLabel) && !standaloneYTag) {
325
+ standaloneYTag = new Tag({
326
+ style: _objectSpread(_objectSpread({}, standaloneTagStyle), {}, {
327
+ text: yText
328
+ })
329
+ });
330
+ standaloneYTag.style.zIndex = 7;
331
+ standaloneYTag.style.pointerEvents = 'none';
332
+ layer.appendChild(standaloneYTag);
333
+ }
244
334
  boundPlot = plot;
245
335
  };
246
336
  var updateCrosshairs = function updateCrosshairs(event) {
247
- var _event$offsetY, _latestXValue, _invertCrosshairValue, _event$data, _view$scale$x$getForm, _view$scale$x, _view$scale$y$getForm, _view$scale$y, _plot$ruleY, _plot$ruleX;
337
+ var _event$offsetY, _latestXValue, _invertCrosshairValue, _event$data, _view$scale$x$getForm, _view$scale$x, _yScale$getFormatter, _plot$ruleY, _plot$ruleX;
248
338
  var context = chart.getContext();
249
339
  var plot = getTooltipPlot(context);
250
- var view = getCartesianView(context);
340
+ var view = getCartesianView(context, yField);
251
341
  if (!plot || !view) {
252
342
  hideCrosshairs();
253
343
  return;
254
344
  }
345
+ var yScale = getYScale(view, yField);
255
346
  var verticalRule = getRuleLine(plot.ruleY);
256
347
  var horizontalRule = getRuleLine(plot.ruleX);
257
348
  if (!verticalRule || !horizontalRule) {
@@ -269,9 +360,9 @@ export var bindCrosshairAxisLabels = function bindCrosshairAxisLabels(chart, the
269
360
  var y = clamp(pointerY, verticalRule.y1, verticalRule.y2);
270
361
  var invertedPosition = invertCoordinate(view, [x, y]);
271
362
  var xValue = (_latestXValue = latestXValue) !== null && _latestXValue !== void 0 ? _latestXValue : invertCrosshairValue(view.scale.x, invertedPosition === null || invertedPosition === void 0 ? void 0 : invertedPosition[0]);
272
- var yValue = (_invertCrosshairValue = invertCrosshairValue(view.scale.y, invertedPosition === null || invertedPosition === void 0 ? void 0 : invertedPosition[1])) !== null && _invertCrosshairValue !== void 0 ? _invertCrosshairValue : (_event$data = event.data) === null || _event$data === void 0 || (_event$data = _event$data.items) === null || _event$data === void 0 || (_event$data = _event$data[0]) === null || _event$data === void 0 ? void 0 : _event$data.value;
363
+ var yValue = (_invertCrosshairValue = invertCrosshairValue(yScale, invertedPosition === null || invertedPosition === void 0 ? void 0 : invertedPosition[1])) !== null && _invertCrosshairValue !== void 0 ? _invertCrosshairValue : (_event$data = event.data) === null || _event$data === void 0 || (_event$data = _event$data.items) === null || _event$data === void 0 || (_event$data = _event$data[0]) === null || _event$data === void 0 ? void 0 : _event$data.value;
273
364
  var xText = formatCrosshairAxisValue(xValue, (_view$scale$x$getForm = (_view$scale$x = view.scale.x).getFormatter) === null || _view$scale$x$getForm === void 0 ? void 0 : _view$scale$x$getForm.call(_view$scale$x));
274
- var yText = formatCrosshairAxisValue(yValue, (_view$scale$y$getForm = (_view$scale$y = view.scale.y).getFormatter) === null || _view$scale$y$getForm === void 0 ? void 0 : _view$scale$y$getForm.call(_view$scale$y), getCrosshairScalePrecision(view.scale.y));
365
+ var yText = formatCrosshairAxisValue(yValue, yScale === null || yScale === void 0 || (_yScale$getFormatter = yScale.getFormatter) === null || _yScale$getFormatter === void 0 ? void 0 : _yScale$getFormatter.call(yScale), getCrosshairScalePrecision(yScale));
275
366
  if (!xText || !yText) {
276
367
  hideCrosshairs();
277
368
  return;
@@ -293,13 +384,25 @@ export var bindCrosshairAxisLabels = function bindCrosshairAxisLabels(chart, the
293
384
  y2: y
294
385
  });
295
386
  ensureCrosshairs(plot, displayVerticalRule, displayHorizontalRule, xText, yText);
296
- if (!xCrosshair || !yCrosshair) return;
297
- xCrosshair.setText(xText);
298
- xCrosshair.setPointer([x + plotX, verticalRule.y2 + plotY]);
299
- xCrosshair.style.visibility = 'visible';
300
- yCrosshair.setText(yText);
301
- yCrosshair.setPointer([horizontalRule.x1 + plotX, y + plotY]);
302
- yCrosshair.style.visibility = 'visible';
387
+ if (showXLabel && !xCrosshair || (useStandaloneYLabel ? !standaloneYTag : !yCrosshair && !standaloneYTag)) return;
388
+ if (xCrosshair) {
389
+ xCrosshair.setText(xText);
390
+ xCrosshair.setPointer([x + plotX, verticalRule.y2 + plotY]);
391
+ xCrosshair.style.visibility = 'visible';
392
+ }
393
+ if (yCrosshair) {
394
+ yCrosshair.setText(yText);
395
+ yCrosshair.setPointer([(yAxisPosition === 'right' ? horizontalRule.x2 : horizontalRule.x1) + plotX, y + plotY]);
396
+ yCrosshair.style.visibility = 'visible';
397
+ }
398
+ if (standaloneYTag) {
399
+ var yAxisX = getYAxisLinePosition(view, yField, yAxisPosition, yAxisPosition === 'right' ? horizontalRule.x2 : horizontalRule.x1, plotX);
400
+ standaloneYTag.update({
401
+ text: yText
402
+ });
403
+ standaloneYTag.setLocalPosition([yAxisX + plotX, y + plotY]);
404
+ standaloneYTag.style.visibility = 'visible';
405
+ }
303
406
  };
304
407
  var onPointerMove = function onPointerMove(event) {
305
408
  var _event$offsetY2;
@@ -0,0 +1 @@
1
+ export declare const escapeHtml: (value: unknown) => string;
@@ -0,0 +1,3 @@
1
+ export var escapeHtml = function escapeHtml(value) {
2
+ return (value == null ? '' : String(value)).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
3
+ };
@@ -113,12 +113,12 @@ var createTheme = function createTheme(type) {
113
113
  gridLineDash: [0, 0]
114
114
  } : {}),
115
115
  axisY: {
116
- lineLineWidth: isAcademy ? 1 : 0.75,
116
+ lineLineWidth: 1,
117
117
  grid: true,
118
118
  gridStroke: tokens.axisGrid,
119
119
  gridStrokeOpacity: 1,
120
- gridLineWidth: isAcademy ? 1 : 0.5,
121
- gridLineDash: isAcademy ? [0, 0] : [2, 4],
120
+ gridLineWidth: isAcademy ? 1 : 0.75,
121
+ gridLineDash: isAcademy ? [0, 0] : [3, 3],
122
122
  gridFilter: filterBaselineGrid
123
123
  },
124
124
  axisRadar: {
@@ -17,8 +17,8 @@ var LIGHT_TOKENS = {
17
17
  textPrimary: '#1F2937',
18
18
  textSecondary: '#667085',
19
19
  grid: '#E7EAF0',
20
- axisGrid: '#EAECF0',
21
- axisLine: '#D0D5DD',
20
+ axisGrid: '#D0D5DD',
21
+ axisLine: '#98A2B3',
22
22
  axisTick: '#98A2B3',
23
23
  separator: '#FFFFFF',
24
24
  tooltipBackground: 'rgba(255, 255, 255, 0.96)',
@@ -32,8 +32,8 @@ var DARK_TOKENS = {
32
32
  textPrimary: '#F3F4F6',
33
33
  textSecondary: '#A7AFBE',
34
34
  grid: '#343841',
35
- axisGrid: '#2B2F36',
36
- axisLine: '#454B56',
35
+ axisGrid: '#475467',
36
+ axisLine: '#667085',
37
37
  axisTick: '#596170',
38
38
  separator: '#141414',
39
39
  tooltipBackground: 'rgba(26, 27, 31, 0.96)',
@@ -11,7 +11,7 @@ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symb
11
11
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
12
12
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
13
13
  import { Chart } from '@antv/g2';
14
- import { CHART_STYLE_DEFAULTS, getCartesianAxis, getCartesianLayout, getChartAnimation, getLineHighlightState, getSeriesHighlightByColorInteraction, getSharedTooltipInteraction, getThemeObject, normalizePalette } from "../../util";
14
+ import { CHART_STYLE_DEFAULTS, bindCrosshairAxisLabels, getCartesianAxis, getCartesianLayout, getChartAnimation, getLineHighlightState, getSeriesHighlightByColorInteraction, getSharedTooltipInteraction, getThemeObject, normalizePalette } from "../../util";
15
15
 
16
16
  /**
17
17
  * DualAxesSeriesItem defines a single series in the dual-axes chart.
@@ -83,6 +83,7 @@ export var DualAxes = function DualAxes(options) {
83
83
  chartTheme = _options$theme === void 0 ? 'default' : _options$theme;
84
84
  var chart = null;
85
85
  var hasRendered = false;
86
+ var cleanupCrosshairAxisLabels = null;
86
87
 
87
88
  /**
88
89
  * Render the dual-axes chart with the given configuration.
@@ -99,6 +100,9 @@ export var DualAxes = function DualAxes(options) {
99
100
 
100
101
  // Clean up previous chart if exists
101
102
  if (chart) {
103
+ var _cleanupCrosshairAxis;
104
+ (_cleanupCrosshairAxis = cleanupCrosshairAxisLabels) === null || _cleanupCrosshairAxis === void 0 || _cleanupCrosshairAxis();
105
+ cleanupCrosshairAxisLabels = null;
102
106
  chart.destroy();
103
107
  }
104
108
  var _style$startAtZero = style.startAtZero,
@@ -294,6 +298,29 @@ export var DualAxes = function DualAxes(options) {
294
298
  theme: getThemeObject(theme)
295
299
  });
296
300
  chart.options(chartOptions);
301
+ var lineYFields = seriesMeta.filter(function (_ref6) {
302
+ var item = _ref6.item;
303
+ return item.type === 'line';
304
+ }).map(function (_ref7) {
305
+ var yField = _ref7.yField;
306
+ return yField;
307
+ });
308
+ if (lineYFields.length) {
309
+ var currentChart = chart;
310
+ var cleanups = lineYFields.map(function (yField, index) {
311
+ return bindCrosshairAxisLabels(currentChart, theme, {
312
+ showXLabel: index === 0,
313
+ useStandaloneYLabel: true,
314
+ yAxisPosition: 'right',
315
+ yField: yField
316
+ });
317
+ });
318
+ cleanupCrosshairAxisLabels = function cleanupCrosshairAxisLabels() {
319
+ return cleanups.forEach(function (cleanup) {
320
+ return cleanup();
321
+ });
322
+ };
323
+ }
297
324
  chart.render();
298
325
  hasRendered = true;
299
326
  };
@@ -303,6 +330,9 @@ export var DualAxes = function DualAxes(options) {
303
330
  */
304
331
  var destroy = function destroy() {
305
332
  if (chart) {
333
+ var _cleanupCrosshairAxis2;
334
+ (_cleanupCrosshairAxis2 = cleanupCrosshairAxisLabels) === null || _cleanupCrosshairAxis2 === void 0 || _cleanupCrosshairAxis2();
335
+ cleanupCrosshairAxisLabels = null;
306
336
  chart.destroy();
307
337
  chart = null;
308
338
  }
@@ -14,7 +14,6 @@ export interface FunnelConfig {
14
14
  data: FunnelDataItem[];
15
15
  theme?: VisualizationTheme;
16
16
  title?: string;
17
- locale?: string;
18
17
  conversionRateLabel?: string;
19
18
  style?: {
20
19
  backgroundColor?: string;