57190 lines
2.1 MiB
Executable File
57190 lines
2.1 MiB
Executable File
"use strict";
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
if (decorator = decorators[i])
|
|
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
if (kind && result)
|
|
__defProp(target, key, result);
|
|
return result;
|
|
};
|
|
|
|
// packages/ag-charts-community/src/main.ts
|
|
var main_exports = {};
|
|
__export(main_exports, {
|
|
AG_CHARTS_LOCALE_EN_US: () => AG_CHARTS_LOCALE_EN_US,
|
|
AgCharts: () => AgCharts,
|
|
AgChartsCommunityModule: () => AgChartsCommunityModule,
|
|
AgTooltipAnchorToType: () => AgTooltipAnchorToType,
|
|
AgTooltipPlacementType: () => AgTooltipPlacementType,
|
|
AllCartesianAxesModule: () => AllCartesianAxesModule,
|
|
AllCartesianModule: () => AllCartesianModule,
|
|
AllCartesianSeriesModule: () => AllCartesianSeriesModule,
|
|
AllCommunityModule: () => AllCommunityModule,
|
|
AllPolarModule: () => AllPolarModule,
|
|
AreaSeriesModule: () => AreaSeriesModule,
|
|
BarSeriesModule: () => BarSeriesModule,
|
|
BubbleSeriesModule: () => BubbleSeriesModule,
|
|
CartesianChartModule: () => CartesianChartModule,
|
|
CategoryAxisModule: () => CategoryAxisModule,
|
|
DonutSeriesModule: () => DonutSeriesModule,
|
|
GroupedCategoryAxisModule: () => GroupedCategoryAxisModule,
|
|
HistogramSeriesModule: () => HistogramSeriesModule,
|
|
LegendModule: () => LegendModule,
|
|
LineSeriesModule: () => LineSeriesModule,
|
|
LocaleModule: () => LocaleModule,
|
|
LogAxisModule: () => LogAxisModule,
|
|
ModuleRegistry: () => import_ag_charts_core286.ModuleRegistry,
|
|
NumberAxisModule: () => NumberAxisModule,
|
|
PieSeriesModule: () => PieSeriesModule,
|
|
PolarChartModule: () => PolarChartModule,
|
|
ScatterSeriesModule: () => ScatterSeriesModule,
|
|
SparklinePresetModule: () => SparklinePresetModule,
|
|
TimeAxisModule: () => TimeAxisModule,
|
|
UnitTimeAxisModule: () => UnitTimeAxisModule,
|
|
VERSION: () => VERSION,
|
|
_ModuleSupport: () => module_support_exports,
|
|
_Scene: () => integrated_charts_scene_exports,
|
|
_Theme: () => integrated_charts_theme_exports,
|
|
_Util: () => integrated_charts_util_exports,
|
|
_Widget: () => exports_exports,
|
|
time: () => time
|
|
});
|
|
module.exports = __toCommonJS(main_exports);
|
|
|
|
// packages/ag-charts-locale/src/en-US.ts
|
|
var AG_CHARTS_LOCALE_EN_US = {
|
|
// Initial screen reader alt-text of the series area
|
|
ariaInitSeriesArea: "interactive chart",
|
|
// Screen reader announcement when focusing an item in the chart
|
|
ariaAnnounceHoverDatum: "${datum}",
|
|
// Screen reader announcement when focusing a chart
|
|
ariaAnnounceChart: "chart, ${seriesCount}[number] series",
|
|
// Screen reader announcement when focusing a standalone chart (gauges, pyramid)
|
|
ariaAnnounceStandaloneChart: "chart, ${caption}",
|
|
// Screen reader announcement when focusing a hierarchy chart
|
|
ariaAnnounceHierarchyChart: "hierarchy chart, ${caption}",
|
|
// Screen reader announcement when focusing a gauge chart
|
|
ariaAnnounceGaugeChart: "gauge chart, ${caption}",
|
|
// Screen reader announcement when focusing an item in a treemap or sunburst chart
|
|
ariaAnnounceHierarchyDatum: "level ${level}[number], ${count}[number] children, ${description}",
|
|
// Screen reader announcement when focusing a link in a Sankey or chord chart
|
|
ariaAnnounceFlowProportionLink: "link ${index} of ${count}, from ${from} to ${to}, ${sizeName} ${size}",
|
|
// Screen reader announcement when focusing a node in a Sankey or chord chart
|
|
ariaAnnounceFlowProportionNode: "node ${index} of ${count}, ${description}",
|
|
// Screen reader description for legend items
|
|
ariaDescriptionLegendItem: "Press Space or Enter to toggle visibility",
|
|
// Screen reader for the '+' horizontal line button on the Y-axis
|
|
ariaLabelAddHorizontalLine: "Add Horizontal Line",
|
|
// Screen reader text for annotations toolbar
|
|
ariaLabelAnnotationsToolbar: "Annotations",
|
|
// Screen reader text for annotation-options toolbar
|
|
ariaLabelAnnotationOptionsToolbar: "Annotation Options",
|
|
// Screen reader text for annotation-settings dialog
|
|
ariaLabelAnnotationSettingsDialog: "Annotation Settings",
|
|
// Screen reader text for the color-code label in the picker dialog
|
|
ariaLabelColor: "Color",
|
|
// Screen reader text for the color picker dialog
|
|
ariaLabelColorPicker: "Color picker",
|
|
// Screen reader text for the alpha-channel slider label
|
|
ariaLabelColorPickerAlpha: "Transparency",
|
|
// Screen reader text for the hue slider label
|
|
ariaLabelColorPickerHue: "Hue",
|
|
// Screen reader text for when the color-code is multi-colored
|
|
ariaLabelColorPickerMultiColor: "Multi Color",
|
|
// Screen reader text for the 2D palette slider label
|
|
ariaLabelColorPickerPalette: "Palette",
|
|
// Screen reader text for the financial charts toolbar
|
|
ariaLabelFinancialCharts: "Financial Charts",
|
|
// Screen reader text label for the gauge targets
|
|
ariaLabelGaugeTarget: "Target",
|
|
// Screen reader text label for the gauge values
|
|
ariaLabelGaugeValue: "Value",
|
|
// Screen reader text for the legend toolbar
|
|
ariaLabelLegend: "Legend",
|
|
// Screen reader text for the legend pagination button
|
|
ariaLabelLegendPagination: "Legend Pagination",
|
|
// Screen reader text for the previous legend page button
|
|
ariaLabelLegendPagePrevious: "Previous Legend Page",
|
|
// Screen reader text for the next legend page button
|
|
ariaLabelLegendPageNext: "Next Legend Page",
|
|
// Screen reader text for the an item in the legend
|
|
ariaLabelLegendItem: "${label}, Legend item ${index}[number] of ${count}[number]",
|
|
// Screen reader text for the an unknown item in the legend
|
|
ariaLabelLegendItemUnknown: "Unknown legend item",
|
|
// Screen reader text for the navigator element
|
|
ariaLabelNavigator: "Navigator",
|
|
// Screen reader text for an accessibility control that changes the position of the navigator's range
|
|
ariaLabelNavigatorRange: "Range",
|
|
// Screen reader text for the horizontal axis scrollbar
|
|
ariaLabelScrollbarHorizontal: "X-axis scrollbar",
|
|
// Screen reader text for the vertical axis scrollbar
|
|
ariaLabelScrollbarVertical: "Y-axis scrollbar",
|
|
// Screen reader text for an accessibility control that changes the start of the navigator's range
|
|
ariaLabelNavigatorMinimum: "Minimum",
|
|
// Screen reader text for an accessibility control that changes the end of the navigator's range
|
|
ariaLabelNavigatorMaximum: "Maximum",
|
|
// Screen reader text for ranges toolbar
|
|
ariaLabelRangesToolbar: "Ranges",
|
|
// Screen reader text for the settings dialog tab-bar
|
|
ariaLabelSettingsTabBar: "Settings",
|
|
// Screen reader text for zoom toolbar
|
|
ariaLabelZoomToolbar: "Zoom",
|
|
// Aria role description for a 2D role="slider"
|
|
ariaRoleDescription2DSlider: "2D slider",
|
|
// Screen reader text for color picker's 2D slider palette
|
|
ariaValueColorPalette: "s ${s}[percent0to2dp], v ${v}[percent0to2dp]",
|
|
// Screen reader text for color picker's 2D slider palette (when arrowing up or down)
|
|
ariaValueColorPaletteFirstV: "v ${v}[percent0to2dp], s ${s}[percent0to2dp]",
|
|
// Screen reader text for the value of the navigator's range
|
|
ariaValuePanRange: "${min}[percent0to2dp] to ${max}[percent0to2dp]",
|
|
// Alt-text for the solid line dash style menu item icon
|
|
iconAltTextLineStyleSolid: "Solid",
|
|
// Alt-text for the long-dashed line dash style menu item icon
|
|
iconAltTextLineStyleDashed: "Long-dashed",
|
|
// Alt-text for the short-dashed line dash style menu item icon
|
|
iconAltTextLineStyleDotted: "Short-dashed",
|
|
// Alt-text for the 'position-top' icon
|
|
iconAltTextPositionTop: "Top",
|
|
// Alt-text for the 'position-center' icon
|
|
iconAltTextPositionCenter: "Center",
|
|
// Alt-text for the 'position-bottom' icon
|
|
iconAltTextPositionBottom: "Bottom",
|
|
// Alt-text for the 'position-left' icon
|
|
iconAltTextAlignLeft: "Left",
|
|
// Alt-text for the 'align-center' icon
|
|
iconAltTextAlignCenter: "Center",
|
|
// Alt-text for the 'position-right' icon
|
|
iconAltTextAlignRight: "Right",
|
|
// Alt-text for the 'close' icon
|
|
iconAltTextClose: "Close",
|
|
// Default text for the 'loading data' overlay
|
|
overlayLoadingData: "Loading data...",
|
|
// Default text for the 'no data' overlay
|
|
overlayNoData: "No data to display",
|
|
// Default text for the 'no visible series' overlay
|
|
overlayNoVisibleSeries: "No visible series",
|
|
// Default text for the 'unsupported browser' overlay
|
|
overlayUnsupportedBrowser: "Incompatible browser version. Please upgrade your browser.",
|
|
// Text for frequency label in Histogram Series tooltip
|
|
seriesHistogramTooltipFrequency: "Frequency",
|
|
// Text for sum label in Histogram Series tooltip
|
|
seriesHistogramTooltipSum: "${yName} (sum)",
|
|
// Text for sum label in Histogram Series tooltip
|
|
seriesHistogramTooltipCount: "${yName} (count)",
|
|
// Text for sum label in Histogram Series tooltip
|
|
seriesHistogramTooltipMean: "${yName} (mean)",
|
|
// Text for the series type toolbar's chart type button
|
|
toolbarSeriesTypeDropdown: "Chart Type",
|
|
// Text for the series type toolbar's OHLC chart type button
|
|
toolbarSeriesTypeOHLC: "OHLC",
|
|
// Text for the series type toolbar's HLC chart type button
|
|
toolbarSeriesTypeHLC: "HLC",
|
|
// Text for the series type toolbar's high low chart type button
|
|
toolbarSeriesTypeHighLow: "High Low",
|
|
// Text for the series type toolbar's candles chart type button
|
|
toolbarSeriesTypeCandles: "Candles",
|
|
// Text for the series type toolbar's hollow candles chart type button
|
|
toolbarSeriesTypeHollowCandles: "Hollow Candles",
|
|
// Text for the series type toolbar's line chart type button
|
|
toolbarSeriesTypeLine: "Line",
|
|
// Text for the series type toolbar's line with markers chart type button
|
|
toolbarSeriesTypeLineWithMarkers: "Line with Markers",
|
|
// Text for the series type toolbar's line with step line chart type button
|
|
toolbarSeriesTypeStepLine: "Step Line",
|
|
// Text for the annotation toolbar's trend line button
|
|
toolbarAnnotationsTrendLine: "Trend Line",
|
|
// Text for the annotation toolbar's Fibonacci Retracement button
|
|
toolbarAnnotationsFibonacciRetracement: "Fib Retracement",
|
|
// Text for the annotation toolbar's Fibonacci Retracement Trend Based button
|
|
toolbarAnnotationsFibonacciRetracementTrendBased: "Fib Trend Based",
|
|
// Text for the annotation toolbar's horizontal line button
|
|
toolbarAnnotationsHorizontalLine: "Horizontal Line",
|
|
// Text for the annotation toolbar's vertical line button
|
|
toolbarAnnotationsVerticalLine: "Vertical Line",
|
|
// Text for the annotation toolbar's parallel channel button
|
|
toolbarAnnotationsParallelChannel: "Parallel Channel",
|
|
// Text for the annotation toolbar's disjoint channel button
|
|
toolbarAnnotationsDisjointChannel: "Disjoint Channel",
|
|
// Text for the annotation toolbar's clear all button
|
|
toolbarAnnotationsClearAll: "Clear All",
|
|
// Text for the annotation toolbar's fill color picker annotation button
|
|
toolbarAnnotationsFillColor: "Fill Color",
|
|
// Text for the annotation toolbar's line color picker annotation button
|
|
toolbarAnnotationsLineColor: "Line Color",
|
|
// Text for the annotation toolbar's line style type button
|
|
toolbarAnnotationsLineStyle: "Line Style",
|
|
// Text for the annotation toolbar's line stroke width button
|
|
toolbarAnnotationsLineStrokeWidth: "Line Stroke Width",
|
|
// Text for the annotation toolbar's settings annotation button
|
|
toolbarAnnotationsSettings: "Settings",
|
|
// Text for the annotation toolbar's text color picker annotation button
|
|
toolbarAnnotationsTextColor: "Text Color",
|
|
// Text for the annotation toolbar's text size picker annotation button
|
|
toolbarAnnotationsTextSize: "Text Size",
|
|
// Text for the annotation toolbar's lock annotation button
|
|
toolbarAnnotationsLock: "Lock",
|
|
// Text for the annotation toolbar's unlock annotation button
|
|
toolbarAnnotationsUnlock: "Unlock",
|
|
// Text for the annotation toolbar's delete annotation button
|
|
toolbarAnnotationsDelete: "Delete",
|
|
// Text for the annotation toolbar's drag handle
|
|
toolbarAnnotationsDragHandle: "Drag Toolbar",
|
|
// Text for the annotation toolbar's line drawings menu button
|
|
toolbarAnnotationsLineAnnotations: "Trend Lines",
|
|
// Text for the annotation toolbar's Fibonacci drawings menu button
|
|
toolbarAnnotationsFibonacciAnnotations: "Fibonacci",
|
|
// Text for the annotation toolbar's text annotations menu button
|
|
toolbarAnnotationsTextAnnotations: "Text Annotations",
|
|
// Text for the annotation toolbar's shapes menu button
|
|
toolbarAnnotationsShapeAnnotations: "Arrows",
|
|
// Text for the annotation toolbar's measurers menu button
|
|
toolbarAnnotationsMeasurerAnnotations: "Measurers",
|
|
// Text for the annotation toolbar's callout button
|
|
toolbarAnnotationsCallout: "Callout",
|
|
// Text for the annotation toolbar's comment button
|
|
toolbarAnnotationsComment: "Comment",
|
|
// Text for the annotation toolbar's note button
|
|
toolbarAnnotationsNote: "Note",
|
|
// Text for the annotation toolbar's text button
|
|
toolbarAnnotationsText: "Text",
|
|
// Text for the annotation toolbar's arrow button
|
|
toolbarAnnotationsArrow: "Arrow",
|
|
// Text for the annotation toolbar's arrow up button
|
|
toolbarAnnotationsArrowUp: "Arrow Up",
|
|
// Text for the annotation toolbar's arrow down button
|
|
toolbarAnnotationsArrowDown: "Arrow Down",
|
|
// Text for the annotation toolbar's date range button
|
|
toolbarAnnotationsDateRange: "Date Range",
|
|
// Text for the annotation toolbar's price range button
|
|
toolbarAnnotationsPriceRange: "Price Range",
|
|
// Text for the annotation toolbar's date and price range button
|
|
toolbarAnnotationsDatePriceRange: "Date and Price",
|
|
// Text for the annotation toolbar's quick date and price range button
|
|
toolbarAnnotationsQuickDatePriceRange: "Measure",
|
|
// Text for the range toolbar's 1 month button
|
|
toolbarRange1Month: "1M",
|
|
// Aria label for the range toolbar's 1 month button
|
|
toolbarRange1MonthAria: "1 month",
|
|
// Text for the range toolbar's 3 month button
|
|
toolbarRange3Months: "3M",
|
|
// Aria label for the range toolbar's 3 month button
|
|
toolbarRange3MonthsAria: "3 months",
|
|
// Text for the range toolbar's 6 month button
|
|
toolbarRange6Months: "6M",
|
|
// Aria label for the range toolbar's 6 month button
|
|
toolbarRange6MonthsAria: "6 months",
|
|
// Text for the range toolbar's year to date button
|
|
toolbarRangeYearToDate: "YTD",
|
|
// Aria label for the range toolbar's year to date month button
|
|
toolbarRangeYearToDateAria: "Year to date",
|
|
// Text for the range toolbar's 1 year button
|
|
toolbarRange1Year: "1Y",
|
|
// Aria label for the range toolbar's 1 year button
|
|
toolbarRange1YearAria: "1 year",
|
|
// Text for the range toolbar's full range button
|
|
toolbarRangeAll: "All",
|
|
// Aria label for the range toolbar's full range button
|
|
toolbarRangeAllAria: "All",
|
|
// Text for the zoom toolbar's zoom out button
|
|
toolbarZoomZoomOut: "Zoom out",
|
|
// Text for the zoom toolbar's zoom in button
|
|
toolbarZoomZoomIn: "Zoom in",
|
|
// Text for the zoom toolbar's pan left button
|
|
toolbarZoomPanLeft: "Pan left",
|
|
// Text for the zoom toolbar's pan right button
|
|
toolbarZoomPanRight: "Pan right",
|
|
// Text for the zoom toolbar's pan to the start button
|
|
toolbarZoomPanStart: "Pan to the start",
|
|
// Text for the zoom toolbar's pan to the end button
|
|
toolbarZoomPanEnd: "Pan to the end",
|
|
// Text for the zoom toolbar's pan reset button
|
|
toolbarZoomReset: "Reset the zoom",
|
|
// Text for the context menu's download button
|
|
contextMenuDownload: "Download",
|
|
// Text for the context menu's toggle series visibility button
|
|
contextMenuToggleSeriesVisibility: "Toggle Visibility",
|
|
// Text for the context menu's toggle other series visibility button
|
|
contextMenuToggleOtherSeries: "Toggle Other Series",
|
|
// Text for the context menu's zoom to point button
|
|
contextMenuZoomToCursor: "Zoom to here",
|
|
// Text for the context menu's pan to point button
|
|
contextMenuPanToCursor: "Pan to here",
|
|
// Text for the context menu's reset zoom button
|
|
contextMenuResetZoom: "Reset zoom",
|
|
// Text for the annotation dialog's header channel tab label
|
|
dialogHeaderChannel: "Channel",
|
|
// Text for the annotation dialog's header line tab label
|
|
dialogHeaderLine: "Line",
|
|
// Text for the annotation dialog's header fibonacci retracement line tab label
|
|
dialogHeaderFibonacciRange: "Fib Retracement",
|
|
// Text for the annotation dialog's header date range tab label
|
|
dialogHeaderDateRange: "Date Range",
|
|
// Text for the annotation dialog's header price range tab label
|
|
dialogHeaderPriceRange: "Price Range",
|
|
// Text for the annotation dialog's header date and price range tab label
|
|
dialogHeaderDatePriceRange: "Date and Price",
|
|
// Text for the annotation dialog's header text tab label
|
|
dialogHeaderText: "Text",
|
|
// Text for the annotation dialog's text alignment radio label
|
|
dialogInputAlign: "Align",
|
|
// Text for the annotation dialog's color picker label
|
|
dialogInputColorPicker: "Color",
|
|
// Text for the annotation dialog's color picker alt text
|
|
dialogInputColorPickerAltText: "Text Color",
|
|
// Text for the annotation dialog's fill color picker label
|
|
dialogInputFillColorPicker: "Fill",
|
|
// Text for the annotation dialog's fill color picker alt text
|
|
dialogInputFillColorPickerAltText: "Fill Color",
|
|
// Text for the annotation dialog's extend channel start checkbox
|
|
dialogInputExtendChannelStart: "Extend channel start",
|
|
// Text for the annotation dialog's extend channel end checkbox
|
|
dialogInputExtendChannelEnd: "Extend channel end",
|
|
// Text for the annotation dialog's extend line start checkbox
|
|
dialogInputExtendLineStart: "Extend line start",
|
|
// Text for the annotation dialog's extend line end checkbox
|
|
dialogInputExtendLineEnd: "Extend line end",
|
|
// Text for the annotation dialog's extend above checkbox
|
|
dialogInputExtendAbove: "Extend above",
|
|
// Text for the annotation dialog's extend below checkbox
|
|
dialogInputExtendBelow: "Extend below",
|
|
// Text for the annotation dialog's extend left checkbox
|
|
dialogInputExtendLeft: "Extend left",
|
|
// Text for the annotation dialog's extend right checkbox
|
|
dialogInputExtendRight: "Extend right",
|
|
// Text for the annotation dialog's reverse checkbox
|
|
dialogInputReverse: "Reverse",
|
|
// Text for the annotation dialog's show fill checkbox
|
|
dialogInputShowFill: "Show Fill",
|
|
// Text for the annotation dialog's font size select box label
|
|
dialogInputFontSize: "Size",
|
|
// Text for the annotation dialog's font size select box alt text
|
|
dialogInputFontSizeAltText: "Font Size",
|
|
// Text for the annotation dialog's line style radio label
|
|
dialogInputLineStyle: "Dash",
|
|
// Text for the annotation dialog's text position radio label
|
|
dialogInputPosition: "Position",
|
|
// Text for the annotation dialog's stroke width label
|
|
dialogInputStrokeWidth: "Weight",
|
|
// Text for the annotation dialog's stroke width label
|
|
dialogInputStrokeWidthAltText: "Line Weight",
|
|
// Text for the annotation dialog's Fibonacci bands label
|
|
dialogInputFibonacciBands: "Bands",
|
|
// Text for the annotation dialog's Fibonacci bands label
|
|
dialogInputFibonacciBandsAltText: "Fibonacci Bands",
|
|
// Text for text area input placeholders
|
|
inputTextareaPlaceholder: "Add Text",
|
|
// Text for the measurer statistics date range bars value
|
|
measurerDateRangeBars: "${value}[number] bars",
|
|
// Text for the measurer statistics price range value
|
|
measurerPriceRangeValue: "${value}[number]",
|
|
// Text for the measurer statistics price range percentage
|
|
measurerPriceRangePercent: "${value}[percent]",
|
|
// Text for the measurer statistics volume value
|
|
measurerVolume: "Vol ${value}",
|
|
// Status when multiple data are under the cursor, and the user can click to cycle through which one appears in the tooltip
|
|
tooltipPaginationStatus: "${index}[number] of ${count}[number]"
|
|
};
|
|
|
|
// packages/ag-charts-types/src/chart/navigatorOptions.ts
|
|
var __MINI_CHART_SERIES_OPTIONS = void 0;
|
|
var __VERIFY_MINI_CHART_SERIES_OPTIONS = void 0;
|
|
__VERIFY_MINI_CHART_SERIES_OPTIONS = __MINI_CHART_SERIES_OPTIONS;
|
|
|
|
// packages/ag-charts-types/src/chart/themeOptions.ts
|
|
var __THEME_OVERRIDES = void 0;
|
|
var __VERIFY_THEME_OVERRIDES = void 0;
|
|
__VERIFY_THEME_OVERRIDES = __THEME_OVERRIDES;
|
|
|
|
// packages/ag-charts-types/src/chart/tooltipOptions.ts
|
|
var AgTooltipAnchorToType = /* @__PURE__ */ ((AgTooltipAnchorToType2) => {
|
|
AgTooltipAnchorToType2["POINTER"] = "pointer";
|
|
AgTooltipAnchorToType2["NODE"] = "node";
|
|
AgTooltipAnchorToType2["CHART"] = "chart";
|
|
return AgTooltipAnchorToType2;
|
|
})(AgTooltipAnchorToType || {});
|
|
var AgTooltipPlacementType = /* @__PURE__ */ ((AgTooltipPlacementType2) => {
|
|
AgTooltipPlacementType2["TOP"] = "top";
|
|
AgTooltipPlacementType2["RIGHT"] = "right";
|
|
AgTooltipPlacementType2["BOTTOM"] = "bottom";
|
|
AgTooltipPlacementType2["LEFT"] = "left";
|
|
AgTooltipPlacementType2["TOP_RIGHT"] = "top-right";
|
|
AgTooltipPlacementType2["BOTTOM_RIGHT"] = "bottom-right";
|
|
AgTooltipPlacementType2["BOTTOM_LEFT"] = "bottom-left";
|
|
AgTooltipPlacementType2["TOP_LEFT"] = "top-left";
|
|
AgTooltipPlacementType2["CENTER"] = "center";
|
|
return AgTooltipPlacementType2;
|
|
})(AgTooltipPlacementType || {});
|
|
|
|
// packages/ag-charts-types/src/presets/gauge/commonOptions.ts
|
|
var __THEMEABLE_OPTIONS = void 0;
|
|
var __VERIFY_THEMEABLE_OPTIONS = void 0;
|
|
__VERIFY_THEMEABLE_OPTIONS = __THEMEABLE_OPTIONS;
|
|
var __AXIS_LABEL_OPTIONS = void 0;
|
|
var __VERIFY_AXIS_LABEL_OPTIONS = void 0;
|
|
__VERIFY_AXIS_LABEL_OPTIONS = __AXIS_LABEL_OPTIONS;
|
|
|
|
// packages/ag-charts-community/src/util/time-interop.ts
|
|
var import_ag_charts_core = require("ag-charts-core");
|
|
function createTimeInterval(unit, step, epoch, utc) {
|
|
return {
|
|
unit,
|
|
step,
|
|
epoch,
|
|
utc,
|
|
every(count) {
|
|
return createTimeInterval(this.unit, (this.step ?? 1) * count, this.epoch, this.utc);
|
|
}
|
|
};
|
|
}
|
|
var cachedInstances = {};
|
|
function getTimeInterval(unit, step = 1, epoch, utc = false) {
|
|
import_ag_charts_core.Logger.warnOnce("time import is deprecated, use object notation instead");
|
|
const key = `${unit}:${step}:${epoch?.getTime() ?? 0}:${utc}`;
|
|
let instance = cachedInstances[key];
|
|
if (instance == null) {
|
|
instance = createTimeInterval(unit, step, epoch, utc);
|
|
cachedInstances[key] = instance;
|
|
}
|
|
return instance;
|
|
}
|
|
var time = {
|
|
get millisecond() {
|
|
return getTimeInterval("millisecond");
|
|
},
|
|
get second() {
|
|
return getTimeInterval("second");
|
|
},
|
|
get minute() {
|
|
return getTimeInterval("minute");
|
|
},
|
|
get hour() {
|
|
return getTimeInterval("hour");
|
|
},
|
|
get day() {
|
|
return getTimeInterval("day");
|
|
},
|
|
get monday() {
|
|
return getTimeInterval("day", 7, new Date(1970, 0, 5));
|
|
},
|
|
get tuesday() {
|
|
return getTimeInterval("day", 7, new Date(1970, 0, 6));
|
|
},
|
|
get wednesday() {
|
|
return getTimeInterval("day", 7, new Date(1970, 0, 7));
|
|
},
|
|
get thursday() {
|
|
return getTimeInterval("day", 7, new Date(1970, 0, 1));
|
|
},
|
|
get friday() {
|
|
return getTimeInterval("day", 7, new Date(1970, 0, 2));
|
|
},
|
|
get saturday() {
|
|
return getTimeInterval("day", 7, new Date(1970, 0, 3));
|
|
},
|
|
get sunday() {
|
|
return getTimeInterval("day", 7, new Date(1970, 0, 4));
|
|
},
|
|
get month() {
|
|
return getTimeInterval("month");
|
|
},
|
|
get year() {
|
|
return getTimeInterval("year");
|
|
},
|
|
get utcMillisecond() {
|
|
return getTimeInterval("millisecond", 1, void 0, true);
|
|
},
|
|
get utcSecond() {
|
|
return getTimeInterval("second", 1, void 0, true);
|
|
},
|
|
get utcMinute() {
|
|
return getTimeInterval("minute", 1, void 0, true);
|
|
},
|
|
get utcHour() {
|
|
return getTimeInterval("hour", 1, void 0, true);
|
|
},
|
|
get utcDay() {
|
|
return getTimeInterval("day", 1, void 0, true);
|
|
},
|
|
get utcMonth() {
|
|
return getTimeInterval("month", 1, void 0, true);
|
|
},
|
|
get utcYear() {
|
|
return getTimeInterval("year", 1, void 0, true);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/api/agCharts.ts
|
|
var import_ag_charts_core187 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/chart.ts
|
|
var import_ag_charts_core153 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/bbox.ts
|
|
var import_ag_charts_core2 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/util/interpolating.ts
|
|
var interpolate = Symbol("interpolate");
|
|
var isInterpolating = (x) => x[interpolate] != null;
|
|
|
|
// packages/ag-charts-community/src/scene/bbox.ts
|
|
var _BBox = class _BBox {
|
|
constructor(x, y, width, height) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.width = width;
|
|
this.height = height;
|
|
}
|
|
static fromObject({ x, y, width, height }) {
|
|
return new _BBox(x, y, width, height);
|
|
}
|
|
static merge(boxes) {
|
|
let left = Infinity;
|
|
let top = Infinity;
|
|
let right = -Infinity;
|
|
let bottom = -Infinity;
|
|
for (const box of boxes) {
|
|
if (box.x < left) {
|
|
left = box.x;
|
|
}
|
|
if (box.y < top) {
|
|
top = box.y;
|
|
}
|
|
if (end(box.x, box.width) > right) {
|
|
right = end(box.x, box.width);
|
|
}
|
|
if (end(box.y, box.height) > bottom) {
|
|
bottom = end(box.y, box.height);
|
|
}
|
|
}
|
|
return new _BBox(left, top, right - left, bottom - top);
|
|
}
|
|
static nearestBox(x, y, boxes) {
|
|
return (0, import_ag_charts_core2.nearestSquared)(x, y, boxes);
|
|
}
|
|
toDOMRect() {
|
|
return {
|
|
x: this.x,
|
|
y: this.y,
|
|
width: this.width,
|
|
height: this.height,
|
|
top: this.y,
|
|
left: this.x,
|
|
right: end(this.x, this.width),
|
|
bottom: end(this.y, this.height),
|
|
toJSON() {
|
|
return {};
|
|
}
|
|
};
|
|
}
|
|
clone() {
|
|
const { x, y, width, height } = this;
|
|
return new _BBox(x, y, width, height);
|
|
}
|
|
equals(other) {
|
|
return (0, import_ag_charts_core2.boxesEqual)(this, other);
|
|
}
|
|
containsPoint(x, y) {
|
|
return (0, import_ag_charts_core2.boxContains)(this, x, y);
|
|
}
|
|
intersection(other) {
|
|
const x0 = Math.max(this.x, other.x);
|
|
const y0 = Math.max(this.y, other.y);
|
|
const x1 = Math.min(end(this.x, this.width), end(other.x, other.width));
|
|
const y1 = Math.min(end(this.y, this.height), end(other.y, other.height));
|
|
if (x0 > x1 || y0 > y1)
|
|
return;
|
|
return new _BBox(x0, y0, x1 - x0, y1 - y0);
|
|
}
|
|
collidesBBox(other) {
|
|
return this.x < end(other.x, other.width) && end(this.x, this.width) > other.x && this.y < end(other.y, other.height) && end(this.y, this.height) > other.y;
|
|
}
|
|
computeCenter() {
|
|
return { x: this.x + this.width / 2, y: this.y + this.height / 2 };
|
|
}
|
|
isFinite() {
|
|
return Number.isFinite(this.x) && Number.isFinite(this.y) && Number.isFinite(this.width) && Number.isFinite(this.height);
|
|
}
|
|
distanceSquared(x, y) {
|
|
if (this.containsPoint(x, y)) {
|
|
return 0;
|
|
}
|
|
const dx = x - (0, import_ag_charts_core2.clamp)(this.x, x, end(this.x, this.width));
|
|
const dy = y - (0, import_ag_charts_core2.clamp)(this.y, y, end(this.y, this.height));
|
|
return dx * dx + dy * dy;
|
|
}
|
|
shrink(amount, position) {
|
|
if (typeof amount === "number") {
|
|
this.applyMargin(amount, position);
|
|
} else {
|
|
for (const key of Object.keys(amount)) {
|
|
const value = amount[key];
|
|
if (typeof value === "number") {
|
|
this.applyMargin(value, key);
|
|
}
|
|
}
|
|
}
|
|
if (this.width < 0) {
|
|
this.width = 0;
|
|
}
|
|
if (this.height < 0) {
|
|
this.height = 0;
|
|
}
|
|
return this;
|
|
}
|
|
grow(amount, position) {
|
|
if (typeof amount === "number") {
|
|
this.applyMargin(-amount, position);
|
|
} else {
|
|
for (const key of Object.keys(amount)) {
|
|
const value = amount[key];
|
|
if (typeof value === "number") {
|
|
this.applyMargin(-value, key);
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
applyMargin(value, position) {
|
|
switch (position) {
|
|
case "top":
|
|
this.y += value;
|
|
case "bottom":
|
|
this.height -= value;
|
|
break;
|
|
case "left":
|
|
this.x += value;
|
|
case "right":
|
|
this.width -= value;
|
|
break;
|
|
case "vertical":
|
|
this.y += value;
|
|
this.height -= value * 2;
|
|
break;
|
|
case "horizontal":
|
|
this.x += value;
|
|
this.width -= value * 2;
|
|
break;
|
|
case void 0:
|
|
this.x += value;
|
|
this.y += value;
|
|
this.width -= value * 2;
|
|
this.height -= value * 2;
|
|
break;
|
|
}
|
|
}
|
|
translate(x, y) {
|
|
this.x += x;
|
|
this.y += y;
|
|
return this;
|
|
}
|
|
[interpolate](other, d) {
|
|
return new _BBox(
|
|
this.x * (1 - d) + other.x * d,
|
|
this.y * (1 - d) + other.y * d,
|
|
this.width * (1 - d) + other.width * d,
|
|
this.height * (1 - d) + other.height * d
|
|
);
|
|
}
|
|
};
|
|
_BBox.zero = Object.freeze(new _BBox(0, 0, 0, 0));
|
|
_BBox.NaN = Object.freeze(new _BBox(Number.NaN, Number.NaN, Number.NaN, Number.NaN));
|
|
var BBox = _BBox;
|
|
function end(x, width) {
|
|
if (x === -Infinity && width === Infinity)
|
|
return Infinity;
|
|
return x + width;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/group.ts
|
|
var import_ag_charts_core22 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/canvas/hdpiOffscreenCanvas.ts
|
|
var import_ag_charts_core4 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/canvas/canvasUtil.ts
|
|
var import_ag_charts_core3 = require("ag-charts-core");
|
|
function clearContext({
|
|
context,
|
|
pixelRatio,
|
|
width,
|
|
height
|
|
}) {
|
|
context.save();
|
|
try {
|
|
context.resetTransform();
|
|
context.clearRect(0, 0, Math.ceil(width * pixelRatio), Math.ceil(height * pixelRatio));
|
|
} finally {
|
|
context.restore();
|
|
}
|
|
}
|
|
function debugContext(ctx) {
|
|
if (import_ag_charts_core3.Debug.check("canvas")) {
|
|
const save = ctx.save.bind(ctx);
|
|
const restore = ctx.restore.bind(ctx);
|
|
let depth = 0;
|
|
Object.assign(ctx, {
|
|
save() {
|
|
save();
|
|
depth++;
|
|
},
|
|
restore() {
|
|
if (depth === 0) {
|
|
throw new Error("AG Charts - Unable to restore() past depth 0");
|
|
}
|
|
restore();
|
|
depth--;
|
|
},
|
|
verifyDepthZero() {
|
|
if (depth !== 0) {
|
|
throw new Error(`AG Charts - Save/restore depth is non-zero: ${depth}`);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/canvas/hdpiOffscreenCanvas.ts
|
|
function canvasDimensions(width, height, pixelRatio) {
|
|
return [Math.floor(width * pixelRatio), Math.floor(height * pixelRatio)];
|
|
}
|
|
var fallbackCanvas;
|
|
function getFallbackCanvas() {
|
|
const OffscreenCanvasCtor = (0, import_ag_charts_core4.getOffscreenCanvas)();
|
|
fallbackCanvas ?? (fallbackCanvas = new OffscreenCanvasCtor(1, 1));
|
|
return fallbackCanvas;
|
|
}
|
|
var HdpiOffscreenCanvas = class {
|
|
constructor(options) {
|
|
const { width, height, pixelRatio, willReadFrequently = false } = options;
|
|
this.width = width;
|
|
this.height = height;
|
|
this.pixelRatio = pixelRatio;
|
|
const [canvasWidth, canvasHeight] = canvasDimensions(width, height, pixelRatio);
|
|
const OffscreenCanvasCtor = (0, import_ag_charts_core4.getOffscreenCanvas)();
|
|
this.canvas = new OffscreenCanvasCtor(canvasWidth, canvasHeight);
|
|
this.context = this.canvas.getContext("2d", { willReadFrequently });
|
|
this.context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
debugContext(this.context);
|
|
}
|
|
drawImage(context, dx = 0, dy = 0) {
|
|
return context.drawImage(this.canvas, dx, dy);
|
|
}
|
|
transferToImageBitmap() {
|
|
if (this.canvas.width < 1 || this.canvas.height < 1) {
|
|
return getFallbackCanvas().transferToImageBitmap();
|
|
}
|
|
return this.canvas.transferToImageBitmap();
|
|
}
|
|
resize(width, height, pixelRatio) {
|
|
if (!(width > 0 && height > 0))
|
|
return;
|
|
const { canvas, context } = this;
|
|
if (width !== this.width || height !== this.height || pixelRatio !== this.pixelRatio) {
|
|
const [canvasWidth, canvasHeight] = canvasDimensions(width, height, pixelRatio);
|
|
canvas.width = canvasWidth;
|
|
canvas.height = canvasHeight;
|
|
}
|
|
context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
this.width = width;
|
|
this.height = height;
|
|
this.pixelRatio = pixelRatio;
|
|
}
|
|
clear() {
|
|
clearContext(this);
|
|
}
|
|
destroy() {
|
|
this.canvas.width = 0;
|
|
this.canvas.height = 0;
|
|
this.context.clearRect(0, 0, 0, 0);
|
|
this.canvas = null;
|
|
this.context = null;
|
|
Object.freeze(this);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/node.ts
|
|
var import_ag_charts_core5 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/zIndex.ts
|
|
var cmp = (a, b) => Math.sign(a - b);
|
|
function compareZIndex(a, b) {
|
|
if (typeof a === "number" && typeof b === "number") {
|
|
return cmp(a, b);
|
|
}
|
|
const aArray = typeof a === "number" ? [a] : a;
|
|
const bArray = typeof b === "number" ? [b] : b;
|
|
const length = Math.min(aArray.length, bArray.length);
|
|
for (let i = 0; i < length; i += 1) {
|
|
const diff2 = cmp(aArray[i], bArray[i]);
|
|
if (diff2 !== 0)
|
|
return diff2;
|
|
}
|
|
return cmp(aArray.length, bArray.length);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/node.ts
|
|
var import_ag_charts_core6 = require("ag-charts-core");
|
|
var PointerEvents = /* @__PURE__ */ ((PointerEvents2) => {
|
|
PointerEvents2[PointerEvents2["All"] = 0] = "All";
|
|
PointerEvents2[PointerEvents2["None"] = 1] = "None";
|
|
return PointerEvents2;
|
|
})(PointerEvents || {});
|
|
var MAX_ERROR_COUNT = 5;
|
|
var _Node = class _Node {
|
|
constructor(options) {
|
|
/** Unique number to allow creation order to be easily determined. */
|
|
this.serialNumber = _Node._nextSerialNumber++;
|
|
this.childNodeCounts = { groups: 0, nonGroups: 0, thisComplexity: 0, complexity: 0 };
|
|
/** Unique node ID in the form `ClassName-NaturalNumber`. */
|
|
this.id = (0, import_ag_charts_core5.createId)(this);
|
|
this.name = void 0;
|
|
this.transitionOut = void 0;
|
|
this.pointerEvents = 0 /* All */;
|
|
this._datum = void 0;
|
|
this._previousDatum = void 0;
|
|
this.scene = void 0;
|
|
this._debugDirtyProperties = void 0;
|
|
this.parentNode = void 0;
|
|
this.cachedBBox = void 0;
|
|
/**
|
|
* To simplify the type system (especially in Selections) we don't have the `Parent` node
|
|
* (one that has children). Instead, we mimic HTML DOM, where any node can have children.
|
|
* But we still need to distinguish regular leaf nodes from container leafs somehow.
|
|
*/
|
|
this.isContainerNode = false;
|
|
this.visible = true;
|
|
this.zIndex = 0;
|
|
this.batchLevel = 0;
|
|
this.batchDirty = false;
|
|
this.name = options?.name;
|
|
this.tag = options?.tag ?? Number.NaN;
|
|
this.zIndex = options?.zIndex ?? 0;
|
|
this.scene = options?.scene;
|
|
if (options?.debugDirty ?? _Node._debugEnabled) {
|
|
this._debugDirtyProperties = /* @__PURE__ */ new Map([["__first__", []]]);
|
|
}
|
|
}
|
|
static toSVG(node, width, height) {
|
|
const svg = node?.toSVG();
|
|
if (svg == null || !svg.elements.length && !svg.defs?.length)
|
|
return;
|
|
const root = (0, import_ag_charts_core5.createSvgElement)("svg");
|
|
root.setAttribute("width", String(width));
|
|
root.setAttribute("height", String(height));
|
|
root.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
root.setAttribute("overflow", "visible");
|
|
if (svg.defs?.length) {
|
|
const defs = (0, import_ag_charts_core5.createSvgElement)("defs");
|
|
defs.append(...svg.defs);
|
|
root.append(defs);
|
|
}
|
|
root.append(...svg.elements);
|
|
return root.outerHTML;
|
|
}
|
|
static *extractBBoxes(nodes, skipInvisible) {
|
|
for (const n of nodes) {
|
|
if (!skipInvisible || n.visible && !n.transitionOut) {
|
|
const bbox = n.getBBox();
|
|
if (bbox)
|
|
yield bbox;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Some arbitrary data bound to the node.
|
|
*/
|
|
get datum() {
|
|
return this._datum;
|
|
}
|
|
set datum(datum) {
|
|
if (this._datum !== datum) {
|
|
this._previousDatum = this._datum;
|
|
this._datum = datum;
|
|
}
|
|
}
|
|
get previousDatum() {
|
|
return this._previousDatum;
|
|
}
|
|
get layerManager() {
|
|
return this.scene?.layersManager;
|
|
}
|
|
get imageLoader() {
|
|
return this.scene?.imageLoader;
|
|
}
|
|
closestDatum() {
|
|
for (const { datum } of this.traverseUp(true)) {
|
|
if (datum != null) {
|
|
return datum;
|
|
}
|
|
}
|
|
}
|
|
/** Perform any pre-rendering initialization. */
|
|
preRender(_renderCtx, thisComplexity = 1) {
|
|
this.childNodeCounts.groups = 0;
|
|
this.childNodeCounts.nonGroups = 1;
|
|
this.childNodeCounts.complexity = thisComplexity;
|
|
this.childNodeCounts.thisComplexity = thisComplexity;
|
|
if (this.batchLevel > 0 || this.batchDirty) {
|
|
throw new Error("AG Charts - illegal rendering state; batched update in progress");
|
|
}
|
|
return this.childNodeCounts;
|
|
}
|
|
/** Guaranteed isolated render - if there is any failure, the Canvas2D context is returned to its prior state. */
|
|
isolatedRender(renderCtx) {
|
|
renderCtx.ctx.save();
|
|
try {
|
|
this.render(renderCtx);
|
|
} catch (e) {
|
|
const errorCount = e.errorCount ?? 1;
|
|
if (errorCount >= MAX_ERROR_COUNT) {
|
|
e.errorCount = errorCount;
|
|
throw e;
|
|
}
|
|
import_ag_charts_core5.Logger.warnOnce("Error during rendering", e, e.stack);
|
|
} finally {
|
|
renderCtx.ctx.restore();
|
|
}
|
|
}
|
|
render(renderCtx) {
|
|
const { stats } = renderCtx;
|
|
this.debugDirtyProperties();
|
|
if (renderCtx.debugNodeSearch) {
|
|
const idOrName = this.name ?? this.id;
|
|
if (renderCtx.debugNodeSearch.some((v) => typeof v === "string" ? v === idOrName : v.test(idOrName))) {
|
|
renderCtx.debugNodes[this.name ?? this.id] = this;
|
|
}
|
|
}
|
|
if (stats) {
|
|
stats.nodesRendered++;
|
|
stats.opsPerformed += this.childNodeCounts.thisComplexity;
|
|
}
|
|
}
|
|
setScene(scene) {
|
|
this.scene = scene;
|
|
}
|
|
*traverseUp(includeSelf) {
|
|
if (includeSelf) {
|
|
yield this;
|
|
}
|
|
let node = this.parentNode;
|
|
while (node) {
|
|
yield node;
|
|
node = node.parentNode;
|
|
}
|
|
}
|
|
/**
|
|
* Checks if the node is the root (has no parent).
|
|
*/
|
|
isRoot() {
|
|
return !this.parentNode;
|
|
}
|
|
removeChild(node) {
|
|
throw new Error(
|
|
`AG Charts - internal error, unknown child node ${node.name ?? node.id} in $${this.name ?? this.id}`
|
|
);
|
|
}
|
|
remove() {
|
|
this.parentNode?.removeChild(this);
|
|
}
|
|
destroy() {
|
|
if (this.parentNode) {
|
|
this.remove();
|
|
}
|
|
}
|
|
batchedUpdate(fn) {
|
|
this.batchLevel++;
|
|
try {
|
|
fn();
|
|
} finally {
|
|
this.batchLevel--;
|
|
if (this.batchLevel === 0 && this.batchDirty) {
|
|
this.markDirty();
|
|
this.batchDirty = false;
|
|
}
|
|
}
|
|
}
|
|
setProperties(styles) {
|
|
this.batchLevel++;
|
|
try {
|
|
(0, import_ag_charts_core5.assignIfNotStrictlyEqual)(this, styles);
|
|
} finally {
|
|
this.batchLevel--;
|
|
if (this.batchLevel === 0 && this.batchDirty) {
|
|
this.markDirty();
|
|
this.batchDirty = false;
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
setPropertiesWithKeys(styles, keys) {
|
|
this.batchLevel++;
|
|
try {
|
|
(0, import_ag_charts_core5.assignIfNotStrictlyEqual)(this, styles, keys);
|
|
} finally {
|
|
this.batchLevel--;
|
|
if (this.batchLevel === 0 && this.batchDirty) {
|
|
this.markDirty();
|
|
this.batchDirty = false;
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
containsPoint(_x, _y) {
|
|
return false;
|
|
}
|
|
pickNode(x, y) {
|
|
if (this.containsPoint(x, y)) {
|
|
return this;
|
|
}
|
|
}
|
|
pickNodes(x, y, into = []) {
|
|
if (this.containsPoint(x, y)) {
|
|
into.push(this);
|
|
}
|
|
return into;
|
|
}
|
|
getBBox() {
|
|
this.cachedBBox ?? (this.cachedBBox = Object.freeze(this.computeBBox()));
|
|
return this.cachedBBox;
|
|
}
|
|
computeBBox() {
|
|
return;
|
|
}
|
|
onChangeDetection(property) {
|
|
this.markDirty(property);
|
|
}
|
|
markDirtyChildrenOrder() {
|
|
this.cachedBBox = void 0;
|
|
}
|
|
markDirty(property) {
|
|
if (this.batchLevel > 0) {
|
|
this.batchDirty = true;
|
|
return;
|
|
}
|
|
if (property != null && this._debugDirtyProperties) {
|
|
this.markDebugProperties(property);
|
|
}
|
|
this.cachedBBox = void 0;
|
|
this.parentNode?.markDirty();
|
|
}
|
|
markDebugProperties(property) {
|
|
const sources = this._debugDirtyProperties?.get(property) ?? [];
|
|
const caller = new Error("Stack trace for property change tracking").stack?.split("\n").filter((line) => {
|
|
return line !== "Error" && !line.includes(".markDebugProperties") && !line.includes(".markDirty") && !line.includes("Object.assign ") && !line.includes(`${this.constructor.name}.`);
|
|
}) ?? "unknown";
|
|
sources.push(caller[0].replace(" at ", "").trim());
|
|
this._debugDirtyProperties?.set(property, sources);
|
|
}
|
|
debugDirtyProperties() {
|
|
if (this._debugDirtyProperties == null)
|
|
return;
|
|
if (!this._debugDirtyProperties.has("__first__")) {
|
|
for (const [property, sources] of this._debugDirtyProperties.entries()) {
|
|
if (sources.length > 1) {
|
|
import_ag_charts_core5.Logger.logGroup(
|
|
`Property changed multiple times before render: ${this.constructor.name}.${property} (${sources.length}x)`,
|
|
() => {
|
|
for (const source of sources) {
|
|
import_ag_charts_core5.Logger.log(source);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
this._debugDirtyProperties.clear();
|
|
}
|
|
static handleNodeZIndexChange(target) {
|
|
target.onZIndexChange();
|
|
}
|
|
onZIndexChange() {
|
|
this.parentNode?.markDirtyChildrenOrder();
|
|
}
|
|
toSVG() {
|
|
return;
|
|
}
|
|
};
|
|
_Node.className = "AbstractNode";
|
|
_Node._nextSerialNumber = 0;
|
|
// eslint-disable-next-line sonarjs/public-static-readonly
|
|
_Node._debugEnabled = false;
|
|
__decorateClass([
|
|
(0, import_ag_charts_core5.DeclaredSceneChangeDetection)()
|
|
], _Node.prototype, "visible", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core5.DeclaredSceneChangeDetection)({
|
|
equals: import_ag_charts_core5.objectsEqual,
|
|
changeCb: _Node.handleNodeZIndexChange
|
|
})
|
|
], _Node.prototype, "zIndex", 2);
|
|
var Node = _Node;
|
|
|
|
// packages/ag-charts-community/src/scene/shape/shape.ts
|
|
var import_ag_charts_core19 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/gradient/conicGradient.ts
|
|
var import_ag_charts_core10 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/gradient/gradient.ts
|
|
var import_ag_charts_core9 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scale/colorScale.ts
|
|
var import_ag_charts_core8 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scale/abstractScale.ts
|
|
var AbstractScale = class {
|
|
ticks(_ticks, _domain, _visibleRange) {
|
|
return void 0;
|
|
}
|
|
niceDomain(_ticks, domain = this.domain) {
|
|
return domain;
|
|
}
|
|
get bandwidth() {
|
|
return void 0;
|
|
}
|
|
get step() {
|
|
return void 0;
|
|
}
|
|
get inset() {
|
|
return void 0;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scale/invalidating.ts
|
|
var Invalidating = (target, propertyKey) => {
|
|
const mappedProperty = Symbol(String(propertyKey));
|
|
target[mappedProperty] = void 0;
|
|
Object.defineProperty(target, propertyKey, {
|
|
get() {
|
|
return this[mappedProperty];
|
|
},
|
|
set(newValue) {
|
|
const oldValue = this[mappedProperty];
|
|
if (oldValue !== newValue) {
|
|
this[mappedProperty] = newValue;
|
|
this.invalid = true;
|
|
}
|
|
},
|
|
enumerable: true,
|
|
configurable: false
|
|
});
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scale/scaleUtil.ts
|
|
var import_ag_charts_core7 = require("ag-charts-core");
|
|
function visibleTickRange(ticks, reversed, visibleRange) {
|
|
if (visibleRange == null || visibleRange[0] === 0 && visibleRange[1] === 1)
|
|
return;
|
|
const vt0 = (0, import_ag_charts_core7.clamp)(0, Math.floor(visibleRange[0] * ticks.length), ticks.length);
|
|
const vt1 = (0, import_ag_charts_core7.clamp)(0, Math.ceil(visibleRange[1] * ticks.length), ticks.length);
|
|
const t0 = reversed ? ticks.length - vt1 : vt0;
|
|
const t1 = reversed ? ticks.length - vt0 : vt1;
|
|
return [t0, t1];
|
|
}
|
|
function visibleTickSliceIndices(ticks, reversed, visibleRange) {
|
|
return visibleTickRange(ticks, reversed, visibleRange) ?? [0, ticks.length];
|
|
}
|
|
function filterVisibleTicks(ticks, reversed, visibleRange) {
|
|
const tickRange = visibleTickRange(ticks, reversed, visibleRange);
|
|
if (tickRange == null)
|
|
return { ticks, count: ticks.length, firstTickIndex: 0 };
|
|
const [t0, t1] = tickRange;
|
|
return {
|
|
ticks: ticks.slice(t0, t1),
|
|
count: ticks.length,
|
|
firstTickIndex: t0
|
|
};
|
|
}
|
|
function unpackDomainMinMax(domain) {
|
|
const min = (0, import_ag_charts_core7.readIntegratedWrappedValue)(domain.at(0));
|
|
const max = (0, import_ag_charts_core7.readIntegratedWrappedValue)(domain.at(-1));
|
|
return min != void 0 && max != void 0 ? [min, max] : [void 0, void 0];
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scale/colorScale.ts
|
|
var convertColorStringToOklcha = (v) => {
|
|
const color8 = import_ag_charts_core8.Color.fromString(v);
|
|
const [l, c, h] = import_ag_charts_core8.Color.RGBtoOKLCH(color8.r, color8.g, color8.b);
|
|
return { l, c, h, a: color8.a };
|
|
};
|
|
var delta = 1e-6;
|
|
var isAchromatic = (x) => x.c < delta || x.l < delta || x.l > 1 - delta;
|
|
var interpolateOklch = (x, y, d) => {
|
|
d = (0, import_ag_charts_core8.clamp)(0, d, 1);
|
|
let h;
|
|
if (isAchromatic(x)) {
|
|
h = y.h;
|
|
} else if (isAchromatic(y)) {
|
|
h = x.h;
|
|
} else {
|
|
const xH = x.h;
|
|
let yH = y.h;
|
|
const deltaH = y.h - x.h;
|
|
if (deltaH > 180) {
|
|
yH -= 360;
|
|
} else if (deltaH < -180) {
|
|
yH += 360;
|
|
}
|
|
h = xH * (1 - d) + yH * d;
|
|
}
|
|
const c = x.c * (1 - d) + y.c * d;
|
|
const l = x.l * (1 - d) + y.l * d;
|
|
const a = x.a * (1 - d) + y.a * d;
|
|
return import_ag_charts_core8.Color.fromOKLCH(l, c, h, a);
|
|
};
|
|
var ColorScale = class extends AbstractScale {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "color";
|
|
this.defaultTickCount = 0;
|
|
this.invalid = true;
|
|
this.domain = [0, 1];
|
|
this.range = ["red", "blue"];
|
|
this.parsedRange = this.range.map(convertColorStringToOklcha);
|
|
}
|
|
update() {
|
|
const { domain, range: range4 } = this;
|
|
if (domain.length < 2) {
|
|
import_ag_charts_core8.Logger.warnOnce("`colorDomain` should have at least 2 values.");
|
|
if (domain.length === 0) {
|
|
domain.push(0, 1);
|
|
} else if (domain.length === 1) {
|
|
domain.push(domain[0] + 1);
|
|
}
|
|
}
|
|
for (let i = 1; i < domain.length; i++) {
|
|
const a = domain[i - 1];
|
|
const b = domain[i];
|
|
if (a > b) {
|
|
import_ag_charts_core8.Logger.warnOnce("`colorDomain` values should be supplied in ascending order.");
|
|
domain.sort((a2, b2) => a2 - b2);
|
|
break;
|
|
}
|
|
}
|
|
if (range4.length < domain.length) {
|
|
for (let i = range4.length; i < domain.length; i++) {
|
|
range4.push(range4.length > 0 ? range4[0] : "black");
|
|
}
|
|
}
|
|
this.parsedRange = this.range.map(convertColorStringToOklcha);
|
|
}
|
|
normalizeDomains(...domains) {
|
|
return { domain: domains.map((d) => d.domain).flat(), animatable: true };
|
|
}
|
|
toDomain() {
|
|
return;
|
|
}
|
|
convert(x) {
|
|
this.refresh();
|
|
const { domain, range: range4, parsedRange } = this;
|
|
const d0 = domain[0];
|
|
const d1 = domain.at(-1);
|
|
const r0 = range4[0];
|
|
const r1 = range4.at(-1);
|
|
if (x <= d0) {
|
|
return r0;
|
|
}
|
|
if (x >= d1) {
|
|
return r1;
|
|
}
|
|
let index;
|
|
let q;
|
|
if (domain.length === 2) {
|
|
const t = (x - d0) / (d1 - d0);
|
|
const step = 1 / (range4.length - 1);
|
|
index = range4.length <= 2 ? 0 : Math.min(Math.floor(t * (range4.length - 1)), range4.length - 2);
|
|
q = (t - index * step) / step;
|
|
} else {
|
|
for (index = 0; index < domain.length - 2; index++) {
|
|
if (x < domain[index + 1]) {
|
|
break;
|
|
}
|
|
}
|
|
const a = domain[index];
|
|
const b = domain[index + 1];
|
|
q = (x - a) / (b - a);
|
|
}
|
|
const c0 = parsedRange[index];
|
|
const c1 = parsedRange[index + 1];
|
|
return interpolateOklch(c0, c1, q).toRgbaString();
|
|
}
|
|
invert() {
|
|
return;
|
|
}
|
|
getDomainMinMax() {
|
|
return unpackDomainMinMax(this.domain);
|
|
}
|
|
refresh() {
|
|
if (!this.invalid)
|
|
return;
|
|
this.invalid = false;
|
|
this.update();
|
|
if (this.invalid) {
|
|
import_ag_charts_core8.Logger.warnOnce("Expected update to not invalidate scale");
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Invalidating
|
|
], ColorScale.prototype, "domain", 2);
|
|
__decorateClass([
|
|
Invalidating
|
|
], ColorScale.prototype, "range", 2);
|
|
|
|
// packages/ag-charts-community/src/scene/gradient/gradient.ts
|
|
var Gradient = class {
|
|
constructor(colorSpace, stops = [], bbox) {
|
|
this.colorSpace = colorSpace;
|
|
this.stops = stops;
|
|
this.bbox = bbox;
|
|
this._cache = void 0;
|
|
}
|
|
createGradient(ctx, shapeBbox, params) {
|
|
const bbox = this.bbox ?? shapeBbox;
|
|
if (!bbox.isFinite()) {
|
|
return;
|
|
}
|
|
if (this._cache?.ctx === ctx && this._cache.bbox.equals(bbox)) {
|
|
return this._cache.gradient;
|
|
}
|
|
const { stops, colorSpace } = this;
|
|
if (stops.length === 0)
|
|
return;
|
|
if (stops.length === 1)
|
|
return stops[0].color;
|
|
let gradient = this.createCanvasGradient(ctx, bbox, params);
|
|
if (gradient == null)
|
|
return;
|
|
const isOkLch = colorSpace === "oklch";
|
|
const step = 0.05;
|
|
let c0 = stops[0];
|
|
gradient.addColorStop(c0.stop, c0.color);
|
|
for (let i = 1; i < stops.length; i += 1) {
|
|
const c1 = stops[i];
|
|
if (isOkLch) {
|
|
const scale2 = new ColorScale();
|
|
scale2.domain = [c0.stop, c1.stop];
|
|
scale2.range = [c0.color, c1.color];
|
|
for (let stop = c0.stop + step; stop < c1.stop; stop += step) {
|
|
gradient.addColorStop(stop, scale2.convert(stop) ?? "transparent");
|
|
}
|
|
}
|
|
gradient.addColorStop(c1.stop, c1.color);
|
|
c0 = c1;
|
|
}
|
|
if ("createPattern" in gradient) {
|
|
gradient = gradient.createPattern();
|
|
}
|
|
this._cache = { ctx, bbox, gradient };
|
|
return gradient;
|
|
}
|
|
toSvg(shapeBbox) {
|
|
const bbox = this.bbox ?? shapeBbox;
|
|
const gradient = this.createSvgGradient(bbox);
|
|
for (const { stop: offset, color: color8 } of this.stops) {
|
|
const stop = (0, import_ag_charts_core9.createSvgElement)("stop");
|
|
stop.setAttribute("offset", `${offset}`);
|
|
stop.setAttribute("stop-color", `${color8}`);
|
|
gradient.appendChild(stop);
|
|
}
|
|
return gradient;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/gradient/conicGradient.ts
|
|
var ConicGradient = class extends Gradient {
|
|
constructor(colorSpace, stops, angle = 0, bbox) {
|
|
super(colorSpace, stops, bbox);
|
|
this.angle = angle;
|
|
}
|
|
createCanvasGradient(ctx, bbox, params) {
|
|
const angleOffset = -90;
|
|
const { angle } = this;
|
|
const radians = (0, import_ag_charts_core10.normalizeAngle360FromDegrees)(angle + angleOffset);
|
|
const cx = params?.centerX ?? bbox.x + bbox.width * 0.5;
|
|
const cy = params?.centerY ?? bbox.y + bbox.height * 0.5;
|
|
return ctx.createConicGradient(radians, cx, cy);
|
|
}
|
|
createSvgGradient(_bbox) {
|
|
return (0, import_ag_charts_core10.createSvgElement)("linearGradient");
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/gradient/linearGradient.ts
|
|
var import_ag_charts_core11 = require("ag-charts-core");
|
|
var LinearGradient = class extends Gradient {
|
|
constructor(colorSpace, stops, angle = 0, bbox) {
|
|
super(colorSpace, stops, bbox);
|
|
this.angle = angle;
|
|
}
|
|
getGradientPoints(bbox) {
|
|
const angleOffset = 90;
|
|
const { angle } = this;
|
|
const radians = (0, import_ag_charts_core11.normalizeAngle360FromDegrees)(angle + angleOffset);
|
|
const cos = Math.cos(radians);
|
|
const sin = Math.sin(radians);
|
|
const w = bbox.width;
|
|
const h = bbox.height;
|
|
const cx = bbox.x + w * 0.5;
|
|
const cy = bbox.y + h * 0.5;
|
|
const diagonal = Math.hypot(h, w) / 2;
|
|
const diagonalAngle = Math.atan2(h, w);
|
|
let quarteredAngle;
|
|
if (radians < Math.PI / 2) {
|
|
quarteredAngle = radians;
|
|
} else if (radians < Math.PI) {
|
|
quarteredAngle = Math.PI - radians;
|
|
} else if (radians < 1.5 * Math.PI) {
|
|
quarteredAngle = radians - Math.PI;
|
|
} else {
|
|
quarteredAngle = 2 * Math.PI - radians;
|
|
}
|
|
const l = diagonal * Math.abs(Math.cos(quarteredAngle - diagonalAngle));
|
|
return { x0: cx + cos * l, y0: cy + sin * l, x1: cx - cos * l, y1: cy - sin * l };
|
|
}
|
|
createCanvasGradient(ctx, bbox) {
|
|
const { x0, y0, x1, y1 } = this.getGradientPoints(bbox);
|
|
if (Number.isNaN(x0) || Number.isNaN(y0) || Number.isNaN(x1) || Number.isNaN(y1)) {
|
|
return void 0;
|
|
}
|
|
return ctx.createLinearGradient(x0, y0, x1, y1);
|
|
}
|
|
createSvgGradient(bbox) {
|
|
const { x0, y0, x1, y1 } = this.getGradientPoints(bbox);
|
|
const gradient = (0, import_ag_charts_core11.createSvgElement)("linearGradient");
|
|
gradient.setAttribute("x1", String(x0));
|
|
gradient.setAttribute("y1", String(y0));
|
|
gradient.setAttribute("x2", String(x1));
|
|
gradient.setAttribute("y2", String(y1));
|
|
gradient.setAttribute("gradientUnits", "userSpaceOnUse");
|
|
return gradient;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/gradient/radialGradient.ts
|
|
var import_ag_charts_core12 = require("ag-charts-core");
|
|
var RadialGradient = class extends Gradient {
|
|
constructor(colorSpace, stops, bbox) {
|
|
super(colorSpace, stops, bbox);
|
|
}
|
|
createCanvasGradient(ctx, bbox, params) {
|
|
const cx = params?.centerX ?? bbox.x + bbox.width * 0.5;
|
|
const cy = params?.centerY ?? bbox.y + bbox.height * 0.5;
|
|
const innerRadius = params?.innerRadius ?? 0;
|
|
const outerRadius = params?.outerRadius ?? Math.hypot(bbox.width * 0.5, bbox.height * 0.5) / Math.SQRT2;
|
|
return ctx.createRadialGradient(cx, cy, innerRadius, cx, cy, outerRadius);
|
|
}
|
|
createSvgGradient(bbox) {
|
|
const cx = bbox.x + bbox.width * 0.5;
|
|
const cy = bbox.y + bbox.height * 0.5;
|
|
const gradient = (0, import_ag_charts_core12.createSvgElement)("radialGradient");
|
|
gradient.setAttribute("cx", String(cx));
|
|
gradient.setAttribute("cy", String(cy));
|
|
gradient.setAttribute("r", String(Math.hypot(bbox.width * 0.5, bbox.height * 0.5) / Math.SQRT2));
|
|
gradient.setAttribute("gradientUnits", "userSpaceOnUse");
|
|
return gradient;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/gradient/stops.ts
|
|
var import_ag_charts_core13 = require("ag-charts-core");
|
|
var StopProperties = class extends import_ag_charts_core13.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.color = "black";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core13.Property
|
|
], StopProperties.prototype, "stop", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core13.Property
|
|
], StopProperties.prototype, "color", 2);
|
|
function stopsAreAscending(fills) {
|
|
let currentStop;
|
|
for (const fill of fills) {
|
|
if (fill?.stop == null)
|
|
continue;
|
|
if (currentStop != null && fill.stop < currentStop) {
|
|
return false;
|
|
}
|
|
currentStop = fill.stop;
|
|
}
|
|
return true;
|
|
}
|
|
function discreteColorStops(colorStops) {
|
|
return colorStops.flatMap((colorStop, i) => {
|
|
const { stop } = colorStop;
|
|
const nextColor = colorStops.at(i + 1)?.color;
|
|
return nextColor == null ? [colorStop] : [colorStop, { stop, color: nextColor }];
|
|
});
|
|
}
|
|
function getDefaultColorStops(defaultColorStops, fillMode) {
|
|
const stopOffset = fillMode === "discrete" ? 1 : 0;
|
|
const colorStops = defaultColorStops.map(
|
|
(color8, index, { length }) => ({
|
|
stop: (index + stopOffset) / (length - 1 + stopOffset),
|
|
color: color8
|
|
})
|
|
);
|
|
return fillMode === "discrete" ? discreteColorStops(colorStops) : colorStops;
|
|
}
|
|
function getColorStops(baseFills, defaultColorStops, domain, fillMode = "continuous") {
|
|
const fills = baseFills.map((fill) => typeof fill === "string" ? { color: fill } : fill);
|
|
if (fills.length === 0) {
|
|
return getDefaultColorStops(defaultColorStops, fillMode);
|
|
} else if (!stopsAreAscending(fills)) {
|
|
import_ag_charts_core13.Logger.warnOnce(`[fills] must have the stops defined in ascending order`);
|
|
return [];
|
|
}
|
|
const d0 = Math.min(...domain);
|
|
const d1 = Math.max(...domain);
|
|
const isDiscrete = fillMode === "discrete";
|
|
const stops = new Float64Array(fills.length);
|
|
let previousDefinedStopIndex = 0;
|
|
let nextDefinedStopIndex = -1;
|
|
for (let i = 0; i < fills.length; i += 1) {
|
|
const colorStop = fills[i];
|
|
if (i >= nextDefinedStopIndex) {
|
|
nextDefinedStopIndex = fills.length - 1;
|
|
for (let j = i + 1; j < fills.length; j += 1) {
|
|
if (fills[j]?.stop != null) {
|
|
nextDefinedStopIndex = j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
let stop = colorStop?.stop;
|
|
if (stop == null) {
|
|
const stop0 = fills[previousDefinedStopIndex]?.stop;
|
|
const stop1 = fills[nextDefinedStopIndex]?.stop;
|
|
const value0 = stop0 ?? d0;
|
|
const value1 = stop1 ?? d1;
|
|
const stopOffset = isDiscrete && stop0 == null ? 1 : 0;
|
|
stop = value0 + (value1 - value0) * (i - previousDefinedStopIndex + stopOffset) / (nextDefinedStopIndex - previousDefinedStopIndex + stopOffset);
|
|
} else {
|
|
previousDefinedStopIndex = i;
|
|
}
|
|
stops[i] = Math.max(0, Math.min(1, (stop - d0) / (d1 - d0)));
|
|
}
|
|
let lastDefinedColor = fills.find((c) => c.color != null)?.color;
|
|
let colorScale;
|
|
const colorStops = fills.map((fill, i) => {
|
|
let color8 = fill?.color;
|
|
const stop = stops[i];
|
|
if (color8 != null) {
|
|
lastDefinedColor = color8;
|
|
} else if (lastDefinedColor == null) {
|
|
if (colorScale == null) {
|
|
colorScale = new ColorScale();
|
|
colorScale.domain = [0, 1];
|
|
colorScale.range = defaultColorStops;
|
|
}
|
|
color8 = colorScale.convert(stop);
|
|
} else {
|
|
color8 = lastDefinedColor;
|
|
}
|
|
return { stop, color: color8 };
|
|
});
|
|
return fillMode === "discrete" ? discreteColorStops(colorStops) : colorStops;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/image/image.ts
|
|
var import_ag_charts_core14 = require("ag-charts-core");
|
|
var Image = class {
|
|
constructor(imageLoader, imageOptions) {
|
|
this.imageLoader = imageLoader;
|
|
this._cache = void 0;
|
|
this.url = imageOptions.url;
|
|
this.backgroundFill = imageOptions.backgroundFill ?? "black";
|
|
this.backgroundFillOpacity = imageOptions.backgroundFillOpacity ?? 1;
|
|
this.repeat = imageOptions.repeat ?? "no-repeat";
|
|
this.width = imageOptions.width;
|
|
this.height = imageOptions.height;
|
|
this.fit = imageOptions.fit ?? "stretch";
|
|
this.rotation = imageOptions.rotation ?? 0;
|
|
}
|
|
createCanvasImage(ctx, image, width, height) {
|
|
if (!image)
|
|
return null;
|
|
const [renderedWidth, renderedHeight] = this.getSize(image.width, image.height, width, height);
|
|
if (renderedWidth < 1 || renderedHeight < 1) {
|
|
import_ag_charts_core14.Logger.warnOnce("Image fill is too small to render, ignoring.");
|
|
return null;
|
|
}
|
|
return ctx.createPattern(image, this.repeat);
|
|
}
|
|
getSize(imageWidth, imageHeight, width, height) {
|
|
const { fit } = this;
|
|
let dw = imageWidth;
|
|
let dh = imageHeight;
|
|
let scale2 = 1;
|
|
const shapeAspectRatio = width / height;
|
|
const imageAspectRatio = imageWidth / imageHeight;
|
|
if (fit === "stretch" || imageWidth === 0 || imageHeight === 0) {
|
|
dw = width;
|
|
dh = height;
|
|
} else if (fit === "contain") {
|
|
scale2 = imageAspectRatio > shapeAspectRatio ? width / imageWidth : height / imageHeight;
|
|
} else if (fit === "cover") {
|
|
scale2 = imageAspectRatio > shapeAspectRatio ? height / imageHeight : width / imageWidth;
|
|
}
|
|
return [Math.max(1, dw * scale2), Math.max(1, dh * scale2)];
|
|
}
|
|
setImageTransform(pattern, bbox) {
|
|
if (typeof pattern === "string")
|
|
return;
|
|
const { url, rotation, width, height } = this;
|
|
const image = this.imageLoader?.loadImage(url);
|
|
if (!image) {
|
|
return;
|
|
}
|
|
const angle = (0, import_ag_charts_core14.normalizeAngle360FromDegrees)(rotation);
|
|
const cos = Math.cos(angle);
|
|
const sin = Math.sin(angle);
|
|
const [renderedWidth, renderedHeight] = this.getSize(
|
|
image.width,
|
|
image.height,
|
|
width ?? bbox.width,
|
|
height ?? bbox.height
|
|
);
|
|
const widthScale = renderedWidth / image.width;
|
|
const heightScale = renderedHeight / image.height;
|
|
const bboxCenterX = bbox.x + bbox.width / 2;
|
|
const bboxCenterY = bbox.y + bbox.height / 2;
|
|
const rotatedW = cos * renderedWidth - sin * renderedHeight;
|
|
const rotatedH = sin * renderedWidth + cos * renderedHeight;
|
|
const shapeCenterX = rotatedW / 2;
|
|
const shapeCenterY = rotatedH / 2;
|
|
const DOMMatrixCtor = (0, import_ag_charts_core14.getDOMMatrix)();
|
|
pattern?.setTransform(
|
|
new DOMMatrixCtor([
|
|
cos * widthScale,
|
|
sin * heightScale,
|
|
-sin * widthScale,
|
|
cos * heightScale,
|
|
bboxCenterX - shapeCenterX,
|
|
bboxCenterY - shapeCenterY
|
|
])
|
|
);
|
|
}
|
|
createPattern(ctx, shapeWidth, shapeHeight, node) {
|
|
const width = this.width ?? shapeWidth;
|
|
const height = this.height ?? shapeHeight;
|
|
const cache = this._cache;
|
|
if (cache?.ctx === ctx && cache.width === width && cache.height === height) {
|
|
return cache.pattern;
|
|
}
|
|
const image = this.imageLoader?.loadImage(this.url, node);
|
|
const pattern = this.createCanvasImage(ctx, image, width, height);
|
|
if (pattern == null)
|
|
return;
|
|
this._cache = { ctx, pattern, width, height };
|
|
return pattern;
|
|
}
|
|
toSvg(bbox, pixelRatio) {
|
|
const { url, rotation, backgroundFill, backgroundFillOpacity } = this;
|
|
const { x, y, width, height } = bbox;
|
|
const pattern = (0, import_ag_charts_core14.createSvgElement)("pattern");
|
|
pattern.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
pattern.setAttribute("x", String(x));
|
|
pattern.setAttribute("y", String(y));
|
|
pattern.setAttribute("width", String(width));
|
|
pattern.setAttribute("height", String(height));
|
|
pattern.setAttribute("patternUnits", "userSpaceOnUse");
|
|
const rect2 = (0, import_ag_charts_core14.createSvgElement)("rect");
|
|
rect2.setAttribute("x", "0");
|
|
rect2.setAttribute("y", "0");
|
|
rect2.setAttribute("width", String(width));
|
|
rect2.setAttribute("height", String(height));
|
|
rect2.setAttribute("fill", backgroundFill);
|
|
rect2.setAttribute("fill-opacity", String(backgroundFillOpacity));
|
|
pattern.appendChild(rect2);
|
|
const image = (0, import_ag_charts_core14.createSvgElement)("image");
|
|
image.setAttribute("href", url);
|
|
image.setAttribute("x", "0");
|
|
image.setAttribute("y", "0");
|
|
image.setAttribute("width", String(width));
|
|
image.setAttribute("height", String(height));
|
|
image.setAttribute("preserveAspectRatio", "none");
|
|
image.setAttribute("transform", `scale(${1 / pixelRatio}) rotate(${rotation}, ${width / 2}, ${height / 2})`);
|
|
pattern.appendChild(image);
|
|
return pattern;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/pattern/pattern.ts
|
|
var import_ag_charts_core18 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/extendedPath2D.ts
|
|
var import_ag_charts_core16 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/util/svg.ts
|
|
var import_ag_charts_core15 = require("ag-charts-core");
|
|
var commandEx = /^[\t\n\f\r ]*([achlmqstvz])[\t\n\f\r ]*/i;
|
|
var coordinateEx = /^[+-]?((\d*\.\d+)|(\d+\.)|(\d+))(e[+-]?\d+)?/i;
|
|
var commaEx = /[\t\n\f\r ]*,?[\t\n\f\r ]*/;
|
|
var flagEx = /^[01]/;
|
|
var pathParams = {
|
|
z: [],
|
|
h: [coordinateEx],
|
|
v: [coordinateEx],
|
|
m: [coordinateEx, coordinateEx],
|
|
l: [coordinateEx, coordinateEx],
|
|
t: [coordinateEx, coordinateEx],
|
|
s: [coordinateEx, coordinateEx, coordinateEx, coordinateEx],
|
|
q: [coordinateEx, coordinateEx, coordinateEx, coordinateEx],
|
|
c: [coordinateEx, coordinateEx, coordinateEx, coordinateEx, coordinateEx, coordinateEx],
|
|
a: [coordinateEx, coordinateEx, coordinateEx, flagEx, flagEx, coordinateEx, coordinateEx]
|
|
};
|
|
function parseSvg(d) {
|
|
if (!d)
|
|
return;
|
|
const segments = [];
|
|
let i = 0;
|
|
let currentCommand;
|
|
while (i < d.length) {
|
|
const commandMatch = commandEx.exec(d.slice(i));
|
|
let command;
|
|
if (commandMatch == null) {
|
|
if (!currentCommand) {
|
|
import_ag_charts_core15.Logger.warnOnce(`Invalid SVG path, error at index ${i}: Missing command.`);
|
|
return;
|
|
}
|
|
command = currentCommand;
|
|
} else {
|
|
command = commandMatch[1];
|
|
i += commandMatch[0].length;
|
|
}
|
|
const segment = parseSegment(command, d, i);
|
|
if (!segment)
|
|
return;
|
|
i = segment[0];
|
|
currentCommand = command;
|
|
segments.push(segment[1]);
|
|
}
|
|
return segments;
|
|
}
|
|
function parseSegment(command, d, index) {
|
|
const params = pathParams[command.toLocaleLowerCase()];
|
|
const pathSeg = { command, params: [] };
|
|
for (const regex of params) {
|
|
const segment = d.slice(index);
|
|
const match = regex.exec(segment);
|
|
if (match != null) {
|
|
pathSeg.params.push(Number.parseFloat(match[0]));
|
|
index += match[0].length;
|
|
const next = commaEx.exec(segment.slice(match[0].length));
|
|
if (next != null) {
|
|
index += next[0].length;
|
|
}
|
|
} else if (pathSeg.params.length === 1) {
|
|
return [index, pathSeg];
|
|
} else {
|
|
import_ag_charts_core15.Logger.warnOnce(
|
|
`Invalid SVG path, error at index ${index}: No path segment parameters for command [${command}]`
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
return [index, pathSeg];
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/polyRoots.ts
|
|
function linearRoot(a, b) {
|
|
const t = -b / a;
|
|
return a !== 0 && t >= 0 && t <= 1 ? [t] : [];
|
|
}
|
|
function quadraticRoots(a, b, c, delta3 = 1e-6) {
|
|
if (Math.abs(a) < delta3) {
|
|
return linearRoot(b, c);
|
|
}
|
|
const D = b * b - 4 * a * c;
|
|
const roots = [];
|
|
if (Math.abs(D) < delta3) {
|
|
const t = -b / (2 * a);
|
|
if (t >= 0 && t <= 1) {
|
|
roots.push(t);
|
|
}
|
|
} else if (D > 0) {
|
|
const rD = Math.sqrt(D);
|
|
const t1 = (-b - rD) / (2 * a);
|
|
const t2 = (-b + rD) / (2 * a);
|
|
if (t1 >= 0 && t1 <= 1) {
|
|
roots.push(t1);
|
|
}
|
|
if (t2 >= 0 && t2 <= 1) {
|
|
roots.push(t2);
|
|
}
|
|
}
|
|
return roots;
|
|
}
|
|
function cubicRoots(a, b, c, d, delta3 = 1e-6) {
|
|
if (Math.abs(a) < delta3) {
|
|
return quadraticRoots(b, c, d, delta3);
|
|
}
|
|
const A = b / a;
|
|
const B = c / a;
|
|
const C2 = d / a;
|
|
const Q = (3 * B - A * A) / 9;
|
|
const R = (9 * A * B - 27 * C2 - 2 * A * A * A) / 54;
|
|
const D = Q * Q * Q + R * R;
|
|
const third = 1 / 3;
|
|
const roots = [];
|
|
if (D >= 0) {
|
|
const rD = Math.sqrt(D);
|
|
const S = Math.sign(R + rD) * Math.pow(Math.abs(R + rD), third);
|
|
const T = Math.sign(R - rD) * Math.pow(Math.abs(R - rD), third);
|
|
const Im = Math.abs(Math.sqrt(3) * (S - T) / 2);
|
|
const t = -third * A + (S + T);
|
|
if (t >= 0 && t <= 1) {
|
|
roots.push(t);
|
|
}
|
|
if (Math.abs(Im) < delta3) {
|
|
const t2 = -third * A - (S + T) / 2;
|
|
if (t2 >= 0 && t2 <= 1) {
|
|
roots.push(t2);
|
|
}
|
|
}
|
|
} else {
|
|
const theta = Math.acos(R / Math.sqrt(-Q * Q * Q));
|
|
const thirdA = third * A;
|
|
const twoSqrtQ = 2 * Math.sqrt(-Q);
|
|
const t1 = twoSqrtQ * Math.cos(third * theta) - thirdA;
|
|
const t2 = twoSqrtQ * Math.cos(third * (theta + 2 * Math.PI)) - thirdA;
|
|
const t3 = twoSqrtQ * Math.cos(third * (theta + 4 * Math.PI)) - thirdA;
|
|
if (t1 >= 0 && t1 <= 1) {
|
|
roots.push(t1);
|
|
}
|
|
if (t2 >= 0 && t2 <= 1) {
|
|
roots.push(t2);
|
|
}
|
|
if (t3 >= 0 && t3 <= 1) {
|
|
roots.push(t3);
|
|
}
|
|
}
|
|
return roots;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/intersection.ts
|
|
function segmentIntersection(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) {
|
|
const d = (ax2 - ax1) * (by2 - by1) - (ay2 - ay1) * (bx2 - bx1);
|
|
if (d === 0) {
|
|
return 0;
|
|
}
|
|
const ua = ((bx2 - bx1) * (ay1 - by1) - (ax1 - bx1) * (by2 - by1)) / d;
|
|
const ub = ((ax2 - ax1) * (ay1 - by1) - (ay2 - ay1) * (ax1 - bx1)) / d;
|
|
if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
function cubicSegmentIntersections(px1, py1, px2, py2, px3, py3, px4, py4, x1, y1, x2, y2) {
|
|
let intersections = 0;
|
|
const A = y1 - y2;
|
|
const B = x2 - x1;
|
|
const C2 = x1 * (y2 - y1) - y1 * (x2 - x1);
|
|
const bx = bezierCoefficients(px1, px2, px3, px4);
|
|
const by = bezierCoefficients(py1, py2, py3, py4);
|
|
const a = A * bx[0] + B * by[0];
|
|
const b = A * bx[1] + B * by[1];
|
|
const c = A * bx[2] + B * by[2];
|
|
const d = A * bx[3] + B * by[3] + C2;
|
|
const roots = cubicRoots(a, b, c, d);
|
|
for (const t of roots) {
|
|
const tt = t * t;
|
|
const ttt = t * tt;
|
|
const x = bx[0] * ttt + bx[1] * tt + bx[2] * t + bx[3];
|
|
const y = by[0] * ttt + by[1] * tt + by[2] * t + by[3];
|
|
let s;
|
|
if (x1 === x2) {
|
|
s = (y - y1) / (y2 - y1);
|
|
} else {
|
|
s = (x - x1) / (x2 - x1);
|
|
}
|
|
if (s >= 0 && s <= 1) {
|
|
intersections++;
|
|
}
|
|
}
|
|
return intersections;
|
|
}
|
|
function bezierCoefficients(P1, P2, P3, P4) {
|
|
return [
|
|
// Bézier expressed as matrix operations:
|
|
// |-1 3 -3 1| |P1|
|
|
// [t^3 t^2 t 1] | 3 -6 3 0| |P2|
|
|
// |-3 3 0 0| |P3|
|
|
// | 1 0 0 0| |P4|
|
|
-P1 + 3 * P2 - 3 * P3 + P4,
|
|
3 * P1 - 6 * P2 + 3 * P3,
|
|
-3 * P1 + 3 * P2,
|
|
P1
|
|
];
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/extendedPath2D.ts
|
|
var ExtendedPath2D = class {
|
|
constructor() {
|
|
this.previousCommands = [];
|
|
this.previousParams = [];
|
|
this.previousClosedPath = false;
|
|
this.commands = [];
|
|
this.params = [];
|
|
this.commandsLength = 0;
|
|
this.paramsLength = 0;
|
|
this.cx = Number.NaN;
|
|
this.cy = Number.NaN;
|
|
this.sx = Number.NaN;
|
|
this.sy = Number.NaN;
|
|
this.openedPath = false;
|
|
this.closedPath = false;
|
|
const Path2DCtor = (0, import_ag_charts_core16.getPath2D)();
|
|
this.path2d = new Path2DCtor();
|
|
}
|
|
isEmpty() {
|
|
return this.commandsLength === 0;
|
|
}
|
|
isDirty() {
|
|
return this.closedPath !== this.previousClosedPath || this.previousCommands.length !== this.commandsLength || this.previousParams.length !== this.paramsLength || this.previousCommands.toString() !== this.commands.slice(0, this.commandsLength).toString() || this.previousParams.toString() !== this.params.slice(0, this.paramsLength).toString();
|
|
}
|
|
getPath2D() {
|
|
return this.path2d;
|
|
}
|
|
moveTo(x, y) {
|
|
this.openedPath = true;
|
|
this.sx = x;
|
|
this.sy = y;
|
|
this.cx = x;
|
|
this.cy = y;
|
|
this.path2d.moveTo(x, y);
|
|
this.commands[this.commandsLength++] = 0 /* Move */;
|
|
this.params[this.paramsLength++] = x;
|
|
this.params[this.paramsLength++] = y;
|
|
}
|
|
lineTo(x, y) {
|
|
if (this.openedPath) {
|
|
this.cx = x;
|
|
this.cy = y;
|
|
this.path2d.lineTo(x, y);
|
|
this.commands[this.commandsLength++] = 1 /* Line */;
|
|
this.params[this.paramsLength++] = x;
|
|
this.params[this.paramsLength++] = y;
|
|
} else {
|
|
this.moveTo(x, y);
|
|
}
|
|
}
|
|
cubicCurveTo(cx1, cy1, cx2, cy2, x, y) {
|
|
if (!this.openedPath) {
|
|
this.moveTo(cx1, cy1);
|
|
}
|
|
this.path2d.bezierCurveTo(cx1, cy1, cx2, cy2, x, y);
|
|
this.commands[this.commandsLength++] = 2 /* Curve */;
|
|
this.params[this.paramsLength++] = cx1;
|
|
this.params[this.paramsLength++] = cy1;
|
|
this.params[this.paramsLength++] = cx2;
|
|
this.params[this.paramsLength++] = cy2;
|
|
this.params[this.paramsLength++] = x;
|
|
this.params[this.paramsLength++] = y;
|
|
}
|
|
closePath() {
|
|
if (this.openedPath) {
|
|
this.cx = this.sx;
|
|
this.cy = this.sy;
|
|
this.sx = Number.NaN;
|
|
this.sy = Number.NaN;
|
|
this.path2d.closePath();
|
|
this.commands[this.commandsLength++] = 3 /* ClosePath */;
|
|
this.openedPath = false;
|
|
this.closedPath = true;
|
|
}
|
|
}
|
|
rect(x, y, width, height) {
|
|
this.moveTo(x, y);
|
|
this.lineTo(x + width, y);
|
|
this.lineTo(x + width, y + height);
|
|
this.lineTo(x, y + height);
|
|
this.closePath();
|
|
}
|
|
roundRect(x, y, width, height, radii) {
|
|
radii = Math.min(radii, width / 2, height / 2);
|
|
this.moveTo(x, y + radii);
|
|
this.arc(x + radii, y + radii, radii, Math.PI, 1.5 * Math.PI);
|
|
this.lineTo(x + radii, y);
|
|
this.lineTo(x + width - radii, y);
|
|
this.arc(x + width - radii, y + radii, radii, 1.5 * Math.PI, 2 * Math.PI);
|
|
this.lineTo(x + width, y + radii);
|
|
this.lineTo(x + width, y + height - radii);
|
|
this.arc(x + width - radii, y + height - radii, radii, 0, Math.PI / 2);
|
|
this.lineTo(x + width - radii, y + height);
|
|
this.lineTo(x + radii, y + height);
|
|
this.arc(x + +radii, y + height - radii, radii, Math.PI / 2, Math.PI);
|
|
this.lineTo(x, y + height - radii);
|
|
this.closePath();
|
|
}
|
|
ellipse(cx, cy, rx, ry, rotation, sAngle, eAngle, counterClockwise = false) {
|
|
const r = rx;
|
|
const scaleY = ry / rx;
|
|
const mxx = Math.cos(rotation);
|
|
const myx = Math.sin(rotation);
|
|
const mxy = -scaleY * myx;
|
|
const myy = scaleY * mxx;
|
|
const x0 = r * Math.cos(sAngle);
|
|
const y0 = r * Math.sin(sAngle);
|
|
const sx = cx + mxx * x0 + mxy * y0;
|
|
const sy = cy + myx * x0 + myy * y0;
|
|
const distanceSquared = (sx - this.cx) ** 2 + (sy - this.cy) ** 2;
|
|
if (!this.openedPath) {
|
|
this.moveTo(sx, sy);
|
|
} else if (distanceSquared > 1e-6) {
|
|
this.lineTo(sx, sy);
|
|
}
|
|
let sweep = counterClockwise ? -(0, import_ag_charts_core16.normalizeAngle360)(sAngle - eAngle) : (0, import_ag_charts_core16.normalizeAngle360)(eAngle - sAngle);
|
|
if (Math.abs(Math.abs(eAngle - sAngle) - 2 * Math.PI) < 1e-6 && sweep < 2 * Math.PI) {
|
|
sweep += 2 * Math.PI * (counterClockwise ? -1 : 1);
|
|
}
|
|
const arcSections = Math.max(Math.ceil(Math.abs(sweep) / (Math.PI / 2)), 1);
|
|
const step = sweep / arcSections;
|
|
const h = 4 / 3 * Math.tan(step / 4);
|
|
for (let i = 0; i < arcSections; i += 1) {
|
|
const a0 = sAngle + step * (i + 0);
|
|
const a1 = sAngle + step * (i + 1);
|
|
const rSinStart = r * Math.sin(a0);
|
|
const rCosStart = r * Math.cos(a0);
|
|
const rSinEnd = r * Math.sin(a1);
|
|
const rCosEnd = r * Math.cos(a1);
|
|
const cp1x = rCosStart - h * rSinStart;
|
|
const cp1y = rSinStart + h * rCosStart;
|
|
const cp2x = rCosEnd + h * rSinEnd;
|
|
const cp2y = rSinEnd - h * rCosEnd;
|
|
const cp3x = rCosEnd;
|
|
const cp3y = rSinEnd;
|
|
this.cubicCurveTo(
|
|
cx + mxx * cp1x + mxy * cp1y,
|
|
cy + myx * cp1x + myy * cp1y,
|
|
cx + mxx * cp2x + mxy * cp2y,
|
|
cy + myx * cp2x + myy * cp2y,
|
|
cx + mxx * cp3x + mxy * cp3y,
|
|
cy + myx * cp3x + myy * cp3y
|
|
);
|
|
}
|
|
}
|
|
arc(x, y, r, sAngle, eAngle, counterClockwise) {
|
|
this.ellipse(x, y, r, r, 0, sAngle, eAngle, counterClockwise);
|
|
}
|
|
appendSvg(svg) {
|
|
const parts = parseSvg(svg);
|
|
if (parts == null)
|
|
return false;
|
|
let sx = 0;
|
|
let sy = 0;
|
|
let cx;
|
|
let cy;
|
|
let cpx = 0;
|
|
let cpy = 0;
|
|
for (const { command, params } of parts) {
|
|
cx ?? (cx = params[0]);
|
|
cy ?? (cy = params[1]);
|
|
const relative = command === command.toLowerCase();
|
|
const dx = relative ? cx : 0;
|
|
const dy = relative ? cy : 0;
|
|
switch (command.toLowerCase()) {
|
|
case "m":
|
|
this.moveTo(dx + params[0], dy + params[1]);
|
|
cx = dx + params[0];
|
|
cy = dy + params[1];
|
|
sx = cx;
|
|
sy = cy;
|
|
break;
|
|
case "c":
|
|
this.cubicCurveTo(
|
|
dx + params[0],
|
|
dy + params[1],
|
|
dx + params[2],
|
|
dy + params[3],
|
|
dx + params[4],
|
|
dy + params[5]
|
|
);
|
|
cpx = dx + params[2];
|
|
cpy = dy + params[3];
|
|
cx = dx + params[4];
|
|
cy = dy + params[5];
|
|
break;
|
|
case "s":
|
|
this.cubicCurveTo(
|
|
cx + cx - cpx,
|
|
cy + cy - cpy,
|
|
dx + params[0],
|
|
dy + params[1],
|
|
dx + params[2],
|
|
dy + params[3]
|
|
);
|
|
cpx = dx + params[0];
|
|
cpy = dy + params[1];
|
|
cx = dx + params[2];
|
|
cy = dy + params[3];
|
|
break;
|
|
case "q":
|
|
this.cubicCurveTo(
|
|
(dx + 2 * params[0]) / 3,
|
|
(dy + 2 * params[1]) / 3,
|
|
(2 * params[0] + params[2]) / 3,
|
|
(2 * params[1] + params[3]) / 3,
|
|
params[2],
|
|
params[3]
|
|
);
|
|
cpx = params[0];
|
|
cpy = params[1];
|
|
cx = params[2];
|
|
cy = params[3];
|
|
break;
|
|
case "t":
|
|
this.cubicCurveTo(
|
|
(cx + 2 * (cx + cx - cpx)) / 3,
|
|
(cy + 2 * (cy + cy - cpy)) / 3,
|
|
(2 * (cx + cx - cpx) + params[0]) / 3,
|
|
(2 * (cy + cy - cpy) + params[1]) / 3,
|
|
params[0],
|
|
params[1]
|
|
);
|
|
cpx = cx + cx - cpx;
|
|
cpy = cy + cy - cpy;
|
|
cx = params[0];
|
|
cy = params[1];
|
|
break;
|
|
case "a":
|
|
this.svgEllipse(
|
|
cx,
|
|
cy,
|
|
params[0],
|
|
params[1],
|
|
params[2] * Math.PI / 180,
|
|
params[3],
|
|
params[4],
|
|
dx + params[5],
|
|
dy + params[6]
|
|
);
|
|
cx = dx + params[5];
|
|
cy = dy + params[6];
|
|
break;
|
|
case "h":
|
|
this.lineTo(dx + params[0], cy);
|
|
cx = dx + params[0];
|
|
break;
|
|
case "l":
|
|
this.lineTo(dx + params[0], dy + params[1]);
|
|
cx = dx + params[0];
|
|
cy = dy + params[1];
|
|
break;
|
|
case "v":
|
|
this.lineTo(cx, dy + params[0]);
|
|
cy = dy + params[0];
|
|
break;
|
|
case "z":
|
|
this.closePath();
|
|
cx = sx;
|
|
cy = sy;
|
|
break;
|
|
default:
|
|
throw new Error(`Could not translate command '${command}' with '${params.join(" ")}'`);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
svgEllipse(x1, y1, rx, ry, rotation, fA, fS, x2, y2) {
|
|
rx = Math.abs(rx);
|
|
ry = Math.abs(ry);
|
|
const dx = (x1 - x2) / 2;
|
|
const dy = (y1 - y2) / 2;
|
|
const sin = Math.sin(rotation);
|
|
const cos = Math.cos(rotation);
|
|
const rotX = cos * dx + sin * dy;
|
|
const rotY = -sin * dx + cos * dy;
|
|
const normX = rotX / rx;
|
|
const normY = rotY / ry;
|
|
let scale2 = normX * normX + normY * normY;
|
|
let cx = (x1 + x2) / 2;
|
|
let cy = (y1 + y2) / 2;
|
|
let cpx = 0;
|
|
let cpy = 0;
|
|
if (scale2 >= 1) {
|
|
scale2 = Math.sqrt(scale2);
|
|
rx *= scale2;
|
|
ry *= scale2;
|
|
} else {
|
|
scale2 = Math.sqrt(1 / scale2 - 1);
|
|
if (fA === fS)
|
|
scale2 = -scale2;
|
|
cpx = scale2 * rx * normY;
|
|
cpy = -scale2 * ry * normX;
|
|
cx += cos * cpx - sin * cpy;
|
|
cy += sin * cpx + cos * cpy;
|
|
}
|
|
const sAngle = Math.atan2((rotY - cpy) / ry, (rotX - cpx) / rx);
|
|
const deltaTheta = Math.atan2((-rotY - cpy) / ry, (-rotX - cpx) / rx) - sAngle;
|
|
const eAngle = sAngle + deltaTheta;
|
|
const counterClockwise = !!(1 - fS);
|
|
this.ellipse(cx, cy, rx, ry, rotation, sAngle, eAngle, counterClockwise);
|
|
}
|
|
clear(trackChanges) {
|
|
if (trackChanges) {
|
|
this.previousCommands = this.commands.slice(0, this.commandsLength);
|
|
this.previousParams = this.params.slice(0, this.paramsLength);
|
|
this.previousClosedPath = this.closedPath;
|
|
this.commands = [];
|
|
this.params = [];
|
|
this.commandsLength = 0;
|
|
this.paramsLength = 0;
|
|
} else {
|
|
this.commandsLength = 0;
|
|
this.paramsLength = 0;
|
|
}
|
|
const Path2DCtor = (0, import_ag_charts_core16.getPath2D)();
|
|
this.path2d = new Path2DCtor();
|
|
this.openedPath = false;
|
|
this.closedPath = false;
|
|
}
|
|
isPointInPath(x, y) {
|
|
const commands = this.commands;
|
|
const params = this.params;
|
|
const cn = this.commandsLength;
|
|
const ox = -1e4;
|
|
const oy = -1e4;
|
|
let sx = Number.NaN;
|
|
let sy = Number.NaN;
|
|
let px = 0;
|
|
let py = 0;
|
|
let intersectionCount = 0;
|
|
for (let ci = 0, pi = 0; ci < cn; ci++) {
|
|
switch (commands[ci]) {
|
|
case 0 /* Move */:
|
|
intersectionCount += segmentIntersection(sx, sy, px, py, ox, oy, x, y);
|
|
px = params[pi++];
|
|
sx = px;
|
|
py = params[pi++];
|
|
sy = py;
|
|
break;
|
|
case 1 /* Line */:
|
|
intersectionCount += segmentIntersection(px, py, params[pi++], params[pi++], ox, oy, x, y);
|
|
px = params[pi - 2];
|
|
py = params[pi - 1];
|
|
break;
|
|
case 2 /* Curve */:
|
|
intersectionCount += cubicSegmentIntersections(
|
|
px,
|
|
py,
|
|
params[pi++],
|
|
params[pi++],
|
|
params[pi++],
|
|
params[pi++],
|
|
params[pi++],
|
|
params[pi++],
|
|
ox,
|
|
oy,
|
|
x,
|
|
y
|
|
);
|
|
px = params[pi - 2];
|
|
py = params[pi - 1];
|
|
break;
|
|
case 3 /* ClosePath */:
|
|
intersectionCount += segmentIntersection(sx, sy, px, py, ox, oy, x, y);
|
|
break;
|
|
}
|
|
}
|
|
return intersectionCount % 2 === 1;
|
|
}
|
|
distanceSquared(x, y) {
|
|
let best = Infinity;
|
|
const commands = this.commands;
|
|
const params = this.params;
|
|
const cn = this.commandsLength;
|
|
let sx = Number.NaN;
|
|
let sy = Number.NaN;
|
|
let cx = 0;
|
|
let cy = 0;
|
|
for (let ci = 0, pi = 0; ci < cn; ci++) {
|
|
switch (commands[ci]) {
|
|
case 0 /* Move */:
|
|
cx = sx = params[pi++];
|
|
cy = sy = params[pi++];
|
|
break;
|
|
case 1 /* Line */: {
|
|
const x0 = cx;
|
|
const y0 = cy;
|
|
cx = params[pi++];
|
|
cy = params[pi++];
|
|
best = (0, import_ag_charts_core16.lineDistanceSquared)(x, y, x0, y0, cx, cy, best);
|
|
break;
|
|
}
|
|
case 2 /* Curve */: {
|
|
const cp0x = cx;
|
|
const cp0y = cy;
|
|
const cp1x = params[pi++];
|
|
const cp1y = params[pi++];
|
|
const cp2x = params[pi++];
|
|
const cp2y = params[pi++];
|
|
cx = params[pi++];
|
|
cy = params[pi++];
|
|
best = (0, import_ag_charts_core16.bezier2DDistance)(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cx, cy, x, y) ** 2;
|
|
break;
|
|
}
|
|
case 3 /* ClosePath */:
|
|
best = (0, import_ag_charts_core16.lineDistanceSquared)(x, y, cx, cy, sx, sy, best);
|
|
break;
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d
|
|
toSVG(transform = (x, y) => ({ x, y })) {
|
|
const buffer = [];
|
|
const { commands, params } = this;
|
|
const addCommand = (command, count) => {
|
|
buffer.push(command);
|
|
for (let i = 0; i < count; i += 2) {
|
|
const { x, y } = transform(params[pi++], params[pi++]);
|
|
buffer.push(x, y);
|
|
}
|
|
};
|
|
let pi = 0;
|
|
for (let ci = 0; ci < this.commandsLength; ci++) {
|
|
const command = commands[ci];
|
|
switch (command) {
|
|
case 0 /* Move */:
|
|
addCommand("M", 2);
|
|
break;
|
|
case 1 /* Line */:
|
|
addCommand("L", 2);
|
|
break;
|
|
case 2 /* Curve */:
|
|
addCommand("C", 6);
|
|
break;
|
|
case 3 /* ClosePath */:
|
|
addCommand("Z", 0);
|
|
break;
|
|
}
|
|
}
|
|
return buffer.join(" ");
|
|
}
|
|
computeBBox() {
|
|
const { commands, params } = this;
|
|
let [top, left, right, bot] = [Infinity, Infinity, -Infinity, -Infinity];
|
|
let [cx, cy] = [Number.NaN, Number.NaN];
|
|
let [sx, sy] = [Number.NaN, Number.NaN];
|
|
const joinPoint = (x, y) => {
|
|
top = Math.min(y, top);
|
|
left = Math.min(x, left);
|
|
right = Math.max(x, right);
|
|
bot = Math.max(y, bot);
|
|
cx = x;
|
|
cy = y;
|
|
};
|
|
let pi = 0;
|
|
for (let ci = 0; ci < this.commandsLength; ci++) {
|
|
const command = commands[ci];
|
|
switch (command) {
|
|
case 0 /* Move */:
|
|
joinPoint(params[pi++], params[pi++]);
|
|
sx = cx;
|
|
sy = cy;
|
|
break;
|
|
case 1 /* Line */:
|
|
joinPoint(params[pi++], params[pi++]);
|
|
break;
|
|
case 2 /* Curve */: {
|
|
const cp0x = cx;
|
|
const cp0y = cy;
|
|
const cp1x = params[pi++];
|
|
const cp1y = params[pi++];
|
|
const cp2x = params[pi++];
|
|
const cp2y = params[pi++];
|
|
const cp3x = params[pi++];
|
|
const cp3y = params[pi++];
|
|
const ts = (0, import_ag_charts_core16.bezier2DExtrema)(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y);
|
|
for (const t of ts) {
|
|
const px = (0, import_ag_charts_core16.evaluateBezier)(cp0x, cp1x, cp2x, cp3x, t);
|
|
const py = (0, import_ag_charts_core16.evaluateBezier)(cp0y, cp1y, cp2y, cp3y, t);
|
|
joinPoint(px, py);
|
|
}
|
|
joinPoint(cp3x, cp3y);
|
|
break;
|
|
}
|
|
case 3 /* ClosePath */:
|
|
joinPoint(sx, sy);
|
|
sx = Number.NaN;
|
|
sy = Number.NaN;
|
|
break;
|
|
}
|
|
}
|
|
return new BBox(left, top, right - left, bot - top);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/pattern/patterns.ts
|
|
var import_ag_charts_core17 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/util/pixel.ts
|
|
function align(pixelRatio, start, length) {
|
|
const alignedStart = Math.round(start * pixelRatio) / pixelRatio;
|
|
if (length == null) {
|
|
return alignedStart;
|
|
} else if (length === 0) {
|
|
return 0;
|
|
} else if (length < 1) {
|
|
return Math.ceil(length * pixelRatio) / pixelRatio;
|
|
}
|
|
return Math.round((length + start) * pixelRatio) / pixelRatio - alignedStart;
|
|
}
|
|
function alignBefore(pixelRatio, start) {
|
|
return Math.floor(start * pixelRatio) / pixelRatio;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/pattern/patterns.ts
|
|
function drawPatternUnitPolygon(path, params, moves) {
|
|
const { width, height, padding: padding2, strokeWidth } = params;
|
|
const x0 = width / 2;
|
|
const y0 = height / 2;
|
|
const w = Math.max(1, width - padding2 - strokeWidth / 2);
|
|
const h = Math.max(1, height - padding2 - strokeWidth / 2);
|
|
let didMove = false;
|
|
for (const [dx, dy] of moves) {
|
|
const x = x0 + (dx - 0.5) * w;
|
|
const y = y0 + (dy - 0.5) * h;
|
|
if (didMove) {
|
|
path.lineTo(x, y);
|
|
} else {
|
|
path.moveTo(x, y);
|
|
}
|
|
didMove = true;
|
|
}
|
|
path.closePath();
|
|
}
|
|
var PATTERNS = {
|
|
circles(path, { width, strokeWidth, padding: padding2 }) {
|
|
const c = width / 2;
|
|
const r = Math.max(1, c - padding2 - strokeWidth / 2);
|
|
path.arc(c, c, r, 0, Math.PI * 2);
|
|
},
|
|
squares(path, { width, height, pixelRatio, padding: padding2, strokeWidth }) {
|
|
const offset = padding2 + strokeWidth / 2;
|
|
path.moveTo(align(pixelRatio, offset), align(pixelRatio, offset));
|
|
path.lineTo(align(pixelRatio, width - offset), align(pixelRatio, offset));
|
|
path.lineTo(align(pixelRatio, width - offset), align(pixelRatio, height - offset));
|
|
path.lineTo(align(pixelRatio, offset), align(pixelRatio, height - offset));
|
|
path.closePath();
|
|
},
|
|
triangles(path, params) {
|
|
drawPatternUnitPolygon(path, params, [
|
|
[0.5, 0],
|
|
[1, 1],
|
|
[0, 1]
|
|
]);
|
|
},
|
|
diamonds(path, params) {
|
|
drawPatternUnitPolygon(path, params, [
|
|
[0.5, 0],
|
|
[1, 0.5],
|
|
[0.5, 1],
|
|
[0, 0.5]
|
|
]);
|
|
},
|
|
stars(path, { width, height, padding: padding2 }) {
|
|
const spikes = 5;
|
|
const outerRadius = Math.max(1, (width - padding2) / 2);
|
|
const innerRadius = outerRadius / 2;
|
|
const rotation = Math.PI / 2;
|
|
for (let i = 0; i < spikes * 2; i++) {
|
|
const radius = i % 2 === 0 ? outerRadius : innerRadius;
|
|
const angle = i * Math.PI / spikes - rotation;
|
|
const xCoordinate = width / 2 + Math.cos(angle) * radius;
|
|
const yCoordinate = height / 2 + Math.sin(angle) * radius;
|
|
path.lineTo(xCoordinate, yCoordinate);
|
|
}
|
|
path.closePath();
|
|
},
|
|
hearts(path, { width, height, padding: padding2 }) {
|
|
const r = Math.max(1, width / 4 - padding2 / 2);
|
|
const x = width / 2;
|
|
const y = height / 2 + r / 2;
|
|
path.arc(x - r, y - r, r, (0, import_ag_charts_core17.toRadians)(130), (0, import_ag_charts_core17.toRadians)(330));
|
|
path.arc(x + r, y - r, r, (0, import_ag_charts_core17.toRadians)(220), (0, import_ag_charts_core17.toRadians)(50));
|
|
path.lineTo(x, y + r);
|
|
path.closePath();
|
|
},
|
|
crosses(path, params) {
|
|
drawPatternUnitPolygon(path, params, [
|
|
[0.25, 0],
|
|
[0.5, 0.25],
|
|
[0.75, 0],
|
|
[1, 0.25],
|
|
[0.75, 0.5],
|
|
[1, 0.75],
|
|
[0.75, 1],
|
|
[0.5, 0.75],
|
|
[0.25, 1],
|
|
[0, 0.75],
|
|
[0.25, 0.5],
|
|
[0, 0.25]
|
|
]);
|
|
},
|
|
"vertical-lines"(path, { width, height, pixelRatio, strokeWidth }) {
|
|
const x = align(pixelRatio, width / 2) - strokeWidth % 2 / 2;
|
|
path.moveTo(x, 0);
|
|
path.lineTo(x, height);
|
|
},
|
|
"horizontal-lines"(path, { width, height, pixelRatio, strokeWidth }) {
|
|
const y = align(pixelRatio, height / 2) - strokeWidth % 2 / 2;
|
|
path.moveTo(0, y);
|
|
path.lineTo(width, y);
|
|
},
|
|
"forward-slanted-lines"(path, { width, height, strokeWidth }) {
|
|
const angle = Math.atan2(height, width);
|
|
const insetX = strokeWidth * Math.cos(angle);
|
|
const insetY = strokeWidth * Math.sin(angle);
|
|
path.moveTo(-insetX, insetY);
|
|
path.lineTo(insetX, -insetY);
|
|
path.moveTo(-insetX, height + insetY);
|
|
path.lineTo(width + insetX, -insetY);
|
|
path.moveTo(width - insetX, height + insetY);
|
|
path.lineTo(width + insetX, height - insetY);
|
|
},
|
|
"backward-slanted-lines"(path, { width, height, strokeWidth }) {
|
|
const angle = Math.atan2(height, width);
|
|
const insetX = strokeWidth * Math.cos(angle);
|
|
const insetY = strokeWidth * Math.sin(angle);
|
|
path.moveTo(width - insetX, -insetY);
|
|
path.lineTo(width + insetX, insetY);
|
|
path.moveTo(-insetX, -insetY);
|
|
path.lineTo(width + insetX, height + insetY);
|
|
path.moveTo(-insetX, height - insetY);
|
|
path.lineTo(insetX, height + insetY);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/pattern/pattern.ts
|
|
var Pattern = class {
|
|
constructor(patternOptions) {
|
|
this._cache = void 0;
|
|
this.width = Math.max(patternOptions?.width ?? 10, 1);
|
|
this.height = Math.max(patternOptions?.height ?? 10, 1);
|
|
this.fill = patternOptions.fill ?? "none";
|
|
this.fillOpacity = patternOptions.fillOpacity ?? 1;
|
|
this.backgroundFill = patternOptions.backgroundFill ?? "none";
|
|
this.backgroundFillOpacity = patternOptions.backgroundFillOpacity ?? 1;
|
|
this.stroke = patternOptions.stroke ?? "black";
|
|
this.strokeOpacity = patternOptions.strokeOpacity ?? 1;
|
|
this.strokeWidth = patternOptions.strokeWidth ?? 1;
|
|
this.padding = patternOptions.padding ?? 1;
|
|
this.pattern = patternOptions.pattern ?? "forward-slanted-lines";
|
|
this.rotation = patternOptions.rotation ?? 0;
|
|
this.scale = patternOptions.scale ?? 1;
|
|
this.path = patternOptions.path;
|
|
}
|
|
getPath(pixelRatio) {
|
|
const { pattern, width, height, padding: padding2, strokeWidth, path: svgPath } = this;
|
|
const path = new ExtendedPath2D();
|
|
let renderPattern = PATTERNS[pattern] != null;
|
|
if (svgPath) {
|
|
renderPattern && (renderPattern = !path.appendSvg(svgPath));
|
|
}
|
|
if (renderPattern) {
|
|
PATTERNS[pattern](path, { width, height, pixelRatio, strokeWidth, padding: padding2 });
|
|
}
|
|
return path;
|
|
}
|
|
renderStroke(path2d, ctx) {
|
|
const { stroke, strokeWidth, strokeOpacity } = this;
|
|
if (!strokeWidth)
|
|
return;
|
|
ctx.strokeStyle = stroke;
|
|
ctx.lineWidth = strokeWidth;
|
|
ctx.globalAlpha = strokeOpacity;
|
|
ctx.stroke(path2d);
|
|
}
|
|
renderFill(path2d, ctx) {
|
|
const { fill, fillOpacity } = this;
|
|
if (fill === "none") {
|
|
return;
|
|
}
|
|
ctx.fillStyle = fill;
|
|
ctx.globalAlpha = fillOpacity;
|
|
ctx.fill(path2d);
|
|
}
|
|
createCanvasPattern(ctx, pixelRatio) {
|
|
const { width, height, scale: scale2, backgroundFill, backgroundFillOpacity } = this;
|
|
if (width * scale2 < 1 || height * scale2 < 1) {
|
|
import_ag_charts_core18.Logger.warnOnce("Pattern fill is too small to render, ignoring.");
|
|
return null;
|
|
}
|
|
const offscreenPattern = new HdpiOffscreenCanvas({ width, height, pixelRatio: pixelRatio * scale2 });
|
|
const offscreenPatternCtx = offscreenPattern.context;
|
|
if (backgroundFill !== "none") {
|
|
offscreenPatternCtx.fillStyle = backgroundFill;
|
|
offscreenPatternCtx.globalAlpha = backgroundFillOpacity;
|
|
offscreenPatternCtx.fillRect(0, 0, width, height);
|
|
}
|
|
const path2d = this.getPath(pixelRatio).getPath2D();
|
|
this.renderFill(path2d, offscreenPatternCtx);
|
|
this.renderStroke(path2d, offscreenPatternCtx);
|
|
const pattern = ctx.createPattern(offscreenPattern.canvas, "repeat");
|
|
this.setPatternTransform(pattern, pixelRatio);
|
|
offscreenPattern.destroy();
|
|
return pattern;
|
|
}
|
|
setPatternTransform(pattern, pixelRatio, tx = 0, ty = 0) {
|
|
if (pattern == null)
|
|
return;
|
|
const angle = (0, import_ag_charts_core18.normalizeAngle360FromDegrees)(this.rotation);
|
|
const scale2 = 1 / pixelRatio;
|
|
const cos = Math.cos(angle) * scale2;
|
|
const sin = Math.sin(angle) * scale2;
|
|
const DOMMatrixCtor = (0, import_ag_charts_core18.getDOMMatrix)();
|
|
pattern.setTransform(new DOMMatrixCtor([cos, sin, -sin, cos, tx, ty]));
|
|
}
|
|
createPattern(ctx, pixelRatio) {
|
|
if (this._cache?.ctx === ctx && this._cache.pixelRatio === pixelRatio) {
|
|
return this._cache.pattern;
|
|
}
|
|
const pattern = this.createCanvasPattern(ctx, pixelRatio);
|
|
if (pattern == null)
|
|
return;
|
|
this._cache = { ctx, pattern, pixelRatio };
|
|
return pattern;
|
|
}
|
|
toSvg() {
|
|
const {
|
|
width,
|
|
height,
|
|
fill,
|
|
fillOpacity,
|
|
backgroundFill,
|
|
backgroundFillOpacity,
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
rotation,
|
|
scale: scale2
|
|
} = this;
|
|
const pattern = (0, import_ag_charts_core18.createSvgElement)("pattern");
|
|
pattern.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
pattern.setAttribute("width", String(width));
|
|
pattern.setAttribute("height", String(height));
|
|
pattern.setAttribute("patternUnits", "userSpaceOnUse");
|
|
const rect2 = (0, import_ag_charts_core18.createSvgElement)("rect");
|
|
rect2.setAttribute("x", "0");
|
|
rect2.setAttribute("y", "0");
|
|
rect2.setAttribute("width", String(width));
|
|
rect2.setAttribute("height", String(height));
|
|
rect2.setAttribute("fill", backgroundFill);
|
|
rect2.setAttribute("fill-opacity", String(backgroundFillOpacity));
|
|
pattern.appendChild(rect2);
|
|
const path = (0, import_ag_charts_core18.createSvgElement)("path");
|
|
path.setAttribute("fill", fill);
|
|
path.setAttribute("fill-opacity", String(fillOpacity));
|
|
path.setAttribute("stroke-opacity", String(strokeOpacity));
|
|
path.setAttribute("stroke", stroke);
|
|
path.setAttribute("stroke-width", String(strokeWidth));
|
|
path.setAttribute("transform", `rotate(${rotation}) scale(${scale2})`);
|
|
path.setAttribute("d", this.getPath(1).toSVG());
|
|
pattern.appendChild(path);
|
|
return pattern;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/shape/svgUtils.ts
|
|
function setSvgFontAttributes(element2, options) {
|
|
const { fontStyle, fontWeight: fontWeight2, fontSize, fontFamily } = options;
|
|
if (fontStyle)
|
|
element2.setAttribute("font-style", fontStyle);
|
|
if (fontWeight2)
|
|
element2.setAttribute("font-weight", String(fontWeight2));
|
|
if (fontSize != null)
|
|
element2.setAttribute("font-size", String(fontSize));
|
|
if (fontFamily)
|
|
element2.setAttribute("font-family", fontFamily);
|
|
}
|
|
function setSvgStrokeAttributes(element2, options) {
|
|
const { stroke, strokeWidth, strokeOpacity } = options;
|
|
if (stroke)
|
|
element2.setAttribute("stroke", stroke);
|
|
if (strokeWidth != null)
|
|
element2.setAttribute("stroke-width", String(strokeWidth));
|
|
if (strokeOpacity != null)
|
|
element2.setAttribute("stroke-opacity", String(strokeOpacity));
|
|
}
|
|
function setSvgLineDashAttributes(element2, options) {
|
|
const { lineDash, lineDashOffset } = options;
|
|
if (lineDash?.some((d) => d !== 0)) {
|
|
const lineDashArray = lineDash.length % 2 === 1 ? [...lineDash, ...lineDash] : lineDash;
|
|
element2.setAttribute("stroke-dasharray", lineDashArray.join(" "));
|
|
if (lineDashOffset != null)
|
|
element2.setAttribute("stroke-dashoffset", String(lineDashOffset));
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/shape/shape.ts
|
|
var _Shape = class _Shape extends Node {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.drawingMode = "overlay";
|
|
this.fillOpacity = 1;
|
|
this.strokeOpacity = 1;
|
|
this.fill = "black";
|
|
this.strokeWidth = 0;
|
|
this.lineDashOffset = 0;
|
|
this.opacity = 1;
|
|
}
|
|
// optimised field accessor
|
|
getGradient(fill) {
|
|
if ((0, import_ag_charts_core19.isGradientFill)(fill))
|
|
return this.createGradient(fill);
|
|
}
|
|
createGradient(fill) {
|
|
const { colorSpace = "rgb", gradient = "linear", colorStops, rotation = 0, reverse = false } = fill;
|
|
if (colorStops == null)
|
|
return;
|
|
let stops = getColorStops(colorStops, ["black"], [0, 1]);
|
|
if (reverse) {
|
|
stops = stops.map((s) => ({ color: s.color, stop: 1 - s.stop })).reverse();
|
|
}
|
|
switch (gradient) {
|
|
case "linear":
|
|
return new LinearGradient(colorSpace, stops, rotation);
|
|
case "radial":
|
|
return new RadialGradient(colorSpace, stops);
|
|
case "conic":
|
|
return new ConicGradient(colorSpace, stops, rotation);
|
|
}
|
|
}
|
|
getPattern(fill) {
|
|
if ((0, import_ag_charts_core19.isPatternFill)(fill))
|
|
return this.createPattern(fill);
|
|
}
|
|
createPattern(fill) {
|
|
return new Pattern(fill);
|
|
}
|
|
getImage(fill) {
|
|
if ((0, import_ag_charts_core19.isImageFill)(fill))
|
|
return this.createImage(fill);
|
|
}
|
|
createImage(fill) {
|
|
return new Image(this.imageLoader, fill);
|
|
}
|
|
onFillChange() {
|
|
if (typeof this.fill === "object") {
|
|
if ((0, import_ag_charts_core19.objectsEqual)(this._cachedFill ?? {}, this.fill)) {
|
|
return;
|
|
}
|
|
}
|
|
this.fillGradient = this.getGradient(this.fill);
|
|
this.fillPattern = this.getPattern(this.fill);
|
|
this.fillImage = this.getImage(this.fill);
|
|
this._cachedFill = this.fill;
|
|
}
|
|
// optimised field accessor
|
|
onStrokeChange() {
|
|
this.strokeGradient = this.getGradient(this.stroke);
|
|
}
|
|
// optimised field accessor
|
|
/**
|
|
* Returns a device-pixel aligned coordinate (or length if length is supplied).
|
|
*
|
|
* NOTE: Not suitable for strokes, since the stroke needs to be offset to the middle
|
|
* of a device pixel.
|
|
*/
|
|
align(start, length) {
|
|
return align(this.layerManager?.canvas?.pixelRatio ?? 1, start, length);
|
|
}
|
|
markDirty(property) {
|
|
super.markDirty(property);
|
|
this.cachedDefaultGradientFillBBox = void 0;
|
|
}
|
|
fillStroke(ctx, path) {
|
|
if (this.__drawingMode === "cutout") {
|
|
ctx.globalCompositeOperation = "destination-out";
|
|
this.executeFill(ctx, path);
|
|
ctx.globalCompositeOperation = "source-over";
|
|
}
|
|
this.renderFill(ctx, path);
|
|
this.renderStroke(ctx, path);
|
|
}
|
|
renderFill(ctx, path) {
|
|
const { __fill: fill, __fillOpacity: fillOpacity = 1, fillImage } = this;
|
|
if (fill != null && fill !== "none" && fillOpacity > 0) {
|
|
const globalAlpha = ctx.globalAlpha;
|
|
if (fillImage) {
|
|
ctx.globalAlpha = fillImage.backgroundFillOpacity;
|
|
ctx.fillStyle = fillImage.backgroundFill;
|
|
this.executeFill(ctx, path);
|
|
ctx.globalAlpha = globalAlpha;
|
|
}
|
|
this.applyFillAndAlpha(ctx);
|
|
this.applyShadow(ctx);
|
|
this.executeFill(ctx, path);
|
|
ctx.globalAlpha = globalAlpha;
|
|
if (this.fillShadow?.enabled) {
|
|
ctx.shadowColor = "rgba(0, 0, 0, 0)";
|
|
}
|
|
}
|
|
}
|
|
executeFill(ctx, path) {
|
|
if (path) {
|
|
ctx.fill(path);
|
|
} else {
|
|
ctx.fill();
|
|
}
|
|
}
|
|
applyFillAndAlpha(ctx) {
|
|
const {
|
|
__fill: fill,
|
|
fillGradient,
|
|
fillPattern,
|
|
fillImage,
|
|
__fillOpacity: fillOpacity = 1,
|
|
__opacity: opacity = 1
|
|
} = this;
|
|
const combinedOpacity = opacity * fillOpacity;
|
|
if (combinedOpacity !== 1) {
|
|
ctx.globalAlpha *= combinedOpacity;
|
|
}
|
|
if (fillGradient) {
|
|
const { fillBBox = this.getDefaultGradientFillBBox() ?? this.getBBox(), fillParams } = this;
|
|
ctx.fillStyle = fillGradient.createGradient(ctx, fillBBox, fillParams) ?? "black";
|
|
} else if (fillPattern) {
|
|
const { x, y } = this.getBBox();
|
|
const pixelRatio = this.layerManager?.canvas?.pixelRatio ?? 1;
|
|
const pattern = fillPattern.createPattern(ctx, pixelRatio);
|
|
fillPattern.setPatternTransform(pattern, pixelRatio, x, y);
|
|
if (pattern) {
|
|
ctx.fillStyle = pattern;
|
|
} else {
|
|
ctx.fillStyle = fillPattern.fill;
|
|
ctx.globalAlpha *= fillPattern.fillOpacity;
|
|
}
|
|
} else if (fillImage) {
|
|
const bbox = this.getBBox();
|
|
const image = fillImage.createPattern(ctx, bbox.width, bbox.height, this);
|
|
fillImage.setImageTransform(image, bbox);
|
|
ctx.fillStyle = image ?? "transparent";
|
|
} else {
|
|
ctx.fillStyle = typeof fill === "string" ? fill : "black";
|
|
}
|
|
}
|
|
applyStrokeAndAlpha(ctx) {
|
|
const { __stroke: stroke, __strokeOpacity: strokeOpacity = 1, strokeGradient, __opacity: opacity = 1 } = this;
|
|
ctx.strokeStyle = strokeGradient?.createGradient(ctx, this.getBBox()) ?? (typeof stroke === "string" ? stroke : void 0) ?? "black";
|
|
const combinedOpacity = opacity * strokeOpacity;
|
|
if (combinedOpacity !== 1) {
|
|
ctx.globalAlpha *= combinedOpacity;
|
|
}
|
|
}
|
|
applyShadow(ctx) {
|
|
const pixelRatio = this.layerManager?.canvas.pixelRatio ?? 1;
|
|
const { __fillShadow: fillShadow } = this;
|
|
if (fillShadow?.enabled) {
|
|
ctx.shadowColor = fillShadow.color;
|
|
ctx.shadowOffsetX = fillShadow.xOffset * pixelRatio;
|
|
ctx.shadowOffsetY = fillShadow.yOffset * pixelRatio;
|
|
ctx.shadowBlur = fillShadow.blur * pixelRatio;
|
|
}
|
|
}
|
|
renderStroke(ctx, path) {
|
|
const {
|
|
__stroke: stroke,
|
|
__strokeWidth: strokeWidth = 0,
|
|
__strokeOpacity: strokeOpacity = 1,
|
|
__lineDash: lineDash,
|
|
__lineDashOffset: lineDashOffset,
|
|
__lineCap: lineCap,
|
|
__lineJoin: lineJoin,
|
|
__miterLimit: miterLimit
|
|
} = this;
|
|
if (stroke != null && stroke !== "none" && strokeWidth > 0 && strokeOpacity > 0) {
|
|
const { globalAlpha } = ctx;
|
|
this.applyStrokeAndAlpha(ctx);
|
|
ctx.lineWidth = strokeWidth;
|
|
if (lineDash) {
|
|
ctx.setLineDash(lineDash);
|
|
}
|
|
if (lineDashOffset) {
|
|
ctx.lineDashOffset = lineDashOffset;
|
|
}
|
|
if (lineCap) {
|
|
ctx.lineCap = lineCap;
|
|
}
|
|
if (lineJoin) {
|
|
ctx.lineJoin = lineJoin;
|
|
}
|
|
if (miterLimit != null) {
|
|
ctx.miterLimit = miterLimit;
|
|
}
|
|
this.executeStroke(ctx, path);
|
|
ctx.globalAlpha = globalAlpha;
|
|
}
|
|
}
|
|
executeStroke(ctx, path) {
|
|
if (path) {
|
|
ctx.stroke(path);
|
|
} else {
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
getDefaultGradientFillBBox() {
|
|
this.cachedDefaultGradientFillBBox ?? (this.cachedDefaultGradientFillBBox = Object.freeze(this.computeDefaultGradientFillBBox()));
|
|
return this.cachedDefaultGradientFillBBox;
|
|
}
|
|
computeDefaultGradientFillBBox() {
|
|
return;
|
|
}
|
|
containsPoint(x, y) {
|
|
return this.isPointInPath(x, y);
|
|
}
|
|
applySvgFillAttributes(element2, defs) {
|
|
const { fill, fillOpacity } = this;
|
|
if (typeof fill === "string") {
|
|
element2.setAttribute("fill", fill);
|
|
} else if ((0, import_ag_charts_core19.isGradientFill)(fill) && this.fillGradient) {
|
|
defs ?? (defs = []);
|
|
const gradient = this.fillGradient.toSvg(this.fillBBox ?? this.getBBox());
|
|
const id = (0, import_ag_charts_core19.generateUUID)();
|
|
gradient.setAttribute("id", id);
|
|
defs.push(gradient);
|
|
element2.setAttribute("fill", `url(#${id})`);
|
|
} else if ((0, import_ag_charts_core19.isPatternFill)(fill) && this.fillPattern) {
|
|
defs ?? (defs = []);
|
|
const pattern = this.fillPattern.toSvg();
|
|
const id = (0, import_ag_charts_core19.generateUUID)();
|
|
pattern.setAttribute("id", id);
|
|
defs.push(pattern);
|
|
element2.setAttribute("fill", `url(#${id})`);
|
|
} else if ((0, import_ag_charts_core19.isImageFill)(fill) && this.fillImage) {
|
|
defs ?? (defs = []);
|
|
const pixelRatio = this.layerManager?.canvas?.pixelRatio ?? 1;
|
|
const pattern = this.fillImage.toSvg(this.getBBox(), pixelRatio);
|
|
const id = (0, import_ag_charts_core19.generateUUID)();
|
|
pattern.setAttribute("id", id);
|
|
defs.push(pattern);
|
|
element2.setAttribute("fill", `url(#${id})`);
|
|
} else {
|
|
element2.setAttribute("fill", "none");
|
|
}
|
|
element2.setAttribute("fill-opacity", String(fillOpacity));
|
|
return defs;
|
|
}
|
|
applySvgStrokeAttributes(element2) {
|
|
const { stroke, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = this;
|
|
setSvgStrokeAttributes(element2, { stroke: (0, import_ag_charts_core19.isString)(stroke) ? stroke : void 0, strokeOpacity, strokeWidth });
|
|
setSvgLineDashAttributes(element2, { lineDash, lineDashOffset });
|
|
}
|
|
static handleFillChange(shape) {
|
|
shape.onFillChange();
|
|
}
|
|
static handleStrokeChange(shape) {
|
|
shape.onStrokeChange();
|
|
}
|
|
/**
|
|
* Sets style properties on the shape, optimizing by writing directly to __ prefix fields
|
|
* where possible to avoid setter overhead.
|
|
*/
|
|
setStyleProperties(style, fillBBox, fillParams) {
|
|
const opacity = style?.opacity ?? 1;
|
|
const fill = style?.fill;
|
|
const computedFillOpacity = (style?.fillOpacity ?? 1) * opacity;
|
|
const computedStrokeOpacity = (style?.strokeOpacity ?? 1) * opacity;
|
|
const computedStrokeWidth = style?.strokeWidth ?? 0;
|
|
const computedLineDashOffset = style?.lineDashOffset ?? 0;
|
|
let hasDirectChanges = false;
|
|
if (this.__fillOpacity !== computedFillOpacity) {
|
|
this.__fillOpacity = computedFillOpacity;
|
|
hasDirectChanges = true;
|
|
}
|
|
if (this.__strokeOpacity !== computedStrokeOpacity) {
|
|
this.__strokeOpacity = computedStrokeOpacity;
|
|
hasDirectChanges = true;
|
|
}
|
|
if (this.__strokeWidth !== computedStrokeWidth) {
|
|
this.__strokeWidth = computedStrokeWidth;
|
|
hasDirectChanges = true;
|
|
}
|
|
if (this.__lineDashOffset !== computedLineDashOffset) {
|
|
this.__lineDashOffset = computedLineDashOffset;
|
|
hasDirectChanges = true;
|
|
}
|
|
if (this.__lineDash !== style?.lineDash) {
|
|
this.__lineDash = style?.lineDash;
|
|
hasDirectChanges = true;
|
|
}
|
|
this.setFillProperties(fill, fillBBox, fillParams);
|
|
if (fill !== this.fill) {
|
|
this.fill = fill;
|
|
}
|
|
if (style?.stroke !== this.stroke) {
|
|
this.stroke = style?.stroke;
|
|
}
|
|
if (hasDirectChanges) {
|
|
this.markDirty();
|
|
}
|
|
}
|
|
/**
|
|
* Sets fill-related properties (fillBBox and fillParams) on the shape.
|
|
* Used for gradient fills that need bounding box information.
|
|
*/
|
|
setFillProperties(fill, fillBBox, fillParams) {
|
|
const computedFillBBox = fillBBox == null || !(0, import_ag_charts_core19.isGradientFill)(fill) || fill.bounds == null || fill.bounds === "item" ? void 0 : fillBBox[fill.bounds];
|
|
let hasDirectChanges = false;
|
|
if (this.__fillBBox !== computedFillBBox) {
|
|
this.__fillBBox = computedFillBBox;
|
|
hasDirectChanges = true;
|
|
}
|
|
if (this.__fillParams !== fillParams) {
|
|
this.__fillParams = fillParams;
|
|
hasDirectChanges = true;
|
|
}
|
|
if (hasDirectChanges) {
|
|
this.onFillChange();
|
|
this.markDirty();
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneChangeDetection)()
|
|
], _Shape.prototype, "drawingMode", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneChangeDetection)()
|
|
], _Shape.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneChangeDetection)()
|
|
], _Shape.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneObjectChangeDetection)({
|
|
equals: import_ag_charts_core19.objectsEqual,
|
|
changeCb: _Shape.handleFillChange
|
|
})
|
|
], _Shape.prototype, "fill", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.SceneObjectChangeDetection)({ equals: import_ag_charts_core19.objectsEqual, changeCb: _Shape.handleStrokeChange })
|
|
], _Shape.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneChangeDetection)()
|
|
], _Shape.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.SceneArrayChangeDetection)()
|
|
], _Shape.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneChangeDetection)()
|
|
], _Shape.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneChangeDetection)()
|
|
], _Shape.prototype, "lineCap", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneChangeDetection)()
|
|
], _Shape.prototype, "lineJoin", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneChangeDetection)()
|
|
], _Shape.prototype, "miterLimit", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneChangeDetection)({ convertor: (v) => (0, import_ag_charts_core19.clamp)(0, v ?? 1, 1) })
|
|
], _Shape.prototype, "opacity", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.SceneObjectChangeDetection)({ equals: import_ag_charts_core19.TRIPLE_EQ, checkDirtyOnAssignment: true })
|
|
], _Shape.prototype, "fillShadow", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneObjectChangeDetection)({ equals: import_ag_charts_core19.boxesEqual, changeCb: (s) => s.onFillChange() })
|
|
], _Shape.prototype, "fillBBox", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core19.DeclaredSceneObjectChangeDetection)({ equals: import_ag_charts_core19.objectsEqual, changeCb: (s) => s.onFillChange() })
|
|
], _Shape.prototype, "fillParams", 2);
|
|
var Shape = _Shape;
|
|
|
|
// packages/ag-charts-community/src/scene/transformable.ts
|
|
var import_ag_charts_core21 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/matrix.ts
|
|
var import_ag_charts_core20 = require("ag-charts-core");
|
|
var IDENTITY_MATRIX_ELEMENTS = [1, 0, 0, 1, 0, 0];
|
|
var Matrix = class _Matrix {
|
|
get e() {
|
|
return [...this.elements];
|
|
}
|
|
constructor(elements = IDENTITY_MATRIX_ELEMENTS) {
|
|
this.elements = [...elements];
|
|
}
|
|
setElements(elements) {
|
|
const e = this.elements;
|
|
e[0] = elements[0];
|
|
e[1] = elements[1];
|
|
e[2] = elements[2];
|
|
e[3] = elements[3];
|
|
e[4] = elements[4];
|
|
e[5] = elements[5];
|
|
return this;
|
|
}
|
|
get identity() {
|
|
const e = this.elements;
|
|
return (0, import_ag_charts_core20.isNumberEqual)(e[0], 1) && (0, import_ag_charts_core20.isNumberEqual)(e[1], 0) && (0, import_ag_charts_core20.isNumberEqual)(e[2], 0) && (0, import_ag_charts_core20.isNumberEqual)(e[3], 1) && (0, import_ag_charts_core20.isNumberEqual)(e[4], 0) && (0, import_ag_charts_core20.isNumberEqual)(e[5], 0);
|
|
}
|
|
/**
|
|
* Performs the AxB matrix multiplication and saves the result
|
|
* to `C`, if given, or to `A` otherwise.
|
|
*/
|
|
AxB(A, B, C2) {
|
|
const a = A[0] * B[0] + A[2] * B[1], b = A[1] * B[0] + A[3] * B[1], c = A[0] * B[2] + A[2] * B[3], d = A[1] * B[2] + A[3] * B[3], e = A[0] * B[4] + A[2] * B[5] + A[4], f = A[1] * B[4] + A[3] * B[5] + A[5];
|
|
C2 = C2 ?? A;
|
|
C2[0] = a;
|
|
C2[1] = b;
|
|
C2[2] = c;
|
|
C2[3] = d;
|
|
C2[4] = e;
|
|
C2[5] = f;
|
|
}
|
|
/**
|
|
* The `other` matrix gets post-multiplied to the current matrix.
|
|
* Returns the current matrix.
|
|
* @param other
|
|
*/
|
|
multiplySelf(other) {
|
|
this.AxB(this.elements, other.elements);
|
|
return this;
|
|
}
|
|
/**
|
|
* The `other` matrix gets post-multiplied to the current matrix.
|
|
* Returns a new matrix.
|
|
* @param other
|
|
*/
|
|
multiply(other) {
|
|
const elements = [Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN, Number.NaN];
|
|
if (other instanceof _Matrix) {
|
|
this.AxB(this.elements, other.elements, elements);
|
|
} else {
|
|
this.AxB(this.elements, [other.a, other.b, other.c, other.d, other.e, other.f], elements);
|
|
}
|
|
return new _Matrix(elements);
|
|
}
|
|
preMultiplySelf(other) {
|
|
this.AxB(other.elements, this.elements, this.elements);
|
|
return this;
|
|
}
|
|
/**
|
|
* Returns the inverse of this matrix as a new matrix.
|
|
*/
|
|
inverse() {
|
|
const el = this.elements;
|
|
let a = el[0], b = el[1], c = el[2], d = el[3];
|
|
const e = el[4], f = el[5];
|
|
const rD = 1 / (a * d - b * c);
|
|
a *= rD;
|
|
b *= rD;
|
|
c *= rD;
|
|
d *= rD;
|
|
return new _Matrix([d, -b, -c, a, c * f - d * e, b * e - a * f]);
|
|
}
|
|
invertSelf() {
|
|
const el = this.elements;
|
|
let a = el[0], b = el[1], c = el[2], d = el[3];
|
|
const e = el[4], f = el[5];
|
|
const rD = 1 / (a * d - b * c);
|
|
a *= rD;
|
|
b *= rD;
|
|
c *= rD;
|
|
d *= rD;
|
|
el[0] = d;
|
|
el[1] = -b;
|
|
el[2] = -c;
|
|
el[3] = a;
|
|
el[4] = c * f - d * e;
|
|
el[5] = b * e - a * f;
|
|
return this;
|
|
}
|
|
transformPoint(x, y) {
|
|
const e = this.elements;
|
|
return {
|
|
x: x * e[0] + y * e[2] + e[4],
|
|
y: x * e[1] + y * e[3] + e[5]
|
|
};
|
|
}
|
|
transformBBox(bbox, target) {
|
|
const el = this.elements;
|
|
const xx = el[0];
|
|
const xy = el[1];
|
|
const yx = el[2];
|
|
const yy = el[3];
|
|
const h_w = bbox.width * 0.5;
|
|
const h_h = bbox.height * 0.5;
|
|
const cx = bbox.x + h_w;
|
|
const cy = bbox.y + h_h;
|
|
const w = Math.abs(h_w * xx) + Math.abs(h_h * yx);
|
|
const h = Math.abs(h_w * xy) + Math.abs(h_h * yy);
|
|
target ?? (target = new BBox(0, 0, 0, 0));
|
|
target.x = cx * xx + cy * yx + el[4] - w;
|
|
target.y = cx * xy + cy * yy + el[5] - h;
|
|
target.width = w + w;
|
|
target.height = h + h;
|
|
return target;
|
|
}
|
|
toContext(ctx) {
|
|
if (this.identity) {
|
|
return;
|
|
}
|
|
const e = this.elements;
|
|
ctx.transform(e[0], e[1], e[2], e[3], e[4], e[5]);
|
|
}
|
|
static updateTransformMatrix(matrix, scalingX, scalingY, rotation, translationX, translationY, opts) {
|
|
const sx = scalingX;
|
|
const sy = scalingY;
|
|
let scx;
|
|
let scy;
|
|
if (sx === 1 && sy === 1) {
|
|
scx = 0;
|
|
scy = 0;
|
|
} else {
|
|
scx = opts?.scalingCenterX ?? 0;
|
|
scy = opts?.scalingCenterY ?? 0;
|
|
}
|
|
const r = rotation;
|
|
const cos = Math.cos(r);
|
|
const sin = Math.sin(r);
|
|
let rcx;
|
|
let rcy;
|
|
if (r === 0) {
|
|
rcx = 0;
|
|
rcy = 0;
|
|
} else {
|
|
rcx = opts?.rotationCenterX ?? 0;
|
|
rcy = opts?.rotationCenterY ?? 0;
|
|
}
|
|
const tx = translationX;
|
|
const ty = translationY;
|
|
const tx4 = scx * (1 - sx) - rcx;
|
|
const ty4 = scy * (1 - sy) - rcy;
|
|
matrix.setElements([
|
|
cos * sx,
|
|
sin * sx,
|
|
-sin * sy,
|
|
cos * sy,
|
|
cos * tx4 - sin * ty4 + rcx + tx,
|
|
sin * tx4 + cos * ty4 + rcy + ty
|
|
]);
|
|
return matrix;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/transformable.ts
|
|
function isMatrixTransform(node) {
|
|
return isMatrixTransformType(node.constructor);
|
|
}
|
|
var MATRIX_TRANSFORM_TYPE = Symbol("isMatrixTransform");
|
|
function isMatrixTransformType(cstr) {
|
|
return cstr[MATRIX_TRANSFORM_TYPE] === true;
|
|
}
|
|
function MatrixTransform(Parent) {
|
|
var _a, _b;
|
|
const ParentNode = Parent;
|
|
if (isMatrixTransformType(Parent)) {
|
|
return Parent;
|
|
}
|
|
const TRANSFORM_MATRIX = Symbol("matrix_combined_transform");
|
|
class MatrixTransformInternal extends ParentNode {
|
|
constructor() {
|
|
super(...arguments);
|
|
this[_b] = new Matrix();
|
|
this._dirtyTransform = true;
|
|
}
|
|
onChangeDetection(property) {
|
|
super.onChangeDetection(property);
|
|
this._dirtyTransform = true;
|
|
if (this.batchLevel > 0) {
|
|
return;
|
|
}
|
|
this.markDirty("transform");
|
|
}
|
|
updateMatrix(_matrix) {
|
|
}
|
|
computeTransformMatrix() {
|
|
if (!this._dirtyTransform)
|
|
return;
|
|
this[TRANSFORM_MATRIX].setElements(IDENTITY_MATRIX_ELEMENTS);
|
|
this.updateMatrix(this[TRANSFORM_MATRIX]);
|
|
this._dirtyTransform = false;
|
|
}
|
|
toParent(bbox) {
|
|
this.computeTransformMatrix();
|
|
if (this[TRANSFORM_MATRIX].identity)
|
|
return bbox.clone();
|
|
return this[TRANSFORM_MATRIX].transformBBox(bbox);
|
|
}
|
|
toParentPoint(x, y) {
|
|
this.computeTransformMatrix();
|
|
if (this[TRANSFORM_MATRIX].identity)
|
|
return { x, y };
|
|
return this[TRANSFORM_MATRIX].transformPoint(x, y);
|
|
}
|
|
fromParent(bbox) {
|
|
this.computeTransformMatrix();
|
|
if (this[TRANSFORM_MATRIX].identity)
|
|
return bbox.clone();
|
|
return this[TRANSFORM_MATRIX].inverse().transformBBox(bbox);
|
|
}
|
|
fromParentPoint(x, y) {
|
|
this.computeTransformMatrix();
|
|
if (this[TRANSFORM_MATRIX].identity)
|
|
return { x, y };
|
|
return this[TRANSFORM_MATRIX].inverse().transformPoint(x, y);
|
|
}
|
|
computeBBox() {
|
|
const bbox = super.computeBBox();
|
|
if (!bbox)
|
|
return bbox;
|
|
return this.toParent(bbox);
|
|
}
|
|
computeBBoxWithoutTransforms() {
|
|
return super.computeBBox();
|
|
}
|
|
pickNode(x, y) {
|
|
({ x, y } = this.fromParentPoint(x, y));
|
|
return super.pickNode(x, y);
|
|
}
|
|
pickNodes(x, y, into) {
|
|
({ x, y } = this.fromParentPoint(x, y));
|
|
return super.pickNodes(x, y, into);
|
|
}
|
|
render(renderCtx) {
|
|
this.computeTransformMatrix();
|
|
const { ctx } = renderCtx;
|
|
const matrix = this[TRANSFORM_MATRIX];
|
|
let performRestore = false;
|
|
try {
|
|
if (!matrix.identity) {
|
|
ctx.save();
|
|
performRestore = true;
|
|
matrix.toContext(ctx);
|
|
}
|
|
super.render(renderCtx);
|
|
} finally {
|
|
if (performRestore) {
|
|
ctx.restore();
|
|
}
|
|
}
|
|
}
|
|
toSVG() {
|
|
this.computeTransformMatrix();
|
|
const svg = super.toSVG();
|
|
const matrix = this[TRANSFORM_MATRIX];
|
|
if (matrix.identity || svg == null)
|
|
return svg;
|
|
const g = (0, import_ag_charts_core21.createSvgElement)("g");
|
|
g.append(...svg.elements);
|
|
const [a, b, c, d, e, f] = matrix.e;
|
|
g.setAttribute("transform", `matrix(${a} ${b} ${c} ${d} ${e} ${f})`);
|
|
return {
|
|
elements: [g],
|
|
defs: svg.defs
|
|
};
|
|
}
|
|
}
|
|
_a = MATRIX_TRANSFORM_TYPE, _b = TRANSFORM_MATRIX;
|
|
MatrixTransformInternal[_a] = true;
|
|
return MatrixTransformInternal;
|
|
}
|
|
function Rotatable(Parent) {
|
|
var _a;
|
|
const ParentNode = Parent;
|
|
const ROTATABLE_MATRIX = Symbol("matrix_rotation");
|
|
class RotatableInternal extends MatrixTransform(ParentNode) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this[_a] = new Matrix();
|
|
this.rotationCenterX = 0;
|
|
this.rotationCenterY = 0;
|
|
this.rotation = 0;
|
|
}
|
|
updateMatrix(matrix) {
|
|
super.updateMatrix(matrix);
|
|
const { rotation, rotationCenterX, rotationCenterY } = this;
|
|
if (rotation === 0)
|
|
return;
|
|
Matrix.updateTransformMatrix(this[ROTATABLE_MATRIX], 1, 1, rotation, 0, 0, {
|
|
rotationCenterX,
|
|
rotationCenterY
|
|
});
|
|
matrix.multiplySelf(this[ROTATABLE_MATRIX]);
|
|
}
|
|
}
|
|
_a = ROTATABLE_MATRIX;
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], RotatableInternal.prototype, "rotationCenterX", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], RotatableInternal.prototype, "rotationCenterY", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], RotatableInternal.prototype, "rotation", 2);
|
|
return RotatableInternal;
|
|
}
|
|
function isScalable(node) {
|
|
return "scalingX" in node && "scalingY" in node && "scalingCenterX" in node && "scalingCenterY" in node;
|
|
}
|
|
function Scalable(Parent) {
|
|
var _a;
|
|
const ParentNode = Parent;
|
|
const SCALABLE_MATRIX = Symbol("matrix_scale");
|
|
class ScalableInternal extends MatrixTransform(ParentNode) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this[_a] = new Matrix();
|
|
this.scalingX = 1;
|
|
this.scalingY = 1;
|
|
this.scalingCenterX = 0;
|
|
this.scalingCenterY = 0;
|
|
}
|
|
// optimised field accessor
|
|
updateMatrix(matrix) {
|
|
super.updateMatrix(matrix);
|
|
const { scalingX, scalingY, scalingCenterX, scalingCenterY } = this;
|
|
if (scalingX === 1 && scalingY === 1)
|
|
return;
|
|
Matrix.updateTransformMatrix(this[SCALABLE_MATRIX], scalingX, scalingY, 0, 0, 0, {
|
|
scalingCenterX,
|
|
scalingCenterY
|
|
});
|
|
matrix.multiplySelf(this[SCALABLE_MATRIX]);
|
|
}
|
|
/**
|
|
* Optimised reset for animation hot paths.
|
|
* Bypasses SceneChangeDetection decorators by writing directly to backing fields.
|
|
*/
|
|
resetScalingProperties(scalingX, scalingY, scalingCenterX, scalingCenterY) {
|
|
this.__scalingX = scalingX;
|
|
this.__scalingY = scalingY;
|
|
this.__scalingCenterX = scalingCenterX;
|
|
this.__scalingCenterY = scalingCenterY;
|
|
this.onChangeDetection("scaling");
|
|
}
|
|
}
|
|
_a = SCALABLE_MATRIX;
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], ScalableInternal.prototype, "scalingX", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], ScalableInternal.prototype, "scalingY", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], ScalableInternal.prototype, "scalingCenterX", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], ScalableInternal.prototype, "scalingCenterY", 2);
|
|
return ScalableInternal;
|
|
}
|
|
function Translatable(Parent) {
|
|
var _a;
|
|
const ParentNode = Parent;
|
|
const TRANSLATABLE_MATRIX = Symbol("matrix_translation");
|
|
class TranslatableInternal extends MatrixTransform(ParentNode) {
|
|
constructor() {
|
|
super(...arguments);
|
|
this[_a] = new Matrix();
|
|
this.translationX = 0;
|
|
this.translationY = 0;
|
|
}
|
|
updateMatrix(matrix) {
|
|
super.updateMatrix(matrix);
|
|
const { translationX, translationY } = this;
|
|
if (translationX === 0 && translationY === 0)
|
|
return;
|
|
Matrix.updateTransformMatrix(this[TRANSLATABLE_MATRIX], 1, 1, 0, translationX, translationY);
|
|
matrix.multiplySelf(this[TRANSLATABLE_MATRIX]);
|
|
}
|
|
}
|
|
_a = TRANSLATABLE_MATRIX;
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], TranslatableInternal.prototype, "translationX", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], TranslatableInternal.prototype, "translationY", 2);
|
|
return TranslatableInternal;
|
|
}
|
|
var Transformable = class {
|
|
/**
|
|
* Converts a BBox from canvas coordinate space into the coordinate space of the given Node.
|
|
*/
|
|
static fromCanvas(node, bbox) {
|
|
const parents = [];
|
|
for (const parent of node.traverseUp()) {
|
|
if (isMatrixTransform(parent)) {
|
|
parents.unshift(parent);
|
|
}
|
|
}
|
|
for (const parent of parents) {
|
|
bbox = parent.fromParent(bbox);
|
|
}
|
|
if (isMatrixTransform(node)) {
|
|
bbox = node.fromParent(bbox);
|
|
}
|
|
return bbox;
|
|
}
|
|
/**
|
|
* Converts a Nodes BBox (or an arbitrary BBox if supplied) from local Node coordinate space
|
|
* into the Canvas coordinate space.
|
|
*/
|
|
static toCanvas(node, bbox) {
|
|
if (bbox == null) {
|
|
bbox = node.getBBox();
|
|
} else if (isMatrixTransform(node)) {
|
|
bbox = node.toParent(bbox);
|
|
}
|
|
for (const parent of node.traverseUp()) {
|
|
if (isMatrixTransform(parent)) {
|
|
bbox = parent.toParent(bbox);
|
|
}
|
|
}
|
|
return bbox;
|
|
}
|
|
/**
|
|
* Converts a point from canvas coordinate space into the coordinate space of the given Node.
|
|
*/
|
|
static fromCanvasPoint(node, x, y) {
|
|
const parents = [];
|
|
for (const parent of node.traverseUp()) {
|
|
if (isMatrixTransform(parent)) {
|
|
parents.unshift(parent);
|
|
}
|
|
}
|
|
for (const parent of parents) {
|
|
({ x, y } = parent.fromParentPoint(x, y));
|
|
}
|
|
if (isMatrixTransform(node)) {
|
|
({ x, y } = node.fromParentPoint(x, y));
|
|
}
|
|
return { x, y };
|
|
}
|
|
/**
|
|
* Converts a point from a Nodes local coordinate space into the Canvas coordinate space.
|
|
*/
|
|
static toCanvasPoint(node, x, y) {
|
|
if (isMatrixTransform(node)) {
|
|
({ x, y } = node.toParentPoint(x, y));
|
|
}
|
|
for (const parent of node.traverseUp()) {
|
|
if (isMatrixTransform(parent)) {
|
|
({ x, y } = parent.toParentPoint(x, y));
|
|
}
|
|
}
|
|
return { x, y };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/group.ts
|
|
var sharedOffscreenCanvas;
|
|
var _Group = class _Group extends Node {
|
|
// optimizeForInfrequentRedraws: true
|
|
constructor(opts) {
|
|
super(opts);
|
|
this.childNodes = /* @__PURE__ */ new Set();
|
|
this.dirty = false;
|
|
this.dirtyZIndex = false;
|
|
this.clipRect = void 0;
|
|
this.opacity = 1;
|
|
// Used when renderToOffscreenCanvas: true
|
|
this.layer = void 0;
|
|
// optimizeForInfrequentRedraws: false
|
|
this.image = void 0;
|
|
this._lastWidth = Number.NaN;
|
|
this._lastHeight = Number.NaN;
|
|
this._lastDevicePixelRatio = Number.NaN;
|
|
this.isContainerNode = true;
|
|
this.renderToOffscreenCanvas = opts?.renderToOffscreenCanvas === true;
|
|
this.optimizeForInfrequentRedraws = opts?.optimizeForInfrequentRedraws === true;
|
|
}
|
|
static is(value) {
|
|
return value instanceof _Group;
|
|
}
|
|
static computeChildrenBBox(nodes, skipInvisible = true) {
|
|
return BBox.merge(Node.extractBBoxes(nodes, skipInvisible));
|
|
}
|
|
static compareChildren(a, b) {
|
|
return compareZIndex(a.__zIndex, b.__zIndex) || a.serialNumber - b.serialNumber;
|
|
}
|
|
// We consider a group to be boundless, thus any point belongs to it.
|
|
containsPoint(_x, _y) {
|
|
return true;
|
|
}
|
|
computeBBox() {
|
|
return _Group.computeChildrenBBox(this.children());
|
|
}
|
|
computeSafeClippingBBox(pixelRatio) {
|
|
const bbox = this.computeBBox();
|
|
if (bbox?.isFinite() !== true)
|
|
return;
|
|
let strokeWidth = 0;
|
|
const strokeMiterAmount = 4;
|
|
for (const child of this.descendants()) {
|
|
if (child instanceof Shape) {
|
|
strokeWidth = Math.max(strokeWidth, child.strokeWidth);
|
|
}
|
|
}
|
|
const padding2 = Math.max(
|
|
// Account for anti-aliasing artefacts
|
|
1,
|
|
// Account for strokes (incl. miters) - this may not be the best place to include this
|
|
strokeWidth / 2 * strokeMiterAmount
|
|
);
|
|
const { x: originX, y: originY } = Transformable.toCanvasPoint(this, 0, 0);
|
|
const x = alignBefore(pixelRatio, originX + bbox.x - padding2) - originX;
|
|
const y = alignBefore(pixelRatio, originY + bbox.y - padding2) - originY;
|
|
const width = Math.ceil(bbox.x + bbox.width - x + padding2);
|
|
const height = Math.ceil(bbox.y + bbox.height - y + padding2);
|
|
return new BBox(x, y, width, height);
|
|
}
|
|
prepareSharedCanvas(width, height, pixelRatio) {
|
|
if (sharedOffscreenCanvas?.pixelRatio === pixelRatio) {
|
|
sharedOffscreenCanvas.resize(width, height, pixelRatio);
|
|
} else {
|
|
sharedOffscreenCanvas = new HdpiOffscreenCanvas({ width, height, pixelRatio });
|
|
}
|
|
return sharedOffscreenCanvas;
|
|
}
|
|
setScene(scene) {
|
|
const previousScene = this.scene;
|
|
super.setScene(scene);
|
|
if (this.layer && previousScene && previousScene !== scene) {
|
|
previousScene.layersManager.removeLayer(this.layer);
|
|
this.layer = void 0;
|
|
}
|
|
for (const child of this.children()) {
|
|
child.setScene(scene);
|
|
}
|
|
}
|
|
markDirty(property) {
|
|
this.dirty = true;
|
|
super.markDirty(property);
|
|
}
|
|
markDirtyChildrenOrder() {
|
|
super.markDirtyChildrenOrder();
|
|
this.dirtyZIndex = true;
|
|
this.markDirty();
|
|
}
|
|
/**
|
|
* Appends one or more new node instances to this parent.
|
|
* If one needs to:
|
|
* - move a child to the end of the list of children
|
|
* - move a child from one parent to another (including parents in other scenes)
|
|
* one should use the {@link insertBefore} method instead.
|
|
* @param nodes A node or nodes to append.
|
|
*/
|
|
append(nodes) {
|
|
for (const node of (0, import_ag_charts_core22.toIterable)(nodes)) {
|
|
node.remove();
|
|
this.childNodes.add(node);
|
|
node.parentNode = this;
|
|
node.setScene(this.scene);
|
|
}
|
|
this.markDirtyChildrenOrder();
|
|
this.markDirty();
|
|
}
|
|
appendChild(node) {
|
|
this.append(node);
|
|
return node;
|
|
}
|
|
removeChild(node) {
|
|
if (!this.childNodes?.delete(node)) {
|
|
throw new Error(
|
|
`AG Charts - internal error, unknown child node ${node.name ?? node.id} in $${this.name ?? this.id}`
|
|
);
|
|
}
|
|
node.parentNode = void 0;
|
|
node.setScene();
|
|
this.markDirtyChildrenOrder();
|
|
this.markDirty();
|
|
}
|
|
clear() {
|
|
for (const child of this.children()) {
|
|
delete child.parentNode;
|
|
child.setScene();
|
|
}
|
|
this.childNodes?.clear();
|
|
this.markDirty();
|
|
}
|
|
/**
|
|
* Hit testing method.
|
|
* Recursively checks if the given point is inside this node or any of its children.
|
|
* Returns the first matching node or `undefined`.
|
|
* Nodes that render later (show on top) are hit tested first.
|
|
*/
|
|
pickNode(x, y) {
|
|
if (!this.visible || this.pointerEvents === 1 /* None */ || !this.containsPoint(x, y)) {
|
|
return;
|
|
}
|
|
if (this.childNodes != null && this.childNodes.size !== 0) {
|
|
const children = [...this.children()];
|
|
for (let i = children.length - 1; i >= 0; i--) {
|
|
const child = children[i];
|
|
const hit = child.pickNode(x, y);
|
|
if (hit != null) {
|
|
return hit;
|
|
}
|
|
}
|
|
} else if (!this.isContainerNode) {
|
|
return this;
|
|
}
|
|
}
|
|
pickNodes(x, y, into = []) {
|
|
if (!this.visible || this.pointerEvents === 1 /* None */ || !this.containsPoint(x, y)) {
|
|
return into;
|
|
}
|
|
if (!this.isContainerNode) {
|
|
into.push(this);
|
|
}
|
|
for (const child of this.children()) {
|
|
child.pickNodes(x, y, into);
|
|
}
|
|
return into;
|
|
}
|
|
isDirty(renderCtx) {
|
|
const { width, height, devicePixelRatio } = renderCtx;
|
|
const { dirty, layer } = this;
|
|
const layerResized = layer != null && (this._lastWidth !== width || this._lastHeight !== height);
|
|
const pixelRatioChanged = this._lastDevicePixelRatio !== devicePixelRatio;
|
|
this._lastWidth = width;
|
|
this._lastHeight = height;
|
|
this._lastDevicePixelRatio = devicePixelRatio;
|
|
return dirty || layerResized || pixelRatioChanged;
|
|
}
|
|
preRender(renderCtx) {
|
|
let counts;
|
|
if (this.dirty) {
|
|
counts = super.preRender(renderCtx, 0);
|
|
for (const child of this.children()) {
|
|
const childCounts = child.preRender(renderCtx);
|
|
counts.groups += childCounts.groups;
|
|
counts.nonGroups += childCounts.nonGroups;
|
|
counts.complexity += childCounts.complexity;
|
|
}
|
|
counts.groups += 1;
|
|
counts.nonGroups -= 1;
|
|
} else {
|
|
counts = this.childNodeCounts;
|
|
}
|
|
if (this.renderToOffscreenCanvas && !this.optimizeForInfrequentRedraws && counts.nonGroups > 0 && this.getVisibility()) {
|
|
this.layer ?? (this.layer = this.layerManager?.addLayer({ name: this.name }));
|
|
} else if (this.layer != null) {
|
|
this.layerManager?.removeLayer(this.layer);
|
|
this.layer = void 0;
|
|
}
|
|
return counts;
|
|
}
|
|
render(renderCtx) {
|
|
const { layer, renderToOffscreenCanvas } = this;
|
|
const childRenderCtx = { ...renderCtx };
|
|
const dirty = this.isDirty(renderCtx);
|
|
this.dirty = false;
|
|
if (!renderToOffscreenCanvas) {
|
|
this.renderInContext(childRenderCtx);
|
|
super.render(childRenderCtx);
|
|
return;
|
|
}
|
|
const { ctx, stats, devicePixelRatio: pixelRatio } = renderCtx;
|
|
let { image } = this;
|
|
if (dirty) {
|
|
image?.bitmap.close();
|
|
image = void 0;
|
|
const bbox = layer ? void 0 : this.computeSafeClippingBBox(pixelRatio);
|
|
const renderOffscreen = (offscreenCanvas, ...transform) => {
|
|
const offscreenCtx = offscreenCanvas.context;
|
|
childRenderCtx.ctx = offscreenCtx;
|
|
offscreenCanvas.clear();
|
|
offscreenCtx.save();
|
|
try {
|
|
offscreenCtx.setTransform(...transform);
|
|
offscreenCtx.globalAlpha = 1;
|
|
this.renderInContext(childRenderCtx);
|
|
} finally {
|
|
offscreenCtx.restore();
|
|
offscreenCtx.verifyDepthZero?.();
|
|
}
|
|
};
|
|
if (layer) {
|
|
renderOffscreen(layer, ctx.getTransform());
|
|
} else if (bbox) {
|
|
const { x, y, width, height } = bbox;
|
|
const scaledWidth = Math.floor(width * pixelRatio);
|
|
const scaledHeight = Math.floor(height * pixelRatio);
|
|
if (scaledWidth > 0 && scaledHeight > 0) {
|
|
const canvas = this.prepareSharedCanvas(width, height, pixelRatio);
|
|
renderOffscreen(canvas, pixelRatio, 0, 0, pixelRatio, -x * pixelRatio, -y * pixelRatio);
|
|
image = { bitmap: canvas.transferToImageBitmap(), x, y, width, height };
|
|
}
|
|
}
|
|
this.image = image;
|
|
if (stats)
|
|
stats.layersRendered++;
|
|
} else if (stats) {
|
|
stats.layersSkipped++;
|
|
}
|
|
const { globalAlpha } = ctx;
|
|
ctx.globalAlpha = globalAlpha * this.opacity;
|
|
if (layer) {
|
|
ctx.save();
|
|
try {
|
|
ctx.resetTransform();
|
|
layer.drawImage(ctx);
|
|
} finally {
|
|
ctx.restore();
|
|
}
|
|
} else if (image) {
|
|
const { bitmap, x, y, width, height } = image;
|
|
ctx.drawImage(bitmap, 0, 0, width * pixelRatio, height * pixelRatio, x, y, width, height);
|
|
}
|
|
ctx.globalAlpha = globalAlpha;
|
|
super.render(childRenderCtx);
|
|
}
|
|
applyClip(ctx, clipRect) {
|
|
const { x, y, width, height } = clipRect;
|
|
ctx.beginPath();
|
|
ctx.rect(x, y, width, height);
|
|
ctx.clip();
|
|
}
|
|
renderInContext(childRenderCtx) {
|
|
const { ctx, stats } = childRenderCtx;
|
|
if (this.dirtyZIndex) {
|
|
this.sortChildren(_Group.compareChildren);
|
|
this.dirtyZIndex = false;
|
|
}
|
|
ctx.save();
|
|
try {
|
|
ctx.globalAlpha *= this.opacity;
|
|
if (this.clipRect != null) {
|
|
this.applyClip(ctx, this.clipRect);
|
|
childRenderCtx.clipBBox = Transformable.toCanvas(this, this.clipRect);
|
|
}
|
|
for (const child of this.children()) {
|
|
if (!child.visible) {
|
|
if (stats) {
|
|
stats.nodesSkipped += child.childNodeCounts.nonGroups + child.childNodeCounts.groups;
|
|
stats.opsSkipped += child.childNodeCounts.complexity;
|
|
}
|
|
continue;
|
|
}
|
|
child.isolatedRender(childRenderCtx);
|
|
}
|
|
} finally {
|
|
ctx.restore();
|
|
}
|
|
}
|
|
sortChildren(compareFn) {
|
|
if (!this.childNodes)
|
|
return;
|
|
const sortedChildren = [...this.childNodes].sort(compareFn);
|
|
this.childNodes.clear();
|
|
for (const child of sortedChildren) {
|
|
this.childNodes.add(child);
|
|
}
|
|
}
|
|
*children() {
|
|
yield* this.childNodes;
|
|
}
|
|
*excludeChildren(exclude) {
|
|
for (const child of this.children()) {
|
|
if (exclude.instance && !(child instanceof exclude.instance) || exclude.name && child.name !== exclude.name) {
|
|
yield child;
|
|
}
|
|
}
|
|
}
|
|
*descendants() {
|
|
for (const child of this.children()) {
|
|
yield child;
|
|
if (child instanceof _Group) {
|
|
yield* child.descendants();
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Transforms bbox given in the canvas coordinate space to bbox in this group's coordinate space and
|
|
* sets this group's clipRect to the transformed bbox.
|
|
* @param bbox clipRect bbox in the canvas coordinate space.
|
|
*/
|
|
setClipRect(bbox) {
|
|
this.clipRect = bbox ? Transformable.fromCanvas(this, bbox) : void 0;
|
|
}
|
|
/**
|
|
* Set the clip rect within the canvas coordinate space.
|
|
* @param bbox clipRect bbox in the canvas coordinate space.
|
|
*/
|
|
setClipRectCanvasSpace(bbox) {
|
|
this.clipRect = bbox;
|
|
}
|
|
getVisibility() {
|
|
for (const node of this.traverseUp(true)) {
|
|
if (!node.visible) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
toSVG() {
|
|
if (!this.visible)
|
|
return;
|
|
const defs = [];
|
|
const elements = [];
|
|
for (const child of this.children()) {
|
|
const svg = child.toSVG();
|
|
if (svg != null) {
|
|
elements.push(...svg.elements);
|
|
if (svg.defs != null) {
|
|
defs.push(...svg.defs);
|
|
}
|
|
}
|
|
}
|
|
return { elements, defs };
|
|
}
|
|
};
|
|
_Group.className = "Group";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)({ convertor: (v) => (0, import_ag_charts_core22.clamp)(0, v, 1) })
|
|
], _Group.prototype, "opacity", 2);
|
|
var Group = _Group;
|
|
var ScalableGroup = class extends Scalable(Group) {
|
|
};
|
|
var RotatableGroup = class extends Rotatable(Group) {
|
|
};
|
|
var TranslatableGroup = class extends Translatable(Group) {
|
|
};
|
|
var TransformableGroup = class extends Rotatable(Translatable(Group)) {
|
|
};
|
|
|
|
// packages/ag-charts-community/src/util/mutex.ts
|
|
var Mutex = class {
|
|
constructor() {
|
|
this.available = true;
|
|
this.acquireQueue = [];
|
|
}
|
|
acquire(cb) {
|
|
return new Promise((resolve, reject) => {
|
|
this.acquireQueue.push([cb, resolve, reject]);
|
|
if (this.available) {
|
|
this.dispatchNext().catch(reject);
|
|
}
|
|
});
|
|
}
|
|
async acquireImmediately(cb) {
|
|
if (!this.available) {
|
|
return false;
|
|
}
|
|
await this.acquire(cb);
|
|
return true;
|
|
}
|
|
async waitForClearAcquireQueue() {
|
|
return this.acquire(() => Promise.resolve(void 0));
|
|
}
|
|
async dispatchNext() {
|
|
this.available = false;
|
|
let [next, done, reject] = this.acquireQueue.shift() ?? [];
|
|
while (next) {
|
|
try {
|
|
await next();
|
|
done?.();
|
|
} catch (error) {
|
|
reject?.(error);
|
|
}
|
|
[next, done, reject] = this.acquireQueue.shift() ?? [];
|
|
}
|
|
this.available = true;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/util/observable.ts
|
|
var Observable = class {
|
|
constructor() {
|
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
}
|
|
addEventListener(eventType, listener) {
|
|
if (typeof listener !== "function") {
|
|
throw new TypeError("AG Charts - listener must be a Function");
|
|
}
|
|
const eventTypeListeners = this.eventListeners.get(eventType);
|
|
if (eventTypeListeners) {
|
|
eventTypeListeners.add(listener);
|
|
} else {
|
|
this.eventListeners.set(eventType, /* @__PURE__ */ new Set([listener]));
|
|
}
|
|
}
|
|
removeEventListener(type, listener) {
|
|
const listeners = this.eventListeners.get(type);
|
|
if (listeners == null)
|
|
return;
|
|
listeners.delete(listener);
|
|
if (listeners.size === 0) {
|
|
this.eventListeners.delete(type);
|
|
}
|
|
}
|
|
hasEventListener(type) {
|
|
return this.eventListeners.has(type);
|
|
}
|
|
clearEventListeners() {
|
|
this.eventListeners.clear();
|
|
}
|
|
fireEvent(event) {
|
|
const listeners = this.eventListeners.get(event.type);
|
|
if (listeners) {
|
|
for (const listener of listeners) {
|
|
listener(event);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/util/render.ts
|
|
var import_ag_charts_core23 = require("ag-charts-core");
|
|
function debouncedAnimationFrame(cb) {
|
|
const window = (0, import_ag_charts_core23.getWindow)();
|
|
function scheduleWithAnimationFrame(innerCb, _delayMs) {
|
|
return window.requestAnimationFrame(innerCb);
|
|
}
|
|
function cancelWithAnimationFrame(id) {
|
|
window.cancelAnimationFrame(id);
|
|
}
|
|
return buildScheduler(scheduleWithAnimationFrame, cb, cancelWithAnimationFrame);
|
|
}
|
|
function debouncedCallback(cb) {
|
|
function scheduleWithDelay(innerCb, delayMs = 0) {
|
|
if (delayMs === 0) {
|
|
queueMicrotask(innerCb);
|
|
return void 0;
|
|
}
|
|
return setTimeout(innerCb, delayMs);
|
|
}
|
|
function cancelWithTimeout(id) {
|
|
clearTimeout(id);
|
|
}
|
|
return buildScheduler(scheduleWithDelay, cb, cancelWithTimeout);
|
|
}
|
|
function buildScheduler(scheduleFn, cb, cancelFn) {
|
|
let scheduleCount = 0;
|
|
let promiseRunning = false;
|
|
let awaitingPromise;
|
|
let awaitingDone;
|
|
let scheduledId;
|
|
function busy() {
|
|
return promiseRunning;
|
|
}
|
|
function done() {
|
|
promiseRunning = false;
|
|
scheduledId = void 0;
|
|
awaitingDone?.();
|
|
awaitingDone = void 0;
|
|
awaitingPromise = void 0;
|
|
if (scheduleCount > 0) {
|
|
scheduledId = scheduleFn(scheduleCallback);
|
|
}
|
|
}
|
|
function scheduleCallback() {
|
|
const count = scheduleCount;
|
|
scheduleCount = 0;
|
|
promiseRunning = true;
|
|
const maybePromise = cb({ count });
|
|
if (!maybePromise) {
|
|
done();
|
|
return;
|
|
}
|
|
maybePromise.then(done, done);
|
|
}
|
|
function schedule(delayMs) {
|
|
if (scheduleCount === 0 && !busy()) {
|
|
scheduledId = scheduleFn(scheduleCallback, delayMs);
|
|
}
|
|
scheduleCount++;
|
|
}
|
|
function cancel() {
|
|
if (scheduledId != null && cancelFn) {
|
|
cancelFn(scheduledId);
|
|
scheduledId = void 0;
|
|
scheduleCount = 0;
|
|
}
|
|
}
|
|
async function waitForCompletion() {
|
|
if (!busy()) {
|
|
return;
|
|
}
|
|
awaitingPromise ?? (awaitingPromise = new Promise(resolveAwaitingPromise));
|
|
while (busy()) {
|
|
await awaitingPromise;
|
|
}
|
|
}
|
|
function resolveAwaitingPromise(resolve) {
|
|
awaitingDone = resolve;
|
|
}
|
|
return {
|
|
schedule,
|
|
cancel,
|
|
waitForCompletion
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-community/src/widget/widget.ts
|
|
var import_ag_charts_core28 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/widget/widgetEvents.ts
|
|
var WIDGET_HTML_EVENTS = [
|
|
"blur",
|
|
"change",
|
|
"contextmenu",
|
|
"focus",
|
|
"keydown",
|
|
"keyup",
|
|
"click",
|
|
"dblclick",
|
|
"mouseenter",
|
|
"mousemove",
|
|
"mouseleave",
|
|
"wheel",
|
|
"touchstart",
|
|
"touchmove",
|
|
"touchend",
|
|
"touchcancel"
|
|
];
|
|
function allocMouseEvent(type, sourceEvent, current) {
|
|
const { offsetX, offsetY, clientX, clientY } = sourceEvent;
|
|
const { currentX, currentY } = WidgetEventUtil.calcCurrentXY(current, sourceEvent);
|
|
return { type, device: "mouse", offsetX, offsetY, clientX, clientY, currentX, currentY, sourceEvent };
|
|
}
|
|
function allocTouchEvent(type, sourceEvent, _current) {
|
|
return { type, sourceEvent };
|
|
}
|
|
var WidgetAllocators = {
|
|
blur: (sourceEvent) => {
|
|
return { type: "blur", sourceEvent };
|
|
},
|
|
change: (sourceEvent) => {
|
|
return { type: "change", sourceEvent };
|
|
},
|
|
contextmenu: (sourceEvent, current) => {
|
|
return allocMouseEvent("contextmenu", sourceEvent, current);
|
|
},
|
|
focus: (sourceEvent) => {
|
|
return { type: "focus", sourceEvent };
|
|
},
|
|
keydown: (sourceEvent) => {
|
|
return { type: "keydown", sourceEvent };
|
|
},
|
|
keyup: (sourceEvent) => {
|
|
return { type: "keyup", sourceEvent };
|
|
},
|
|
click: (sourceEvent, current) => {
|
|
return allocMouseEvent("click", sourceEvent, current);
|
|
},
|
|
dblclick: (sourceEvent, current) => {
|
|
return allocMouseEvent("dblclick", sourceEvent, current);
|
|
},
|
|
mouseenter: (sourceEvent, current) => {
|
|
return allocMouseEvent("mouseenter", sourceEvent, current);
|
|
},
|
|
mousemove: (sourceEvent, current) => {
|
|
return allocMouseEvent("mousemove", sourceEvent, current);
|
|
},
|
|
mouseleave: (sourceEvent, current) => {
|
|
return allocMouseEvent("mouseleave", sourceEvent, current);
|
|
},
|
|
wheel: (sourceEvent) => {
|
|
const { offsetX, offsetY, clientX, clientY } = sourceEvent;
|
|
const factor = sourceEvent.deltaMode === 0 ? 0.01 : 1;
|
|
const deltaX = sourceEvent.deltaX * factor;
|
|
const deltaY = sourceEvent.deltaY * factor;
|
|
return { type: "wheel", offsetX, offsetY, clientX, clientY, deltaX, deltaY, sourceEvent };
|
|
},
|
|
touchstart: (sourceEvent, current) => {
|
|
return allocTouchEvent("touchstart", sourceEvent, current);
|
|
},
|
|
touchmove: (sourceEvent, current) => {
|
|
return allocTouchEvent("touchmove", sourceEvent, current);
|
|
},
|
|
touchend: (sourceEvent, current) => {
|
|
return allocTouchEvent("touchend", sourceEvent, current);
|
|
},
|
|
touchcancel: (sourceEvent, current) => {
|
|
return allocTouchEvent("touchcancel", sourceEvent, current);
|
|
}
|
|
};
|
|
var WidgetEventUtil = class {
|
|
static alloc(type, sourceEvent, current) {
|
|
return WidgetAllocators[type](sourceEvent, current);
|
|
}
|
|
static isHTMLEvent(type) {
|
|
const htmlTypes = WIDGET_HTML_EVENTS;
|
|
return htmlTypes.includes(type);
|
|
}
|
|
static calcCurrentXY(current, event) {
|
|
const currentRect = current.getBoundingClientRect();
|
|
return { currentX: event.clientX - currentRect.x, currentY: event.clientY - currentRect.y };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/widgetListenerHTML.ts
|
|
var import_ag_charts_core24 = require("ag-charts-core");
|
|
var WidgetListenerHTML = class {
|
|
constructor() {
|
|
this.widgetListeners = {};
|
|
this.sourceListeners = {};
|
|
}
|
|
initSourceHandler(type, handler) {
|
|
this.sourceListeners ?? (this.sourceListeners = {});
|
|
this.sourceListeners[type] = handler;
|
|
}
|
|
lazyGetWidgetListeners(type, target) {
|
|
var _a;
|
|
if (!(type in (this.sourceListeners ?? {}))) {
|
|
const sourceHandler = (sourceEvent) => {
|
|
const widgetEvent = WidgetEventUtil.alloc(type, sourceEvent, target.getElement());
|
|
this.dispatch(type, target, widgetEvent);
|
|
};
|
|
const opts = {};
|
|
if (type.startsWith("touch") || type === "wheel") {
|
|
opts.passive = false;
|
|
}
|
|
this.initSourceHandler(type, sourceHandler);
|
|
target.getElement().addEventListener(type, sourceHandler, opts);
|
|
}
|
|
this.widgetListeners ?? (this.widgetListeners = {});
|
|
(_a = this.widgetListeners)[type] ?? (_a[type] = []);
|
|
return this.widgetListeners[type];
|
|
}
|
|
add(type, target, handler) {
|
|
const listeners = this.lazyGetWidgetListeners(type, target);
|
|
listeners.push(handler);
|
|
}
|
|
remove(type, target, handler) {
|
|
const listeners = this.lazyGetWidgetListeners(type, target);
|
|
const index = listeners.indexOf(handler);
|
|
if (index > -1)
|
|
listeners.splice(index, 1);
|
|
}
|
|
destroy(target) {
|
|
this.widgetListeners = void 0;
|
|
if (this.sourceListeners) {
|
|
for (const [key, sourceHandler] of (0, import_ag_charts_core24.entries)(this.sourceListeners)) {
|
|
target.getElement().removeEventListener(key, sourceHandler);
|
|
}
|
|
this.sourceListeners = void 0;
|
|
}
|
|
}
|
|
dispatch(type, target, event) {
|
|
for (const widgetListener of this.widgetListeners?.[type] ?? []) {
|
|
widgetListener(event, target);
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/widgetListenerInternal.ts
|
|
var import_ag_charts_core27 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/widget/mouseDragger.ts
|
|
var import_ag_charts_core25 = require("ag-charts-core");
|
|
var MouseDragger = class {
|
|
constructor(glob, self, myCallbacks, downEvent) {
|
|
this.glob = glob;
|
|
this.self = self;
|
|
this.window = (0, import_ag_charts_core25.getWindow)();
|
|
this.cleanup = new import_ag_charts_core25.CleanupRegistry();
|
|
this.mousegeneral = (generalEvent) => {
|
|
generalEvent.stopPropagation();
|
|
generalEvent.stopImmediatePropagation();
|
|
};
|
|
this.mousemove = (moveEvent) => {
|
|
moveEvent.stopPropagation();
|
|
moveEvent.stopImmediatePropagation();
|
|
this.glob.globalMouseDragCallbacks?.mousemove(moveEvent);
|
|
};
|
|
this.mouseup = (upEvent) => {
|
|
if (upEvent.button === 0) {
|
|
upEvent.stopPropagation();
|
|
upEvent.stopImmediatePropagation();
|
|
this.glob.globalMouseDragCallbacks?.mouseup(upEvent);
|
|
this.destroy();
|
|
}
|
|
};
|
|
const { window, mousegeneral, mousemove, mouseup } = this;
|
|
this.cleanup.register(
|
|
(0, import_ag_charts_core25.attachListener)(window, "mousedown", mousegeneral, { capture: true }),
|
|
(0, import_ag_charts_core25.attachListener)(window, "mouseenter", mousegeneral, { capture: true }),
|
|
(0, import_ag_charts_core25.attachListener)(window, "mouseleave", mousegeneral, { capture: true }),
|
|
(0, import_ag_charts_core25.attachListener)(window, "mouseout", mousegeneral, { capture: true }),
|
|
(0, import_ag_charts_core25.attachListener)(window, "mouseover", mousegeneral, { capture: true }),
|
|
(0, import_ag_charts_core25.attachListener)(window, "mousemove", mousemove, { capture: true }),
|
|
(0, import_ag_charts_core25.attachListener)(window, "mouseup", mouseup, { capture: true })
|
|
);
|
|
self.mouseDragger = this;
|
|
glob.globalMouseDragCallbacks = myCallbacks;
|
|
glob.globalMouseDragCallbacks.mousedown(downEvent);
|
|
downEvent.stopPropagation();
|
|
downEvent.stopImmediatePropagation();
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
this.glob.globalMouseDragCallbacks = void 0;
|
|
this.self.mouseDragger = void 0;
|
|
}
|
|
};
|
|
function startMouseDrag(glob, self, myCallbacks, downEvent) {
|
|
if (glob.globalMouseDragCallbacks != null)
|
|
return void 0;
|
|
return new MouseDragger(glob, self, myCallbacks, downEvent);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/widget/touchDragger.ts
|
|
var import_ag_charts_core26 = require("ag-charts-core");
|
|
var LONG_TAP_DURATION_MS = 500;
|
|
var LONG_TAP_INTERRUPT_MIN_TOUCHMOVE_PXPX = 100;
|
|
function deltaClientSquared(a, b) {
|
|
const dx = a.clientX - b.clientX;
|
|
const dy = a.clientY - b.clientY;
|
|
return dx * dx + dy * dy;
|
|
}
|
|
var gIsInLongTap = false;
|
|
var TouchDragger = class {
|
|
constructor(glob, self, myCallbacks, initialTouch, target) {
|
|
this.glob = glob;
|
|
this.self = self;
|
|
this.initialTouch = initialTouch;
|
|
this.target = target;
|
|
this.cleanup = new import_ag_charts_core26.CleanupRegistry();
|
|
this.longTapInterrupted = false;
|
|
this.longtap = () => {
|
|
const { target, initialTouch } = this;
|
|
if (!this.longTapInterrupted) {
|
|
const cleanup = new import_ag_charts_core26.CleanupRegistry();
|
|
target.dispatchEvent(new TouchEvent("touchcancel", { touches: [initialTouch], bubbles: true }));
|
|
gIsInLongTap = true;
|
|
const longTapMove = (e) => e.preventDefault();
|
|
const longTapEnd = (e) => {
|
|
gIsInLongTap = false;
|
|
e.preventDefault();
|
|
cleanup.flush();
|
|
};
|
|
cleanup.register(
|
|
(0, import_ag_charts_core26.attachListener)(target, "touchmove", longTapMove, { passive: false }),
|
|
(0, import_ag_charts_core26.attachListener)(target, "touchend", longTapEnd, { passive: false }),
|
|
(0, import_ag_charts_core26.attachListener)(target, "touchcancel", longTapEnd, { passive: false })
|
|
);
|
|
const { clientX, clientY } = initialTouch;
|
|
const contextMenuEvent = new PointerEvent("contextmenu", {
|
|
bubbles: true,
|
|
cancelable: true,
|
|
view: (0, import_ag_charts_core26.getWindow)(),
|
|
clientX,
|
|
clientY,
|
|
pointerType: "touch"
|
|
});
|
|
target.dispatchEvent(contextMenuEvent);
|
|
}
|
|
};
|
|
this.touchmove = (moveEvent) => {
|
|
const { glob, self, initialTouch } = this;
|
|
const touch = this.findInitialFinger(moveEvent.targetTouches);
|
|
if (touch != null) {
|
|
this.longTapInterrupted = this.longTapInterrupted || deltaClientSquared(initialTouch, touch) > LONG_TAP_INTERRUPT_MIN_TOUCHMOVE_PXPX;
|
|
if (self.dragTouchEnabled) {
|
|
glob.globalTouchDragCallbacks?.touchmove(moveEvent, touch);
|
|
}
|
|
}
|
|
};
|
|
this.touchend = (endEvent) => {
|
|
this.longTapInterrupted = true;
|
|
const touch = this.findInitialFinger(endEvent.changedTouches, endEvent.touches);
|
|
if (touch != null) {
|
|
this.glob.globalTouchDragCallbacks?.touchend(endEvent, touch);
|
|
}
|
|
this.destroy();
|
|
};
|
|
this.longtapTimer = setTimeout(this.longtap, LONG_TAP_DURATION_MS);
|
|
const { touchmove, touchend } = this;
|
|
this.cleanup.register(
|
|
(0, import_ag_charts_core26.attachListener)(target, "touchmove", touchmove, { passive: false }),
|
|
(0, import_ag_charts_core26.attachListener)(target, "touchstart", touchend, { passive: false }),
|
|
(0, import_ag_charts_core26.attachListener)(target, "touchend", touchend, { passive: false }),
|
|
(0, import_ag_charts_core26.attachListener)(target, "touchcancel", touchend, { passive: false })
|
|
);
|
|
self.touchDragger = this;
|
|
glob.globalTouchDragCallbacks = myCallbacks;
|
|
}
|
|
destroy() {
|
|
clearTimeout(this.longtapTimer);
|
|
this.cleanup.flush();
|
|
this.glob.globalTouchDragCallbacks = void 0;
|
|
this.self.touchDragger = void 0;
|
|
}
|
|
findInitialFinger(...touchLists) {
|
|
const touches = touchLists.flatMap((touchList) => Array.from(touchList));
|
|
return Array.from(touches).find((v) => v.identifier === this.initialTouch.identifier);
|
|
}
|
|
};
|
|
function startOneFingerTouch(glob, self, myCallbacks, initialTouch, target) {
|
|
if (glob.globalTouchDragCallbacks != null || gIsInLongTap)
|
|
return void 0;
|
|
return new TouchDragger(glob, self, myCallbacks, initialTouch, target);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/widget/widgetListenerInternal.ts
|
|
function makeMouseDrag(current, type, origin, sourceEvent) {
|
|
const { currentX, currentY } = WidgetEventUtil.calcCurrentXY(current.getElement(), sourceEvent);
|
|
const originDeltaX = sourceEvent.pageX - origin.pageX;
|
|
const originDeltaY = sourceEvent.pageY - origin.pageY;
|
|
return {
|
|
type,
|
|
device: "mouse",
|
|
offsetX: origin.offsetX + originDeltaX,
|
|
offsetY: origin.offsetY + originDeltaY,
|
|
clientX: sourceEvent.clientX,
|
|
clientY: sourceEvent.clientY,
|
|
currentX,
|
|
currentY,
|
|
originDeltaX,
|
|
originDeltaY,
|
|
sourceEvent
|
|
};
|
|
}
|
|
function getTouchOffsets(current, { pageX, pageY }) {
|
|
const { x, y } = current.getElement().getBoundingClientRect();
|
|
return { offsetX: pageX - x, offsetY: pageY - y };
|
|
}
|
|
function makeTouchDrag(current, type, origin, sourceEvent, touch) {
|
|
const { currentX, currentY } = WidgetEventUtil.calcCurrentXY(current.getElement(), touch);
|
|
const originDeltaX = touch.pageX - origin.pageX;
|
|
const originDeltaY = touch.pageY - origin.pageY;
|
|
return {
|
|
type,
|
|
device: "touch",
|
|
offsetX: origin.offsetX + originDeltaX,
|
|
offsetY: origin.offsetY + originDeltaY,
|
|
clientX: touch.clientX,
|
|
clientY: touch.clientY,
|
|
currentX,
|
|
currentY,
|
|
originDeltaX,
|
|
originDeltaY,
|
|
sourceEvent
|
|
};
|
|
}
|
|
var GlobalCallbacks = {};
|
|
var WidgetListenerInternal = class {
|
|
constructor(dispatchCallback) {
|
|
this.dispatchCallback = dispatchCallback;
|
|
this.dragTouchEnabled = true;
|
|
}
|
|
destroy() {
|
|
this.dragTriggerRemover?.();
|
|
this.dragTriggerRemover = void 0;
|
|
this.listeners?.clear();
|
|
this.mouseDragger?.destroy();
|
|
this.touchDragger?.destroy();
|
|
}
|
|
getListenerSet(type) {
|
|
this.listeners ?? (this.listeners = /* @__PURE__ */ new Map());
|
|
let result = this.listeners.get(type);
|
|
if (result === void 0) {
|
|
result = /* @__PURE__ */ new Set();
|
|
this.listeners.set(type, result);
|
|
}
|
|
return result;
|
|
}
|
|
add(type, target, handler) {
|
|
this.getListenerSet(type).add(handler);
|
|
switch (type) {
|
|
case "drag-start":
|
|
case "drag-move":
|
|
case "drag-end": {
|
|
this.registerDragTrigger(target);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
remove(type, _target, handler) {
|
|
this.getListenerSet(type).delete(handler);
|
|
}
|
|
registerDragTrigger(target) {
|
|
if (this.dragTriggerRemover == null) {
|
|
const element2 = target.getElement();
|
|
const cleanup = new import_ag_charts_core27.CleanupRegistry();
|
|
cleanup.register(
|
|
(0, import_ag_charts_core27.attachListener)(element2, "mousedown", (event) => this.triggerMouseDrag(target, event)),
|
|
(0, import_ag_charts_core27.attachListener)(element2, "touchstart", (event) => this.triggerTouchDrag(target, event), {
|
|
passive: false
|
|
})
|
|
);
|
|
this.dragTriggerRemover = () => cleanup.flush();
|
|
}
|
|
}
|
|
triggerMouseDrag(current, downEvent) {
|
|
if (downEvent.button === 0) {
|
|
this.startMouseDrag(current, downEvent);
|
|
}
|
|
}
|
|
startMouseDrag(current, initialDownEvent) {
|
|
const origin = { pageX: Number.NaN, pageY: Number.NaN, offsetX: Number.NaN, offsetY: Number.NaN };
|
|
(0, import_ag_charts_core27.partialAssign)(["pageX", "pageY", "offsetX", "offsetY"], origin, initialDownEvent);
|
|
const dragCallbacks = {
|
|
mousedown: (downEvent) => {
|
|
const dragStartEvent = makeMouseDrag(current, "drag-start", origin, downEvent);
|
|
this.dispatch("drag-start", current, dragStartEvent);
|
|
},
|
|
mousemove: (moveEvent) => {
|
|
const dragMoveEvent = makeMouseDrag(current, "drag-move", origin, moveEvent);
|
|
this.dispatch("drag-move", current, dragMoveEvent);
|
|
},
|
|
mouseup: (upEvent) => {
|
|
const dragEndEvent = makeMouseDrag(current, "drag-end", origin, upEvent);
|
|
this.dispatch("drag-end", current, dragEndEvent);
|
|
this.endDrag(current, dragEndEvent);
|
|
}
|
|
};
|
|
this.mouseDragger = startMouseDrag(GlobalCallbacks, this, dragCallbacks, initialDownEvent);
|
|
}
|
|
endDrag(target, { sourceEvent, clientX, clientY }) {
|
|
const elem = target.getElement();
|
|
const rect2 = elem.getBoundingClientRect();
|
|
if (!(0, import_ag_charts_core27.boxContains)(rect2, clientX, clientY)) {
|
|
elem.dispatchEvent(new MouseEvent("mouseleave", sourceEvent));
|
|
sourceEvent.target?.dispatchEvent(new MouseEvent("mouseenter", sourceEvent));
|
|
}
|
|
}
|
|
triggerTouchDrag(current, startEvent) {
|
|
const touch = startEvent.targetTouches[0];
|
|
if (startEvent.targetTouches.length === 1 && touch != null) {
|
|
this.startOneFingerTouch(current, startEvent, touch);
|
|
}
|
|
}
|
|
startOneFingerTouch(current, initialEvent, initialTouch) {
|
|
const origin = { pageX: Number.NaN, pageY: Number.NaN, ...getTouchOffsets(current, initialTouch) };
|
|
(0, import_ag_charts_core27.partialAssign)(["pageX", "pageY"], origin, initialTouch);
|
|
const dragCallbacks = {
|
|
touchmove: (moveEvent, touch) => {
|
|
const dragMoveEvent = makeTouchDrag(current, "drag-move", origin, moveEvent, touch);
|
|
this.dispatch("drag-move", current, dragMoveEvent);
|
|
},
|
|
touchend: (cancelEvent, touch) => {
|
|
const dragMoveEvent = makeTouchDrag(current, "drag-end", origin, cancelEvent, touch);
|
|
this.dispatch("drag-end", current, dragMoveEvent);
|
|
}
|
|
};
|
|
const target = current.getElement();
|
|
this.touchDragger = startOneFingerTouch(GlobalCallbacks, this, dragCallbacks, initialTouch, target);
|
|
const dragStartEvent = makeTouchDrag(current, "drag-start", origin, initialEvent, initialTouch);
|
|
this.dispatch("drag-start", current, dragStartEvent);
|
|
}
|
|
dispatch(type, current, event) {
|
|
for (const handler of this.getListenerSet(type)) {
|
|
handler(event, current);
|
|
}
|
|
this.dispatchCallback(type, event);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/widget.ts
|
|
var WidgetBounds = class {
|
|
constructor(elem) {
|
|
this.elem = elem;
|
|
}
|
|
setBounds(bounds) {
|
|
(0, import_ag_charts_core28.setElementBBox)(this.elemContainer ?? this.elem, bounds);
|
|
}
|
|
getBounds() {
|
|
return (0, import_ag_charts_core28.getElementBBox)(this.elemContainer ?? this.elem);
|
|
}
|
|
static setElementContainer(widget, elemContainer) {
|
|
const currentBounds = widget.getBounds();
|
|
(0, import_ag_charts_core28.setElementBBox)(elemContainer, currentBounds);
|
|
(0, import_ag_charts_core28.setElementStyles)(widget.elem, { width: "100%", height: "100%" });
|
|
widget.elem.remove();
|
|
widget.elemContainer = elemContainer;
|
|
widget.elemContainer.replaceChildren(widget.elem);
|
|
}
|
|
};
|
|
var Widget = class extends WidgetBounds {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.index = Number.NaN;
|
|
this.children = [];
|
|
}
|
|
set id(elementId) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "id", elementId);
|
|
}
|
|
get id() {
|
|
return (0, import_ag_charts_core28.getAttribute)(this.elem, "id");
|
|
}
|
|
getElement() {
|
|
return this.elem;
|
|
}
|
|
getBoundingClientRect() {
|
|
return this.elem.getBoundingClientRect();
|
|
}
|
|
get clientWidth() {
|
|
return this.elem.clientWidth;
|
|
}
|
|
get clientHeight() {
|
|
return this.elem.clientHeight;
|
|
}
|
|
destroy() {
|
|
this.destroyListener?.();
|
|
this.destroyListener = void 0;
|
|
this.remove();
|
|
for (const child of this.children) {
|
|
child.parent = void 0;
|
|
child.destroy();
|
|
}
|
|
this.children.length = 0;
|
|
this.destructor();
|
|
this.remove();
|
|
this.internalListener?.destroy();
|
|
this.htmlListener?.destroy(this);
|
|
}
|
|
remove() {
|
|
this.elem.remove();
|
|
this.elemContainer?.remove();
|
|
}
|
|
setHidden(hidden) {
|
|
(0, import_ag_charts_core28.setElementStyle)(this.elem, "display", hidden ? "none" : void 0);
|
|
}
|
|
isHidden() {
|
|
return (0, import_ag_charts_core28.getWindow)()?.getComputedStyle?.(this.elem).display === "none";
|
|
}
|
|
setCursor(cursor) {
|
|
(0, import_ag_charts_core28.setElementStyle)(this.elem, "cursor", cursor);
|
|
}
|
|
setTextContent(textContent) {
|
|
this.elem.textContent = textContent ?? null;
|
|
}
|
|
setAriaDescribedBy(ariaDescribedBy) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "aria-describedby", ariaDescribedBy);
|
|
}
|
|
setAriaHidden(ariaHidden) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "aria-hidden", ariaHidden);
|
|
}
|
|
setAriaLabel(ariaLabel) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "aria-label", ariaLabel);
|
|
}
|
|
setAriaExpanded(ariaExpanded) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "aria-expanded", ariaExpanded);
|
|
}
|
|
setAriaControls(ariaControls) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "aria-controls", ariaControls);
|
|
}
|
|
setAriaHasPopup(ariaHasPopup) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "aria-haspopup", ariaHasPopup);
|
|
}
|
|
setInnerHTML(html) {
|
|
this.elem.innerHTML = html;
|
|
}
|
|
setPointerEvents(pointerEvents) {
|
|
(0, import_ag_charts_core28.setElementStyle)(this.elem, "pointer-events", pointerEvents);
|
|
}
|
|
setCSSVariable(key, value) {
|
|
this.elem.style.setProperty(key, value);
|
|
}
|
|
isDisabled() {
|
|
return (0, import_ag_charts_core28.getAttribute)(this.elem, "aria-disabled", false);
|
|
}
|
|
hasPopup() {
|
|
const ariaHasPopup = (0, import_ag_charts_core28.getAttribute)(this.elem, "aria-haspopup");
|
|
return ariaHasPopup !== void 0 && ariaHasPopup !== "false";
|
|
}
|
|
parseFloat(s) {
|
|
return s === "" ? 0 : Number.parseFloat(s);
|
|
}
|
|
cssLeft() {
|
|
return this.parseFloat(this.elem.style.left);
|
|
}
|
|
cssTop() {
|
|
return this.parseFloat(this.elem.style.top);
|
|
}
|
|
cssWidth() {
|
|
return this.parseFloat(this.elem.style.width);
|
|
}
|
|
cssHeight() {
|
|
return this.parseFloat(this.elem.style.height);
|
|
}
|
|
focus(opts) {
|
|
this.elem.focus(opts);
|
|
}
|
|
setFocusOverride(focus) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "data-focus-override", focus);
|
|
}
|
|
setPreventsDefault(preventDefault) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "data-preventdefault", preventDefault);
|
|
}
|
|
setTabIndex(tabIndex) {
|
|
(0, import_ag_charts_core28.setAttribute)(this.elem, "tabindex", tabIndex);
|
|
}
|
|
addChild(child) {
|
|
this.addChildToDOM(child, this.getBefore(child));
|
|
this.children.push(child);
|
|
child.index = this.children.length - 1;
|
|
child.parent = this;
|
|
this.onChildAdded(child);
|
|
}
|
|
removeChild(child) {
|
|
const i = this.children.indexOf(child);
|
|
this.children.splice(i, 1);
|
|
this.removeChildFromDOM(child);
|
|
this.onChildRemoved(child);
|
|
}
|
|
moveChild(child, domIndex) {
|
|
if (child.domIndex === domIndex)
|
|
return;
|
|
child.domIndex = domIndex;
|
|
this.removeChildFromDOM(child);
|
|
this.addChildToDOM(child, this.getBefore(child));
|
|
}
|
|
addClass(...tokens) {
|
|
this.elem.classList.add(...tokens);
|
|
}
|
|
removeClass(...tokens) {
|
|
this.elem.classList.remove(...tokens);
|
|
}
|
|
toggleClass(token, force) {
|
|
this.elem.classList.toggle(token, force);
|
|
}
|
|
appendOrInsert(child, before) {
|
|
if (before) {
|
|
before.getElement().insertAdjacentElement("beforebegin", child);
|
|
} else {
|
|
this.elem.appendChild(child);
|
|
}
|
|
}
|
|
addChildToDOM(child, before) {
|
|
this.appendOrInsert(child.getElement(), before);
|
|
}
|
|
removeChildFromDOM(child) {
|
|
child.getElement().remove();
|
|
}
|
|
onChildAdded(_child) {
|
|
}
|
|
onChildRemoved(_child) {
|
|
}
|
|
getBefore({ domIndex }) {
|
|
if (domIndex === void 0)
|
|
return void 0;
|
|
return this.children.filter((child) => child.domIndex !== void 0 && child.domIndex > domIndex).reduce((prev, curr) => !prev || curr.domIndex < prev.domIndex ? curr : prev, void 0);
|
|
}
|
|
addListener(type, listener) {
|
|
if (WidgetEventUtil.isHTMLEvent(type)) {
|
|
this.htmlListener ?? (this.htmlListener = new WidgetListenerHTML());
|
|
this.htmlListener.add(type, this, listener);
|
|
} else {
|
|
this.internalListener ?? (this.internalListener = new WidgetListenerInternal(this.onDispatch.bind(this)));
|
|
this.internalListener.add(type, this, listener);
|
|
}
|
|
return () => this.removeListener(type, listener);
|
|
}
|
|
removeListener(type, listener) {
|
|
if (WidgetEventUtil.isHTMLEvent(type)) {
|
|
this.htmlListener?.remove(type, this, listener);
|
|
} else if (this.htmlListener != null) {
|
|
this.internalListener?.remove(type, this, listener);
|
|
}
|
|
}
|
|
setDragTouchEnabled(dragTouchEnabled) {
|
|
this.internalListener ?? (this.internalListener = new WidgetListenerInternal(this.onDispatch.bind(this)));
|
|
this.internalListener.dragTouchEnabled = dragTouchEnabled;
|
|
}
|
|
onDispatch(type, event) {
|
|
if (!event.sourceEvent?.bubbles)
|
|
return;
|
|
let { parent } = this;
|
|
while (parent != null) {
|
|
const { internalListener } = parent;
|
|
if (internalListener != null) {
|
|
const parentEvent = { ...event, ...WidgetEventUtil.calcCurrentXY(parent.getElement(), event) };
|
|
internalListener.dispatch(type, parent, parentEvent);
|
|
}
|
|
parent = parent.parent;
|
|
}
|
|
}
|
|
static addWindowEvent(_type, listener) {
|
|
const pagehideHandler = (event) => {
|
|
if (event.persisted) {
|
|
return;
|
|
}
|
|
listener();
|
|
};
|
|
return (0, import_ag_charts_core28.attachListener)((0, import_ag_charts_core28.getWindow)(), "pagehide", pagehideHandler);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/background/background.ts
|
|
var import_ag_charts_core33 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/shape/rect.ts
|
|
var import_ag_charts_core30 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/util/corner.ts
|
|
var drawCorner = (path, { x0, y0, x1, y1, cx, cy }, cornerRadius, move) => {
|
|
if (move) {
|
|
path.moveTo(x0, y0);
|
|
}
|
|
if (x0 !== x1 || y0 !== y1) {
|
|
const r0 = Math.atan2(y0 - cy, x0 - cx);
|
|
const r1 = Math.atan2(y1 - cy, x1 - cx);
|
|
path.arc(cx, cy, cornerRadius, r0, r1);
|
|
} else {
|
|
path.lineTo(x0, y0);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/shape/path.ts
|
|
var import_ag_charts_core29 = require("ag-charts-core");
|
|
var Path = class extends Shape {
|
|
constructor() {
|
|
super(...arguments);
|
|
/**
|
|
* Declare a path to retain for later rendering and hit testing
|
|
* using custom Path2D class. Think of it as a TypeScript version
|
|
* of the native Path2D (with some differences) that works in all browsers.
|
|
*/
|
|
this.path = new ExtendedPath2D();
|
|
this._clipX = Number.NaN;
|
|
this._clipY = Number.NaN;
|
|
this.clip = false;
|
|
/**
|
|
* The path only has to be updated when certain attributes change.
|
|
* For example, if transform attributes (such as `translationX`)
|
|
* are changed, we don't have to update the path. The `dirtyPath` flag
|
|
* is how we keep track if the path has to be updated or not.
|
|
*/
|
|
this._dirtyPath = true;
|
|
this.lastPixelRatio = Number.NaN;
|
|
}
|
|
set clipX(value) {
|
|
this._clipX = value;
|
|
this.dirtyPath = true;
|
|
}
|
|
set clipY(value) {
|
|
this._clipY = value;
|
|
this.dirtyPath = true;
|
|
}
|
|
set dirtyPath(value) {
|
|
if (this._dirtyPath !== value) {
|
|
this._dirtyPath = value;
|
|
if (value) {
|
|
this.markDirty("path");
|
|
}
|
|
}
|
|
}
|
|
get dirtyPath() {
|
|
return this._dirtyPath;
|
|
}
|
|
checkPathDirty() {
|
|
if (this._dirtyPath) {
|
|
return;
|
|
}
|
|
this.dirtyPath = this.path.isDirty() || (this.fillShadow?.isDirty() ?? false) || (this._clipPath?.isDirty() ?? false);
|
|
}
|
|
resetPathDirty() {
|
|
this.path.clear(true);
|
|
this._dirtyPath = false;
|
|
}
|
|
isPathDirty() {
|
|
return this.path.isDirty();
|
|
}
|
|
onChangeDetection(property) {
|
|
if (!this._dirtyPath) {
|
|
this._dirtyPath = true;
|
|
super.onChangeDetection(property);
|
|
}
|
|
}
|
|
computeBBox() {
|
|
this.updatePathIfDirty();
|
|
return this.path.computeBBox();
|
|
}
|
|
isPointInPath(x, y) {
|
|
this.updatePathIfDirty();
|
|
return this.path.closedPath && this.path.isPointInPath(x, y);
|
|
}
|
|
distanceSquared(x, y) {
|
|
return this.distanceSquaredTransformedPoint(x, y);
|
|
}
|
|
svgPathData(transform) {
|
|
this.updatePathIfDirty();
|
|
return this.path.toSVG(transform);
|
|
}
|
|
distanceSquaredTransformedPoint(x, y) {
|
|
this.updatePathIfDirty();
|
|
if (this.path.closedPath && this.path.isPointInPath(x, y)) {
|
|
return 0;
|
|
}
|
|
return this.path.distanceSquared(x, y);
|
|
}
|
|
isDirtyPath() {
|
|
return false;
|
|
}
|
|
updatePath() {
|
|
}
|
|
updatePathIfDirty() {
|
|
if (this.dirtyPath || this.isDirtyPath()) {
|
|
this.updatePath();
|
|
this.dirtyPath = false;
|
|
}
|
|
}
|
|
preRender(renderCtx) {
|
|
if (renderCtx.devicePixelRatio !== this.lastPixelRatio) {
|
|
this.dirtyPath = true;
|
|
}
|
|
this.lastPixelRatio = renderCtx.devicePixelRatio;
|
|
this.updatePathIfDirty();
|
|
return super.preRender(renderCtx, this.path.commands.length);
|
|
}
|
|
render(renderCtx) {
|
|
const { ctx } = renderCtx;
|
|
if (this.clip && !Number.isNaN(this._clipX) && !Number.isNaN(this._clipY)) {
|
|
ctx.save();
|
|
try {
|
|
const margin = this.strokeWidth / 2;
|
|
this._clipPath ?? (this._clipPath = new ExtendedPath2D());
|
|
this._clipPath.clear();
|
|
this._clipPath.rect(-margin, -margin, this._clipX + margin, this._clipY + margin + margin);
|
|
ctx.clip(this._clipPath?.getPath2D());
|
|
if (this._clipX > 0 && this._clipY > 0) {
|
|
this.drawPath(ctx);
|
|
}
|
|
} finally {
|
|
ctx.restore();
|
|
}
|
|
} else {
|
|
this._clipPath = void 0;
|
|
this.drawPath(ctx);
|
|
}
|
|
this.fillShadow?.markClean();
|
|
super.render(renderCtx);
|
|
}
|
|
drawPath(ctx) {
|
|
this.fillStroke(ctx, this.path.getPath2D());
|
|
}
|
|
toSVG() {
|
|
if (!this.visible)
|
|
return;
|
|
const element2 = (0, import_ag_charts_core29.createSvgElement)("path");
|
|
element2.setAttribute("d", this.svgPathData());
|
|
const defs = this.applySvgFillAttributes(element2, []);
|
|
this.applySvgStrokeAttributes(element2);
|
|
return {
|
|
elements: [element2],
|
|
defs
|
|
};
|
|
}
|
|
};
|
|
Path.className = "Path";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core29.SceneChangeDetection)()
|
|
], Path.prototype, "clip", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core29.SceneChangeDetection)()
|
|
], Path.prototype, "clipX", 1);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core29.SceneChangeDetection)()
|
|
], Path.prototype, "clipY", 1);
|
|
|
|
// packages/ag-charts-community/src/scene/shape/rect.ts
|
|
function cornerEdges(leadingEdge, trailingEdge, leadingInset, trailingInset, cornerRadius) {
|
|
let leadingClipped = false;
|
|
let trailingClipped = false;
|
|
let leading0 = trailingInset - Math.sqrt(Math.max(cornerRadius ** 2 - leadingInset ** 2, 0));
|
|
let leading1 = 0;
|
|
let trailing0 = 0;
|
|
let trailing1 = leadingInset - Math.sqrt(Math.max(cornerRadius ** 2 - trailingInset ** 2, 0));
|
|
if (leading0 > leadingEdge) {
|
|
leadingClipped = true;
|
|
leading0 = leadingEdge;
|
|
leading1 = leadingInset - Math.sqrt(Math.max(cornerRadius ** 2 - (trailingInset - leadingEdge) ** 2));
|
|
} else if ((0, import_ag_charts_core30.isNumberEqual)(leading0, 0)) {
|
|
leading0 = 0;
|
|
}
|
|
if (trailing1 > trailingEdge) {
|
|
trailingClipped = true;
|
|
trailing0 = trailingInset - Math.sqrt(Math.max(cornerRadius ** 2 - (leadingInset - trailingEdge) ** 2));
|
|
trailing1 = trailingEdge;
|
|
} else if ((0, import_ag_charts_core30.isNumberEqual)(trailing1, 0)) {
|
|
trailing1 = 0;
|
|
}
|
|
return { leading0, leading1, trailing0, trailing1, leadingClipped, trailingClipped };
|
|
}
|
|
function clippedRoundRect(path, x, y, width, height, cornerRadii, clipBBox) {
|
|
let {
|
|
topLeft: topLeftCornerRadius,
|
|
topRight: topRightCornerRadius,
|
|
bottomRight: bottomRightCornerRadius,
|
|
bottomLeft: bottomLeftCornerRadius
|
|
} = cornerRadii;
|
|
const maxVerticalCornerRadius = Math.max(
|
|
topLeftCornerRadius + bottomLeftCornerRadius,
|
|
topRightCornerRadius + bottomRightCornerRadius
|
|
);
|
|
const maxHorizontalCornerRadius = Math.max(
|
|
topLeftCornerRadius + topRightCornerRadius,
|
|
bottomLeftCornerRadius + bottomRightCornerRadius
|
|
);
|
|
if (maxVerticalCornerRadius <= 0 && maxHorizontalCornerRadius <= 0) {
|
|
if (clipBBox == null) {
|
|
path.rect(x, y, width, height);
|
|
} else {
|
|
const x0 = Math.max(x, clipBBox.x);
|
|
const x1 = Math.min(x + width, clipBBox.x + clipBBox.width);
|
|
const y0 = Math.max(y, clipBBox.y);
|
|
const y1 = Math.min(y + height, clipBBox.y + clipBBox.height);
|
|
path.rect(x0, y0, x1 - x0, y1 - y0);
|
|
}
|
|
return;
|
|
} else if (clipBBox == null && topLeftCornerRadius === topRightCornerRadius && topLeftCornerRadius === bottomRightCornerRadius && topLeftCornerRadius === bottomLeftCornerRadius) {
|
|
path.roundRect(x, y, width, height, topLeftCornerRadius);
|
|
return;
|
|
}
|
|
if (width < 0) {
|
|
x += width;
|
|
width = Math.abs(width);
|
|
}
|
|
if (height < 0) {
|
|
y += height;
|
|
height = Math.abs(height);
|
|
}
|
|
if (width <= 0 || height <= 0)
|
|
return;
|
|
if (clipBBox == null) {
|
|
clipBBox = new BBox(x, y, width, height);
|
|
} else {
|
|
const x0 = Math.max(x, clipBBox.x);
|
|
const x1 = Math.min(x + width, clipBBox.x + clipBBox.width);
|
|
const y0 = Math.max(y, clipBBox.y);
|
|
const y1 = Math.min(y + height, clipBBox.y + clipBBox.height);
|
|
clipBBox = new BBox(x0, y0, x1 - x0, y1 - y0);
|
|
}
|
|
const borderScale = Math.max(maxVerticalCornerRadius / height, maxHorizontalCornerRadius / width, 1);
|
|
if (borderScale > 1) {
|
|
topLeftCornerRadius /= borderScale;
|
|
topRightCornerRadius /= borderScale;
|
|
bottomRightCornerRadius /= borderScale;
|
|
bottomLeftCornerRadius /= borderScale;
|
|
}
|
|
let drawTopLeftCorner = true;
|
|
let drawTopRightCorner = true;
|
|
let drawBottomRightCorner = true;
|
|
let drawBottomLeftCorner = true;
|
|
let topLeftCorner;
|
|
let topRightCorner;
|
|
let bottomRightCorner;
|
|
let bottomLeftCorner;
|
|
if (drawTopLeftCorner) {
|
|
const nodes = cornerEdges(
|
|
clipBBox.height,
|
|
clipBBox.width,
|
|
Math.max(x + topLeftCornerRadius - clipBBox.x, 0),
|
|
Math.max(y + topLeftCornerRadius - clipBBox.y, 0),
|
|
topLeftCornerRadius
|
|
);
|
|
if (nodes.leadingClipped)
|
|
drawBottomLeftCorner = false;
|
|
if (nodes.trailingClipped)
|
|
drawTopRightCorner = false;
|
|
const x0 = Math.max(clipBBox.x + nodes.leading1, clipBBox.x);
|
|
const y0 = Math.max(clipBBox.y + nodes.leading0, clipBBox.y);
|
|
const x1 = Math.max(clipBBox.x + nodes.trailing1, clipBBox.x);
|
|
const y1 = Math.max(clipBBox.y + nodes.trailing0, clipBBox.y);
|
|
const cx = x + topLeftCornerRadius;
|
|
const cy = y + topLeftCornerRadius;
|
|
topLeftCorner = { x0, y0, x1, y1, cx, cy };
|
|
}
|
|
if (drawTopRightCorner) {
|
|
const nodes = cornerEdges(
|
|
clipBBox.width,
|
|
clipBBox.height,
|
|
Math.max(y + topRightCornerRadius - clipBBox.y, 0),
|
|
Math.max(clipBBox.x + clipBBox.width - (x + width - topRightCornerRadius), 0),
|
|
topRightCornerRadius
|
|
);
|
|
if (nodes.leadingClipped)
|
|
drawTopLeftCorner = false;
|
|
if (nodes.trailingClipped)
|
|
drawBottomRightCorner = false;
|
|
const x0 = Math.min(clipBBox.x + clipBBox.width - nodes.leading0, clipBBox.x + clipBBox.width);
|
|
const y0 = Math.max(clipBBox.y + nodes.leading1, clipBBox.y);
|
|
const x1 = Math.min(clipBBox.x + clipBBox.width - nodes.trailing0, clipBBox.x + clipBBox.width);
|
|
const y1 = Math.max(clipBBox.y + nodes.trailing1, clipBBox.y);
|
|
const cx = x + width - topRightCornerRadius;
|
|
const cy = y + topRightCornerRadius;
|
|
topRightCorner = { x0, y0, x1, y1, cx, cy };
|
|
}
|
|
if (drawBottomRightCorner) {
|
|
const nodes = cornerEdges(
|
|
clipBBox.height,
|
|
clipBBox.width,
|
|
Math.max(clipBBox.x + clipBBox.width - (x + width - bottomRightCornerRadius), 0),
|
|
Math.max(clipBBox.y + clipBBox.height - (y + height - bottomRightCornerRadius), 0),
|
|
bottomRightCornerRadius
|
|
);
|
|
if (nodes.leadingClipped)
|
|
drawTopRightCorner = false;
|
|
if (nodes.trailingClipped)
|
|
drawBottomLeftCorner = false;
|
|
const x0 = Math.min(clipBBox.x + clipBBox.width - nodes.leading1, clipBBox.x + clipBBox.width);
|
|
const y0 = Math.min(clipBBox.y + clipBBox.height - nodes.leading0, clipBBox.y + clipBBox.height);
|
|
const x1 = Math.min(clipBBox.x + clipBBox.width - nodes.trailing1, clipBBox.x + clipBBox.width);
|
|
const y1 = Math.min(clipBBox.y + clipBBox.height - nodes.trailing0, clipBBox.y + clipBBox.height);
|
|
const cx = x + width - bottomRightCornerRadius;
|
|
const cy = y + height - bottomRightCornerRadius;
|
|
bottomRightCorner = { x0, y0, x1, y1, cx, cy };
|
|
}
|
|
if (drawBottomLeftCorner) {
|
|
const nodes = cornerEdges(
|
|
clipBBox.width,
|
|
clipBBox.height,
|
|
Math.max(clipBBox.y + clipBBox.height - (y + height - bottomLeftCornerRadius), 0),
|
|
Math.max(x + bottomLeftCornerRadius - clipBBox.x, 0),
|
|
bottomLeftCornerRadius
|
|
);
|
|
if (nodes.leadingClipped)
|
|
drawBottomRightCorner = false;
|
|
if (nodes.trailingClipped)
|
|
drawTopLeftCorner = false;
|
|
const x0 = Math.max(clipBBox.x + nodes.leading0, clipBBox.x);
|
|
const y0 = Math.min(clipBBox.y + clipBBox.height - nodes.leading1, clipBBox.y + clipBBox.height);
|
|
const x1 = Math.max(clipBBox.x + nodes.trailing0, clipBBox.x);
|
|
const y1 = Math.min(clipBBox.y + clipBBox.height - nodes.trailing1, clipBBox.y + clipBBox.height);
|
|
const cx = x + bottomLeftCornerRadius;
|
|
const cy = y + height - bottomLeftCornerRadius;
|
|
bottomLeftCorner = { x0, y0, x1, y1, cx, cy };
|
|
}
|
|
let didMove = false;
|
|
if (drawTopLeftCorner && topLeftCorner != null) {
|
|
drawCorner(path, topLeftCorner, topLeftCornerRadius, !didMove);
|
|
didMove || (didMove = true);
|
|
}
|
|
if (drawTopRightCorner && topRightCorner != null) {
|
|
drawCorner(path, topRightCorner, topRightCornerRadius, !didMove);
|
|
didMove || (didMove = true);
|
|
}
|
|
if (drawBottomRightCorner && bottomRightCorner != null) {
|
|
drawCorner(path, bottomRightCorner, bottomRightCornerRadius, !didMove);
|
|
didMove || (didMove = true);
|
|
}
|
|
if (drawBottomLeftCorner && bottomLeftCorner != null) {
|
|
drawCorner(path, bottomLeftCorner, bottomLeftCornerRadius, !didMove);
|
|
}
|
|
path.closePath();
|
|
}
|
|
var Rect = class extends Path {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.borderPath = new ExtendedPath2D();
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.width = 10;
|
|
this.height = 10;
|
|
this.topLeftCornerRadius = 0;
|
|
this.topRightCornerRadius = 0;
|
|
this.bottomRightCornerRadius = 0;
|
|
this.bottomLeftCornerRadius = 0;
|
|
this.clipBBox = void 0;
|
|
this.crisp = false;
|
|
this.lastUpdatePathStrokeWidth = this.__strokeWidth;
|
|
this.effectiveStrokeWidth = this.__strokeWidth;
|
|
this.hittester = super.isPointInPath.bind(this);
|
|
this.distanceCalculator = super.distanceSquaredTransformedPoint.bind(this);
|
|
/**
|
|
* When the rectangle's width or height is less than a pixel
|
|
* and crisp mode is on, the rectangle will still fit into the pixel,
|
|
* but will be less opaque to make an effect of holding less space.
|
|
*/
|
|
this.microPixelEffectOpacity = 1;
|
|
}
|
|
// optimised field accessor
|
|
set cornerRadius(cornerRadius) {
|
|
this.topLeftCornerRadius = cornerRadius;
|
|
this.topRightCornerRadius = cornerRadius;
|
|
this.bottomRightCornerRadius = cornerRadius;
|
|
this.bottomLeftCornerRadius = cornerRadius;
|
|
}
|
|
isDirtyPath() {
|
|
return this.lastUpdatePathStrokeWidth !== this.__strokeWidth || Boolean(this.path.isDirty() || this.borderPath.isDirty());
|
|
}
|
|
updatePath() {
|
|
const {
|
|
path,
|
|
borderPath,
|
|
__crisp: crisp,
|
|
__topLeftCornerRadius: topLeft,
|
|
__topRightCornerRadius: topRight,
|
|
__bottomRightCornerRadius: bottomRight,
|
|
__bottomLeftCornerRadius: bottomLeft
|
|
} = this;
|
|
let { __x: x, __y: y, __width: w, __height: h, __strokeWidth: strokeWidth, __clipBBox: clipBBox } = this;
|
|
const pixelRatio = this.layerManager?.canvas.pixelRatio ?? 1;
|
|
const pixelSize = 1 / pixelRatio;
|
|
let microPixelEffectOpacity = 1;
|
|
path.clear();
|
|
borderPath.clear();
|
|
if (w === 0 || h === 0) {
|
|
this.effectiveStrokeWidth = 0;
|
|
this.lastUpdatePathStrokeWidth = 0;
|
|
this.microPixelEffectOpacity = 0;
|
|
return;
|
|
}
|
|
if (crisp) {
|
|
if (w <= pixelSize) {
|
|
microPixelEffectOpacity *= w / pixelSize;
|
|
}
|
|
if (h <= pixelSize) {
|
|
microPixelEffectOpacity *= h / pixelSize;
|
|
}
|
|
w = this.align(x, w);
|
|
h = this.align(y, h);
|
|
x = this.align(x);
|
|
y = this.align(y);
|
|
clipBBox = clipBBox == null ? void 0 : new BBox(
|
|
this.align(clipBBox.x),
|
|
this.align(clipBBox.y),
|
|
this.align(clipBBox.x, clipBBox.width),
|
|
this.align(clipBBox.y, clipBBox.height)
|
|
);
|
|
}
|
|
if (strokeWidth) {
|
|
if (w < pixelSize) {
|
|
const lx = x + pixelSize / 2;
|
|
borderPath.moveTo(lx, y);
|
|
borderPath.lineTo(lx, y + h);
|
|
strokeWidth = pixelSize;
|
|
this.borderClipPath = void 0;
|
|
} else if (h < pixelSize) {
|
|
const ly = y + pixelSize / 2;
|
|
borderPath.moveTo(x, ly);
|
|
borderPath.lineTo(x + w, ly);
|
|
strokeWidth = pixelSize;
|
|
this.borderClipPath = void 0;
|
|
} else if (strokeWidth < w && strokeWidth < h) {
|
|
const halfStrokeWidth = strokeWidth / 2;
|
|
x += halfStrokeWidth;
|
|
y += halfStrokeWidth;
|
|
w -= strokeWidth;
|
|
h -= strokeWidth;
|
|
const adjustedClipBBox = clipBBox?.clone().shrink(halfStrokeWidth);
|
|
const cornerRadii = {
|
|
topLeft: topLeft > 0 ? topLeft - strokeWidth : 0,
|
|
topRight: topRight > 0 ? topRight - strokeWidth : 0,
|
|
bottomRight: bottomRight > 0 ? bottomRight - strokeWidth : 0,
|
|
bottomLeft: bottomLeft > 0 ? bottomLeft - strokeWidth : 0
|
|
};
|
|
this.borderClipPath = void 0;
|
|
if (w > 0 && h > 0 && (adjustedClipBBox == null || adjustedClipBBox?.width > 0 && adjustedClipBBox?.height > 0)) {
|
|
clippedRoundRect(path, x, y, w, h, cornerRadii, adjustedClipBBox);
|
|
clippedRoundRect(borderPath, x, y, w, h, cornerRadii, adjustedClipBBox);
|
|
}
|
|
} else {
|
|
this.borderClipPath = this.borderClipPath ?? new ExtendedPath2D();
|
|
this.borderClipPath.clear();
|
|
this.borderClipPath.rect(x, y, w, h);
|
|
borderPath.rect(x, y, w, h);
|
|
}
|
|
} else {
|
|
const cornerRadii = { topLeft, topRight, bottomRight, bottomLeft };
|
|
this.borderClipPath = void 0;
|
|
clippedRoundRect(path, x, y, w, h, cornerRadii, clipBBox);
|
|
}
|
|
if ([topLeft, topRight, bottomRight, bottomLeft].every(areCornersZero)) {
|
|
let distanceSquaredFromRect2 = function(hitX, hitY) {
|
|
return rectInstance.getBBox().distanceSquared(hitX, hitY);
|
|
};
|
|
var distanceSquaredFromRect = distanceSquaredFromRect2;
|
|
const bbox = this.getBBox();
|
|
this.hittester = bbox.containsPoint.bind(bbox);
|
|
const rectInstance = this;
|
|
this.distanceSquared = distanceSquaredFromRect2;
|
|
} else {
|
|
this.hittester = super.isPointInPath;
|
|
this.distanceCalculator = super.distanceSquaredTransformedPoint;
|
|
}
|
|
this.effectiveStrokeWidth = strokeWidth;
|
|
this.lastUpdatePathStrokeWidth = strokeWidth;
|
|
this.microPixelEffectOpacity = microPixelEffectOpacity;
|
|
}
|
|
computeBBox() {
|
|
const { __x: x, __y: y, __width: width, __height: height, __clipBBox: clipBBox } = this;
|
|
return clipBBox?.clone() ?? new BBox(x, y, width, height);
|
|
}
|
|
isPointInPath(x, y) {
|
|
return this.hittester(x, y);
|
|
}
|
|
get midPoint() {
|
|
return { x: this.__x + this.__width / 2, y: this.__y + this.__height / 2 };
|
|
}
|
|
/**
|
|
* High-performance static property setter that bypasses the decorator system entirely.
|
|
* Writes directly to backing fields (__propertyName) to avoid:
|
|
* - Decorator setter chains and equality checks
|
|
* - Multiple onChangeDetection calls per property
|
|
* - Object.keys() iteration in assignIfNotStrictlyEqual
|
|
* - Object allocation overhead
|
|
*
|
|
* A single markDirty() call at the end ensures the scene graph is properly invalidated.
|
|
* WARNING: Only use for hot paths where performance is critical and properties don't need
|
|
* individual change detection (e.g., when updating many nodes in a loop).
|
|
*/
|
|
setStaticProperties(drawingMode, topLeftCornerRadius, topRightCornerRadius, bottomRightCornerRadius, bottomLeftCornerRadius, visible, crisp, fillShadow) {
|
|
this.__drawingMode = drawingMode;
|
|
this.__topLeftCornerRadius = topLeftCornerRadius;
|
|
this.__topRightCornerRadius = topRightCornerRadius;
|
|
this.__bottomRightCornerRadius = bottomRightCornerRadius;
|
|
this.__bottomLeftCornerRadius = bottomLeftCornerRadius;
|
|
this.__visible = visible;
|
|
this.__crisp = crisp;
|
|
this.__fillShadow = fillShadow;
|
|
this.dirtyPath = true;
|
|
this.markDirty();
|
|
}
|
|
/**
|
|
* High-performance animation reset that bypasses the decorator system entirely.
|
|
* Writes directly to backing fields (__x, __y, etc.) to avoid:
|
|
* - Decorator setter chains and equality checks
|
|
* - Multiple onChangeDetection calls
|
|
* - Object.keys() iteration
|
|
*
|
|
* A single markDirty() call at the end ensures the scene graph is properly invalidated.
|
|
* WARNING: Only use for animation hot paths where performance is critical.
|
|
*/
|
|
resetAnimationProperties(x, y, width, height, opacity, clipBBox) {
|
|
this.__x = x;
|
|
this.__y = y;
|
|
this.__width = width;
|
|
this.__height = height;
|
|
this.__opacity = opacity;
|
|
this.__clipBBox = clipBBox;
|
|
this.dirtyPath = true;
|
|
this.markDirty();
|
|
}
|
|
distanceSquared(x, y) {
|
|
return this.distanceCalculator(x, y);
|
|
}
|
|
applyFillAndAlpha(ctx) {
|
|
super.applyFillAndAlpha(ctx);
|
|
ctx.globalAlpha *= this.microPixelEffectOpacity;
|
|
}
|
|
applyStrokeAndAlpha(ctx) {
|
|
super.applyStrokeAndAlpha(ctx);
|
|
ctx.globalAlpha *= this.microPixelEffectOpacity;
|
|
}
|
|
renderStroke(ctx) {
|
|
const { stroke, effectiveStrokeWidth } = this;
|
|
if (stroke && effectiveStrokeWidth) {
|
|
const { globalAlpha } = ctx;
|
|
const { lineDash, lineDashOffset, lineCap, lineJoin, borderPath, borderClipPath } = this;
|
|
if (borderClipPath) {
|
|
ctx.clip(borderClipPath.getPath2D());
|
|
}
|
|
this.applyStrokeAndAlpha(ctx);
|
|
ctx.lineWidth = effectiveStrokeWidth;
|
|
if (lineDash) {
|
|
ctx.setLineDash(lineDash);
|
|
}
|
|
if (lineDashOffset) {
|
|
ctx.lineDashOffset = lineDashOffset;
|
|
}
|
|
if (lineCap) {
|
|
ctx.lineCap = lineCap;
|
|
}
|
|
if (lineJoin) {
|
|
ctx.lineJoin = lineJoin;
|
|
}
|
|
ctx.stroke(borderPath.getPath2D());
|
|
ctx.globalAlpha = globalAlpha;
|
|
}
|
|
}
|
|
};
|
|
Rect.className = "Rect";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)()
|
|
], Rect.prototype, "x", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)()
|
|
], Rect.prototype, "y", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)()
|
|
], Rect.prototype, "width", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)()
|
|
], Rect.prototype, "height", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)()
|
|
], Rect.prototype, "topLeftCornerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)()
|
|
], Rect.prototype, "topRightCornerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)()
|
|
], Rect.prototype, "bottomRightCornerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)()
|
|
], Rect.prototype, "bottomLeftCornerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)({ equals: import_ag_charts_core30.boxesEqual })
|
|
], Rect.prototype, "clipBBox", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core30.DeclaredSceneChangeDetection)()
|
|
], Rect.prototype, "crisp", 2);
|
|
function areCornersZero(cornerRadius) {
|
|
return cornerRadius === 0;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/shape/text.ts
|
|
var import_ag_charts_core32 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/sceneDebug.ts
|
|
var import_ag_charts_core31 = require("ag-charts-core");
|
|
var StatsAccumulator = class {
|
|
// Log every 10 seconds
|
|
constructor() {
|
|
this.stats = /* @__PURE__ */ new Map();
|
|
this.lastLogTime = Date.now();
|
|
this.LOG_INTERVAL_MS = 1e4;
|
|
this.startPeriodicLogging();
|
|
}
|
|
startPeriodicLogging() {
|
|
if (!import_ag_charts_core31.Debug.check("scene:stats" /* SCENE_STATS */, "scene:stats:verbose" /* SCENE_STATS_VERBOSE */)) {
|
|
return;
|
|
}
|
|
this.stopPeriodicLogging();
|
|
this.intervalId = setInterval(() => {
|
|
this.logAccumulatedStats();
|
|
}, this.LOG_INTERVAL_MS);
|
|
}
|
|
stopPeriodicLogging() {
|
|
if (this.intervalId) {
|
|
clearInterval(this.intervalId);
|
|
this.intervalId = void 0;
|
|
}
|
|
}
|
|
recordTiming(category, duration) {
|
|
const existing = this.stats.get(category);
|
|
if (existing) {
|
|
existing.min = Math.min(existing.min, duration);
|
|
existing.max = Math.max(existing.max, duration);
|
|
existing.sum += duration;
|
|
existing.count += 1;
|
|
} else {
|
|
this.stats.set(category, {
|
|
min: duration,
|
|
max: duration,
|
|
sum: duration,
|
|
count: 1
|
|
});
|
|
}
|
|
}
|
|
recordTimings(durations) {
|
|
for (const [category, duration] of Object.entries(durations)) {
|
|
if (category !== "start" && typeof duration === "number") {
|
|
this.recordTiming(category, duration);
|
|
}
|
|
}
|
|
}
|
|
logAccumulatedStats() {
|
|
if (this.stats.size === 0)
|
|
return;
|
|
const timeSinceLastLog = (Date.now() - this.lastLogTime) / 1e3;
|
|
const categories = Array.from(this.stats.keys()).sort((a, b) => {
|
|
if (a === "\u23F1\uFE0F")
|
|
return -1;
|
|
if (b === "\u23F1\uFE0F")
|
|
return 1;
|
|
return a.localeCompare(b);
|
|
});
|
|
const parts = [];
|
|
for (const category of categories) {
|
|
const stats = this.stats.get(category);
|
|
const avg = stats.sum / stats.count;
|
|
parts.push(`${category}[${stats.min.toFixed(1)}/${avg.toFixed(1)}/${stats.max.toFixed(1)}]ms`);
|
|
}
|
|
const totalStats = this.stats.get("\u23F1\uFE0F");
|
|
const count = totalStats?.count ?? 0;
|
|
import_ag_charts_core31.Logger.log(`\u{1F4CA} Stats (${timeSinceLastLog.toFixed(0)}s, ${count} renders): ${parts.join(" ")}`);
|
|
this.stats.clear();
|
|
this.lastLogTime = Date.now();
|
|
}
|
|
destroy() {
|
|
this.stopPeriodicLogging();
|
|
this.stats.clear();
|
|
}
|
|
};
|
|
var globalStatsAccumulator;
|
|
var statsAccumulatorConsumers = 0;
|
|
function getStatsAccumulator() {
|
|
globalStatsAccumulator ?? (globalStatsAccumulator = new StatsAccumulator());
|
|
return globalStatsAccumulator;
|
|
}
|
|
function registerDebugStatsConsumer() {
|
|
statsAccumulatorConsumers++;
|
|
let released = false;
|
|
return () => {
|
|
if (released || statsAccumulatorConsumers === 0)
|
|
return;
|
|
released = true;
|
|
statsAccumulatorConsumers--;
|
|
if (statsAccumulatorConsumers === 0) {
|
|
cleanupDebugStats();
|
|
}
|
|
};
|
|
}
|
|
function formatBytes(value) {
|
|
for (const unit of ["B", "KB", "MB", "GB"]) {
|
|
if (value < 1536) {
|
|
return `${value.toFixed(1)}${unit}`;
|
|
}
|
|
value /= 1024;
|
|
}
|
|
return `${value.toFixed(1)}TB}`;
|
|
}
|
|
function memoryUsage() {
|
|
if (!("memory" in performance))
|
|
return;
|
|
const { totalJSHeapSize, usedJSHeapSize, jsHeapSizeLimit } = performance.memory;
|
|
const result = [];
|
|
for (const amount of [usedJSHeapSize, totalJSHeapSize, jsHeapSizeLimit]) {
|
|
if (typeof amount !== "number")
|
|
continue;
|
|
result.push(formatBytes(amount));
|
|
}
|
|
return `Heap ${result.join(" / ")}`;
|
|
}
|
|
function debugStats(layersManager, debugSplitTimes, ctx, renderCtxStats, extraDebugStats = {}, seriesRect = BBox.zero, colors) {
|
|
if (!import_ag_charts_core31.Debug.check("scene:stats" /* SCENE_STATS */, "scene:stats:verbose" /* SCENE_STATS_VERBOSE */))
|
|
return;
|
|
const {
|
|
layersRendered = 0,
|
|
layersSkipped = 0,
|
|
nodesRendered = 0,
|
|
nodesSkipped = 0,
|
|
opsPerformed = 0,
|
|
opsSkipped = 0
|
|
} = renderCtxStats ?? {};
|
|
const end2 = performance.now();
|
|
const { start, ...durations } = debugSplitTimes;
|
|
const totalTime = end2 - start;
|
|
const statsAccumulator = getStatsAccumulator();
|
|
statsAccumulator.recordTimings(durations);
|
|
statsAccumulator.recordTiming("\u23F1\uFE0F", totalTime);
|
|
const splits = Object.entries(durations).map(([n, t]) => time2(n, t)).filter((v) => v != null).join(" + ");
|
|
const extras = Object.entries(extraDebugStats).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(" ; ");
|
|
const detailedStats = import_ag_charts_core31.Debug.check("scene:stats:verbose" /* SCENE_STATS_VERBOSE */);
|
|
const memUsage = detailedStats ? memoryUsage() : null;
|
|
const metrics = detailedStats ? import_ag_charts_core31.DebugMetrics.flush() : {};
|
|
const metricsEntries = Object.entries(metrics);
|
|
const aggregationMetrics = [];
|
|
const nodeDataMetrics = [];
|
|
for (const [k, v] of metricsEntries) {
|
|
if (k.endsWith(":aggregation") && Array.isArray(v)) {
|
|
aggregationMetrics.push(`${k.replace(":aggregation", "")}(${v.join(",")})`);
|
|
} else if (k.endsWith(":nodeData") && typeof v === "number") {
|
|
nodeDataMetrics.push(`${k.replace(":nodeData", "")}(${v})`);
|
|
}
|
|
}
|
|
const aggregationText = aggregationMetrics.length > 0 ? `Aggregation: ${aggregationMetrics.join(", ")}` : null;
|
|
const nodeDataText = nodeDataMetrics.length > 0 ? `NodeData: ${nodeDataMetrics.join(", ")}` : null;
|
|
const stats = [
|
|
`${time2("\u23F1\uFE0F", start, end2)} (${splits})`,
|
|
`${extras}`,
|
|
aggregationText,
|
|
nodeDataText,
|
|
`Layers: ${detailedStats ? pct(layersRendered, layersSkipped) : layersManager.size}`,
|
|
detailedStats ? `Nodes: ${pct(nodesRendered, nodesSkipped)}` : null,
|
|
detailedStats ? `Ops: ${pct(opsPerformed, opsSkipped)}` : null,
|
|
memUsage
|
|
].filter(import_ag_charts_core31.isString);
|
|
const measurer = new import_ag_charts_core31.TextMeasurer(ctx);
|
|
const statsSize = new Map(stats.map((t) => [t, measurer.measureText(t)]));
|
|
const width = Math.max(...Array.from(statsSize.values(), (s) => s.width));
|
|
const height = accumulate(statsSize.values(), (s) => s.height);
|
|
const x = 2 + seriesRect.x;
|
|
ctx.save();
|
|
try {
|
|
ctx.fillStyle = colors?.background ?? "white";
|
|
ctx.fillRect(x, 0, width, height);
|
|
ctx.fillStyle = colors?.foreground ?? "black";
|
|
let y = 0;
|
|
for (const [stat, size] of statsSize.entries()) {
|
|
y += size.height;
|
|
ctx.fillText(stat, x, y);
|
|
}
|
|
} catch (e) {
|
|
import_ag_charts_core31.Logger.warnOnce("Error during debug stats rendering", e);
|
|
} finally {
|
|
ctx.restore();
|
|
}
|
|
}
|
|
function prepareSceneNodeHighlight(ctx) {
|
|
const config = (0, import_ag_charts_core31.toArray)((0, import_ag_charts_core31.getWindow)("agChartsSceneDebug"));
|
|
const result = [];
|
|
for (const name of config) {
|
|
if (name === "layout") {
|
|
result.push("seriesRoot", "legend", "root", /.*Axis-\d+-axis.*/);
|
|
} else {
|
|
result.push(name);
|
|
}
|
|
}
|
|
ctx.debugNodeSearch = result;
|
|
}
|
|
function debugSceneNodeHighlight(ctx, debugNodes) {
|
|
ctx.save();
|
|
try {
|
|
for (const [name, node] of Object.entries(debugNodes)) {
|
|
const bbox = Transformable.toCanvas(node);
|
|
if (!bbox) {
|
|
import_ag_charts_core31.Logger.log(`Scene.render() - no bbox for debugged node [${name}].`);
|
|
continue;
|
|
}
|
|
ctx.globalAlpha = 0.8;
|
|
ctx.strokeStyle = "red";
|
|
ctx.lineWidth = 1;
|
|
ctx.strokeRect(bbox.x, bbox.y, bbox.width, bbox.height);
|
|
ctx.fillStyle = "red";
|
|
ctx.strokeStyle = "white";
|
|
ctx.font = "16px sans-serif";
|
|
ctx.textBaseline = "top";
|
|
ctx.textAlign = "left";
|
|
ctx.lineWidth = 2;
|
|
ctx.strokeText(name, bbox.x, bbox.y, bbox.width);
|
|
ctx.fillText(name, bbox.x, bbox.y, bbox.width);
|
|
}
|
|
} catch (e) {
|
|
import_ag_charts_core31.Logger.warnOnce("Error during debug rendering", e);
|
|
} finally {
|
|
ctx.restore();
|
|
}
|
|
}
|
|
var skippedProperties = /* @__PURE__ */ new Set();
|
|
var allowedProperties = /* @__PURE__ */ new Set([
|
|
"gradient",
|
|
// '_datum',
|
|
"zIndex",
|
|
"clipRect",
|
|
"cachedBBox",
|
|
"childNodeCounts",
|
|
"path",
|
|
"__zIndex",
|
|
"name",
|
|
"__scalingCenterX",
|
|
"__scalingCenterY",
|
|
"__rotationCenterX",
|
|
"__rotationCenterY",
|
|
"_previousDatum",
|
|
"__fill",
|
|
"__lineDash",
|
|
"borderPath",
|
|
"borderClipPath",
|
|
"_clipPath"
|
|
]);
|
|
function nodeProps(node) {
|
|
const { ...allProps } = node;
|
|
for (const prop of Object.keys(allProps)) {
|
|
if (allowedProperties.has(prop))
|
|
continue;
|
|
if (typeof allProps[prop] === "number")
|
|
continue;
|
|
if (typeof allProps[prop] === "string")
|
|
continue;
|
|
if (typeof allProps[prop] === "boolean")
|
|
continue;
|
|
skippedProperties.add(prop);
|
|
delete allProps[prop];
|
|
}
|
|
return allProps;
|
|
}
|
|
function buildTree(node, mode) {
|
|
if (!import_ag_charts_core31.Debug.check(true, "scene" /* SCENE */)) {
|
|
return {};
|
|
}
|
|
let order = 0;
|
|
return {
|
|
node: mode === "json" ? nodeProps(node) : node,
|
|
name: node.name ?? node.id,
|
|
dirty: node instanceof Group ? node.dirty : void 0,
|
|
...Array.from(node instanceof Group ? node.children() : [], (c) => buildTree(c, mode)).reduce((result, childTree) => {
|
|
let { name: treeNodeName } = childTree;
|
|
const {
|
|
node: { visible, opacity, zIndex, translationX, translationY, rotation, scalingX, scalingY },
|
|
node: childNode
|
|
} = childTree;
|
|
if (!visible || opacity <= 0) {
|
|
treeNodeName = `(${treeNodeName})`;
|
|
}
|
|
if (Group.is(childNode) && childNode.renderToOffscreenCanvas) {
|
|
treeNodeName = `*${treeNodeName}*`;
|
|
}
|
|
const zIndexString = Array.isArray(zIndex) ? `(${zIndex.join(", ")})` : zIndex;
|
|
const key = [
|
|
`${(order++).toString().padStart(3, "0")}|`,
|
|
`${treeNodeName ?? "<unknown>"}`,
|
|
`z: ${zIndexString}`,
|
|
translationX && `x: ${translationX}`,
|
|
translationY && `y: ${translationY}`,
|
|
rotation && `r: ${rotation}`,
|
|
scalingX != null && scalingX !== 1 && `sx: ${scalingX}`,
|
|
scalingY != null && scalingY !== 1 && `sy: ${scalingY}`
|
|
].filter((v) => !!v).join(" ");
|
|
let selectedKey = key;
|
|
let index = 1;
|
|
while (result[selectedKey] != null && index < 100) {
|
|
selectedKey = `${key} (${index++})`;
|
|
}
|
|
result[selectedKey] = childTree;
|
|
return result;
|
|
}, {})
|
|
};
|
|
}
|
|
function buildDirtyTree(node) {
|
|
const nodeDirty = node instanceof Group ? node.dirty : void 0;
|
|
if (!nodeDirty) {
|
|
return { dirtyTree: {}, paths: [] };
|
|
}
|
|
const childrenDirtyTree = Array.from(node instanceof Group ? node.children() : [], (c) => buildDirtyTree(c)).filter(
|
|
(c) => c.paths.length > 0
|
|
);
|
|
const name = Group.is(node) ? node.name ?? node.id : node.id;
|
|
const paths = childrenDirtyTree.length ? childrenDirtyTree.flatMap((c) => c.paths).map((p) => `${name}.${p}`) : [name];
|
|
return {
|
|
dirtyTree: {
|
|
name,
|
|
node,
|
|
dirty: nodeDirty,
|
|
...childrenDirtyTree.map((c) => c.dirtyTree).filter((t) => t.dirty != null).reduce((result, childTree) => {
|
|
result[childTree.name ?? "<unknown>"] = childTree;
|
|
return result;
|
|
}, {})
|
|
},
|
|
paths
|
|
};
|
|
}
|
|
function pct(rendered, skipped) {
|
|
const total = rendered + skipped;
|
|
return `${rendered} / ${total} (${Math.round(100 * rendered / total)}%)`;
|
|
}
|
|
function time2(name, start, end2) {
|
|
const duration = end2 == null ? start : end2 - start;
|
|
return `${name}: ${Math.round(duration * 100) / 100}ms`;
|
|
}
|
|
function accumulate(iterator, mapper) {
|
|
let sum = 0;
|
|
for (const item of iterator) {
|
|
sum += mapper(item);
|
|
}
|
|
return sum;
|
|
}
|
|
function cleanupDebugStats(force = false) {
|
|
if (!globalStatsAccumulator) {
|
|
if (force) {
|
|
statsAccumulatorConsumers = 0;
|
|
}
|
|
return;
|
|
}
|
|
if (!force && statsAccumulatorConsumers > 0) {
|
|
return;
|
|
}
|
|
globalStatsAccumulator.destroy();
|
|
globalStatsAccumulator = void 0;
|
|
if (force) {
|
|
statsAccumulatorConsumers = 0;
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/shape/text.ts
|
|
var _Text = class _Text extends Shape {
|
|
constructor(options) {
|
|
super(options);
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.lines = [];
|
|
this.text = void 0;
|
|
this.fontCache = void 0;
|
|
this.fontSize = _Text.defaultFontSize;
|
|
this.fontFamily = "sans-serif";
|
|
this.textAlign = "start";
|
|
this.textBaseline = "alphabetic";
|
|
this.boxPadding = 0;
|
|
this.trimText = options?.trimText ?? true;
|
|
}
|
|
onTextChange() {
|
|
this.richText?.clear();
|
|
this.textMap?.clear();
|
|
if ((0, import_ag_charts_core32.isArray)(this.text)) {
|
|
this.lines = [];
|
|
this.richText ?? (this.richText = new Group());
|
|
this.richText.setScene(this.scene);
|
|
this.richText.append(
|
|
this.text.flatMap((s) => (0, import_ag_charts_core32.toTextString)(s.text).split(import_ag_charts_core32.LineSplitter)).filter(Boolean).map(() => new _Text({ trimText: false }))
|
|
);
|
|
} else {
|
|
const lines = (0, import_ag_charts_core32.toTextString)(this.text).split(import_ag_charts_core32.LineSplitter);
|
|
this.lines = this.trimText ? lines.map((line) => line.trim()) : lines;
|
|
}
|
|
}
|
|
get font() {
|
|
this.fontCache ?? (this.fontCache = (0, import_ag_charts_core32.toFontString)(this));
|
|
return this.fontCache;
|
|
}
|
|
static measureBBox(text, x, y, options) {
|
|
if ((0, import_ag_charts_core32.isArray)(text)) {
|
|
const { font, lineHeight, textAlign, textBaseline } = options;
|
|
const { width, height, lineMetrics } = (0, import_ag_charts_core32.measureTextSegments)(text, font);
|
|
const totalHeight = lineHeight ? lineHeight * lineMetrics.length : height;
|
|
const offsetTop = _Text.calcTopOffset(totalHeight, lineMetrics[0], textBaseline);
|
|
const offsetLeft = _Text.calcLeftOffset(width, textAlign);
|
|
return new BBox(x - offsetLeft, y - offsetTop, width, totalHeight);
|
|
} else {
|
|
return _Text.computeBBox((0, import_ag_charts_core32.toTextString)(text).split(import_ag_charts_core32.LineSplitter), x, y, options);
|
|
}
|
|
}
|
|
static computeBBox(lines, x, y, opts) {
|
|
const { font, lineHeight, textAlign, textBaseline } = opts;
|
|
const { width, height, lineMetrics } = (0, import_ag_charts_core32.cachedTextMeasurer)(font).measureLines(lines);
|
|
const totalHeight = lineHeight ? lineHeight * lineMetrics.length : height;
|
|
const offsetTop = _Text.calcTopOffset(totalHeight, lineMetrics[0], textBaseline);
|
|
const offsetLeft = _Text.calcLeftOffset(width, textAlign);
|
|
return new BBox(x - offsetLeft, y - offsetTop, width, totalHeight);
|
|
}
|
|
static calcTopOffset(height, textMetrics, textBaseline) {
|
|
switch (textBaseline) {
|
|
case "alphabetic":
|
|
return textMetrics?.ascent ?? 0;
|
|
case "middle":
|
|
return height / 2;
|
|
case "bottom":
|
|
return height;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
static calcSegmentedTopOffset(height, lineMetrics, textBaseline) {
|
|
switch (textBaseline) {
|
|
case "alphabetic":
|
|
return lineMetrics[0]?.ascent ?? 0;
|
|
case "middle":
|
|
return lineMetrics.length === 1 ? lineMetrics[0].ascent + lineMetrics[0].segments.reduce(
|
|
(offsetY, segment) => Math.min(offsetY, (0, import_ag_charts_core32.cachedTextMeasurer)(segment).baselineDistance("middle")),
|
|
0
|
|
) : height / 2;
|
|
case "bottom":
|
|
return height;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
static calcLeftOffset(width, textAlign) {
|
|
let offset = 0;
|
|
switch (textAlign) {
|
|
case "center":
|
|
offset = 0.5;
|
|
break;
|
|
case "right":
|
|
case "end":
|
|
offset = 1;
|
|
}
|
|
return width * offset;
|
|
}
|
|
getBBox() {
|
|
const bbox = super.getBBox();
|
|
if (!this.textMap?.size || !(0, import_ag_charts_core32.isArray)(this.text))
|
|
return bbox;
|
|
const { height, lineMetrics } = (0, import_ag_charts_core32.measureTextSegments)(this.text, this);
|
|
const offsetTop = _Text.calcSegmentedTopOffset(height, lineMetrics, this.textBaseline);
|
|
const y = this.y - offsetTop;
|
|
if (bbox.y === y)
|
|
return bbox;
|
|
return new BBox(bbox.x, y, bbox.width, bbox.height);
|
|
}
|
|
computeBBox() {
|
|
this.generateTextMap();
|
|
if (this.textMap?.size) {
|
|
const bbox = BBox.merge(this.textMap.values());
|
|
bbox.x = this.x - _Text.calcLeftOffset(bbox.width, this.textAlign);
|
|
bbox.y = this.y;
|
|
return bbox;
|
|
}
|
|
const { x, y, lines, textBaseline, textAlign } = this;
|
|
const measuredTextBounds = _Text.computeBBox(lines, x, y, { font: this, textBaseline, textAlign });
|
|
if (this.boxing != null)
|
|
measuredTextBounds.grow(this.boxPadding);
|
|
return measuredTextBounds;
|
|
}
|
|
getTextMeasureBBox() {
|
|
return this.computeBBox();
|
|
}
|
|
getPlainText() {
|
|
return (0, import_ag_charts_core32.toPlainText)(this.text);
|
|
}
|
|
isPointInPath(x, y) {
|
|
return this.getBBox()?.containsPoint(x, y) ?? false;
|
|
}
|
|
setScene(scene) {
|
|
this.richText?.setScene(scene);
|
|
super.setScene(scene);
|
|
}
|
|
generateTextMap() {
|
|
if (!(0, import_ag_charts_core32.isArray)(this.text) || this.textMap?.size)
|
|
return;
|
|
this.textMap ?? (this.textMap = /* @__PURE__ */ new Map());
|
|
let offsetY = 0;
|
|
const textNodes = this.richText.children();
|
|
for (const { width, height, ascent, segments } of (0, import_ag_charts_core32.measureTextSegments)(this.text, this).lineMetrics) {
|
|
let offsetX = 0;
|
|
for (const { color: color8, textMetrics, ...segment } of segments) {
|
|
const textNode = textNodes.next().value;
|
|
textNode.x = this.x - width / 2 + offsetX;
|
|
textNode.y = ascent + offsetY;
|
|
textNode.setProperties({ ...segment, fill: color8 ?? this.fill });
|
|
const textBBox = textNode.getBBox();
|
|
this.textMap.set(textNode, textBBox);
|
|
offsetX += textMetrics.width;
|
|
}
|
|
offsetY += height;
|
|
}
|
|
}
|
|
render(renderCtx) {
|
|
const { ctx, stats } = renderCtx;
|
|
if (!this.layerManager || !this.hasRenderableText()) {
|
|
if (stats)
|
|
stats.nodesSkipped += 1;
|
|
return super.render(renderCtx);
|
|
}
|
|
if ((0, import_ag_charts_core32.isArray)(this.text) && this.richText) {
|
|
this.generateTextMap();
|
|
const richTextBBox = this.richText.getBBox();
|
|
const { width, height, lineMetrics } = (0, import_ag_charts_core32.measureTextSegments)(this.text, this);
|
|
let translateX = 0;
|
|
switch (this.textAlign) {
|
|
case "left":
|
|
case "start":
|
|
translateX = width / 2;
|
|
break;
|
|
case "right":
|
|
case "end":
|
|
translateX = width / -2;
|
|
}
|
|
const translateY = this.y - _Text.calcSegmentedTopOffset(height, lineMetrics, this.textBaseline);
|
|
this.renderBoxing(renderCtx, richTextBBox.clone().translate(translateX, translateY));
|
|
ctx.save();
|
|
ctx.translate(translateX, translateY);
|
|
this.richText.opacity = this.opacity;
|
|
this.richText.render(renderCtx);
|
|
ctx.restore();
|
|
} else {
|
|
this.renderText(renderCtx);
|
|
}
|
|
if (_Text.debug.check()) {
|
|
const bbox = this.getBBox();
|
|
ctx.lineWidth = this.textMap?.size ? 2 : 1;
|
|
ctx.strokeStyle = this.textMap?.size ? "blue" : "red";
|
|
ctx.strokeRect(bbox.x, bbox.y, bbox.width, bbox.height);
|
|
}
|
|
super.render(renderCtx);
|
|
}
|
|
markDirty(property) {
|
|
this.textMap?.clear();
|
|
return super.markDirty(property);
|
|
}
|
|
renderText(renderCtx) {
|
|
const { fill, stroke, strokeWidth, font, textAlign } = this;
|
|
if (!fill && !(stroke && strokeWidth) || !this.layerManager) {
|
|
return super.render(renderCtx);
|
|
}
|
|
const { ctx } = renderCtx;
|
|
if (ctx.font !== font) {
|
|
ctx.font = font;
|
|
}
|
|
ctx.textAlign = textAlign;
|
|
this.renderBoxing(renderCtx);
|
|
this.fillStroke(ctx);
|
|
}
|
|
renderBoxing(renderCtx, bbox) {
|
|
if (!this.boxing)
|
|
return;
|
|
const textBBox = bbox ?? _Text.computeBBox(this.lines, this.x, this.y, this);
|
|
if (textBBox.width === 0 || textBBox.height === 0)
|
|
return;
|
|
const { x, y, width, height } = textBBox.grow(this.boxPadding);
|
|
this.boxing.opacity = this.opacity;
|
|
this.boxing.x = x;
|
|
this.boxing.y = y;
|
|
this.boxing.width = width;
|
|
this.boxing.height = height;
|
|
this.boxing.preRender(renderCtx);
|
|
this.boxing.render(renderCtx);
|
|
}
|
|
executeFill(ctx) {
|
|
this.renderLines((line, x, y) => ctx.fillText(line, x, y));
|
|
}
|
|
executeStroke(ctx) {
|
|
this.renderLines((line, x, y) => ctx.strokeText(line, x, y));
|
|
}
|
|
renderLines(renderCallback) {
|
|
const { x, y, lines } = this;
|
|
if (!Number.isFinite(x) || !Number.isFinite(y))
|
|
return;
|
|
const measurer = (0, import_ag_charts_core32.cachedTextMeasurer)(this);
|
|
const { lineMetrics } = measurer.measureLines(lines);
|
|
const { textBaseline, lineHeight = measurer.lineHeight() } = this;
|
|
let offsetY = 0;
|
|
if (textBaseline === "top") {
|
|
offsetY = lineMetrics[0].ascent;
|
|
} else if (textBaseline === "middle" || textBaseline === "bottom") {
|
|
offsetY = lineHeight * (1 - lines.length);
|
|
if (textBaseline === "middle") {
|
|
offsetY /= 2;
|
|
offsetY -= measurer.baselineDistance(textBaseline);
|
|
} else {
|
|
offsetY -= lineMetrics[0].descent;
|
|
}
|
|
}
|
|
for (const line of lineMetrics) {
|
|
renderCallback(line.text, x, y + offsetY);
|
|
offsetY += lineHeight;
|
|
}
|
|
}
|
|
setFont(props) {
|
|
this.fontFamily = props.fontFamily;
|
|
this.fontSize = props.fontSize;
|
|
this.fontStyle = props.fontStyle;
|
|
this.fontWeight = props.fontWeight;
|
|
}
|
|
setAlign(props) {
|
|
this.textAlign = props.textAlign;
|
|
this.textBaseline = props.textBaseline;
|
|
}
|
|
setBoxing(props) {
|
|
const stroke = props.border?.enabled ? props.border?.stroke : void 0;
|
|
if (props.fill != null || stroke != null) {
|
|
this.boxing ?? (this.boxing = new Rect({ scene: this.scene }));
|
|
this.boxing.fill = props.fill;
|
|
this.boxing.fillOpacity = props.fillOpacity ?? 1;
|
|
this.boxing.cornerRadius = props.cornerRadius ?? 0;
|
|
this.boxing.stroke = stroke;
|
|
this.boxing.strokeWidth = props.border?.strokeWidth ?? 0;
|
|
this.boxing.strokeOpacity = props.border?.strokeOpacity ?? 1;
|
|
this.boxPadding = props.padding ?? 0;
|
|
} else if (this.boxing) {
|
|
this.boxing.destroy();
|
|
this.boxing = void 0;
|
|
}
|
|
}
|
|
getBoxingProperties() {
|
|
const { fill, fillOpacity, cornerRadius, stroke, strokeWidth, strokeOpacity } = this.boxing ?? {};
|
|
return {
|
|
border: { enabled: stroke != null, stroke, strokeWidth, strokeOpacity },
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
padding: this.boxPadding
|
|
};
|
|
}
|
|
toSVG() {
|
|
if (!this.visible || !this.hasRenderableText())
|
|
return;
|
|
const text = this.text;
|
|
if (text == null)
|
|
return;
|
|
const element2 = (0, import_ag_charts_core32.createSvgElement)("text");
|
|
if ((0, import_ag_charts_core32.isArray)(text)) {
|
|
for (const segment of text) {
|
|
const segmentElement = (0, import_ag_charts_core32.createSvgElement)("tspan");
|
|
setSvgFontAttributes(segmentElement, {
|
|
fontSize: segment.fontSize ?? this.fontSize,
|
|
fontFamily: segment.fontFamily ?? this.fontFamily,
|
|
fontWeight: segment.fontWeight ?? this.fontWeight,
|
|
fontStyle: segment.fontStyle ?? this.fontStyle
|
|
});
|
|
this.applySvgFillAttributes(segmentElement);
|
|
segmentElement.textContent = (0, import_ag_charts_core32.toTextString)(segment.text);
|
|
element2.append(segmentElement);
|
|
}
|
|
} else {
|
|
this.applySvgFillAttributes(element2);
|
|
setSvgFontAttributes(element2, this);
|
|
element2.setAttribute(
|
|
"text-anchor",
|
|
{
|
|
center: "middle",
|
|
left: "start",
|
|
right: "end",
|
|
start: "start",
|
|
end: "end"
|
|
}[this.textAlign ?? "start"]
|
|
);
|
|
element2.setAttribute("alignment-baseline", this.textBaseline);
|
|
element2.setAttribute("x", String(this.x));
|
|
element2.setAttribute("y", String(this.y));
|
|
element2.textContent = (0, import_ag_charts_core32.toTextString)(text);
|
|
}
|
|
return { elements: [element2] };
|
|
}
|
|
hasRenderableText() {
|
|
const { text } = this;
|
|
if (text == null) {
|
|
return false;
|
|
}
|
|
return (0, import_ag_charts_core32.isArray)(text) ? true : (0, import_ag_charts_core32.toTextString)(text) !== "";
|
|
}
|
|
};
|
|
_Text.className = "Text";
|
|
_Text.debug = import_ag_charts_core32.Debug.create(true, "scene:text" /* SCENE_TEXT */);
|
|
_Text.defaultFontSize = 10;
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], _Text.prototype, "x", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], _Text.prototype, "y", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core32.SceneRefChangeDetection)({
|
|
changeCb: (o) => o.onTextChange()
|
|
})
|
|
], _Text.prototype, "text", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)({
|
|
changeCb: (o) => {
|
|
o.fontCache = void 0;
|
|
}
|
|
})
|
|
], _Text.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)({
|
|
changeCb: (o) => {
|
|
o.fontCache = void 0;
|
|
}
|
|
})
|
|
], _Text.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)({
|
|
changeCb: (o) => {
|
|
o.fontCache = void 0;
|
|
}
|
|
})
|
|
], _Text.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)({
|
|
changeCb: (o) => {
|
|
o.fontCache = void 0;
|
|
}
|
|
})
|
|
], _Text.prototype, "fontFamily", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], _Text.prototype, "textAlign", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], _Text.prototype, "textBaseline", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], _Text.prototype, "lineHeight", 2);
|
|
var Text = _Text;
|
|
var RotatableText = class extends Rotatable(Text) {
|
|
};
|
|
var TransformableText = class extends Rotatable(Translatable(Text)) {
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/background/background.ts
|
|
var Background = class extends import_ag_charts_core33.AbstractModuleInstance {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.rectNode = new Rect();
|
|
this.textNode = new Text();
|
|
this.fill = "white";
|
|
this.node = this.createNode();
|
|
this.node.append([this.rectNode, this.textNode]);
|
|
this.visible = true;
|
|
this.cleanup.register(
|
|
ctx.scene.attachNode(this.node),
|
|
ctx.eventsHub.on("layout:complete", (e) => this.onLayoutComplete(e))
|
|
);
|
|
}
|
|
createNode() {
|
|
return new Group({ name: "background", zIndex: import_ag_charts_core33.ZIndexMap.CHART_BACKGROUND });
|
|
}
|
|
onLayoutComplete(e) {
|
|
const { width, height } = e.chart;
|
|
this.rectNode.width = width;
|
|
this.rectNode.height = height;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core33.Property,
|
|
(0, import_ag_charts_core33.ProxyPropertyOnWrite)("node", "visible")
|
|
], Background.prototype, "visible", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core33.Property,
|
|
(0, import_ag_charts_core33.ProxyPropertyOnWrite)("rectNode", "fill")
|
|
], Background.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core33.Property
|
|
], Background.prototype, "image", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core33.Property,
|
|
(0, import_ag_charts_core33.ProxyPropertyOnWrite)("textNode")
|
|
], Background.prototype, "text", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/caption.ts
|
|
var import_ag_charts_core34 = require("ag-charts-core");
|
|
var Caption = class extends import_ag_charts_core34.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.id = (0, import_ag_charts_core34.createId)(this);
|
|
this.node = new RotatableText({ zIndex: 1 }).setProperties({
|
|
textAlign: "center",
|
|
pointerEvents: 1 /* None */
|
|
});
|
|
this.enabled = false;
|
|
this.textAlign = "center";
|
|
this.fontSize = import_ag_charts_core34.FONT_SIZE.SMALLER;
|
|
this.fontFamily = "sans-serif";
|
|
this.wrapping = "always";
|
|
this.padding = 0;
|
|
this.layoutStyle = "block";
|
|
this.truncated = false;
|
|
}
|
|
registerInteraction(moduleCtx, where) {
|
|
return moduleCtx.eventsHub.on("layout:complete", () => this.updateA11yText(moduleCtx, where));
|
|
}
|
|
computeTextWrap(containerWidth, containerHeight) {
|
|
const { text, padding: padding2, wrapping } = this;
|
|
const maxWidth = Math.min(this.maxWidth ?? Infinity, containerWidth) - padding2 * 2;
|
|
const maxHeight = this.maxHeight ?? containerHeight - padding2 * 2;
|
|
const options = { maxWidth, maxHeight, font: this, textWrap: wrapping };
|
|
if (!Number.isFinite(maxWidth) && !Number.isFinite(maxHeight)) {
|
|
this.node.text = text;
|
|
return;
|
|
}
|
|
let wrappedText;
|
|
if ((0, import_ag_charts_core34.isArray)(text)) {
|
|
wrappedText = (0, import_ag_charts_core34.wrapTextSegments)(text, options);
|
|
this.truncated = wrappedText.some(import_ag_charts_core34.isSegmentTruncated);
|
|
} else {
|
|
wrappedText = (0, import_ag_charts_core34.wrapText)((0, import_ag_charts_core34.toTextString)(text), options);
|
|
this.truncated = (0, import_ag_charts_core34.isTextTruncated)(wrappedText);
|
|
}
|
|
this.node.text = wrappedText;
|
|
}
|
|
updateA11yText(moduleCtx, where) {
|
|
const { proxyInteractionService } = moduleCtx;
|
|
if (!this.enabled || !this.text) {
|
|
this.destroyProxyText();
|
|
return;
|
|
}
|
|
const bbox = Transformable.toCanvas(this.node);
|
|
if (!bbox)
|
|
return;
|
|
const { id: domManagerId } = this;
|
|
if (this.proxyText == null) {
|
|
this.proxyText = proxyInteractionService.createProxyElement({ type: "text", domManagerId, where });
|
|
this.proxyTextListeners = [
|
|
this.proxyText.addListener("mousemove", (ev) => this.handleMouseMove(moduleCtx, ev)),
|
|
this.proxyText.addListener("mouseleave", (ev) => this.handleMouseLeave(moduleCtx, ev))
|
|
];
|
|
}
|
|
const textContent = (0, import_ag_charts_core34.toPlainText)(this.text);
|
|
if (textContent !== this.lastProxyTextContent) {
|
|
this.proxyText.textContent = textContent;
|
|
this.lastProxyTextContent = textContent;
|
|
}
|
|
const { lastProxyBBox } = this;
|
|
if (lastProxyBBox == null || bbox.x !== lastProxyBBox.x || bbox.y !== lastProxyBBox.y || bbox.width !== lastProxyBBox.width || bbox.height !== lastProxyBBox.height) {
|
|
this.proxyText.setBounds(bbox);
|
|
this.lastProxyBBox = { x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height };
|
|
}
|
|
}
|
|
handleMouseMove(moduleCtx, event) {
|
|
if (event != null && this.enabled && this.truncated) {
|
|
const { x, y } = Transformable.toCanvas(this.node);
|
|
const canvasX = event.sourceEvent.offsetX + x;
|
|
const canvasY = event.sourceEvent.offsetY + y;
|
|
moduleCtx.tooltipManager.updateTooltip(this.id, { canvasX, canvasY, showArrow: false }, [
|
|
{ type: "structured", title: (0, import_ag_charts_core34.toPlainText)(this.text) }
|
|
]);
|
|
}
|
|
}
|
|
handleMouseLeave(moduleCtx, _event) {
|
|
moduleCtx.tooltipManager.removeTooltip(this.id, void 0, true);
|
|
}
|
|
destroy() {
|
|
this.destroyProxyText();
|
|
}
|
|
destroyProxyText() {
|
|
if (this.proxyText == null)
|
|
return;
|
|
for (const cleanup of this.proxyTextListeners ?? []) {
|
|
cleanup();
|
|
}
|
|
this.proxyTextListeners = void 0;
|
|
this.proxyText.destroy();
|
|
this.proxyText = void 0;
|
|
this.lastProxyTextContent = void 0;
|
|
this.lastProxyBBox = void 0;
|
|
}
|
|
};
|
|
Caption.className = "Caption";
|
|
Caption.SMALL_PADDING = 10;
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property,
|
|
(0, import_ag_charts_core34.ProxyPropertyOnWrite)("node", "visible")
|
|
], Caption.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property,
|
|
(0, import_ag_charts_core34.ProxyPropertyOnWrite)("node")
|
|
], Caption.prototype, "text", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property,
|
|
(0, import_ag_charts_core34.ProxyPropertyOnWrite)("node")
|
|
], Caption.prototype, "textAlign", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property,
|
|
(0, import_ag_charts_core34.ProxyPropertyOnWrite)("node")
|
|
], Caption.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property,
|
|
(0, import_ag_charts_core34.ProxyPropertyOnWrite)("node")
|
|
], Caption.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property,
|
|
(0, import_ag_charts_core34.ProxyPropertyOnWrite)("node")
|
|
], Caption.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property,
|
|
(0, import_ag_charts_core34.ProxyPropertyOnWrite)("node")
|
|
], Caption.prototype, "fontFamily", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property,
|
|
(0, import_ag_charts_core34.ProxyPropertyOnWrite)("node", "fill")
|
|
], Caption.prototype, "color", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property
|
|
], Caption.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property
|
|
], Caption.prototype, "maxWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property
|
|
], Caption.prototype, "maxHeight", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property
|
|
], Caption.prototype, "wrapping", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property
|
|
], Caption.prototype, "padding", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core34.Property
|
|
], Caption.prototype, "layoutStyle", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/chartAxes.ts
|
|
var import_ag_charts_core35 = require("ag-charts-core");
|
|
var ChartAxes = class extends Array {
|
|
destroy() {
|
|
for (const axis of this) {
|
|
axis.destroy();
|
|
}
|
|
this.length = 0;
|
|
}
|
|
findById(id) {
|
|
return this.find((a) => a.id === id);
|
|
}
|
|
matches(comparison) {
|
|
return this.length === Object.keys(comparison).length && (0, import_ag_charts_core35.every)(
|
|
comparison,
|
|
(id, object5) => (0, import_ag_charts_core35.isObject)(object5) && "type" in object5 && this.findById(id)?.type === object5.type
|
|
);
|
|
}
|
|
getById(id) {
|
|
const axis = this.findById(id);
|
|
if (!axis)
|
|
throw new Error(`Could not find axis by id [${id}].`);
|
|
return axis;
|
|
}
|
|
};
|
|
var CartesianChartAxes = class extends ChartAxes {
|
|
get [import_ag_charts_core35.ChartAxisDirection.X]() {
|
|
return this.getById(import_ag_charts_core35.ChartAxisDirection.X);
|
|
}
|
|
get [import_ag_charts_core35.ChartAxisDirection.Y]() {
|
|
return this.getById(import_ag_charts_core35.ChartAxisDirection.Y);
|
|
}
|
|
perpendicular(to) {
|
|
const direction = to.direction === import_ag_charts_core35.ChartAxisDirection.X ? import_ag_charts_core35.ChartAxisDirection.Y : import_ag_charts_core35.ChartAxisDirection.X;
|
|
return this[direction];
|
|
}
|
|
};
|
|
var PolarChartAxes = class extends ChartAxes {
|
|
get [import_ag_charts_core35.ChartAxisDirection.Angle]() {
|
|
return this.getById(import_ag_charts_core35.ChartAxisDirection.Angle);
|
|
}
|
|
get [import_ag_charts_core35.ChartAxisDirection.Radius]() {
|
|
return this.getById(import_ag_charts_core35.ChartAxisDirection.Radius);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/chartCaptions.ts
|
|
var import_ag_charts_core36 = require("ag-charts-core");
|
|
var ChartCaptions = class {
|
|
constructor() {
|
|
this.title = new Caption();
|
|
this.subtitle = new Caption();
|
|
this.footnote = new Caption();
|
|
}
|
|
positionCaptions({ layoutBox }) {
|
|
const { title, subtitle, footnote } = this;
|
|
const maxHeight = layoutBox.height / 10;
|
|
if (title.enabled) {
|
|
this.positionCaption("top", title, layoutBox, maxHeight);
|
|
this.shrinkLayoutByCaption("top", title, layoutBox);
|
|
}
|
|
if (subtitle.enabled) {
|
|
this.positionCaption("top", subtitle, layoutBox, maxHeight);
|
|
this.shrinkLayoutByCaption("top", subtitle, layoutBox);
|
|
}
|
|
if (footnote.enabled) {
|
|
this.positionCaption("bottom", footnote, layoutBox, maxHeight);
|
|
this.shrinkLayoutByCaption("bottom", footnote, layoutBox);
|
|
}
|
|
}
|
|
positionAbsoluteCaptions(ctx) {
|
|
const { title, subtitle, footnote } = this;
|
|
const { rect: rect2 } = ctx.series;
|
|
for (const caption of [title, subtitle, footnote]) {
|
|
if (caption.layoutStyle !== "overlay")
|
|
continue;
|
|
if (caption.textAlign === "left") {
|
|
caption.node.x = rect2.x + caption.padding;
|
|
} else if (caption.textAlign === "right") {
|
|
const bbox = caption.node.getBBox();
|
|
caption.node.x = rect2.x + rect2.width - bbox.width - caption.padding;
|
|
}
|
|
}
|
|
}
|
|
computeX(align2, layoutBox) {
|
|
if (align2 === "left") {
|
|
return layoutBox.x;
|
|
} else if (align2 === "right") {
|
|
return layoutBox.x + layoutBox.width;
|
|
}
|
|
return layoutBox.x + layoutBox.width / 2;
|
|
}
|
|
positionCaption(vAlign, caption, layoutBox, maxHeight) {
|
|
if (!caption.text)
|
|
return;
|
|
const { lineMetrics } = (0, import_ag_charts_core36.isArray)(caption.text) ? (0, import_ag_charts_core36.measureTextSegments)(caption.text, caption) : (0, import_ag_charts_core36.cachedTextMeasurer)(caption).measureLines((0, import_ag_charts_core36.toTextString)(caption.text));
|
|
const containerHeight = Math.max(lineMetrics[0].height, maxHeight);
|
|
caption.node.x = this.computeX(caption.textAlign, layoutBox) + caption.padding;
|
|
caption.node.y = layoutBox.y + (vAlign === "top" ? 0 : layoutBox.height) + caption.padding;
|
|
caption.node.textBaseline = vAlign;
|
|
caption.computeTextWrap(layoutBox.width, containerHeight);
|
|
}
|
|
shrinkLayoutByCaption(vAlign, caption, layoutBox) {
|
|
if (caption.layoutStyle === "block") {
|
|
const bbox = caption.node.getBBox().clone();
|
|
const { spacing = 0 } = caption;
|
|
if (vAlign === "bottom" && (0, import_ag_charts_core36.isArray)(caption.text)) {
|
|
bbox.y -= bbox.height;
|
|
}
|
|
layoutBox.shrink(
|
|
vAlign === "top" ? Math.ceil(bbox.y - layoutBox.y + bbox.height + spacing) : Math.ceil(layoutBox.y + layoutBox.height - bbox.y + spacing),
|
|
vAlign
|
|
);
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core36.Property
|
|
], ChartCaptions.prototype, "title", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core36.Property
|
|
], ChartCaptions.prototype, "subtitle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core36.Property
|
|
], ChartCaptions.prototype, "footnote", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/chartContext.ts
|
|
var import_ag_charts_core98 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/api/preset/chartTypeOriginator.ts
|
|
var import_ag_charts_core37 = require("ag-charts-core");
|
|
var chartTypes = [
|
|
"candlestick",
|
|
"hollow-candlestick",
|
|
"ohlc",
|
|
"line",
|
|
"step-line",
|
|
"hlc",
|
|
"high-low"
|
|
];
|
|
var ChartTypeOriginator = class {
|
|
constructor(chartService) {
|
|
this.chartService = chartService;
|
|
this.mementoOriginatorKey = "chartType";
|
|
}
|
|
createMemento() {
|
|
let chartType = this.chartService.publicApi?.getOptions()?.chartType;
|
|
chartType ?? (chartType = "candlestick");
|
|
return chartType;
|
|
}
|
|
guardMemento(blob) {
|
|
return blob == null || chartTypes.includes(blob);
|
|
}
|
|
restoreMemento(_version, _mementoVersion, memento) {
|
|
if (memento == null)
|
|
return;
|
|
const options = { chartType: memento };
|
|
this.chartService.publicApi?.updateDelta(options).catch((e) => import_ag_charts_core37.Logger.error("error restoring state", e));
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/api/state/historyManager.ts
|
|
var import_ag_charts_core38 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/version.ts
|
|
var VERSION = "13.1.0";
|
|
|
|
// packages/ag-charts-community/src/api/state/historyManager.ts
|
|
var NOT_FOUND = Symbol("previous-memento-not-found");
|
|
var HistoryManager = class {
|
|
constructor(eventsHub) {
|
|
this.history = [];
|
|
this.historyIndex = -1;
|
|
this.originators = /* @__PURE__ */ new Map();
|
|
this.clearState = /* @__PURE__ */ new Map();
|
|
this.maxHistoryLength = 100;
|
|
this.debug = import_ag_charts_core38.Debug.create(true, "history");
|
|
this.cleanup = new import_ag_charts_core38.CleanupRegistry();
|
|
this.cleanup.register(
|
|
eventsHub.on("series:undo", this.undo.bind(this)),
|
|
eventsHub.on("series:redo", this.redo.bind(this))
|
|
);
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
addMementoOriginator(originator) {
|
|
this.originators.set(originator.mementoOriginatorKey, originator);
|
|
this.clearState.set(originator.mementoOriginatorKey, originator.createMemento());
|
|
this.debugEvent("History add originator:", originator.mementoOriginatorKey);
|
|
}
|
|
clear() {
|
|
this.debug(`History clear:`, Object.keys(this.originators));
|
|
this.history = [];
|
|
this.historyIndex = -1;
|
|
for (const [mementoOriginatorKey, originator] of this.originators.entries()) {
|
|
this.clearState.set(mementoOriginatorKey, originator.createMemento());
|
|
}
|
|
}
|
|
record(label, ...originators) {
|
|
if (this.historyIndex < this.history.length - 1) {
|
|
this.history = this.history.slice(0, this.historyIndex + 1);
|
|
}
|
|
if (this.history.length > this.maxHistoryLength) {
|
|
this.history = this.history.slice(-this.maxHistoryLength);
|
|
}
|
|
const mementos = /* @__PURE__ */ new Map();
|
|
for (const originator of originators) {
|
|
if (!this.originators.has(originator.mementoOriginatorKey)) {
|
|
throw new Error(
|
|
`Originator [${originator.mementoOriginatorKey}] has not been added to the HistoryManager.`
|
|
);
|
|
}
|
|
mementos.set(originator.mementoOriginatorKey, originator.createMemento());
|
|
}
|
|
this.history.push({ label, mementos });
|
|
this.historyIndex = this.history.length - 1;
|
|
this.debugEvent(`History record: [${label}]`);
|
|
}
|
|
undo() {
|
|
const undoAction = this.history[this.historyIndex];
|
|
if (!undoAction)
|
|
return;
|
|
for (const mementoOriginatorKey of undoAction.mementos.keys()) {
|
|
const previousMemento = this.findPreviousMemento(mementoOriginatorKey);
|
|
if (previousMemento === NOT_FOUND) {
|
|
throw new Error(`Could not find previous memento for [${mementoOriginatorKey}].`);
|
|
}
|
|
this.restoreMemento(mementoOriginatorKey, previousMemento);
|
|
}
|
|
this.historyIndex -= 1;
|
|
this.debugEvent(`History undo: [${undoAction.label}]`);
|
|
}
|
|
redo() {
|
|
const redoAction = this.history[this.historyIndex + 1];
|
|
if (!redoAction)
|
|
return;
|
|
for (const [mementoOriginatorKey, memento] of redoAction.mementos.entries()) {
|
|
this.restoreMemento(mementoOriginatorKey, memento);
|
|
}
|
|
this.historyIndex += 1;
|
|
this.debugEvent(`History redo: [${redoAction.label}]`);
|
|
}
|
|
findPreviousMemento(mementoOriginatorKey) {
|
|
for (let i = this.historyIndex - 1; i >= 0; i--) {
|
|
if (this.history[i].mementos.has(mementoOriginatorKey)) {
|
|
return this.history[i].mementos.get(mementoOriginatorKey);
|
|
}
|
|
}
|
|
if (this.clearState.has(mementoOriginatorKey)) {
|
|
return this.clearState.get(mementoOriginatorKey);
|
|
}
|
|
return NOT_FOUND;
|
|
}
|
|
restoreMemento(mementoOriginatorKey, memento) {
|
|
this.originators.get(mementoOriginatorKey)?.restoreMemento(VERSION, VERSION, memento);
|
|
}
|
|
debugEvent(...logContent) {
|
|
this.debug(
|
|
...logContent,
|
|
this.history.map((action, index) => index === this.historyIndex ? `** ${action.label} **` : action.label)
|
|
);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/api/state/stateManager.ts
|
|
var import_ag_charts_core39 = require("ag-charts-core");
|
|
var StateManager = class {
|
|
constructor() {
|
|
this.caretaker = new import_ag_charts_core39.MementoCaretaker(VERSION);
|
|
this.state = /* @__PURE__ */ new Map();
|
|
}
|
|
setState(originator, value) {
|
|
if ((0, import_ag_charts_core39.objectsEqual)(this.state.get(originator.mementoOriginatorKey), value)) {
|
|
return;
|
|
}
|
|
this.setStateAndRestore(originator, value);
|
|
}
|
|
setStateAndRestore(originator, value) {
|
|
this.state.set(originator.mementoOriginatorKey, value);
|
|
this.restoreState(originator);
|
|
}
|
|
restoreState(originator) {
|
|
const { caretaker, state } = this;
|
|
if (!state.has(originator.mementoOriginatorKey))
|
|
return;
|
|
const value = state.get(originator.mementoOriginatorKey);
|
|
caretaker.restore({ version: caretaker.version, [originator.mementoOriginatorKey]: value }, originator);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/dom/domManager.ts
|
|
var import_ag_charts_core44 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/styles.css
|
|
var styles_default = '.ag-charts-wrapper,.ag-charts-wrapper:after,.ag-charts-wrapper:before,.ag-charts-wrapper *,.ag-charts-wrapper *:after,.ag-charts-wrapper *:before{box-sizing:border-box}.ag-charts-wrapper{--align-items: center;--justify-content: center;position:relative;user-select:none;-webkit-user-select:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.ag-charts-wrapper--safe-horizontal{--justify-content: flex-start}.ag-charts-wrapper--safe-vertical{--align-items: flex-start}.ag-charts-tab-guard{width:0%;height:0%;position:absolute;pointer-events:none}.ag-charts-canvas-background{position:absolute}.ag-charts-canvas-center{width:100%;height:100%;position:absolute;touch-action:auto;pointer-events:auto;display:flex;align-items:var(--align-items);justify-content:var(--justify-content)}.ag-charts-canvas-container,.ag-charts-canvas{position:relative;user-select:none;-webkit-user-select:none}.ag-charts-canvas-container>*,.ag-charts-canvas>*{pointer-events:none}.ag-charts-canvas canvas{display:block}.ag-charts-series-area{outline:none;pointer-events:auto;position:absolute}.ag-charts-swapchain{top:0;left:0;outline:none;opacity:0;pointer-events:none;position:absolute;width:100%;height:100%}.ag-charts-swapchain:focus-visible{opacity:1}.ag-charts-canvas-proxy,.ag-charts-canvas-overlay{inset:0;pointer-events:none;position:absolute;user-select:none;-webkit-user-select:none}.ag-charts-canvas-overlay>*{position:absolute;pointer-events:auto}.ag-charts-theme-default,.ag-charts-theme-default-dark{--ag-charts-accent-color: #2196f3;--ag-charts-background-color: #fff;--ag-charts-border-color: #dddddd;--ag-charts-border-radius: 4px;--ag-charts-chart-background-color: #fff;--ag-charts-chart-padding: 20px;--ag-charts-focus-shadow: 0 0 0 3px #2196f3;--ag-charts-foreground-color: #181d1f;--ag-charts-font-family: Verdana, sans-serif;--ag-charts-font-size: 12px;--ag-charts-font-weight: 400;--ag-charts-popup-shadow: 0 0 16px rgba(0, 0, 0, .15);--ag-charts-subtle-text-color: #8c8c8c;--ag-charts-text-color: #181d1f;--ag-charts-chrome-background-color: #fafafa;--ag-charts-chrome-font-family: Verdana, sans-serif;--ag-charts-chrome-font-size: 12px;--ag-charts-chrome-font-weight: 400;--ag-charts-chrome-subtle-text-color: #8c8c8c;--ag-charts-chrome-text-color: #181d1f;--ag-charts-button-background-color: #fff;--ag-charts-button-border: 1px solid #dddddd;--ag-charts-button-font-weight: normal;--ag-charts-button-text-color: inherit;--ag-charts-input-background-color: #fff;--ag-charts-input-border: 1px solid #dddddd;--ag-charts-input-text-color: #181d1f;--ag-charts-menu-background-color: #fafafa;--ag-charts-menu-border: 1px solid #dddddd;--ag-charts-menu-text-color: #181d1f;--ag-charts-panel-background-color: #fafafa;--ag-charts-panel-text-color: #181d1f;--ag-charts-tooltip-background-color: #fafafa;--ag-charts-tooltip-border: 1px solid #dddddd;--ag-charts-tooltip-text-color: #181d1f;--ag-charts-tooltip-subtle-text-color: #8c8c8c;--ag-charts-crosshair-label-background-color: #fafafa;--ag-charts-crosshair-label-text-color: #181d1f;--ag-charts-spacing: 4px;--ag-charts-icon-size: 16px;--ag-charts-focus-color: color-mix(in srgb, var(--ag-charts-background-color), var(--ag-charts-accent-color) 12%);--ag-charts-input-border-radius: var(--ag-charts-border-radius);--ag-charts-input-focus-border-color: var(--ag-charts-accent-color);--ag-charts-input-focus-text-color: var(--ag-charts-accent-color);--ag-charts-input-disabled-background-color: color-mix( in srgb, var(--ag-charts-chrome-background-color), var(--ag-charts-foreground-color) 6% );--ag-charts-input-disabled-border-color: var(--ag-charts-border-color);--ag-charts-input-disabled-text-color: color-mix( in srgb, var(--ag-charts-chrome-background-color), var(--ag-charts-input-text-color) 50% );--ag-charts-input-placeholder-text-color: color-mix( in srgb, var(--ag-charts-input-background-color), var(--ag-charts-input-text-color) 60% );--ag-charts-button-border-radius: var(--ag-charts-border-radius);--ag-charts-button-focus-background-color: color-mix( in srgb, var(--ag-charts-button-background-color), var(--ag-charts-accent-color) 12% );--ag-charts-button-focus-border-color: var(--ag-charts-accent-color);--ag-charts-button-focus-text-color: var(--ag-charts-accent-color);--ag-charts-button-disabled-background-color: color-mix( in srgb, var(--ag-charts-chrome-background-color), var(--ag-charts-foreground-color) 6% );--ag-charts-button-disabled-border-color: var(--ag-charts-border-color);--ag-charts-button-disabled-text-color: color-mix( in srgb, var(--ag-charts-chrome-background-color), var(--ag-charts-chrome-text-color) 50% );--ag-charts-checkbox-background-color: color-mix( in srgb, var(--ag-charts-background-color), var(--ag-charts-foreground-color) 35% );--ag-charts-checkbox-checked-background-color: var(--ag-charts-accent-color);--ag-charts-tooltip-border-radius: var(--ag-charts-border-radius);--ag-charts-menu-border-radius: var(--ag-charts-border-radius);--ag-charts-chrome-font-size-small: var(--ag-charts-chrome-font-size);--ag-charts-chrome-font-size-medium: calc(var(--ag-charts-chrome-font-size) * (13 / 12));--ag-charts-chrome-font-size-large: calc(var(--ag-charts-chrome-font-size) * (14 / 12));--ag-charts-border: 1px solid var(--ag-charts-border-color);--ag-charts-focus-border: 1px solid var(--ag-charts-accent-color);--ag-charts-focus-border-shadow: 0 0 0 3px color-mix(in srgb, transparent, var(--ag-charts-accent-color) 20%);--ag-charts-layer-menu: 6;--ag-charts-layer-ui-overlay: 5;--ag-charts-layer-tooltip: 4;--ag-charts-layer-toolbar: 3;--ag-charts-layer-crosshair: 2;--ag-charts-layer-annotations: 1}.ag-charts-theme-default-dark{--ag-charts-focus-color: color-mix(in srgb, var(--ag-charts-background-color), var(--ag-charts-accent-color) 22%)}.ag-chart-canvas-wrapper .ag-charts-theme-default{--ag-charts-border-radius: var(--ag-border-radius, 4px);--ag-charts-border: var(--ag-borders-critical, solid 1px) var(--ag-charts-border-color);--ag-charts-focus-shadow: var(--ag-focus-shadow, 0 0 0 3px var(--ag-charts-accent-color));--ag-charts-focus-border-shadow: var( --ag-focus-shadow, 0 0 0 3px color-mix(in srgb, transparent, var(--ag-charts-accent-color) 20%) )}.ag-charts-icon{display:block;width:20px;height:20px;speak:none;speak:never;mask:var(--icon) center / contain no-repeat;background-color:currentColor;transition:background-color .25s ease-in-out}.ag-charts-icon-align-center{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNNyAxMGg2djFIN3pNNCA3aDEydjFINHptMSA2aDEwdjFINXoiLz48L3N2Zz4=)}.ag-charts-icon-align-left{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNNCAxMGg2djFINHptMC0zaDEydjFINHptMCA2aDEwdjFINHoiLz48L3N2Zz4=)}.ag-charts-icon-align-right{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMTAgMTBoNnYxaC02ek00IDdoMTJ2MUg0em0yIDZoMTB2MUg2eiIvPjwvc3ZnPg==)}.ag-charts-icon-arrow-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTE1LjI5MyA0LjVIMTIuNXYtMUgxN3Y0aC0xVjUuMjA3bC05LjY0NiA5LjY0Ny0uNzA4LS43MDh6IiBmaWxsPSIjMDAwIi8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03IDE2YTIuNSAyLjUgMCAxIDEtNSAwIDIuNSAyLjUgMCAwIDEgNSAwbS0yLjUgMS41YTEuNSAxLjUgMCAxIDAgMC0zIDEuNSAxLjUgMCAwIDAgMCAzIiBmaWxsPSIjMDAwIi8+PC9zdmc+)}.ag-charts-icon-arrow-down-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik02IDhMMS41IDhMMTAgMThMMTguNSA4TDE0IDhMMTQgM0w2IDNMNiA4Wk03IDRMNyA5SDMuNjYyNDRMMTAgMTYuNDU2TDE2LjMzNzYgOUwxMyA5TDEzIDRMNyA0WiIgZmlsbD0iYmxhY2siLz4KPC9zdmc+Cg==)}.ag-charts-icon-arrow-up-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNCAxMkgxOC41TDEwIDJMMS41IDEySDZMNi4wMDAwMiAxN0gxNFYxMlpNMTMgMTZWMTFIMTYuMzM3NkwxMCAzLjU0NDA1TDMuNjYyNDQgMTFIN0w3LjAwMDAyIDE2SDEzWiIgZmlsbD0iYmxhY2siLz4KPC9zdmc+Cg==)}.ag-charts-icon-callout-annotation{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMyA0LjVBMS41IDEuNSAwIDAgMSA0LjUgM2gxMUExLjUgMS41IDAgMCAxIDE3IDQuNXY4YTEuNSAxLjUgMCAwIDEtMS41IDEuNWgtNC41MTRhMjYgMjYgMCAwIDAtMi4wMTcgMS41NGwtLjMxNC4yNmMtLjU1LjQ1Ny0xLjExNS45MjYtMS43NiAxLjQtLjY2OS40OTEtMS41NjItLjAxMi0xLjU2Mi0uOFYxNEg0LjVBMS41IDEuNSAwIDAgMSAzIDEyLjV6TTQuNSA0YS41LjUgMCAwIDAtLjUuNXY4YS41LjUgMCAwIDAgLjUuNWgxLjgzM3YzLjM3MmEzNiAzNiAwIDAgMCAxLjY3OC0xLjMzOGwuMzItLjI2NWEyNiAyNiAwIDAgMSAyLjIyNS0xLjY4NWwuMTI2LS4wODRIMTUuNWEuNS41IDAgMCAwIC41LS41di04YS41LjUgMCAwIDAtLjUtLjV6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ag-charts-icon-candlestick-series{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNyAxdjNoMnYxMkg3djNINnYtM0g0VjRoMlYxek01IDVoM3YxMEg1ek0xMSAxNFY2aDJWMy4yNWgxVjZoMnY4aC0ydjIuNzVoLTFWMTR6bTEtN2gzdjZoLTN6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ag-charts-icon-close{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNSA1IDEwIDEwTTUgMTUgMTUgNSIgc3Ryb2tlPSIjMDAwIi8+PC9zdmc+)}.ag-charts-icon-comment-annotation{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNy41MTMgMy45OTVhNi41IDYuNSAwIDAgMSA2LjA5OCAxMS40MWMtLjU4OC4zOTMtMS4yMTcuNTM2LTEuODI5LjU4NWExMyAxMyAwIDAgMS0xLjI3LjAxN0EyNyAyNyAwIDAgMCAxMCAxNkg0LjVhLjUuNSAwIDAgMS0uNS0uNVYxMHEwLS4yNDctLjAwNy0uNTEzYy0uMDA4LS40MTYtLjAxNi0uODU3LjAxNy0xLjI2OS4wNS0uNjEyLjE5Mi0xLjI0LjU4NS0xLjgzYTYuNSA2LjUgMCAwIDEgMi45MTgtMi4zOTNtMy41Ni42MWE1LjUgNS41IDAgMCAwLTUuNjQ2IDIuMzRjLS4yNjYuMzk3LS4zNzkuODQyLS40MiAxLjM1NC0uMDMuMzYtLjAyMi43MTgtLjAxNSAxLjEwOFE1IDkuNjg5IDUgMTB2NWg1cS4zMTEuMDAxLjU5My4wMDhjLjM5LjAwNy43NDcuMDE1IDEuMTA4LS4wMTUuNTEyLS4wNDEuOTU3LS4xNTQgMS4zNTUtLjQyYTUuNSA1LjUgMCAwIDAtMS45ODMtOS45NjciIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-crosshair-add-line{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZD0iTTEwIDUuNWEuNS41IDAgMCAxIC41LjV2My41aDMuODc1YS41LjUgMCAwIDEgMCAxSDEwLjV2NC4yNWEuNS41IDAgMSAxLTEgMFYxMC41SDUuNjI1YS41LjUgMCAxIDEgMC0xSDkuNVY2YS41LjUgMCAwIDEgLjUtLjUiLz48L3N2Zz4=)}.ag-charts-icon-date-range-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMiAyaDF2MTZIMnptMTUgMGgxdjE2aC0xeiIgZmlsbD0iIzE4MUQxRiIvPjxwYXRoIGQ9Ik0xMy4xNTcgMTFINXYtMWg3Ljc5M0wxMSA4LjIwN2wuNzA3LS43MDcgMy4xODIgMy4xODItMy4xODIgMy4xODItLjcwNy0uNzA3eiIgZmlsbD0iIzAwMCIvPjwvc3ZnPg==)}.ag-charts-icon-date-price-range-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMyAySDJ2MTZoMXptMy41MDcgNC44OUw4LjUgNC44OTVWMTBINXYxaDMuNXY3aDF2LTdoNS4wODhsLTEuOTU3IDEuOTU3LjcwNy43MDcgMy4xODItMy4xODJMMTMuMzM4IDcuM2wtLjcwNy43MDdMMTQuNjI0IDEwSDkuNVY0LjkzMmwxLjk1NyAxLjk1Ny43MDctLjcwN0w4Ljk4MiAzIDUuOCA2LjE4MnoiIGZpbGw9IiMxODFEMUYiLz48L3N2Zz4=)}.ag-charts-icon-delete{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZD0iTTguNDk2IDguOTk2QS41LjUgMCAwIDEgOSA5LjQ5MnY0YS41LjUgMCAxIDEtMSAuMDA4di00YS41LjUgMCAwIDEgLjQ5Ni0uNTA0TTEyIDkuNWEuNS41IDAgMCAwLTEgMHY0YS41LjUgMCAwIDAgMSAweiIvPjxwYXRoIGZpbGw9IiMxMzE3MjIiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTYgNVYzLjVBMi41IDIuNSAwIDAgMSA4LjUgMWgzQTIuNSAyLjUgMCAwIDEgMTQgMy41VjVoMi44MzNhLjUuNSAwIDAgMSAwIDFIMTV2MTAuMjVjMCAuNDE1LS4wNjYuODYzLS4zIDEuMjIxLS4yNTcuMzk0LS42NzIuNjEyLTEuMi42MTJoLTdjLS41MjggMC0uOTQzLS4yMTgtMS4yLS42MTItLjIzNC0uMzU4LS4zLS44MDYtLjMtMS4yMjFWNkgzLjMzM2EuNS41IDAgMCAxIDAtMXptMS0xLjVBMS41IDEuNSAwIDAgMSA4LjUgMmgzQTEuNSAxLjUgMCAwIDEgMTMgMy41VjVIN3pNNiAxNi4yNVY2aDh2MTAuMjVjMCAuMzM1LS4wNTkuNTU0LS4xMzguNjc1LS4wNTUuMDg1LS4xNC4xNTgtLjM2Mi4xNThoLTdjLS4yMjIgMC0uMzA3LS4wNzMtLjM2Mi0uMTU4LS4wOC0uMTIxLS4xMzgtLjM0LS4xMzgtLjY3NSIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+)}.ag-charts-icon-disjoint-channel,.ag-charts-icon-disjoint-channel-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTkuMDI4IDE3LjQ2YTIuMjUgMi4yNSAwIDAgMC00LjA5Mi0xLjg1bC05LjUxMS0yLjM3OGEyLjI1IDIuMjUgMCAxIDAtLjIyNS45NzRsOS40NzUgMi4zNjlhMi4yNTEgMi4yNTEgMCAwIDAgNC4zNTMuODg2bS0xLjY2Mi0xLjk2NWExLjI1IDEuMjUgMCAxIDEtLjg4NSAyLjMzOCAxLjI1IDEuMjUgMCAwIDEgLjg4NS0yLjMzOE00LjM0MyAxMy42NjlhMS4yNSAxLjI1IDAgMSAwLTIuMzM4LS44ODUgMS4yNSAxLjI1IDAgMCAwIDIuMzM4Ljg4NU0zLjk3IDguNzY5YTIuMjUgMi4yNSAwIDAgMCAxLjQ1NS0yLjExbDkuNTExLTIuMzc4YTIuMjUgMi4yNSAwIDEgMC0uMjYtLjk2NUw1LjIgNS42ODVhMi4yNSAyLjI1IDAgMSAwLTEuMjMgMy4wODRtLjM3My0yLjU0N2ExLjI1IDEuMjUgMCAxIDEtMi4zMzguODg1IDEuMjUgMS4yNSAwIDAgMSAyLjMzOC0uODg1bTEzLjc1LTMuNDM4YTEuMjUgMS4yNSAwIDEgMS0yLjMzOC44ODUgMS4yNSAxLjI1IDAgMCAxIDIuMzM4LS44ODUiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-drag-handle{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSI1Ljc1IiBjeT0iNy43NSIgcj0iLjc1IiBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9Ii41Ii8+PGNpcmNsZSBjeD0iOS43NSIgY3k9IjcuNzUiIHI9Ii43NSIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNSIvPjxjaXJjbGUgY3g9IjEzLjc1IiBjeT0iNy43NSIgcj0iLjc1IiBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9Ii41Ii8+PGNpcmNsZSBjeD0iMTMuNzUiIGN5PSIxMS43NSIgcj0iLjc1IiBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9Ii41Ii8+PGNpcmNsZSBjeD0iOS43NSIgY3k9IjExLjc1IiByPSIuNzUiIGZpbGw9IiMwMDAiIGZpbGwtb3BhY2l0eT0iLjUiLz48Y2lyY2xlIGN4PSI1Ljc1IiBjeT0iMTEuNzUiIHI9Ii43NSIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNSIvPjwvc3ZnPg==)}.ag-charts-icon-fibonacci-retracement-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMiA1aDEydjFIMnoiLz48Y2lyY2xlIGN4PSIxNS43NSIgY3k9IjUuNSIgcj0iMS43NSIgc3Ryb2tlPSIjMDAwIi8+PGNpcmNsZSBjeD0iNC4yNSIgY3k9IjE0LjUiIHI9IjEuNzUiIHN0cm9rZT0iIzAwMCIvPjxwYXRoIGZpbGw9IiMwMDAiIGQ9Ik0xOCAxNUg2di0xaDEyem0wLTQuNUgydi0xaDE2eiIvPjwvc3ZnPg==)}.ag-charts-icon-fibonacci-retracement-trend-based-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJtNC45OTYgMTIuNjc0IDMuMjkxLTUuNzQzLjg2OC40OTctMy4yOTEgNS43NDN6Ii8+PGNpcmNsZSBjeD0iOS43NSIgY3k9IjUuNSIgcj0iMS43NSIgc3Ryb2tlPSIjMDAwIi8+PGNpcmNsZSBjeD0iNC4zNTEiIGN5PSIxNC41IiByPSIxLjc1IiBzdHJva2U9IiMwMDAiLz48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMTggNmgtN1Y1aDd6bTAgNC41aC03di0xaDd6bTAgNC41SDZ2LTFoMTJ6Ii8+PC9zdmc+)}.ag-charts-icon-fill-color{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJtOC4wNzEgNC4wNi0uOTI0LS45MjQuNzA3LS43MDcgNy4yODggNy4yODgtNC45NSA0Ljk1YTMuNSAzLjUgMCAwIDEtNC45NSAwbC0xLjQxNC0xLjQxNGEzLjUgMy41IDAgMCAxIDAtNC45NXptLjcwNy43MDhMNC41MzYgOS4wMWEyLjUgMi41IDAgMCAwIDAgMy41MzZMNS45NSAxMy45NmEyLjUgMi41IDAgMCAwIDMuNTM1IDBsNC4yNDMtNC4yNDN6bTYuOSA3LjIwMi0uMzQ1LjM2My0uMzQ0LS4zNjNhLjUuNSAwIDAgMSAuNjg4IDBtLS4zNDUgMS4wOGE4IDggMCAwIDAtLjI4LjMyMyA0LjMgNC4zIDAgMCAwLS40MDkuNTgyYy0uMTEzLjIwMS0uMTQ0LjMyNi0uMTQ0LjM3OGEuODMzLjgzMyAwIDAgMCAxLjY2NyAwYzAtLjA1Mi0uMDMxLS4xNzctLjE0NC0uMzc4YTQuMyA0LjMgMCAwIDAtLjQxLS41ODIgOCA4IDAgMCAwLS4yOC0uMzIybS0uMzQ0LTEuMDguMzQ0LjM2My4zNDQtLjM2My4wMDIuMDAyLjAwNC4wMDQuMDEzLjAxMmE2IDYgMCAwIDEgLjIwNi4yMDhjLjEzMS4xMzYuMzA4LjMyNy40ODUuNTQ1LjE3Ni4yMTUuMzYzLjQ2Ny41MDcuNzI0LjEzNy4yNDMuMjczLjU1My4yNzMuODY4YTEuODMzIDEuODMzIDAgMSAxLTMuNjY3IDBjMC0uMzE1LjEzNi0uNjI1LjI3My0uODY4LjE0NC0uMjU3LjMzLS41MDkuNTA3LS43MjRhOSA5IDAgMCAxIC42NDUtLjcwOGwuMDQ2LS4wNDUuMDEzLS4wMTIuMDA0LS4wMDR6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ag-charts-icon-hollow-candlestick-series{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1vcGFjaXR5PSIuMTUiIGQ9Ik01IDVoM3YxMEg1eiIvPjxwYXRoIGZpbGw9IiMxMzE3MjIiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTcgMXYzaDJ2MTJIN3YzSDZ2LTNINFY0aDJWMXpNNSA1aDN2MTBINXptNyAyaDN2NmgtM3ptLTEgN1Y2aDJWMy4yNWgxVjZoMnY4aC0ydjIuNzVoLTFWMTR6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ag-charts-icon-horizontal-line,.ag-charts-icon-horizontal-line-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNLjUgOS41aDcuMzA2YTIuMjUgMi4yNSAwIDAgMSA0LjM4OCAwSDE5LjV2MWgtNy4zMDZhMi4yNSAyLjI1IDAgMCAxLTQuMzg4IDBILjV6bTkuNSAxLjc1YTEuMjUgMS4yNSAwIDEgMCAwLTIuNSAxLjI1IDEuMjUgMCAwIDAgMCAyLjUiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-line-color{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTQuMjQyIDIuNzIyYy0uNjEyIDAtMS4yLjI0My0xLjYzMi42NzVsLTEuMzQzIDEuMzQ0YS41LjUgMCAwIDAtLjExMi4xMTJMNC4wNSAxMS45NTljLS4yMDcuMjA3LS4zNi40Ni0uNDQ2Ljc0di4wMDFsLS42OSAyLjc2N3YuMDAyYS44Mi44MiAwIDAgMCAxLjAyMiAxLjAyMWguMDAybDIuNjM0LS44MjJjLjI4LS4wODUuNTM0LS4yMzcuNzQtLjQ0M2w3LjEwNy03LjEwOGEuNS41IDAgMCAwIC4xMTItLjExMmwxLjM0My0xLjM0M2EyLjMwOCAyLjMwOCAwIDAgMC0xLjYzMi0zLjk0TTE0LjEyMiA3bDEuMDQ0LTEuMDQ1YTEuMzA4IDEuMzA4IDAgMSAwLTEuODQ5LTEuODVMMTIuMjcxIDUuMTV6bS0yLjU1OC0xLjE0Mi02LjgwNyA2LjgwOWEuOC44IDAgMCAwLS4xOTYuMzI1bC0uNzUgMi40NjggMi40Ny0uNzQ5YS44LjggMCAwIDAgLjMyNS0uMTk0bDYuODA4LTYuODF6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ag-charts-icon-line-series{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJtMTcuMzYyIDQuODczLTQuNTk0IDYuNjU0LTQuODUtMy4zMTctNC4yNTEgNi45NzctLjg1NC0uNTJMNy42MTIgNi43OWw0Ljg5OSAzLjM1IDQuMDI4LTUuODM2eiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+)}.ag-charts-icon-line-style-dashed{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMiA5aDR2MUgyem0xMiAwaDR2MWgtNHpNOCA5aDR2MUg4eiIvPjwvc3ZnPg==)}.ag-charts-icon-line-style-dotted{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSIyLjUiIGN5PSI5LjUiIHI9Ii41IiBmaWxsPSIjMDAwIi8+PGNpcmNsZSBjeD0iNC41IiBjeT0iOS41IiByPSIuNSIgZmlsbD0iIzAwMCIvPjxjaXJjbGUgY3g9IjYuNSIgY3k9IjkuNSIgcj0iLjUiIGZpbGw9IiMwMDAiLz48Y2lyY2xlIGN4PSI4LjUiIGN5PSI5LjUiIHI9Ii41IiBmaWxsPSIjMDAwIi8+PGNpcmNsZSBjeD0iMTAuNSIgY3k9IjkuNSIgcj0iLjUiIGZpbGw9IiMwMDAiLz48Y2lyY2xlIGN4PSIxMi41IiBjeT0iOS41IiByPSIuNSIgZmlsbD0iIzAwMCIvPjxjaXJjbGUgY3g9IjE0LjUiIGN5PSI5LjUiIHI9Ii41IiBmaWxsPSIjMDAwIi8+PGNpcmNsZSBjeD0iMTYuNSIgY3k9IjkuNSIgcj0iLjUiIGZpbGw9IiMwMDAiLz48L3N2Zz4=)}.ag-charts-icon-line-style-solid{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMiA5aDE2djFIMnoiLz48L3N2Zz4=)}.ag-charts-icon-line-with-markers-series{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJtMTguMTk4IDQuODg4LTMuNTU2IDQuOTE4YTIuMjUgMi4yNSAwIDEgMS0zLjg2Ni43NWwtMS40MzItLjlhMi4yNCAyLjI0IDAgMCAxLTIuMDA5LjQzNWwtMy44MjggNi40MjgtLjg2LS41MTJMNi40NSA5LjYyM2EyLjI1IDIuMjUgMCAxIDEgMy41MS0uNzYxbDEuMzI5LjgzNWEyLjI0IDIuMjQgMCAwIDEgMi41NTctLjQ5N2wzLjU0Mi00Ljg5OHptLTQuOTYgNS4xNTNhMS4yNSAxLjI1IDAgMSAwLS42NCAyLjQxOSAxLjI1IDEuMjUgMCAwIDAgLjY0LTIuNDE5TTkuMSA4LjMyMXEuMDY2LS4xOTIuMDY3LS40MDRhMS4yNSAxLjI1IDAgMSAwLS4wNjcuNDA0IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ag-charts-icon-lock,.ag-charts-icon-locked{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTAuMjA3IDMuNzY0YTIuODk0IDIuODk0IDAgMCAwLTIuODk1IDIuODk0VjloNS43ODlWNi42NThhMi44OTQgMi44OTQgMCAwIDAtMi44OTUtMi44OTRNMTQuMSA5VjYuNjU4YTMuODk0IDMuODk0IDAgMSAwLTcuNzg5IDB2Mi4zNDlBMi41IDIuNSAwIDAgMCA0IDExLjV2M0EyLjUgMi41IDAgMCAwIDYuNSAxN2g4YTIuNSAyLjUgMCAwIDAgMi41LTIuNXYtM0EyLjUgMi41IDAgMCAwIDE0LjUgOXpNNi41IDEwQTEuNSAxLjUgMCAwIDAgNSAxMS41djNBMS41IDEuNSAwIDAgMCA2LjUgMTZoOGExLjUgMS41IDAgMCAwIDEuNS0xLjV2LTNhMS41IDEuNSAwIDAgMC0xLjUtMS41eiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+)}.ag-charts-icon-measurer-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0ibTQuNDYxIDEyLjcxIDEuNTMyLTEuNTMxIDEuNDE0IDEuNDE0LjcwNy0uNzA3TDYuNyAxMC40NzJsMS41MzItMS41MzMgMiAyIC43MDctLjcwNy0yLTIgNi4wMS02LjAxIDIuODMgMi44MjhMNS4wNSAxNy43NzggMi4yMjIgMTQuOTVsMS41MzItMS41MzIgMS40MTQgMS40MTQuNzA3LS43MDd6TS44MDggMTQuOTVsLjcwNy0uNzA3TDE0LjI0MyAxLjUxNWwuNzA3LS43MDcuNzA3LjcwNyAyLjgyOCAyLjgyOC43MDcuNzA3LS43MDcuNzA3TDUuNzU3IDE4LjQ4NWwtLjcwNy43MDctLjcwNy0uNzA3LTIuODI4LTIuODI4em0xMS4wNzgtNi44MzVMMTAuNDcgNi43bC43MDctLjcwNyAxLjQxNSAxLjQxNHptLjgyNC0zLjY1NCAxIDEgLjcwOC0uNzA3LTEtMXoiIGZpbGw9IiMxODFEMUYiLz48L3N2Zz4=)}.ag-charts-icon-note-annotation{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMyA0LjVBMS41IDEuNSAwIDAgMSA0LjUgM2gxMUExLjUgMS41IDAgMCAxIDE3IDQuNXY4YTEuNSAxLjUgMCAwIDEtMS41IDEuNWgtMy4yMWwtMS40NjkgMi41N2ExIDEgMCAwIDEtMS42ODIuMDg1TDcuMjQzIDE0SDQuNUExLjUgMS41IDAgMCAxIDMgMTIuNXpNNC41IDRhLjUuNSAwIDAgMC0uNS41djhhLjUuNSAwIDAgMCAuNS41aDMuMjU3bDIuMTk2IDMuMDc0TDExLjcxIDEzaDMuNzlhLjUuNSAwIDAgMCAuNS0uNXYtOGEuNS41IDAgMCAwLS41LS41eiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNi41IDYuNUEuNS41IDAgMCAxIDcgNmg2YS41LjUgMCAwIDEgMCAxSDdhLjUuNSAwIDAgMS0uNS0uNU02LjUgOS41QS41LjUgMCAwIDEgNyA5aDZhLjUuNSAwIDAgMSAwIDFIN2EuNS41IDAgMCAxLS41LS41IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ag-charts-icon-ohlc-series{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZD0iTTEzIDExaC0zdi0xaDNWM2gxdjJoNHYxaC00djExaC0xek02IDE3di0yaDN2LTFINlY0SDV2MUgydjFoM3YxMXoiLz48L3N2Zz4=)}.ag-charts-icon-pan-end{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZD0ibTYuNjQ2IDEzLjgxMy0uMzUzLjM1NC43MDcuNzA3LjM1NC0uMzU0ek0xMS4xNjYgMTBsLjM1NC4zNTQuMzU0LS4zNTQtLjM1NC0uMzU0ek03LjM1NSA1LjQ4IDcgNS4xMjZsLS43MDcuNzA3LjM1My4zNTR6bTAgOS4wNCA0LjE2Ni00LjE2Ni0uNzA3LS43MDgtNC4xNjcgNC4xNjd6bTQuMTY2LTQuODc0TDcuMzU0IDUuNDhsLS43MDguNzA3IDQuMTY3IDQuMTY3ek0xMy4wODMgNXYxMGgxVjV6Ii8+PC9zdmc+)}.ag-charts-icon-pan-left{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTIuNzkgNS44MzMgOC42MjUgMTBsNC4xNjYgNC4xNjctLjcwNy43MDdMNy4yMSAxMGw0Ljg3My00Ljg3NHoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-pan-right{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNy4yMSAxNC4xNjcgMTEuMzc2IDEwIDcuMjEgNS44MzNsLjcwNy0uNzA3TDEyLjc5IDEwbC00Ljg3MyA0Ljg3NHoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-pan-start{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZD0iTTYgNXYxMGgxVjV6TTkuNjI0IDEwbDQuMTY2LTQuMTY3LS43MDctLjcwN0w4LjIxIDEwbDQuODc0IDQuODc0LjcwNy0uNzA3eiIvPjwvc3ZnPg==)}.ag-charts-icon-parallel-channel,.ag-charts-icon-parallel-channel-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTcuNzIgNS4zMzFBMi4yNSAyLjI1IDAgMSAwIDE0LjcwNSAzLjZsLTkuNDkgNC41NjJhMi4yNSAyLjI1IDAgMSAwIC4yMDkgMS4wMWw5LjY2Mi00LjY0NmEyLjI1IDIuMjUgMCAwIDAgMi42MzQuODA1bS4zNzMtMi41NDdhMS4yNSAxLjI1IDAgMSAxLTIuMzM4Ljg4NSAxLjI1IDEuMjUgMCAwIDEgMi4zMzgtLjg4NU00LjM0MyA4LjY3YTEuMjUgMS4yNSAwIDEgMS0yLjMzOC44ODUgMS4yNSAxLjI1IDAgMCAxIDIuMzM4LS44ODVNNS4zMDcgMTYuNzI4YTIuMjUgMi4yNSAwIDEgMS0uNTI1LS44NThsOS45MjMtNC43N2EyLjI1IDIuMjUgMCAxIDEgLjM4MS45MjZ6bS0uOTY0LjI3NGExLjI1IDEuMjUgMCAxIDEtMi4zMzguODg1IDEuMjUgMS4yNSAwIDAgMSAyLjMzOC0uODg1bTEzLjAyMy01LjEwNmExLjI1IDEuMjUgMCAxIDAtLjg4NS0yLjMzOSAxLjI1IDEuMjUgMCAwIDAgLjg4NSAyLjMzOSIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+)}.ag-charts-icon-position-bottom{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9Ii4yNSIgZD0iTTMgMTBoMTR2MUgzem0zLTNoOHYxSDZ6Ii8+PHBhdGggZmlsbD0iIzAwMCIgZD0iTTYgMTNoOHYxSDZ6Ii8+PC9zdmc+)}.ag-charts-icon-position-center{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMyAxMGgxNHYxSDN6Ii8+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuMjUiIGQ9Ik02IDdoOHYxSDZ6bTAgNmg4djFINnoiLz48L3N2Zz4=)}.ag-charts-icon-position-top{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9Ii4yNSIgZD0iTTMgMTBoMTR2MUgzeiIvPjxwYXRoIGZpbGw9IiMwMDAiIGQ9Ik02IDdoOHYxSDZ6Ii8+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuMjUiIGQ9Ik02IDEzaDh2MUg2eiIvPjwvc3ZnPg==)}.ag-charts-icon-price-label-annotation{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNC41IDNBMS41IDEuNSAwIDAgMCAzIDQuNVYxM2ExLjUgMS41IDAgMCAwIDEuNSAxLjVoLjgzM3YuMDU3Yy4yNDItLjI5OS41OTctLjUwMyAxLS41NDhWMTMuNUg0LjVBLjUuNSAwIDAgMSA0IDEzVjQuNWEuNS41IDAgMCAxIC41LS41aDExYS41LjUgMCAwIDEgLjUuNXY4YS41LjUgMCAwIDEtLjUuNWgtNC44MThsLS4xMjYuMDg0YTI2IDI2IDAgMCAwLTIuMjI1IDEuNjg1bC0uMzIuMjY1LS4wNjguMDU2YTEuNSAxLjUgMCAwIDEtMi42MDkgMS4zNTRjLjAzMy43NjMuOTA1IDEuMjM4IDEuNTYuNzU2LjY0Ni0uNDc0IDEuMjEtLjk0MyAxLjc2MS0xLjRsLjMxMy0uMjZBMjYgMjYgMCAwIDEgMTAuOTg2IDE0SDE1LjVhMS41IDEuNSAwIDAgMCAxLjUtMS41di04QTEuNSAxLjUgMCAwIDAgMTUuNSAzeiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNOC43MTYgMTQuODE1YTIuMjUgMi4yNSAwIDEgMS00LjIxIDEuNTkzIDIuMjUgMi4yNSAwIDAgMSA0LjIxLTEuNTkzbS0xLjY2MiAxLjk2NmExLjI1IDEuMjUgMCAxIDAtLjg4NS0yLjMzOSAxLjI1IDEuMjUgMCAwIDAgLjg4NSAyLjMzOSIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+)}.ag-charts-icon-price-range-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOS4wNDYgMTVWNS44NzdoLjk0MlYxNXoiIGZpbGw9IiMxODFEMUYiLz48cGF0aCBkPSJNOS4wNDYgMTVWNS44NzdoLjk0MlYxNXoiIGZpbGw9IiMxODFEMUYiLz48cGF0aCBkPSJNOS41IDYuMjI4IDcuMTY3IDguMzc2IDYuNSA3Ljc2MiA5LjUgNWwzIDIuNzYyLS42NjcuNjE0eiIgZmlsbD0iIzAwMCIvPjxwYXRoIGQ9Ik0yIDE4di0xaDE2djF6TTIgM1YyaDE2djF6IiBmaWxsPSIjMTgxRDFGIi8+PC9zdmc+)}.ag-charts-icon-reset{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTIuMDQgNC40NDVhNS44MSA1LjgxIDAgMCAwLTcuMjU3IDIuNDUzLjUuNSAwIDAgMS0uODY1LS41MDJBNi44MSA2LjgxIDAgMSAxIDMgOS44MTNhLjUuNSAwIDAgMSAxIDAgNS44MSA1LjgxIDAgMSAwIDguMDQtNS4zNjgiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTQuMjg5IDMuMDAyYS41LjUgMCAwIDEgLjUuNXYyLjY1NWgyLjY1NWEuNS41IDAgMCAxIDAgMUg0LjI5YS41LjUgMCAwIDEtLjUtLjVWMy41MDJhLjUuNSAwIDAgMSAuNS0uNSIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+)}.ag-charts-icon-settings{--icon: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjAgMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgc3R5bGU9ImZpbGwtcnVsZTpldmVub2RkIj48cGF0aCBkPSJNMTAgMTNhMyAzIDAgMSAwIDAtNiAzIDMgMCAwIDAgMCA2bTAtMWEyIDIgMCAxIDEtLjAwMS0zLjk5OUEyIDIgMCAwIDEgMTAgMTIiLz48cGF0aCBkPSJNMi4zMSAxNC4zNDVjLS44MTctMS40OTEuMDI3LTIuNDk5LjQ3NC0yLjg2NS41MzEtLjQzNC45NjktLjM2NS45NzItMS40OC0uMDAzLTEuMTE1LS40NDEtMS4wNDYtLjk3Mi0xLjQ4MS0uNDU0LS4zNzEtMS4zMTctMS40MDUtLjQzNC0yLjkzNmwuMDA1LS4wMDljLjg4NC0xLjUyIDIuMjA3LTEuMjkgMi43NTUtMS4wODMuNjQxLjI0My44MDEuNjU2IDEuNzY4LjEwMS45NjQtLjU2LjY4Ni0uOTA0Ljc5Ni0xLjU4Mi4wOTQtLjU3OC41NTktMS44NDMgMi4zMjYtMS44NDNoLjAxYzEuNzU5LjAwNSAyLjIyMiAxLjI2NiAyLjMxNiAxLjg0My4xMS42NzgtLjE2OCAxLjAyMi43OTYgMS41ODIuOTY3LjU1NSAxLjEyNy4xNDIgMS43NjgtLjEwMS41NDktLjIwOCAxLjg3Ni0uNDM4IDIuNzYgMS4wOTJzLjAyIDIuNTY1LS40MzQgMi45MzZjLS41MzEuNDM1LS45NjkuMzY2LS45NzIgMS40ODEuMDAzIDEuMTE1LjQ0MSAxLjA0Ni45NzIgMS40OC40NTQuMzcyIDEuMzE3IDEuNDA2LjQzNCAyLjkzN2wtLjAwNS4wMDljLS44ODQgMS41Mi0yLjIwNyAxLjI5LTIuNzU1IDEuMDgzLS42NDEtLjI0My0uODAxLS42NTYtMS43NjgtLjEwMS0uOTY0LjU2LS42ODYuOTA0LS43OTYgMS41ODEtLjA5NC41NzktLjU1OSAxLjg0NC0yLjMyNiAxLjg0NGgtLjAxYy0xLjc1OS0uMDA1LTIuMjIyLTEuMjY2LTIuMzE2LTEuODQ0LS4xMS0uNjc3LjE2OC0xLjAyMS0uNzk2LTEuNTgxLS45NjctLjU1NS0xLjEyNy0uMTQyLTEuNzY4LjEwMS0uNTQ5LjIwOC0xLjg3Ni40MzgtMi43Ni0xLjA5MmwtLjAyLS4wMzZ6TTkuOTg0IDIuMTYySDEwYzEuMzU1IDAgMS4zNDIgMS4wMzkgMS4zNTMgMS40MjUuMDA4LjMxMi4wNCAxLjE2IDEuMjU5IDEuODcybC4wMTUuMDA4YzEuMjI1LjcgMS45NzYuMzA0IDIuMjUxLjE1NS4zMzctLjE4MyAxLjIyNi0uNzExIDEuOTAyLjQ0NWwuMDA4LjAxNGMuNjc4IDEuMTczLS4yMjkgMS42ODItLjU1OCAxLjg4NC0uMjY2LjE2My0uOTg0LjYxNS0uOTkxIDIuMDI3di4wMTZjLjAwNyAxLjQxMi43MjUgMS44NjQuOTkxIDIuMDI3LjMyOC4yMDEgMS4yMjkuNzA3LjU2NiAxLjg3bC0uMDA4LjAxNGMtLjY3NyAxLjE3NC0xLjU3MS42NDMtMS45MS40NTktLjI3NS0uMTQ5LTEuMDI2LS41NDUtMi4yNTEuMTU0bC0uMDE1LjAwOWMtMS4yMTkuNzEyLTEuMjUxIDEuNTYtMS4yNTkgMS44NzItLjAxMS4zODYuMDAyIDEuNDI1LTEuMzUzIDEuNDI1cy0xLjM0Mi0xLjAzOS0xLjM1My0xLjQyNWMtLjAwOC0uMzEyLS4wNC0xLjE2LTEuMjU5LTEuODcybC0uMDE1LS4wMDljLTEuMjI1LS42OTktMS45NzYtLjMwMy0yLjI1MS0uMTU0LS4zMzYuMTgzLTEuMjE5LjcwNi0xLjg5NC0uNDMybC0uMDE2LS4wMjdjLS42NzgtMS4xNzQuMjI5LTEuNjgyLjU1OC0xLjg4NC4yNjYtLjE2My45ODQtLjYxNS45OTEtMi4wMjd2LS4wMTZjLS4wMDctMS40MTItLjcyNS0xLjg2NC0uOTkxLTIuMDI3LS4zMjgtLjIwMS0xLjIyOS0uNzA3LS41NjYtMS44N2wuMDA4LS4wMTRjLjY3Ny0xLjE3NCAxLjU3MS0uNjQzIDEuOTEtLjQ1OS4yNzUuMTQ5IDEuMDI2LjU0NSAyLjI1MS0uMTU1bC4wMTUtLjAwOGMxLjIxOS0uNzEyIDEuMjUxLTEuNTYgMS4yNTktMS44NzIuMDEtLjM4NC0uMDAyLTEuNDE3IDEuMzM3LTEuNDI1Ii8+PC9zdmc+)}.ag-charts-icon-step-line-series{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzE4MUQxRiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNiA0aDV2OGgzVjhoNXYxaC00djRoLTVWNUg3djEwSDJ2LTFoNHoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-text-annotation{--icon: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00IDRIMTZWN0gxNVY1SDEwLjVWMTVIMTRWMTZINlYxNUg5LjVWNUg1VjdINFY0WiIgZmlsbD0iYmxhY2siLz4KPC9zdmc+Cg==)}.ag-charts-icon-trend-line,.ag-charts-icon-trend-line-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNS4zMTQgMTAuOTM4YTIuMjUgMi4yNSAwIDEgMSAuMDEtMWg5LjM1MmEyLjI1IDIuMjUgMCAxIDEgLjAxIDF6bS0yLjE4OS43MjlhMS4yNSAxLjI1IDAgMSAwIDAtMi41IDEuMjUgMS4yNSAwIDAgMCAwIDIuNW0xMy43NSAwYTEuMjUgMS4yNSAwIDEgMCAwLTIuNSAxLjI1IDEuMjUgMCAwIDAgMCAyLjUiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-unlock,.ag-charts-icon-unlocked{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTAuNjUxIDMuNWEyLjg5NCAyLjg5NCAwIDAgMC0yLjg5NCAyLjg5NFY5SDE0LjVhMi41IDIuNSAwIDAgMSAyLjUgMi41djNhMi41IDIuNSAwIDAgMS0yLjUgMi41aC04QTIuNSAyLjUgMCAwIDEgNCAxNC41di0zQTIuNSAyLjUgMCAwIDEgNi41IDloLjI1N1Y2LjM5NGEzLjg5NCAzLjg5NCAwIDEgMSA3Ljc4OSAwIC41LjUgMCAwIDEtMSAwQTIuODk0IDIuODk0IDAgMCAwIDEwLjY1IDMuNU02LjUgMTBBMS41IDEuNSAwIDAgMCA1IDExLjV2M0ExLjUgMS41IDAgMCAwIDYuNSAxNmg4YTEuNSAxLjUgMCAwIDAgMS41LTEuNXYtM2ExLjUgMS41IDAgMCAwLTEuNS0xLjV6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ag-charts-icon-vertical-line,.ag-charts-icon-vertical-line-drawing{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTAuNSA3LjgwNmEyLjI1IDIuMjUgMCAwIDEgMCA0LjM4OFYxOS41aC0xdi03LjMwNmEyLjI1IDIuMjUgMCAwIDEgMC00LjM4OFYuNWgxem0tLjUuOTQ0YTEuMjUgMS4yNSAwIDEgMSAwIDIuNSAxLjI1IDEuMjUgMCAwIDEgMC0yLjUiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-zoom-in{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZD0iTTEwIDUuNWEuNS41IDAgMCAxIC41LjV2My41aDMuODc1YS41LjUgMCAwIDEgMCAxSDEwLjV2NC4yNWEuNS41IDAgMSAxLTEgMFYxMC41SDUuNjI1YS41LjUgMCAxIDEgMC0xSDkuNVY2YS41LjUgMCAwIDEgLjUtLjUiLz48L3N2Zz4=)}.ag-charts-icon-zoom-out{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNS41IDEwYS41LjUgMCAwIDEgLjUtLjVoOGEuNS41IDAgMCAxIDAgMUg2YS41LjUgMCAwIDEtLjUtLjUiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-high-low-series{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNyA0aDJ2MTJINFY0aDNNNSA1aDN2MTBINXpNMTEgMTRWNmg1djhoLTVtMS03aDN2NmgtM3oiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==)}.ag-charts-icon-hlc-series{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzEzMTcyMiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJtMTguMTYzIDEuODM3LTUuMzM0IDExLjYyMUw2Ljk1NyA4LjEybC00LjE5OSA5LjYyMi0uOTE2LS40IDQuNzU2LTEwLjlMMTIuNDkgMTEuOCAxNy4yNTQgMS40MnoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjxwYXRoIGZpbGw9IiMwMDAiIGZpbGwtb3BhY2l0eT0iLjQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTUuODI1IDIuNzA0LjU1IDEzLjc4NWwuOTAyLjQzIDQuNzI0LTkuOTE5IDYuMDM0IDUuMDI5IDMuMjU1LTguMTQtLjkyOC0uMzctMi43NDUgNi44NnptNy44NTIgMTQuNjM2IDUuNzgtMTMuMTM5LS45MTUtLjQwMi01LjIxOSAxMS44Ni02LjAwNS01LjUwNC0zLjI3OCA3LjY0OC45Mi4zOTQgMi43MjItNi4zNTJ6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ag-charts-icon-chevron-right{--icon: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjAgMjAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03LjQ3IDUuNDdhLjc1Ljc1IDAgMCAxIDEuMDYgMGw0IDRhLjc1Ljc1IDAgMCAxIDAgMS4wNmwtNCA0YS43NS43NSAwIDAgMS0xLjA2LTEuMDZMMTAuOTQgMTAgNy40NyA2LjUzYS43NS43NSAwIDAgMSAwLTEuMDYiIGZpbGw9IiMwMDAiLz48L3N2Zz4=)}.ag-charts-icon-zoom-in-alt{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLXpvb20taW4iPjxjaXJjbGUgY3g9IjExIiBjeT0iMTEiIHI9IjgiLz48bGluZSB4MT0iMjEiIHgyPSIxNi42NSIgeTE9IjIxIiB5Mj0iMTYuNjUiLz48bGluZSB4MT0iMTEiIHgyPSIxMSIgeTE9IjgiIHkyPSIxNCIvPjxsaW5lIHgxPSI4IiB4Mj0iMTQiIHkxPSIxMSIgeTI9IjExIi8+PC9zdmc+)}.ag-charts-icon-zoom-out-alt{--icon: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLXpvb20tb3V0Ij48Y2lyY2xlIGN4PSIxMSIgY3k9IjExIiByPSI4Ii8+PGxpbmUgeDE9IjIxIiB4Mj0iMTYuNjUiIHkxPSIyMSIgeTI9IjE2LjY1Ii8+PGxpbmUgeDE9IjgiIHgyPSIxNCIgeTE9IjExIiB5Mj0iMTEiLz48L3N2Zz4=)}.ag-charts-input{--input-layer-active: 1;--input-layer-focus: 2;--input-padding: calc(var(--ag-charts-spacing) * 2);--input-padding-large: calc(var(--ag-charts-spacing) * 2.5);color:var(--ag-charts-input-text-color);font-family:var(--ag-charts-chrome-font-family);font-size:var(--ag-charts-chrome-font-size-large);transition-duration:.25s;transition-property:none;transition-timing-function:ease-out}.ag-charts-input:focus-visible{outline:var(--ag-charts-focus-border);box-shadow:var(--ag-charts-focus-border-shadow);z-index:var(--input-layer-focus)}.ag-charts-button{background:var(--ag-charts-button-background-color);border:var(--ag-charts-button-border);border-radius:var(--ag-charts-button-border-radius);color:var(--ag-charts-button-text-color);cursor:pointer;padding:var(--input-padding);transition-property:background,border-color}.ag-charts-button:hover{background:var(--ag-charts-focus-color)}.ag-charts-button:has(.ag-charts-icon){padding:2px}.ag-charts-checkbox{--checkbox-transition-duration: .1s;appearance:none;background:var(--ag-charts-checkbox-background-color);border-radius:calc(var(--ag-charts-border-radius) * 9);cursor:pointer;height:18px;margin:0;transition-duration:var(--checkbox-transition-duration);transition-property:margin;width:29px}.ag-charts-checkbox:before{display:block;background:var(--ag-charts-input-background-color);border-radius:calc(var(--ag-charts-border-radius) * 7);content:" ";height:14px;margin:2px;transition-duration:var(--checkbox-transition-duration);transition-property:margin;transition-timing-function:var(--ag-charts-input-transition-easing);width:14px}.ag-charts-checkbox:checked{background:var(--ag-charts-checkbox-checked-background-color)}.ag-charts-checkbox:checked:before{margin-left:13px}.ag-charts-select{background:var(--ag-charts-input-background-color);border:var(--ag-charts-input-border);border-radius:var(--ag-charts-input-border-radius);padding:3px 2px 4px;font-size:inherit}.ag-charts-textarea{--textarea-line-height: 1.38;background:var(--ag-charts-input-background-color);border:var(--ag-charts-input-border);border-radius:var(--ag-charts-input-border-radius);line-height:var(--textarea-line-height);font-family:var(--ag-charts-chrome-font-family);font-size:var(--ag-charts-chrome-font-size-large);padding:var(--input-padding-large) var(--input-padding)}.ag-charts-textarea::placeholder{color:var(--ag-charts-input-placeholder-text-color)}.ag-charts-proxy-container{pointer-events:none;position:absolute}.ag-charts-proxy-legend-toolbar{pointer-events:auto}.ag-charts-proxy-legend-toolbar>div[role=listitem]{pointer-events:none}.ag-charts-proxy-elem{-webkit-appearance:none;appearance:none;background:none;border:none;color:#0000;overflow:hidden;pointer-events:auto;position:absolute}.ag-charts-proxy-elem::-moz-range-thumb,.ag-charts-proxy-elem::-moz-range-track{opacity:0}.ag-charts-proxy-elem::-webkit-slider-runnable-track,.ag-charts-proxy-elem::-webkit-slider-thumb{opacity:0}.ag-charts-proxy-elem:focus-visible{outline:var(--ag-charts-focus-border);box-shadow:var(--ag-charts-focus-border-shadow)}.ag-charts-proxy-elem svg{display:block}.ag-charts-proxy-scrollbar-slider:focus-visible{outline:none;box-shadow:none}.ag-charts-proxy-scrollbar-thumb-focus{border:var(--ag-charts-focus-border);box-shadow:var(--ag-charts-focus-border-shadow);box-sizing:border-box;opacity:0;pointer-events:none}.ag-charts-proxy-scrollbar-slider:focus-visible~.ag-charts-proxy-scrollbar-thumb-focus{opacity:1}.ag-charts-focus-indicator{position:absolute;display:block;pointer-events:none;user-select:none;-webkit-user-select:none;width:100%;height:100%}.ag-charts-focus-indicator>div{position:absolute;outline:solid 1px var(--ag-charts-chrome-background-color);box-shadow:var(--ag-charts-focus-shadow)}.ag-charts-focus-indicator>svg{width:100%;height:100%;fill:none;overflow:visible}.ag-charts-focus-svg-outer-path{stroke:var(--ag-charts-chrome-background-color);stroke-width:4px}.ag-charts-focus-svg-inner-path{stroke:var(--ag-charts-accent-color);stroke-width:2px}.ag-charts-overlay{color:#181d1f;pointer-events:none}.ag-charts-overlay.ag-charts-dark-overlay{color:#fff}.ag-charts-overlay--loading{color:#8c8c8c}.ag-charts-overlay__loading-background{background:#fff;pointer-events:none}.ag-charts-overlay.ag-charts-dark-overlay .ag-charts-overlay__loading-background{background:#192232}.ag-charts-tooltip{--tooltip-arrow-size: 8px;--tooltip-row-spacing: 8px;--tooltip-column-spacing: 16px;position:fixed;inset:unset;margin:0;padding:0;overflow:visible;top:var(--top, 0px);left:var(--left, 0px);width:max-content;max-width:100%;font-family:var(--ag-charts-chrome-font-family);font-size:var(--ag-charts-chrome-font-size);font-weight:var(--ag-charts-chrome-font-weight);color:var(--ag-charts-tooltip-text-color);background:var(--ag-charts-tooltip-background-color);border:var(--ag-charts-tooltip-border);border-radius:var(--ag-charts-tooltip-border-radius);box-shadow:var(--ag-charts-popup-shadow)}.ag-charts-tooltip--compact .ag-charts-tooltip-content{--tooltip-row-spacing: 2px;--tooltip-column-spacing: 8px;padding:3px 6px}.ag-charts-tooltip--arrow-top:before,.ag-charts-tooltip--arrow-right:before,.ag-charts-tooltip--arrow-bottom:before,.ag-charts-tooltip--arrow-left:before{content:"";position:absolute;display:block;width:var(--tooltip-arrow-size);height:var(--tooltip-arrow-size);border:inherit;border-bottom-color:transparent;border-right-color:transparent;background:inherit;clip-path:polygon(0 0,100% 0,100% 1px,1px 100%,0 100%)}.ag-charts-tooltip--arrow-top:before{bottom:100%;left:50%;transform:translate(-50%) translateY(calc(var(--tooltip-arrow-size) * .5)) rotate(45deg)}.ag-charts-tooltip--arrow-bottom:before{top:100%;left:50%;transform:translate(-50%) translateY(calc(var(--tooltip-arrow-size) * -.5)) rotate(225deg)}.ag-charts-tooltip--arrow-left:before{right:100%;top:50%;transform:translateY(-50%) translate(calc(var(--tooltip-arrow-size) * .5)) rotate(315deg)}.ag-charts-tooltip--arrow-right:before{left:100%;top:50%;transform:translateY(-50%) translate(calc(var(--tooltip-arrow-size) * -.5)) rotate(135deg)}.ag-charts-tooltip--no-interaction{pointer-events:none;user-select:none;-webkit-user-select:none}.ag-charts-tooltip--wrap-always{overflow-wrap:break-word;word-break:break-word;hyphens:none}.ag-charts-tooltip--wrap-hyphenate{overflow-wrap:break-word;word-break:break-word;hyphens:auto}.ag-charts-tooltip--wrap-on-space{overflow-wrap:normal;word-break:normal}.ag-charts-tooltip--wrap-never{white-space:nowrap}.ag-charts-tooltip-heading,.ag-charts-tooltip-title,.ag-charts-tooltip-label,.ag-charts-tooltip-value{overflow:hidden;text-overflow:ellipsis}.ag-charts-tooltip-content{display:grid;grid:auto-flow minmax(1em,auto) / 1fr;padding:8px 12px;gap:var(--tooltip-row-spacing)}.ag-charts-tooltip-content:has(.ag-charts-tooltip-symbol){grid:auto-flow minmax(1em,auto) / auto 1fr}.ag-charts-tooltip-heading{grid-column:1 / -1}.ag-charts-tooltip-symbol{grid-column:1 / 2;place-self:center}.ag-charts-tooltip-symbol svg{display:block}.ag-charts-tooltip-title{grid-column:-2 / -1}.ag-charts-tooltip-row{grid-column:1 / -1;display:flex;gap:var(--tooltip-column-spacing);align-items:baseline;justify-content:space-between;overflow:hidden}.ag-charts-tooltip-row--inline{grid-column:-2 / -1}.ag-charts-tooltip-label{flex:1;min-width:0}.ag-charts-tooltip-value{min-width:0}.ag-charts-tooltip-footer{grid-column:1 / -1;color:var(--ag-charts-tooltip-subtle-text-color);text-align:center}.ag-charts-popover{position:absolute;border:var(--ag-charts-border);border-radius:var(--ag-charts-border-radius);background:var(--ag-charts-panel-background-color);color:var(--ag-charts-chrome-text-color);font-family:var(--ag-charts-chrome-font-family);font-size:var(--ag-charts-chrome-font-size);font-weight:var(--ag-charts-chrome-font-weight);box-shadow:var(--ag-charts-popup-shadow);z-index:var(--ag-charts-layer-ui-overlay)}.ag-charts-menu{--item-padding: 6px 12px;--icon-color: var(--ag-charts-menu-text-color);display:grid;grid:auto-flow auto / 1fr;column-gap:12px;font-size:var(--ag-charts-chrome-font-size)}.ag-charts-menu:has(.ag-charts-menu__icon,.ag-charts-menu__row--stroke-width-visible){grid:auto-flow auto / auto 1fr}.ag-charts-menu__row--stroke-width-visible:before{content:"";height:var(--strokeWidth);width:12px;background:var(--icon-color)}.ag-charts-menu__row--stroke-width-visible[aria-disabled=true]:before{filter:grayscale(1);opacity:.5}.ag-charts-menu__row{display:grid;grid-column:1 / -1;grid-template-columns:subgrid;align-items:center;padding:var(--item-padding)}.ag-charts-menu__row:not(.ag-charts-menu__row--active){cursor:pointer}.ag-charts-menu__row:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.ag-charts-menu__row:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.ag-charts-menu__row:focus{background:var(--ag-charts-focus-color)}.ag-charts-menu__row:focus-visible{outline:var(--ag-charts-focus-border);box-shadow:var(--ag-charts-focus-border-shadow);z-index:var(--ag-charts-layer-menu)}.ag-charts-menu__row--active{--icon-color: var(--ag-charts-accent-color);background:var(--ag-charts-focus-color);color:var(--ag-charts-accent-color)}.ag-charts-menu__label{grid-column:-1 / span 1}.ag-charts-toolbar{--toolbar-gap: calc(var(--ag-charts-spacing) * 2);--toolbar-size: 34px;--toolbar-button-padding: 6px;align-items:center;display:flex;flex-wrap:nowrap;position:absolute}.ag-charts-toolbar__button{align-items:center;background:var(--ag-charts-chrome-background-color);border:var(--ag-charts-button-border);color:var(--ag-charts-button-text-color);cursor:pointer;display:flex;font-family:var(--ag-charts-chrome-font-family);font-size:var(--ag-charts-chrome-font-size-medium);font-weight:var(--ag-charts-chrome-font-weight);justify-content:center;min-height:var(--toolbar-size);min-width:var(--toolbar-size);padding:var(--toolbar-button-padding);position:relative;transition:background-color .25s ease-in-out,border-color .25s ease-in-out,color .25s ease-in-out;white-space:nowrap}.ag-charts-toolbar__button:hover{background:var(--ag-charts-focus-color);z-index:1}.ag-charts-toolbar__button:focus-visible{outline:var(--ag-charts-focus-border);box-shadow:var(--ag-charts-focus-border-shadow);z-index:calc(var(--ag-charts-layer-ui-overlay) + 1)}.ag-charts-toolbar__button--active{background:var(--ag-charts-focus-color);border-color:var(--ag-charts-accent-color);color:var(--ag-charts-accent-color);z-index:2;+.ag-charts-toolbar__button{border-left-color:var(--ag-charts-accent-color)}}.ag-charts-toolbar__button[aria-disabled=true]{background:var(--ag-charts-button-disabled-background-color);color:var(--ag-charts-button-disabled-text-color);cursor:default}.ag-charts-toolbar--horizontal{flex-direction:row;.ag-charts-toolbar__button{border-right-width:0}.ag-charts-toolbar__button--first{border-bottom-left-radius:var(--ag-charts-border-radius);border-top-left-radius:var(--ag-charts-border-radius);margin:0}.ag-charts-toolbar__button--last{border-bottom-right-radius:var(--ag-charts-border-radius);border-top-right-radius:var(--ag-charts-border-radius);border-right-width:1px}}.ag-charts-toolbar--vertical{flex-direction:column;.ag-charts-toolbar__button{margin:-1px 0 0;max-width:100%}.ag-charts-toolbar__button--first{border-top-left-radius:var(--ag-charts-border-radius);border-top-right-radius:var(--ag-charts-border-radius);margin:0}.ag-charts-toolbar__button--last{border-bottom-left-radius:var(--ag-charts-border-radius);border-bottom-right-radius:var(--ag-charts-border-radius)}}.ag-charts-toolbar__icon+.ag-charts-toolbar__label{margin-left:var(--toolbar-gap)}.ag-charts-toolbar__icon,.ag-charts-toolbar__label{pointer-events:none}.ag-charts-floating-toolbar{border:none;display:flex;.ag-charts-toolbar{align-items:unset;position:unset}}.ag-charts-floating-toolbar__drag-handle{align-items:center;background:var(--ag-charts-chrome-background-color);border:var(--ag-charts-border);border-bottom-left-radius:var(--ag-charts-border-radius);border-top-left-radius:var(--ag-charts-border-radius);border-right-width:0;cursor:grab;display:flex;justify-content:center;min-width:24px;padding-left:0;padding-right:0}.ag-charts-floating-toolbar__drag-handle--dragging{cursor:grabbing}\n';
|
|
|
|
// packages/ag-charts-community/src/util/baseManager.ts
|
|
var import_ag_charts_core40 = require("ag-charts-core");
|
|
var BaseManager = class {
|
|
constructor() {
|
|
this.cleanup = new import_ag_charts_core40.CleanupRegistry();
|
|
this.destroyed = false;
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
this.destroyed = true;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/util/guardedElement.ts
|
|
var import_ag_charts_core41 = require("ag-charts-core");
|
|
var GuardedElement = class _GuardedElement {
|
|
constructor(element2, topTabGuard, bottomTabGuard) {
|
|
this.element = element2;
|
|
this.topTabGuard = topTabGuard;
|
|
this.bottomTabGuard = bottomTabGuard;
|
|
this.cleanup = new import_ag_charts_core41.CleanupRegistry();
|
|
this.guardTabIndex = 0;
|
|
this.hasFocus = false;
|
|
this.initTabGuard(this.topTabGuard, false);
|
|
this.initTabGuard(this.bottomTabGuard, true);
|
|
this.element.addEventListener("focus", () => this.onFocus(), { capture: true });
|
|
this.element.addEventListener("blur", (ev) => this.onBlur(ev), { capture: true });
|
|
}
|
|
set tabIndex(index) {
|
|
this.guardTabIndex = index;
|
|
if (this.guardTabIndex === 0) {
|
|
this.setGuardIndices(void 0);
|
|
} else if (!this.hasFocus) {
|
|
this.setGuardIndices(this.guardTabIndex);
|
|
}
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
initTabGuard(guard, reverse) {
|
|
this.cleanup.register((0, import_ag_charts_core41.attachListener)(guard, "focus", () => this.onTab(guard, reverse)));
|
|
}
|
|
setGuardIndices(index) {
|
|
const tabindex = index;
|
|
(0, import_ag_charts_core41.setAttribute)(this.topTabGuard, "tabindex", tabindex);
|
|
(0, import_ag_charts_core41.setAttribute)(this.bottomTabGuard, "tabindex", tabindex);
|
|
}
|
|
onFocus() {
|
|
this.hasFocus = true;
|
|
if (this.guardTabIndex !== 0) {
|
|
this.setGuardIndices(0);
|
|
}
|
|
}
|
|
onBlur({ relatedTarget }) {
|
|
const { topTabGuard: top, bottomTabGuard: bot } = this;
|
|
this.hasFocus = false;
|
|
if (this.guardTabIndex !== 0 && relatedTarget !== top && relatedTarget !== bot) {
|
|
this.setGuardIndices(this.guardTabIndex);
|
|
}
|
|
}
|
|
onTab(guard, reverse) {
|
|
if (this.guardTabIndex !== 0) {
|
|
let focusTarget;
|
|
if (guard.tabIndex === 0) {
|
|
focusTarget = this.findExitTarget(!reverse);
|
|
this.setGuardIndices(this.guardTabIndex);
|
|
} else {
|
|
focusTarget = this.findEnterTarget(reverse);
|
|
}
|
|
focusTarget?.focus();
|
|
}
|
|
}
|
|
static queryFocusable(element2, selectors) {
|
|
const myWindow = (0, import_ag_charts_core41.getWindow)();
|
|
return Array.from(element2.querySelectorAll(selectors)).filter((e) => {
|
|
if ((0, import_ag_charts_core41.isHTMLElement)(e)) {
|
|
const style = myWindow.getComputedStyle(e);
|
|
return style.display !== "none" && style.visibility !== "none";
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
findEnterTarget(reverse) {
|
|
const focusables = _GuardedElement.queryFocusable(this.element, '[tabindex="0"]');
|
|
const index = reverse ? focusables.length - 1 : 0;
|
|
return focusables[index];
|
|
}
|
|
findExitTarget(reverse) {
|
|
const focusables = _GuardedElement.queryFocusable((0, import_ag_charts_core41.getDocument)(), "[tabindex]").filter((e) => e.tabIndex > 0).sort((a, b) => a.tabIndex - b.tabIndex);
|
|
const { before, after } = _GuardedElement.findBeforeAndAfter(focusables, this.guardTabIndex);
|
|
return reverse ? before : after;
|
|
}
|
|
static findBeforeAndAfter(elements, targetTabIndex) {
|
|
let left = 0;
|
|
let right = elements.length - 1;
|
|
let before = void 0;
|
|
let after = void 0;
|
|
while (left <= right) {
|
|
const mid = Math.floor((left + right) / 2);
|
|
const currentTabIndex = elements[mid].tabIndex;
|
|
if (currentTabIndex === targetTabIndex) {
|
|
before = elements[mid - 1] || void 0;
|
|
after = elements[mid + 1] || void 0;
|
|
break;
|
|
} else if (currentTabIndex < targetTabIndex) {
|
|
before = elements[mid];
|
|
left = mid + 1;
|
|
} else {
|
|
after = elements[mid];
|
|
right = mid - 1;
|
|
}
|
|
}
|
|
return { before, after };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/util/sizeMonitor.ts
|
|
var import_ag_charts_core43 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/util/pixelRatioObserver.ts
|
|
var import_ag_charts_core42 = require("ag-charts-core");
|
|
var PixelRatioObserver = class {
|
|
constructor(callback4) {
|
|
this.callback = callback4;
|
|
this.devicePixelRatio = (0, import_ag_charts_core42.getWindow)("devicePixelRatio") ?? 1;
|
|
this.devicePixelRatioMediaQuery = void 0;
|
|
this.devicePixelRatioListener = (e) => {
|
|
if (e.matches)
|
|
return;
|
|
this.devicePixelRatio = (0, import_ag_charts_core42.getWindow)("devicePixelRatio") ?? 1;
|
|
this.unregisterDevicePixelRatioListener();
|
|
this.registerDevicePixelRatioListener();
|
|
this.callback(this.pixelRatio);
|
|
};
|
|
}
|
|
get pixelRatio() {
|
|
return this.devicePixelRatio;
|
|
}
|
|
observe() {
|
|
this.registerDevicePixelRatioListener();
|
|
}
|
|
disconnect() {
|
|
this.unregisterDevicePixelRatioListener();
|
|
}
|
|
unregisterDevicePixelRatioListener() {
|
|
this.devicePixelRatioMediaQuery?.removeEventListener("change", this.devicePixelRatioListener);
|
|
this.devicePixelRatioMediaQuery = void 0;
|
|
}
|
|
registerDevicePixelRatioListener() {
|
|
const devicePixelRatioMediaQuery = (0, import_ag_charts_core42.getWindow)("matchMedia")?.(`(resolution: ${this.pixelRatio}dppx)`);
|
|
devicePixelRatioMediaQuery?.addEventListener("change", this.devicePixelRatioListener);
|
|
this.devicePixelRatioMediaQuery = devicePixelRatioMediaQuery;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/util/sizeMonitor.ts
|
|
var SizeMonitor = class {
|
|
constructor() {
|
|
this.elements = /* @__PURE__ */ new Map();
|
|
this.documentReady = false;
|
|
this.queuedObserveRequests = [];
|
|
this.onLoad = () => {
|
|
this.documentReady = true;
|
|
for (const [el, cb] of this.queuedObserveRequests) {
|
|
this.observe(el, cb);
|
|
}
|
|
this.queuedObserveRequests = [];
|
|
this.observeWindow();
|
|
};
|
|
const ResizeObserverCtor = (0, import_ag_charts_core43.getResizeObserver)();
|
|
if (ResizeObserverCtor !== void 0) {
|
|
this.resizeObserver = new ResizeObserverCtor((entries7) => {
|
|
for (const {
|
|
target,
|
|
contentRect: { width, height }
|
|
} of entries7) {
|
|
const entry = this.elements.get(target);
|
|
this.checkSize(entry, target, width, height);
|
|
}
|
|
});
|
|
}
|
|
let animationFrame;
|
|
this.pixelRatioObserver = new PixelRatioObserver(() => {
|
|
clearTimeout(animationFrame);
|
|
animationFrame = setTimeout(() => this.checkPixelRatio(), 0);
|
|
});
|
|
this.documentReady = (0, import_ag_charts_core43.getDocument)("readyState") === "complete";
|
|
if (this.documentReady) {
|
|
this.observeWindow();
|
|
} else {
|
|
(0, import_ag_charts_core43.getWindow)()?.addEventListener("load", this.onLoad);
|
|
}
|
|
}
|
|
destroy() {
|
|
(0, import_ag_charts_core43.getWindow)()?.removeEventListener("load", this.onLoad);
|
|
this.resizeObserver?.disconnect();
|
|
this.resizeObserver = void 0;
|
|
this.pixelRatioObserver?.disconnect();
|
|
this.pixelRatioObserver = void 0;
|
|
}
|
|
observeWindow() {
|
|
this.pixelRatioObserver?.observe();
|
|
}
|
|
checkPixelRatio() {
|
|
const pixelRatio = this.pixelRatioObserver?.pixelRatio ?? 1;
|
|
for (const [element2, entry] of this.elements) {
|
|
if (entry.size != null && entry.size.pixelRatio !== pixelRatio) {
|
|
const { width, height } = entry.size;
|
|
entry.size = { width, height, pixelRatio };
|
|
entry.cb(entry.size, element2);
|
|
}
|
|
}
|
|
}
|
|
checkSize(entry, element2, width, height) {
|
|
if (!entry)
|
|
return;
|
|
if (width !== entry.size?.width || height !== entry.size?.height) {
|
|
const pixelRatio = this.pixelRatioObserver?.pixelRatio ?? 1;
|
|
entry.size = { width, height, pixelRatio };
|
|
entry.cb(entry.size, element2);
|
|
}
|
|
}
|
|
// Only a single callback is supported.
|
|
observe(element2, cb) {
|
|
if (!this.documentReady) {
|
|
this.queuedObserveRequests.push([element2, cb]);
|
|
return;
|
|
}
|
|
if (this.elements.has(element2)) {
|
|
this.removeFromQueue(element2);
|
|
} else {
|
|
this.resizeObserver?.observe(element2);
|
|
}
|
|
const entry = { cb };
|
|
this.elements.set(element2, entry);
|
|
}
|
|
unobserve(element2) {
|
|
this.resizeObserver?.unobserve(element2);
|
|
this.elements.delete(element2);
|
|
this.removeFromQueue(element2);
|
|
if (!this.elements.size) {
|
|
this.destroy();
|
|
}
|
|
}
|
|
removeFromQueue(element2) {
|
|
this.queuedObserveRequests = this.queuedObserveRequests.filter(([el]) => el !== element2);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/util/stateTracker.ts
|
|
var StateTracker = class extends Map {
|
|
constructor(defaultValue, defaultState) {
|
|
super();
|
|
this.defaultValue = defaultValue;
|
|
this.defaultState = defaultState;
|
|
}
|
|
set(key, value) {
|
|
this.delete(key);
|
|
if (value !== void 0) {
|
|
super.set(key, value);
|
|
}
|
|
delete this.cachedState;
|
|
delete this.cachedValue;
|
|
return this;
|
|
}
|
|
delete(key) {
|
|
delete this.cachedState;
|
|
delete this.cachedValue;
|
|
return super.delete(key);
|
|
}
|
|
stateId() {
|
|
this.cachedState ?? (this.cachedState = Array.from(this.keys()).pop() ?? this.defaultState);
|
|
return this.cachedState;
|
|
}
|
|
stateValue() {
|
|
this.cachedValue ?? (this.cachedValue = Array.from(this.values()).pop() ?? this.defaultValue);
|
|
return this.cachedValue;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/dom/domLayout.html
|
|
var domLayout_default = '<div role="presentation" class="ag-charts-wrapper ag-charts-styles" data-ag-charts><div role="presentation" class="ag-charts-canvas-center"><div role="presentation" class="ag-charts-canvas-container"><div role="presentation" class="ag-charts-canvas-background" aria-hidden="true"></div><div role="presentation" class="ag-charts-canvas" aria-hidden="true"></div><div role="figure" class="ag-charts-canvas-proxy"><div role="presentation" class="ag-charts-series-area"></div></div><div role="presentation" class="ag-charts-canvas-overlay ag-charts-tooltip-container"></div></div></div></div>';
|
|
|
|
// packages/ag-charts-community/src/dom/domManager.ts
|
|
var DOM_ELEMENT_CLASSES = [
|
|
"styles",
|
|
"canvas",
|
|
"canvas-background",
|
|
"canvas-center",
|
|
"canvas-container",
|
|
"canvas-overlay",
|
|
"canvas-proxy",
|
|
"series-area",
|
|
"tooltip-container"
|
|
];
|
|
var MINIMAL_DOM_ELEMENT_ROLES = /* @__PURE__ */ new Set(["styles", "canvas-container", "canvas", "tooltip-container"]);
|
|
var CONTAINER_MODIFIERS = {
|
|
safeHorizontal: "ag-charts-wrapper--safe-horizontal",
|
|
safeVertical: "ag-charts-wrapper--safe-vertical"
|
|
};
|
|
var domElementConfig = /* @__PURE__ */ new Map([
|
|
["styles", { childElementType: "style" }],
|
|
["canvas", { childElementType: "canvas" }],
|
|
["canvas-proxy", { childElementType: "div" }],
|
|
["canvas-overlay", { childElementType: "div" }],
|
|
["canvas-center", { childElementType: "div" }],
|
|
["series-area", { childElementType: "div" }],
|
|
["tooltip-container", { childElementType: "div" }]
|
|
]);
|
|
function setupObserver(element2, cb) {
|
|
if (typeof IntersectionObserver === "undefined")
|
|
return;
|
|
const observer = new IntersectionObserver(
|
|
(observedEntries) => {
|
|
for (const entry of observedEntries) {
|
|
if (entry.target === element2) {
|
|
cb(entry.intersectionRatio);
|
|
}
|
|
}
|
|
},
|
|
{ root: element2 }
|
|
);
|
|
observer.observe(element2);
|
|
return observer;
|
|
}
|
|
var NULL_DOMRECT = {
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0,
|
|
top: 0,
|
|
bottom: 0,
|
|
left: 0,
|
|
right: 0,
|
|
toJSON() {
|
|
return NULL_DOMRECT;
|
|
}
|
|
};
|
|
function createTabGuardElement(guardedElem, where) {
|
|
const div = (0, import_ag_charts_core44.createElement)("div");
|
|
div.className = "ag-charts-tab-guard";
|
|
guardedElem.insertAdjacentElement(where, div);
|
|
return div;
|
|
}
|
|
var _DOMManager = class _DOMManager extends BaseManager {
|
|
constructor(eventsHub, chart, initialContainer, styleContainer, skipCss, mode = "normal") {
|
|
super();
|
|
this.eventsHub = eventsHub;
|
|
this.chart = chart;
|
|
this.styleContainer = styleContainer;
|
|
this.skipCss = skipCss;
|
|
this.mode = mode;
|
|
this.anchorName = `--${(0, import_ag_charts_core44.createId)(this)}`;
|
|
this.styles = /* @__PURE__ */ new Map();
|
|
this.pendingContainer = void 0;
|
|
this.container = void 0;
|
|
this.documentRoot = void 0;
|
|
this.initiallyConnected = void 0;
|
|
this.containerSize = void 0;
|
|
this.sizeMonitor = new SizeMonitor();
|
|
this.cursorState = new StateTracker("default");
|
|
this.minWidth = 0;
|
|
this.minHeight = 0;
|
|
this.element = this.initDOM();
|
|
this.rootElements = this.initRootElements();
|
|
this.rootElements["canvas"].element.style.setProperty("anchor-name", this.anchorName);
|
|
let hidden = false;
|
|
this.observer = setupObserver(this.element, (intersectionRatio) => {
|
|
if (intersectionRatio === 0 && !hidden) {
|
|
this.eventsHub.emit("dom:hidden", null);
|
|
}
|
|
hidden = intersectionRatio === 0;
|
|
});
|
|
this.setSizeOptions();
|
|
this.updateContainerSize();
|
|
this.addStyles("ag-charts-community", styles_default);
|
|
this.setContainer(initialContainer);
|
|
this.cleanup.register((0, import_ag_charts_core44.stopPageScrolling)(this.element));
|
|
if (this.mode === "normal") {
|
|
const guardedElement = this.rootElements["canvas-center"].element;
|
|
if (guardedElement == null)
|
|
throw new Error("Error initializing tab guards");
|
|
const topGuard = createTabGuardElement(guardedElement, "beforebegin");
|
|
const botGuard = createTabGuardElement(guardedElement, "afterend");
|
|
this.tabGuards = new GuardedElement(guardedElement, topGuard, botGuard);
|
|
}
|
|
}
|
|
initDOM() {
|
|
if (this.mode === "normal") {
|
|
const templateEl = (0, import_ag_charts_core44.createElement)("div");
|
|
templateEl.innerHTML = domLayout_default;
|
|
return templateEl.firstChild;
|
|
}
|
|
const element2 = (0, import_ag_charts_core44.createElement)("div");
|
|
element2.role = "presentation";
|
|
element2.dataset.agCharts = "";
|
|
element2.classList.add("ag-charts-wrapper");
|
|
const seriesArea = (0, import_ag_charts_core44.createElement)("div");
|
|
element2.appendChild(seriesArea);
|
|
seriesArea.role = "presentation";
|
|
seriesArea.classList.add("ag-charts-series-area");
|
|
return element2;
|
|
}
|
|
initRootElements() {
|
|
const { mode, element: element2 } = this;
|
|
const rootElements = {};
|
|
for (const domElement of DOM_ELEMENT_CLASSES) {
|
|
const className = `ag-charts-${domElement}`;
|
|
let el;
|
|
if (mode === "normal") {
|
|
el = element2.classList.contains(className) ? element2 : element2.getElementsByClassName(className)[0];
|
|
} else if (MINIMAL_DOM_ELEMENT_ROLES.has(domElement)) {
|
|
el = element2;
|
|
} else {
|
|
el = element2.getElementsByClassName(className)[0] ?? (0, import_ag_charts_core44.createElement)("div");
|
|
}
|
|
if (el == null) {
|
|
throw new Error(`AG Charts - unable to find DOM element ${className}`);
|
|
}
|
|
rootElements[domElement] = {
|
|
element: el,
|
|
children: /* @__PURE__ */ new Map(),
|
|
listeners: []
|
|
};
|
|
}
|
|
return rootElements;
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.observer?.unobserve(this.element);
|
|
if (this.container) {
|
|
this.sizeMonitor.unobserve(this.container);
|
|
}
|
|
this.pendingContainer = void 0;
|
|
for (const el of Object.values(this.rootElements)) {
|
|
for (const c of el.children.values()) {
|
|
c.remove();
|
|
}
|
|
el.element.remove();
|
|
}
|
|
this.element.remove();
|
|
}
|
|
postRenderUpdate() {
|
|
this.updateStylesLocation();
|
|
if (this.mode === "minimal")
|
|
return;
|
|
if (this.pendingContainer == null || this.pendingContainer === this.container)
|
|
return;
|
|
if (_DOMManager.batchedUpdateContainer.length === 0) {
|
|
(0, import_ag_charts_core44.getWindow)().setTimeout(this.applyBatchedUpdateContainer.bind(this), 0);
|
|
}
|
|
_DOMManager.batchedUpdateContainer.push(this);
|
|
}
|
|
applyBatchedUpdateContainer() {
|
|
for (const manager of _DOMManager.batchedUpdateContainer) {
|
|
if (!manager.destroyed) {
|
|
manager.updateContainer();
|
|
}
|
|
}
|
|
_DOMManager.batchedUpdateContainer.splice(0);
|
|
}
|
|
updateStylesLocation() {
|
|
if (this.initiallyConnected === true || this.container?.isConnected === false)
|
|
return;
|
|
this.documentRoot = this.getShadowDocumentRoot(this.container);
|
|
this.initiallyConnected = true;
|
|
for (const id of this.rootElements["styles"].children.keys()) {
|
|
this.removeChild("styles", id);
|
|
}
|
|
for (const [id, styles] of this.styles) {
|
|
this.addStyles(id, styles);
|
|
}
|
|
}
|
|
setSizeOptions(minWidth = 300, minHeight = 300, optionsWidth, optionsHeight) {
|
|
const { style } = this.element;
|
|
style.width = `${optionsWidth ?? minWidth}px`;
|
|
style.height = `${optionsHeight ?? minHeight}px`;
|
|
this.minWidth = optionsWidth ?? minWidth;
|
|
this.minHeight = optionsHeight ?? minHeight;
|
|
this.updateContainerClassName();
|
|
}
|
|
updateContainerSize() {
|
|
const { style: centerStyle } = this.rootElements["canvas-center"].element;
|
|
centerStyle.visibility = this.containerSize == null ? "hidden" : "";
|
|
if (this.containerSize) {
|
|
centerStyle.width = `${this.containerSize.width ?? 0}px`;
|
|
centerStyle.height = `${this.containerSize.height ?? 0}px`;
|
|
} else {
|
|
centerStyle.width = "";
|
|
centerStyle.height = "";
|
|
}
|
|
this.updateContainerClassName();
|
|
}
|
|
setTabGuardIndex(tabIndex) {
|
|
if (!this.tabGuards)
|
|
return;
|
|
this.tabGuards.tabIndex = tabIndex;
|
|
}
|
|
setContainer(newContainer) {
|
|
if (newContainer === this.container)
|
|
return;
|
|
this.pendingContainer = newContainer;
|
|
if (this.mode === "minimal" || this.container == null) {
|
|
this.updateContainer();
|
|
}
|
|
}
|
|
updateContainer() {
|
|
const { pendingContainer } = this;
|
|
if (pendingContainer == null || pendingContainer === this.container)
|
|
return;
|
|
if (this.container) {
|
|
this.element.remove();
|
|
this.sizeMonitor.unobserve(this.container);
|
|
}
|
|
if (this.documentRoot != null) {
|
|
for (const id of this.rootElements["styles"].children.keys()) {
|
|
this.removeChild("styles", id);
|
|
}
|
|
}
|
|
this.container = pendingContainer;
|
|
this.pendingContainer = void 0;
|
|
this.documentRoot = this.getShadowDocumentRoot(pendingContainer);
|
|
this.initiallyConnected = pendingContainer.isConnected;
|
|
for (const [id, styles] of this.styles) {
|
|
this.addStyles(id, styles);
|
|
}
|
|
pendingContainer.appendChild(this.element);
|
|
this.sizeMonitor.observe(pendingContainer, (size) => {
|
|
this.containerSize = size;
|
|
this.updateContainerSize();
|
|
this.eventsHub.emit("dom:resize", null);
|
|
});
|
|
this.eventsHub.emit("dom:container-change", null);
|
|
}
|
|
setThemeClass(themeClassName) {
|
|
const themeClassNamePrefix = "ag-charts-theme-";
|
|
for (const className of Array.from(this.element.classList)) {
|
|
if (className.startsWith(themeClassNamePrefix) && className !== themeClassName) {
|
|
this.element.classList.remove(className);
|
|
}
|
|
}
|
|
this.element.classList.add(themeClassName);
|
|
}
|
|
setThemeParameters(params) {
|
|
for (const [key, value] of (0, import_ag_charts_core44.entries)(params)) {
|
|
let formattedValue = `${value}`;
|
|
if (key.endsWith("Size") || key.endsWith("Radius")) {
|
|
formattedValue = `${value}px`;
|
|
} else if (key.endsWith("Border") && typeof value === "boolean") {
|
|
formattedValue = value ? "var(--ag-charts-border)" : "none";
|
|
}
|
|
this.element.style.setProperty(`--ag-charts-${(0, import_ag_charts_core44.kebabCase)(key)}`, formattedValue);
|
|
}
|
|
}
|
|
updateCanvasLabel(ariaLabel) {
|
|
(0, import_ag_charts_core44.setAttribute)(this.rootElements["canvas-proxy"].element, "aria-label", ariaLabel);
|
|
}
|
|
getEventElement(defaultElem, eventType) {
|
|
const events = ["focus", "blur", "keydown", "keyup"];
|
|
return events.includes(eventType) ? this.rootElements["series-area"].element : defaultElem;
|
|
}
|
|
addEventListener(type, listener, options) {
|
|
const element2 = this.getEventElement(this.element, type);
|
|
return (0, import_ag_charts_core44.attachListener)(element2, type, listener, options);
|
|
}
|
|
removeEventListener(type, listener, options) {
|
|
this.getEventElement(this.element, type).removeEventListener(type, listener, options);
|
|
}
|
|
/** Get the main chart area client bound rect. */
|
|
getBoundingClientRect() {
|
|
return this.rootElements["canvas"].element.getBoundingClientRect();
|
|
}
|
|
/**
|
|
* Get the client bounding rect for overlay elements that might float outside the bounds of the
|
|
* main chart area.
|
|
*/
|
|
getOverlayClientRect() {
|
|
const window = (0, import_ag_charts_core44.getWindow)();
|
|
const windowBBox = new BBox(0, 0, window.innerWidth, window.innerHeight);
|
|
const containerBBox = this.getRawOverlayClientRect();
|
|
return windowBBox.intersection(containerBBox)?.toDOMRect() ?? NULL_DOMRECT;
|
|
}
|
|
getRawOverlayClientRect() {
|
|
let element2 = this.element;
|
|
const fullScreenElement = this.element.getRootNode()?.fullscreenElement;
|
|
while (element2 != null) {
|
|
let isContainer;
|
|
if (fullScreenElement != null && element2 === fullScreenElement) {
|
|
isContainer = true;
|
|
} else {
|
|
const styleMap = element2.computedStyleMap?.();
|
|
const overflowY = styleMap?.get("overflow-y")?.toString();
|
|
isContainer = overflowY === "auto" || overflowY === "scroll";
|
|
}
|
|
if (isContainer) {
|
|
return BBox.fromObject(element2.getBoundingClientRect());
|
|
}
|
|
element2 = element2.parentElement;
|
|
}
|
|
if (this.documentRoot != null)
|
|
return BBox.fromObject(this.documentRoot.getBoundingClientRect());
|
|
const { innerWidth, innerHeight } = (0, import_ag_charts_core44.getWindow)();
|
|
return new BBox(0, 0, innerWidth, innerHeight);
|
|
}
|
|
getShadowDocumentRoot(current = this.container) {
|
|
const docRoot = current?.ownerDocument?.body ?? (0, import_ag_charts_core44.getDocument)("body");
|
|
while (current != null) {
|
|
if (current === docRoot) {
|
|
return void 0;
|
|
}
|
|
if ((0, import_ag_charts_core44.isDocumentFragment)(current.parentNode)) {
|
|
return current;
|
|
}
|
|
current = current.parentNode;
|
|
}
|
|
}
|
|
getParent(domElementClass) {
|
|
return this.rootElements[domElementClass].element;
|
|
}
|
|
getChildBoundingClientRect(type) {
|
|
const { children } = this.rootElements[type];
|
|
const childRects = [];
|
|
for (const child of children.values()) {
|
|
childRects.push(BBox.fromObject(child.getBoundingClientRect()));
|
|
}
|
|
return BBox.merge(childRects);
|
|
}
|
|
isManagedChildDOMElement(el, domElementClass, id) {
|
|
const { children } = this.rootElements[domElementClass];
|
|
const search = children?.get(id);
|
|
return search != null && el.contains(search);
|
|
}
|
|
contains(element2, domElementClass) {
|
|
if (domElementClass == null)
|
|
return this.element.contains(element2);
|
|
return this.rootElements[domElementClass].element.contains(element2);
|
|
}
|
|
addStyles(id, styles) {
|
|
const dataAttribute = "data-ag-charts";
|
|
this.styles.set(id, styles);
|
|
if (this.container == null)
|
|
return;
|
|
if (this.skipCss)
|
|
return;
|
|
const checkId = (el) => {
|
|
return el.getAttribute(dataAttribute) === id;
|
|
};
|
|
const addStyleElement = (el) => {
|
|
const metaElements = /* @__PURE__ */ new Set(["TITLE", "META"]);
|
|
let skippingMetaElements = true;
|
|
let insertAfterEl;
|
|
for (const child of el.children) {
|
|
if (skippingMetaElements && metaElements.has(child.tagName)) {
|
|
insertAfterEl = child;
|
|
continue;
|
|
}
|
|
skippingMetaElements = false;
|
|
if (checkId(child))
|
|
return;
|
|
if (child.hasAttribute(dataAttribute)) {
|
|
insertAfterEl = child;
|
|
}
|
|
}
|
|
const styleEl = (0, import_ag_charts_core44.createElement)("style");
|
|
if (this.chart.styleNonce != null) {
|
|
styleEl.nonce = this.chart.styleNonce;
|
|
}
|
|
if (insertAfterEl == null) {
|
|
el.prepend(styleEl);
|
|
} else {
|
|
el.insertBefore(styleEl, insertAfterEl.nextSibling);
|
|
}
|
|
return styleEl;
|
|
};
|
|
let styleElement;
|
|
if (this.styleContainer) {
|
|
styleElement = addStyleElement(this.styleContainer);
|
|
} else if (this.initiallyConnected === false) {
|
|
styleElement = this.addChild("styles", id);
|
|
} else if (this.documentRoot == null && !_DOMManager.headStyles.has(id)) {
|
|
styleElement = addStyleElement((0, import_ag_charts_core44.getDocument)("head"));
|
|
_DOMManager.headStyles.add(id);
|
|
} else if (this.documentRoot != null) {
|
|
styleElement = this.addChild("styles", id);
|
|
}
|
|
if (styleElement == null || checkId(styleElement))
|
|
return;
|
|
styleElement.setAttribute(dataAttribute, id);
|
|
styleElement.innerHTML = styles;
|
|
}
|
|
removeStyles(id) {
|
|
this.removeChild("styles", id);
|
|
}
|
|
updateCursor(callerId, style) {
|
|
this.cursorState.set(callerId, style);
|
|
this.element.style.cursor = this.cursorState.stateValue();
|
|
}
|
|
getCursor() {
|
|
return this.element.style.cursor;
|
|
}
|
|
addChild(domElementClass, id, child, insert) {
|
|
const { element: element2, children, listeners } = this.rootElements[domElementClass];
|
|
if (!children) {
|
|
throw new Error("AG Charts - unable to create DOM elements after destroy()");
|
|
}
|
|
if (children.has(id)) {
|
|
return children.get(id);
|
|
}
|
|
const { childElementType = "div" } = domElementConfig.get(domElementClass) ?? {};
|
|
if (child && child.tagName.toLowerCase() !== childElementType.toLowerCase()) {
|
|
throw new Error("AG Charts - mismatching DOM element type");
|
|
}
|
|
const newChild = child ?? (0, import_ag_charts_core44.createElement)(childElementType);
|
|
for (const [type, fn, opts] of listeners) {
|
|
newChild.addEventListener(type, fn, opts);
|
|
}
|
|
children.set(id, newChild);
|
|
if (childElementType === "style" && this.chart.styleNonce != null) {
|
|
newChild.nonce = this.chart.styleNonce;
|
|
}
|
|
if (insert) {
|
|
const queryResult = element2.querySelector(insert.query);
|
|
if (queryResult == null) {
|
|
throw new Error(`AG Charts - addChild query failed ${insert.query}`);
|
|
}
|
|
queryResult.insertAdjacentElement(insert.where, newChild);
|
|
} else {
|
|
element2?.appendChild(newChild);
|
|
}
|
|
return newChild;
|
|
}
|
|
removeChild(domElementClass, id) {
|
|
const { children } = this.rootElements[domElementClass];
|
|
if (!children)
|
|
return;
|
|
children.get(id)?.remove();
|
|
children.delete(id);
|
|
}
|
|
incrementDataCounter(name) {
|
|
const { dataset } = this.element;
|
|
dataset[name] ?? (dataset[name] = "0");
|
|
dataset[name] = String(Number(dataset[name]) + 1);
|
|
}
|
|
setDataBoolean(name, value) {
|
|
this.element.dataset[name] = String(value);
|
|
}
|
|
setDataNumber(name, value) {
|
|
this.element.dataset[name] = String(value);
|
|
}
|
|
updateContainerClassName() {
|
|
const { element: element2, containerSize, minWidth, minHeight } = this;
|
|
element2.classList.toggle(CONTAINER_MODIFIERS.safeHorizontal, minWidth >= (containerSize?.width ?? Infinity));
|
|
element2.classList.toggle(CONTAINER_MODIFIERS.safeVertical, minHeight >= (containerSize?.height ?? Infinity));
|
|
}
|
|
};
|
|
_DOMManager.className = "DOMManager";
|
|
_DOMManager.batchedUpdateContainer = [];
|
|
_DOMManager.headStyles = /* @__PURE__ */ new Set();
|
|
var DOMManager = _DOMManager;
|
|
|
|
// packages/ag-charts-community/src/dom/proxyInteractionService.ts
|
|
var import_ag_charts_core53 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/widget/boundedTextWidget.ts
|
|
var import_ag_charts_core45 = require("ag-charts-core");
|
|
var BoundedTextWidget = class extends Widget {
|
|
constructor() {
|
|
super((0, import_ag_charts_core45.createElement)("div"));
|
|
this.textElement = (0, import_ag_charts_core45.createSvgElement)("text");
|
|
this.textElement.role = "presentation";
|
|
this.svgElement = (0, import_ag_charts_core45.createSvgElement)("svg");
|
|
this.svgElement.appendChild(this.textElement);
|
|
this.svgElement.style.width = "100%";
|
|
this.svgElement.style.opacity = "0";
|
|
this.svgElement.role = "presentation";
|
|
this.elem.appendChild(this.svgElement);
|
|
this.elem.role = "presentation";
|
|
}
|
|
set textContent(text) {
|
|
this.textElement.textContent = text;
|
|
const bboxCalculator = this.textElement;
|
|
const bbox = bboxCalculator.getBBox?.();
|
|
if (bbox) {
|
|
this.svgElement.setAttribute("viewBox", `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`);
|
|
}
|
|
}
|
|
get textContent() {
|
|
return this.textElement.textContent;
|
|
}
|
|
destructor() {
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/buttonWidget.ts
|
|
var import_ag_charts_core47 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/widget/abstractButtonWidget.ts
|
|
var import_ag_charts_core46 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/widget/expansionControllerImpl.ts
|
|
var ExpansionControllerImpl = class {
|
|
constructor(controller, getDispatcher) {
|
|
this.getDispatcher = getDispatcher;
|
|
this.onExpanded = () => {
|
|
this.controller.setAriaExpanded(true);
|
|
const dispatcher = this.getDispatcher();
|
|
if (dispatcher && this.controls) {
|
|
const event = {
|
|
type: "expand-controlled-widget",
|
|
controlled: this.controls
|
|
};
|
|
dispatcher.dispatch("expand-controlled-widget", this.controller, event);
|
|
}
|
|
};
|
|
this.onCollapsed = (e) => {
|
|
this.controller.setAriaExpanded(false);
|
|
if (e.mode === "0" /* CLOSE */) {
|
|
this.controller.focus();
|
|
}
|
|
};
|
|
controller.setAriaExpanded(false);
|
|
this.controller = controller;
|
|
}
|
|
destroy() {
|
|
this.controls?.collapse({ mode: "2" /* DESTROY */ });
|
|
this.setControlled(void 0);
|
|
}
|
|
setControlled(controls) {
|
|
if (this.controls) {
|
|
this.controls.removeListener("expand-widget", this.onExpanded);
|
|
this.controls.removeListener("collapse-widget", this.onCollapsed);
|
|
}
|
|
this.controls = controls;
|
|
if (this.controls) {
|
|
this.controller.setAriaControls(this.controls.id);
|
|
this.controls.addListener("expand-widget", this.onExpanded);
|
|
this.controls.addListener("collapse-widget", this.onCollapsed);
|
|
}
|
|
}
|
|
getControlled() {
|
|
return this.controls;
|
|
}
|
|
expandControlled(opts) {
|
|
if (!this.controller.isDisabled()) {
|
|
this.controls?.expand({
|
|
controller: this.controller,
|
|
sourceEvent: void 0,
|
|
overrideFocusVisible: opts?.overrideFocusVisible
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/abstractButtonWidget.ts
|
|
var AbstractButtonWidget = class extends Widget {
|
|
constructor(element2, role) {
|
|
super(element2);
|
|
(0, import_ag_charts_core46.setAttribute)(this.elem, "role", role);
|
|
this.setEnabled(true);
|
|
this.addListener("keydown", ({ sourceEvent }) => {
|
|
if ((0, import_ag_charts_core46.isButtonClickEvent)(sourceEvent)) {
|
|
sourceEvent.preventDefault();
|
|
this.htmlListener?.dispatch("click", this, { type: "click", device: "keyboard", sourceEvent });
|
|
}
|
|
});
|
|
}
|
|
lazyControllerImpl() {
|
|
this.controllerImpl ?? (this.controllerImpl = new ExpansionControllerImpl(this, () => this.internalListener));
|
|
return this.controllerImpl;
|
|
}
|
|
destructor() {
|
|
this.controllerImpl?.destroy();
|
|
}
|
|
setEnabled(enabled) {
|
|
(0, import_ag_charts_core46.setAttribute)(this.elem, "aria-disabled", !enabled);
|
|
}
|
|
setControlled(controls) {
|
|
return this.lazyControllerImpl().setControlled(controls);
|
|
}
|
|
getControlled() {
|
|
return this.lazyControllerImpl().getControlled();
|
|
}
|
|
expandControlled(opts) {
|
|
return this.lazyControllerImpl().expandControlled(opts);
|
|
}
|
|
addListener(type, listener) {
|
|
return super.addListener(type, (ev, current) => {
|
|
if ((type === "click" || type === "dblclick") && this.isDisabled())
|
|
return;
|
|
listener(ev, current);
|
|
});
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/buttonWidget.ts
|
|
var ButtonWidget = class extends AbstractButtonWidget {
|
|
constructor() {
|
|
super((0, import_ag_charts_core47.createElement)("button"));
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/groupWidget.ts
|
|
var import_ag_charts_core48 = require("ag-charts-core");
|
|
var GroupWidget = class extends Widget {
|
|
constructor() {
|
|
super((0, import_ag_charts_core48.createElement)("div"));
|
|
(0, import_ag_charts_core48.setAttribute)(this.elem, "role", "group");
|
|
}
|
|
destructor() {
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/listWidget.ts
|
|
var import_ag_charts_core50 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/widget/rovingTabContainerWidget.ts
|
|
var import_ag_charts_core49 = require("ag-charts-core");
|
|
var RovingTabContainerWidget = class extends Widget {
|
|
constructor(initialOrientation, role) {
|
|
super((0, import_ag_charts_core49.createElement)("div"));
|
|
this.focusedChildIndex = 0;
|
|
this.onChildFocus = (_event, child) => {
|
|
const oldFocus = this.children[this.focusedChildIndex];
|
|
this.focusedChildIndex = child.index;
|
|
oldFocus?.setTabIndex(-1);
|
|
child.setTabIndex(0);
|
|
};
|
|
this.onChildKeyDown = (event, child) => {
|
|
const rovingOrientation = this.orientation;
|
|
const [primaryKeys, secondaryKeys] = rovingOrientation === "both" ? [import_ag_charts_core49.PREV_NEXT_KEYS["horizontal"], import_ag_charts_core49.PREV_NEXT_KEYS["vertical"]] : [import_ag_charts_core49.PREV_NEXT_KEYS[rovingOrientation], void 0];
|
|
let targetIndex = -1;
|
|
if ((0, import_ag_charts_core49.hasNoModifiers)(event.sourceEvent)) {
|
|
const key = event.sourceEvent.key;
|
|
if (key === primaryKeys.nextKey || key === secondaryKeys?.nextKey) {
|
|
targetIndex = child.index + 1;
|
|
} else if (key === primaryKeys.prevKey || key === secondaryKeys?.prevKey) {
|
|
targetIndex = child.index - 1;
|
|
}
|
|
}
|
|
this.children[targetIndex]?.focus();
|
|
};
|
|
(0, import_ag_charts_core49.setAttribute)(this.elem, "role", role);
|
|
this.orientation = initialOrientation;
|
|
}
|
|
get orientation() {
|
|
return (0, import_ag_charts_core49.getAttribute)(this.elem, "aria-orientation") ?? "both";
|
|
}
|
|
set orientation(orientation) {
|
|
(0, import_ag_charts_core49.setAttribute)(this.elem, "aria-orientation", orientation === "both" ? void 0 : orientation);
|
|
}
|
|
focus() {
|
|
this.children[this.focusedChildIndex]?.focus();
|
|
}
|
|
clear() {
|
|
this.focusedChildIndex = 0;
|
|
for (const child of this.children) {
|
|
this.removeChildListeners(child);
|
|
child.parent = void 0;
|
|
}
|
|
this.elem.textContent = "";
|
|
this.children.length = 0;
|
|
}
|
|
addChildListeners(child) {
|
|
child.addListener("focus", this.onChildFocus);
|
|
child.addListener("keydown", this.onChildKeyDown);
|
|
}
|
|
removeChildListeners(child) {
|
|
child.removeListener("focus", this.onChildFocus);
|
|
child.removeListener("keydown", this.onChildKeyDown);
|
|
}
|
|
onChildAdded(child) {
|
|
this.addChildListeners(child);
|
|
child.setTabIndex(this.children.length === 1 ? 0 : -1);
|
|
}
|
|
onChildRemoved(removedChild) {
|
|
this.removeChildListeners(removedChild);
|
|
const { focusedChildIndex, children } = this;
|
|
const removedFocusedChild = focusedChildIndex === removedChild.index;
|
|
for (let i = 0; i < children.length; i++) {
|
|
const child = children[i];
|
|
if (child.index === focusedChildIndex) {
|
|
this.focusedChildIndex = i;
|
|
}
|
|
child.index = i;
|
|
}
|
|
if (removedFocusedChild) {
|
|
const newFocusChild = children[focusedChildIndex] ?? children[focusedChildIndex - 1];
|
|
if (newFocusChild) {
|
|
this.focusedChildIndex = newFocusChild.index;
|
|
newFocusChild.setTabIndex(0);
|
|
} else {
|
|
this.focusedChildIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/listWidget.ts
|
|
var ListWidget = class extends RovingTabContainerWidget {
|
|
constructor() {
|
|
super("both", "list");
|
|
this.setHidden(true);
|
|
}
|
|
destructor() {
|
|
for (const c of this.children) {
|
|
c.getElement().parentElement.remove();
|
|
}
|
|
}
|
|
addChildToDOM(child, before) {
|
|
const listItem = (0, import_ag_charts_core50.createElement)("div");
|
|
(0, import_ag_charts_core50.setAttribute)(listItem, "role", "listitem");
|
|
(0, import_ag_charts_core50.setElementStyle)(listItem, "position", "absolute");
|
|
Widget.setElementContainer(child, listItem);
|
|
this.appendOrInsert(listItem, before);
|
|
this.setHidden(false);
|
|
}
|
|
removeChildFromDOM(child) {
|
|
child.getElement().parentElement.remove();
|
|
this.setHidden(this.children.length === 0);
|
|
}
|
|
setHidden(hidden) {
|
|
if (this.children.length === 0) {
|
|
hidden = true;
|
|
}
|
|
super.setHidden(hidden);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/nativeWidget.ts
|
|
var NativeWidget = class extends Widget {
|
|
constructor(elem) {
|
|
super(elem);
|
|
}
|
|
destructor() {
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/sliderWidget.ts
|
|
var import_ag_charts_core51 = require("ag-charts-core");
|
|
var _SliderWidget = class _SliderWidget extends Widget {
|
|
constructor() {
|
|
super((0, import_ag_charts_core51.createElement)("input"));
|
|
this._step = _SliderWidget.STEP_ONE;
|
|
this.orientation = "both";
|
|
}
|
|
get step() {
|
|
return this._step;
|
|
}
|
|
set step(step) {
|
|
this._step = step;
|
|
this.getElement().step = step.attributeValue;
|
|
}
|
|
get keyboardStep() {
|
|
return this._keyboardStep?.step ?? this._step;
|
|
}
|
|
set keyboardStep(step) {
|
|
if (step === this._keyboardStep?.step)
|
|
return;
|
|
if (this._keyboardStep !== void 0) {
|
|
this.removeListener("keydown", this._keyboardStep.onKeyDown);
|
|
this.removeListener("keyup", this._keyboardStep.onKeyUp);
|
|
this.removeListener("blur", this._keyboardStep.onBlur);
|
|
this._keyboardStep = void 0;
|
|
}
|
|
if (step !== void 0) {
|
|
const onKeyDown = () => this.getElement().step = step.attributeValue;
|
|
const resetStep = () => this.getElement().step = this._step.attributeValue;
|
|
this._keyboardStep = { step, onKeyDown, onKeyUp: resetStep, onBlur: resetStep };
|
|
this.addListener("keydown", this._keyboardStep.onKeyDown);
|
|
this.addListener("keyup", this._keyboardStep.onKeyUp);
|
|
this.addListener("blur", this._keyboardStep.onBlur);
|
|
}
|
|
}
|
|
get orientation() {
|
|
return (0, import_ag_charts_core51.getAttribute)(this.elem, "aria-orientation") ?? "both";
|
|
}
|
|
set orientation(orientation) {
|
|
(0, import_ag_charts_core51.setAttribute)(this.elem, "aria-orientation", orientation === "both" ? void 0 : orientation);
|
|
_SliderWidget.registerDefaultPreventers(this, orientation);
|
|
}
|
|
destructor() {
|
|
}
|
|
clampValueRatio(clampMin, clampMax) {
|
|
const ratio10 = this.getValueRatio();
|
|
const clampedRatio = (0, import_ag_charts_core51.clamp)(clampMin, ratio10, clampMax);
|
|
if (clampedRatio !== ratio10) {
|
|
this.setValueRatio(clampedRatio);
|
|
}
|
|
return clampedRatio;
|
|
}
|
|
setValueRatio(ratio10, opts) {
|
|
const { divider } = this.step;
|
|
const value = Math.round(ratio10 * 1e4) / divider;
|
|
const { ariaValueText = (0, import_ag_charts_core51.formatPercent)(value / divider) } = opts ?? {};
|
|
const elem = this.getElement();
|
|
elem.value = `${value}`;
|
|
elem.ariaValueText = ariaValueText;
|
|
elem.ariaValueNow = `${value}`;
|
|
}
|
|
getValueRatio() {
|
|
return this.getElement().valueAsNumber / this.step.divider;
|
|
}
|
|
static registerDefaultPreventers(target, orientation) {
|
|
if (orientation === "both") {
|
|
target.removeListener("keydown", _SliderWidget.onKeyDown);
|
|
} else {
|
|
target.addListener("keydown", _SliderWidget.onKeyDown);
|
|
}
|
|
}
|
|
static onKeyDown(ev, current) {
|
|
let ignoredKeys = [];
|
|
const { orientation } = current;
|
|
if (orientation === "horizontal") {
|
|
ignoredKeys = ["ArrowUp", "ArrowDown"];
|
|
} else if (orientation === "vertical") {
|
|
ignoredKeys = ["ArrowLeft", "ArrowRight"];
|
|
}
|
|
if (ignoredKeys.includes(ev.sourceEvent.code)) {
|
|
ev.sourceEvent.preventDefault();
|
|
}
|
|
}
|
|
};
|
|
_SliderWidget.STEP_ONE = { attributeValue: "1", divider: 1 };
|
|
_SliderWidget.STEP_HUNDRETH = { attributeValue: "0.01", divider: 100 };
|
|
var SliderWidget = _SliderWidget;
|
|
|
|
// packages/ag-charts-community/src/widget/switchWidget.ts
|
|
var import_ag_charts_core52 = require("ag-charts-core");
|
|
var SwitchWidget = class extends ButtonWidget {
|
|
constructor() {
|
|
super();
|
|
(0, import_ag_charts_core52.setAttribute)(this.elem, "role", "switch");
|
|
this.setChecked(false);
|
|
}
|
|
setChecked(checked) {
|
|
(0, import_ag_charts_core52.setAttribute)(this.elem, "aria-checked", checked);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/toolbarWidget.ts
|
|
var ToolbarWidget = class extends RovingTabContainerWidget {
|
|
constructor(orientation = "horizontal") {
|
|
super(orientation, "toolbar");
|
|
}
|
|
destructor() {
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/dom/proxyInteractionService.ts
|
|
function checkType(type, meta) {
|
|
return meta.params?.type === type;
|
|
}
|
|
function allocateResult(type) {
|
|
if ("button" === type) {
|
|
return new ButtonWidget();
|
|
} else if ("slider" === type) {
|
|
return new SliderWidget();
|
|
} else if ("toolbar" === type) {
|
|
return new ToolbarWidget();
|
|
} else if ("group" === type) {
|
|
return new GroupWidget();
|
|
} else if ("list" === type) {
|
|
return new ListWidget();
|
|
} else if ("region" === type) {
|
|
return new NativeWidget((0, import_ag_charts_core53.createElement)("div"));
|
|
} else if ("text" === type) {
|
|
return new BoundedTextWidget();
|
|
} else if ("listswitch" === type) {
|
|
return new SwitchWidget();
|
|
} else {
|
|
throw new Error("AG Charts - error allocating meta");
|
|
}
|
|
}
|
|
function allocateMeta(params) {
|
|
const meta = { params, result: void 0 };
|
|
meta.result = allocateResult(meta.params.type);
|
|
return meta;
|
|
}
|
|
var ProxyInteractionService = class {
|
|
constructor(eventsHub, localeManager, domManager) {
|
|
this.eventsHub = eventsHub;
|
|
this.localeManager = localeManager;
|
|
this.domManager = domManager;
|
|
this.cleanup = new import_ag_charts_core53.CleanupRegistry();
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
addLocalisation(fn) {
|
|
fn();
|
|
this.cleanup.register(this.eventsHub.on("locale:change", fn));
|
|
}
|
|
createProxyContainer(args) {
|
|
const meta = allocateMeta(args);
|
|
const { params, result } = meta;
|
|
const div = result.getElement();
|
|
this.domManager.addChild("canvas-proxy", params.domManagerId, div);
|
|
div.classList.add(...params.classList, "ag-charts-proxy-container");
|
|
div.role = params.role ?? params.type;
|
|
if (checkType("toolbar", meta)) {
|
|
meta.result.orientation = meta.params.orientation;
|
|
}
|
|
const { ariaLabel } = params;
|
|
if (ariaLabel) {
|
|
this.addLocalisation(() => {
|
|
div.ariaLabel = this.localeManager.t(ariaLabel.id, ariaLabel.params);
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
createProxyElement(args) {
|
|
const meta = allocateMeta(args);
|
|
if (checkType("button", meta)) {
|
|
const { params, result } = meta;
|
|
const button = result.getElement();
|
|
this.initInteract(params, result);
|
|
if (typeof params.textContent === "string") {
|
|
button.textContent = params.textContent;
|
|
} else {
|
|
const { textContent } = params;
|
|
this.addLocalisation(() => {
|
|
button.textContent = this.localeManager.t(textContent.id, textContent.params);
|
|
});
|
|
}
|
|
this.setParent(meta.params, meta.result);
|
|
}
|
|
if (checkType("slider", meta)) {
|
|
const { params, result } = meta;
|
|
const slider = result.getElement();
|
|
this.initInteract(params, result);
|
|
slider.type = "range";
|
|
slider.role = params.role ?? "presentation";
|
|
slider.style.margin = "0px";
|
|
this.addLocalisation(() => {
|
|
slider.ariaLabel = this.localeManager.t(params.ariaLabel.id, params.ariaLabel.params);
|
|
});
|
|
this.setParent(meta.params, meta.result);
|
|
}
|
|
if (checkType("text", meta)) {
|
|
const { params, result } = meta;
|
|
this.initElement(params, result);
|
|
this.setParent(meta.params, meta.result);
|
|
}
|
|
if (checkType("listswitch", meta)) {
|
|
const { params, result: button } = meta;
|
|
this.initInteract(params, button);
|
|
button.setTextContent(params.textContent);
|
|
button.setChecked(params.ariaChecked);
|
|
button.setAriaDescribedBy(params.ariaDescribedBy);
|
|
this.setParent(meta.params, meta.result);
|
|
}
|
|
if (checkType("region", meta)) {
|
|
const { params, result } = meta;
|
|
const region = result.getElement();
|
|
this.initInteract(params, result);
|
|
region.role = params.role ?? "region";
|
|
this.setParent(meta.params, meta.result);
|
|
}
|
|
return meta.result;
|
|
}
|
|
initElement(params, widget) {
|
|
const element2 = widget.getElement();
|
|
(0, import_ag_charts_core53.setElementStyle)(element2, "cursor", params.cursor);
|
|
element2.classList.toggle("ag-charts-proxy-elem", true);
|
|
if (params.classList?.length) {
|
|
element2.classList.add(...params.classList);
|
|
}
|
|
return element2;
|
|
}
|
|
initInteract(params, widget) {
|
|
const { tabIndex, domIndex } = params;
|
|
const element2 = this.initElement(params, widget);
|
|
if (tabIndex !== void 0) {
|
|
element2.tabIndex = tabIndex;
|
|
}
|
|
if (domIndex !== void 0) {
|
|
widget.domIndex = domIndex;
|
|
}
|
|
}
|
|
setParent(params, element2) {
|
|
if ("parent" in params) {
|
|
params.parent?.addChild(element2);
|
|
} else {
|
|
const insert = { where: params.where, query: ".ag-charts-series-area" };
|
|
this.domManager.addChild("canvas-proxy", params.domManagerId, element2.getElement(), insert);
|
|
element2.destroyListener = () => {
|
|
this.domManager.removeChild("canvas-proxy", params.domManagerId);
|
|
};
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/locale/defaultMessageFormatter.ts
|
|
var import_ag_charts_core54 = require("ag-charts-core");
|
|
var messageRegExp = /\$\{(\w+)}(?:\[(\w+)])?/gi;
|
|
var formatters = {
|
|
number: new Intl.NumberFormat("en-US"),
|
|
percent: new Intl.NumberFormat("en-US", { style: "percent", minimumFractionDigits: 2, maximumFractionDigits: 2 }),
|
|
percent0to2dp: new Intl.NumberFormat("en-US", {
|
|
style: "percent",
|
|
minimumFractionDigits: 0,
|
|
maximumFractionDigits: 2
|
|
}),
|
|
date: new Intl.DateTimeFormat("en-US", { dateStyle: "full" }),
|
|
time: new Intl.DateTimeFormat("en-US", { timeStyle: "full" }),
|
|
datetime: new Intl.DateTimeFormat("en-US", { dateStyle: "full", timeStyle: "full" })
|
|
};
|
|
var defaultMessageFormatter = ({ defaultValue, variables }) => {
|
|
return defaultValue?.replaceAll(messageRegExp, (_, match, format) => {
|
|
const value = variables[match];
|
|
const formatter = format == null ? null : formatters[format];
|
|
if (format != null && formatter == null) {
|
|
import_ag_charts_core54.Logger.warnOnce(`Format style [${format}] is not supported`);
|
|
}
|
|
if (formatter != null) {
|
|
return formatter.format(value);
|
|
} else if (typeof value === "number") {
|
|
return formatters.number.format(value);
|
|
} else if (value instanceof Date) {
|
|
return formatters.datetime.format(value);
|
|
}
|
|
return String(value);
|
|
});
|
|
};
|
|
|
|
// packages/ag-charts-community/src/locale/localeManager.ts
|
|
var LocaleManager = class {
|
|
constructor(eventsHub) {
|
|
this.eventsHub = eventsHub;
|
|
this.localeText = void 0;
|
|
this.getLocaleText = void 0;
|
|
}
|
|
setLocaleText(localeText) {
|
|
if (this.localeText !== localeText) {
|
|
this.localeText = localeText;
|
|
this.eventsHub.emit("locale:change", null);
|
|
}
|
|
}
|
|
setLocaleTextFormatter(getLocaleText) {
|
|
this.getLocaleText = getLocaleText;
|
|
if (this.getLocaleText !== getLocaleText) {
|
|
this.getLocaleText = getLocaleText;
|
|
this.eventsHub.emit("locale:change", null);
|
|
}
|
|
}
|
|
t(key, variables = {}) {
|
|
const { localeText = AG_CHARTS_LOCALE_EN_US, getLocaleText } = this;
|
|
const defaultValue = localeText[key];
|
|
return String(
|
|
getLocaleText?.({ key, defaultValue, variables }) ?? defaultMessageFormatter({ key, defaultValue, variables }) ?? key
|
|
);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/scene.ts
|
|
var import_ag_charts_core58 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/canvas/hdpiCanvas.ts
|
|
var import_ag_charts_core55 = require("ag-charts-core");
|
|
var HdpiCanvas = class {
|
|
constructor(options) {
|
|
this.enabled = true;
|
|
this.width = 600;
|
|
this.height = 300;
|
|
const { width, height, canvasElement, willReadFrequently = false } = options;
|
|
this.pixelRatio = options.pixelRatio ?? (0, import_ag_charts_core55.getWindow)("devicePixelRatio") ?? 1;
|
|
this.element = canvasElement ?? (0, import_ag_charts_core55.createElement)("canvas");
|
|
this.element.style.display = "block";
|
|
this.element.style.width = (width ?? this.width) + "px";
|
|
this.element.style.height = (height ?? this.height) + "px";
|
|
this.element.width = Math.round((width ?? this.width) * this.pixelRatio);
|
|
this.element.height = Math.round((height ?? this.height) * this.pixelRatio);
|
|
this.context = this.element.getContext("2d", { willReadFrequently });
|
|
this.onEnabledChange();
|
|
this.resize(width ?? 0, height ?? 0, this.pixelRatio);
|
|
debugContext(this.context);
|
|
}
|
|
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- OffscreenCanvasRenderingContext2D is intentionally `any` for Angular 13+ compatibility (AG-6969)
|
|
drawImage(context, dx = 0, dy = 0) {
|
|
return context.drawImage(this.context.canvas, dx, dy);
|
|
}
|
|
toDataURL(type) {
|
|
return this.element.toDataURL(type);
|
|
}
|
|
resize(width, height, pixelRatio) {
|
|
if (!(width > 0 && height > 0))
|
|
return;
|
|
const { element: element2, context } = this;
|
|
element2.width = Math.round(width * pixelRatio);
|
|
element2.height = Math.round(height * pixelRatio);
|
|
context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
element2.style.width = width + "px";
|
|
element2.style.height = height + "px";
|
|
this.width = width;
|
|
this.height = height;
|
|
this.pixelRatio = pixelRatio;
|
|
}
|
|
clear() {
|
|
clearContext(this);
|
|
}
|
|
destroy() {
|
|
this.element.remove();
|
|
this.element.width = 0;
|
|
this.element.height = 0;
|
|
this.context.clearRect(0, 0, 0, 0);
|
|
Object.freeze(this);
|
|
}
|
|
reset() {
|
|
this.context.reset();
|
|
this.context.verifyDepthZero?.();
|
|
}
|
|
onEnabledChange() {
|
|
if (this.element) {
|
|
this.element.style.display = this.enabled ? "" : "none";
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core55.ObserveChanges)((target) => target.onEnabledChange())
|
|
], HdpiCanvas.prototype, "enabled", 2);
|
|
|
|
// packages/ag-charts-community/src/scene/image/imageLoader.ts
|
|
var import_ag_charts_core56 = require("ag-charts-core");
|
|
var ImageLoader = class extends import_ag_charts_core56.EventEmitter {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.cache = /* @__PURE__ */ new Map();
|
|
this.imageLoadingCount = 0;
|
|
}
|
|
loadImage(uri, affectedNode) {
|
|
const entry = this.cache.get(uri);
|
|
if (entry?.image) {
|
|
return entry.image;
|
|
} else if (entry != null && affectedNode) {
|
|
entry.nodes.add(affectedNode);
|
|
return;
|
|
}
|
|
if (!affectedNode) {
|
|
return;
|
|
}
|
|
const nextEntry = { image: void 0, nodes: /* @__PURE__ */ new Set([affectedNode]) };
|
|
const ImageCtor = (0, import_ag_charts_core56.getImage)();
|
|
const image = new ImageCtor();
|
|
this.imageLoadingCount++;
|
|
image.onload = () => {
|
|
nextEntry.image = image;
|
|
for (const node of nextEntry.nodes) {
|
|
node.markDirty();
|
|
}
|
|
nextEntry.nodes.clear();
|
|
this.imageLoadingCount--;
|
|
this.emit("image-loaded", { uri });
|
|
};
|
|
image.onerror = () => {
|
|
this.imageLoadingCount--;
|
|
nextEntry.nodes.clear();
|
|
this.emit("image-error", { uri });
|
|
};
|
|
image.src = uri;
|
|
this.cache.set(uri, nextEntry);
|
|
return nextEntry.image;
|
|
}
|
|
waitingToLoad() {
|
|
return this.imageLoadingCount > 0;
|
|
}
|
|
destroy() {
|
|
for (const entry of this.cache.values()) {
|
|
entry.nodes.clear();
|
|
}
|
|
this.cache.clear();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/layersManager.ts
|
|
var import_ag_charts_core57 = require("ag-charts-core");
|
|
var LayersManager = class {
|
|
constructor(canvas) {
|
|
this.canvas = canvas;
|
|
this.debug = import_ag_charts_core57.Debug.create(true, "scene");
|
|
this.layersMap = /* @__PURE__ */ new Map();
|
|
this.nextLayerId = 0;
|
|
}
|
|
get size() {
|
|
return this.layersMap.size;
|
|
}
|
|
resize(width, height, pixelRatio) {
|
|
this.canvas.resize(width, height, pixelRatio);
|
|
for (const { canvas } of this.layersMap.values()) {
|
|
canvas.resize(width, height, pixelRatio);
|
|
}
|
|
}
|
|
addLayer(opts) {
|
|
const { width, height, pixelRatio } = this.canvas;
|
|
const { name } = opts;
|
|
const canvas = new HdpiOffscreenCanvas({ width, height, pixelRatio });
|
|
this.layersMap.set(canvas, {
|
|
id: this.nextLayerId++,
|
|
name,
|
|
canvas
|
|
});
|
|
this.debug("Scene.addLayer() - layers", this.layersMap);
|
|
return canvas;
|
|
}
|
|
removeLayer(canvas) {
|
|
if (this.layersMap.has(canvas)) {
|
|
this.layersMap.delete(canvas);
|
|
canvas.destroy();
|
|
this.debug("Scene.removeLayer() - layers", this.layersMap);
|
|
}
|
|
}
|
|
clear() {
|
|
for (const layer of this.layersMap.values()) {
|
|
layer.canvas.destroy();
|
|
}
|
|
this.layersMap.clear();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/scene.ts
|
|
var Scene = class extends import_ag_charts_core58.EventEmitter {
|
|
constructor(canvasOptions) {
|
|
super();
|
|
this.debug = import_ag_charts_core58.Debug.create(true, "scene" /* SCENE */);
|
|
this.id = (0, import_ag_charts_core58.createId)(this);
|
|
this.imageLoader = new ImageLoader();
|
|
this.root = null;
|
|
this.pendingSize = null;
|
|
this.isDirty = false;
|
|
this.cleanup = new import_ag_charts_core58.CleanupRegistry();
|
|
this.updateDebugFlags();
|
|
this.canvas = new HdpiCanvas(canvasOptions);
|
|
this.layersManager = new LayersManager(this.canvas);
|
|
this.cleanup.register(
|
|
this.imageLoader.on("image-loaded", () => {
|
|
this.emit("scene-changed", {});
|
|
}),
|
|
this.imageLoader.on("image-error", ({ uri }) => {
|
|
import_ag_charts_core58.Logger.warnOnce(`Unable to load image ${uri}`);
|
|
})
|
|
);
|
|
}
|
|
waitingForUpdate() {
|
|
return this.imageLoader?.waitingToLoad() ?? false;
|
|
}
|
|
get width() {
|
|
return this.pendingSize?.[0] ?? this.canvas.width;
|
|
}
|
|
get height() {
|
|
return this.pendingSize?.[1] ?? this.canvas.height;
|
|
}
|
|
get pixelRatio() {
|
|
return this.pendingSize?.[2] ?? this.canvas.pixelRatio;
|
|
}
|
|
/**
|
|
* @deprecated v10.2.0 Only used by AG Grid Sparklines + Mini Charts
|
|
*
|
|
* DO NOT REMOVE WITHOUT FIXING THE GRID DEPENDENCIES.
|
|
*/
|
|
setContainer(value) {
|
|
const { element: element2 } = this.canvas;
|
|
element2.remove();
|
|
value.appendChild(element2);
|
|
return this;
|
|
}
|
|
setRoot(node) {
|
|
if (this.root === node) {
|
|
return this;
|
|
}
|
|
this.isDirty = true;
|
|
this.root?.setScene();
|
|
this.root = node;
|
|
if (node) {
|
|
node.visible = true;
|
|
node.setScene(this);
|
|
}
|
|
return this;
|
|
}
|
|
updateDebugFlags() {
|
|
import_ag_charts_core58.Debug.inDevelopmentMode(() => Node._debugEnabled = true);
|
|
}
|
|
clearCanvas() {
|
|
this.canvas.clear();
|
|
}
|
|
attachNode(node) {
|
|
this.appendChild(node);
|
|
return () => node.remove();
|
|
}
|
|
appendChild(node) {
|
|
this.root?.appendChild(node);
|
|
return this;
|
|
}
|
|
removeChild(node) {
|
|
node.remove();
|
|
return this;
|
|
}
|
|
download(fileName, fileFormat) {
|
|
(0, import_ag_charts_core58.downloadUrl)(this.canvas.toDataURL(fileFormat), fileName?.trim() ?? "image");
|
|
}
|
|
/** NOTE: Integrated Charts undocumented image download method. */
|
|
getDataURL(fileFormat) {
|
|
return this.canvas.toDataURL(fileFormat);
|
|
}
|
|
resize(width, height, pixelRatio) {
|
|
width = Math.round(width);
|
|
height = Math.round(height);
|
|
pixelRatio ?? (pixelRatio = this.pixelRatio);
|
|
if (width > 0 && height > 0 && (width !== this.width || height !== this.height || pixelRatio !== this.pixelRatio)) {
|
|
this.pendingSize = [width, height, pixelRatio];
|
|
this.isDirty = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
applyPendingResize() {
|
|
if (this.pendingSize) {
|
|
this.layersManager.resize(...this.pendingSize);
|
|
this.pendingSize = null;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
render(opts) {
|
|
const { debugSplitTimes = { start: performance.now() }, extraDebugStats, seriesRect, debugColors } = opts ?? {};
|
|
const { canvas, canvas: { context: ctx } = {}, root, width, height, pixelRatio: devicePixelRatio } = this;
|
|
if (!ctx) {
|
|
return;
|
|
}
|
|
const statsEnabled = import_ag_charts_core58.Debug.check("scene:stats" /* SCENE_STATS */, "scene:stats:verbose" /* SCENE_STATS_VERBOSE */);
|
|
if (statsEnabled) {
|
|
this.ensureDebugStatsRegistration();
|
|
}
|
|
const renderStartTime = performance.now();
|
|
const resized = this.applyPendingResize();
|
|
if (root && !root.visible) {
|
|
this.isDirty = false;
|
|
return;
|
|
}
|
|
let rootDirty;
|
|
if (root instanceof Group) {
|
|
rootDirty = root.dirty;
|
|
}
|
|
if (root != null && rootDirty === false && !this.isDirty) {
|
|
if (this.debug.check()) {
|
|
this.debug("Scene.render() - no-op", {
|
|
tree: buildTree(root, "console")
|
|
});
|
|
}
|
|
if (statsEnabled) {
|
|
debugStats(
|
|
this.layersManager,
|
|
debugSplitTimes,
|
|
ctx,
|
|
void 0,
|
|
extraDebugStats,
|
|
seriesRect,
|
|
debugColors
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
const renderCtx = {
|
|
ctx,
|
|
width,
|
|
height,
|
|
devicePixelRatio,
|
|
debugNodes: {}
|
|
};
|
|
if (import_ag_charts_core58.Debug.check("scene:stats:verbose" /* SCENE_STATS_VERBOSE */)) {
|
|
renderCtx.stats = {
|
|
layersRendered: 0,
|
|
layersSkipped: 0,
|
|
nodesRendered: 0,
|
|
nodesSkipped: 0,
|
|
opsPerformed: 0,
|
|
opsSkipped: 0
|
|
};
|
|
}
|
|
prepareSceneNodeHighlight(renderCtx);
|
|
let canvasCleared = false;
|
|
if (rootDirty !== false || resized) {
|
|
canvasCleared = true;
|
|
canvas.clear();
|
|
}
|
|
if (root && import_ag_charts_core58.Debug.check("scene:dirtyTree" /* SCENE_DIRTY_TREE */)) {
|
|
const { dirtyTree, paths } = buildDirtyTree(root);
|
|
import_ag_charts_core58.Debug.create("scene:dirtyTree" /* SCENE_DIRTY_TREE */)("Scene.render() - dirtyTree", { dirtyTree, paths });
|
|
}
|
|
if (root && canvasCleared) {
|
|
if (root.visible) {
|
|
root.preRender(renderCtx);
|
|
}
|
|
if (this.debug.check()) {
|
|
const tree = buildTree(root, "console");
|
|
this.debug("Scene.render() - before", {
|
|
canvasCleared,
|
|
tree
|
|
});
|
|
}
|
|
if (root.visible) {
|
|
try {
|
|
ctx.save();
|
|
root.render(renderCtx);
|
|
ctx.restore();
|
|
} catch (e) {
|
|
this.canvas.reset();
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
debugSplitTimes["\u270D\uFE0F"] = performance.now() - renderStartTime;
|
|
ctx.verifyDepthZero?.();
|
|
this.isDirty = false;
|
|
if (statsEnabled) {
|
|
debugStats(
|
|
this.layersManager,
|
|
debugSplitTimes,
|
|
ctx,
|
|
renderCtx.stats,
|
|
extraDebugStats,
|
|
seriesRect,
|
|
debugColors
|
|
);
|
|
}
|
|
debugSceneNodeHighlight(ctx, renderCtx.debugNodes);
|
|
if (root && this.debug.check()) {
|
|
this.debug("Scene.render() - after", {
|
|
tree: buildTree(root, "console"),
|
|
canvasCleared
|
|
});
|
|
}
|
|
}
|
|
ensureDebugStatsRegistration() {
|
|
if (this.releaseDebugStats)
|
|
return;
|
|
const release = registerDebugStatsConsumer();
|
|
const cleanup = () => {
|
|
release();
|
|
this.releaseDebugStats = void 0;
|
|
};
|
|
this.releaseDebugStats = cleanup;
|
|
this.cleanup.register(cleanup);
|
|
}
|
|
toSVG() {
|
|
const { root, width, height } = this;
|
|
if (root == null)
|
|
return;
|
|
return Node.toSVG(root, width, height);
|
|
}
|
|
/** Alternative to destroy() that preserves re-usable resources. */
|
|
strip() {
|
|
const { context, pixelRatio } = this.canvas;
|
|
context.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
this.layersManager.clear();
|
|
this.setRoot(null);
|
|
this.isDirty = false;
|
|
this.clear();
|
|
}
|
|
destroy() {
|
|
this.strip();
|
|
this.canvas.destroy();
|
|
this.imageLoader.destroy();
|
|
this.cleanup.flush();
|
|
cleanupDebugStats();
|
|
Object.assign(this, { canvas: void 0 });
|
|
}
|
|
};
|
|
Scene.className = "Scene";
|
|
|
|
// packages/ag-charts-community/src/chart/annotation/annotationManager.ts
|
|
var import_ag_charts_core59 = require("ag-charts-core");
|
|
var AnnotationManager = class {
|
|
constructor(eventsHub, annotationRoot, fireChartEvent) {
|
|
this.eventsHub = eventsHub;
|
|
this.annotationRoot = annotationRoot;
|
|
this.fireChartEvent = fireChartEvent;
|
|
this.mementoOriginatorKey = "annotations";
|
|
this.annotations = [];
|
|
}
|
|
createMemento() {
|
|
return this.annotations;
|
|
}
|
|
guardMemento(blob) {
|
|
return blob == null || (0, import_ag_charts_core59.isArray)(blob);
|
|
}
|
|
restoreMemento(_version, _mementoVersion, memento) {
|
|
this.annotations = this.cleanData(memento ?? []).map((annotation) => {
|
|
const annotationTheme = this.getAnnotationTypeStyles(annotation.type);
|
|
return (0, import_ag_charts_core59.mergeDefaults)(annotation, annotationTheme);
|
|
});
|
|
this.eventsHub.emit("annotations:restore", { annotations: this.annotations });
|
|
}
|
|
updateData(annotations) {
|
|
this.annotations = this.cleanData(annotations ?? []);
|
|
}
|
|
fireChangedEvent() {
|
|
this.fireChartEvent({ type: "annotations", annotations: (0, import_ag_charts_core59.deepClone)([...this.annotations]) });
|
|
}
|
|
attachNode(node) {
|
|
this.annotationRoot.append(node);
|
|
return () => {
|
|
node.remove();
|
|
return this;
|
|
};
|
|
}
|
|
setAnnotationStyles(styles) {
|
|
this.styles = styles;
|
|
}
|
|
getAnnotationTypeStyles(type) {
|
|
return this.styles?.[type];
|
|
}
|
|
cleanData(annotations) {
|
|
for (const annotation of annotations) {
|
|
if ("textAlign" in annotation)
|
|
delete annotation.textAlign;
|
|
}
|
|
return annotations;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axisManager.ts
|
|
var import_ag_charts_core60 = require("ag-charts-core");
|
|
var AxisManager = class {
|
|
constructor(eventsHub, sceneRoot) {
|
|
this.eventsHub = eventsHub;
|
|
this.sceneRoot = sceneRoot;
|
|
this.axes = /* @__PURE__ */ new Map();
|
|
this.axisGridGroup = new Group({ name: "Axes-Grids", zIndex: import_ag_charts_core60.ZIndexMap.AXIS_GRID });
|
|
this.axisGroup = new Group({ name: "Axes", zIndex: import_ag_charts_core60.ZIndexMap.AXIS });
|
|
this.axisLabelGroup = new Group({ name: "Axes-Labels", zIndex: import_ag_charts_core60.ZIndexMap.SERIES_LABEL });
|
|
this.axisCrosslineRangeGroup = new Group({
|
|
name: "Axes-Crosslines-Range",
|
|
zIndex: import_ag_charts_core60.ZIndexMap.SERIES_CROSSLINE_RANGE
|
|
});
|
|
this.axisCrosslineLineGroup = new Group({
|
|
name: "Axes-Crosslines-Line",
|
|
zIndex: import_ag_charts_core60.ZIndexMap.SERIES_CROSSLINE_LINE
|
|
});
|
|
this.axisCrosslineLabelGroup = new Group({
|
|
name: "Axes-Crosslines-Label",
|
|
zIndex: import_ag_charts_core60.ZIndexMap.SERIES_LABEL
|
|
});
|
|
this.sceneRoot.appendChild(this.axisGroup);
|
|
this.sceneRoot.appendChild(this.axisGridGroup);
|
|
this.sceneRoot.appendChild(this.axisLabelGroup);
|
|
this.sceneRoot.appendChild(this.axisCrosslineRangeGroup);
|
|
this.sceneRoot.appendChild(this.axisCrosslineLineGroup);
|
|
this.sceneRoot.appendChild(this.axisCrosslineLabelGroup);
|
|
}
|
|
updateAxes(oldAxes, newAxes) {
|
|
const axisNodes = {
|
|
axisNode: this.axisGroup,
|
|
gridNode: this.axisGridGroup,
|
|
labelNode: this.axisLabelGroup,
|
|
crossLineRangeNode: this.axisCrosslineRangeGroup,
|
|
crossLineLineNode: this.axisCrosslineLineGroup,
|
|
crossLineLabelNode: this.axisCrosslineLabelGroup
|
|
};
|
|
for (const axis of oldAxes) {
|
|
if (newAxes.includes(axis))
|
|
continue;
|
|
axis.detachAxis(axisNodes);
|
|
axis.destroy();
|
|
}
|
|
for (const axis of newAxes) {
|
|
if (oldAxes?.includes(axis))
|
|
continue;
|
|
axis.attachAxis(axisNodes);
|
|
}
|
|
this.axes.clear();
|
|
for (const axis of newAxes) {
|
|
const ctx = axis.createAxisContext();
|
|
if (this.axes.has(ctx.direction)) {
|
|
this.axes.get(ctx.direction)?.push(ctx);
|
|
} else {
|
|
this.axes.set(ctx.direction, [ctx]);
|
|
}
|
|
}
|
|
this.eventsHub.emit("axis:change", null);
|
|
}
|
|
getAxisIdContext(id) {
|
|
for (const [, contextsInThisDir] of this.axes) {
|
|
for (const ctx of contextsInThisDir) {
|
|
if (ctx.axisId === id)
|
|
return ctx;
|
|
}
|
|
}
|
|
}
|
|
getAxisContext(direction) {
|
|
return this.axes.get(direction) ?? [];
|
|
}
|
|
destroy() {
|
|
this.axes.clear();
|
|
this.axisGroup.remove();
|
|
this.axisGridGroup.remove();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/dataService.ts
|
|
var import_ag_charts_core61 = require("ag-charts-core");
|
|
var DataService = class {
|
|
constructor(eventsHub, caller, animationManager) {
|
|
this.eventsHub = eventsHub;
|
|
this.caller = caller;
|
|
this.animationManager = animationManager;
|
|
this.dispatchOnlyLatest = true;
|
|
this.dispatchThrottle = 0;
|
|
this.requestThrottle = 300;
|
|
this.isLoadingInitialData = false;
|
|
this.isLoadingData = false;
|
|
this.freshRequests = [];
|
|
this.requestCounter = 0;
|
|
this.pendingData = void 0;
|
|
this.debug = import_ag_charts_core61.Debug.create(true, "data-model", "data-source");
|
|
this.throttledFetch = this.createThrottledFetch(this.requestThrottle);
|
|
this.throttledDispatch = this.createThrottledDispatch(this.dispatchThrottle);
|
|
}
|
|
updateCallback(dataSourceCallback) {
|
|
if (typeof dataSourceCallback !== "function")
|
|
return;
|
|
this.debug("DataService - updated data source callback");
|
|
this.dataSourceCallback = dataSourceCallback;
|
|
this.isLoadingInitialData = true;
|
|
this.animationManager.skip();
|
|
this.eventsHub.emit("data:source-change", null);
|
|
}
|
|
clearCallback() {
|
|
this.dataSourceCallback = void 0;
|
|
}
|
|
load(params) {
|
|
const { pendingData } = this;
|
|
if (pendingData != null && (pendingData.params.windowStart == null && pendingData.params.windowEnd == null || pendingData.params.windowStart?.valueOf() === params.windowStart?.valueOf() && pendingData.params.windowEnd?.valueOf() === params.windowEnd?.valueOf())) {
|
|
const id = this.requestCounter++;
|
|
this.isLoadingInitialData = false;
|
|
this.dispatch(id, pendingData.data);
|
|
return;
|
|
}
|
|
this.isLoadingData = true;
|
|
this.throttledFetch(params);
|
|
}
|
|
isLazy() {
|
|
return this.dataSourceCallback != null;
|
|
}
|
|
isLoading() {
|
|
return this.isLazy() && (this.isLoadingInitialData || this.isLoadingData);
|
|
}
|
|
async getData() {
|
|
const { latestRequest } = this;
|
|
if (!latestRequest)
|
|
return;
|
|
const { params, fetchRequest } = latestRequest;
|
|
const data = await fetchRequest;
|
|
return { params, data };
|
|
}
|
|
restoreData(data) {
|
|
this.pendingData = data;
|
|
}
|
|
createThrottledFetch(requestThrottle) {
|
|
return (0, import_ag_charts_core61.throttle)(
|
|
(params) => this.fetch(params).catch((e) => import_ag_charts_core61.Logger.error("callback failed", e)),
|
|
requestThrottle,
|
|
{ leading: false, trailing: true }
|
|
);
|
|
}
|
|
createThrottledDispatch(dispatchThrottle) {
|
|
return (0, import_ag_charts_core61.throttle)((id, data) => this.dispatch(id, data), dispatchThrottle, {
|
|
leading: true,
|
|
trailing: true
|
|
});
|
|
}
|
|
dispatch(id, data) {
|
|
this.debug(`DataService - dispatching 'data-load' | ${id}`);
|
|
this.eventsHub.emit("data:load", { data });
|
|
}
|
|
async fetch(params) {
|
|
if ("context" in this.caller) {
|
|
params.context = this.caller.context;
|
|
}
|
|
const fetchRequest = Promise.resolve().then(async () => {
|
|
if (!this.dataSourceCallback) {
|
|
throw new Error("DataService - [dataSource.getData] callback not initialised");
|
|
}
|
|
const start = performance.now();
|
|
const id = this.requestCounter++;
|
|
this.debug(`DataService - requesting | ${id}`);
|
|
let response;
|
|
try {
|
|
response = await this.dataSourceCallback(params);
|
|
this.debug(`DataService - response | ${performance.now() - start}ms | ${id}`);
|
|
} catch (error) {
|
|
this.debug(`DataService - request failed | ${id}`);
|
|
import_ag_charts_core61.Logger.errorOnce(`DataService - request failed | [${error}]`);
|
|
}
|
|
this.isLoadingInitialData = false;
|
|
const requestIndex = this.freshRequests.indexOf(fetchRequest);
|
|
if (requestIndex === -1 || this.dispatchOnlyLatest && requestIndex !== this.freshRequests.length - 1) {
|
|
this.debug(`DataService - discarding stale request | ${id}`);
|
|
return response;
|
|
}
|
|
this.freshRequests = this.freshRequests.slice(requestIndex + 1);
|
|
if (this.freshRequests.length === 0) {
|
|
this.isLoadingData = false;
|
|
}
|
|
if (Array.isArray(response)) {
|
|
this.throttledDispatch(id, response);
|
|
} else {
|
|
this.eventsHub.emit("data:error", null);
|
|
}
|
|
return response;
|
|
});
|
|
this.latestRequest = { params, fetchRequest };
|
|
this.freshRequests.push(fetchRequest);
|
|
await fetchRequest;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core61.ActionOnSet)({
|
|
newValue(dispatchThrottle) {
|
|
this.throttledDispatch = this.createThrottledDispatch(dispatchThrottle);
|
|
}
|
|
})
|
|
], DataService.prototype, "dispatchThrottle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core61.ActionOnSet)({
|
|
newValue(requestThrottle) {
|
|
this.throttledFetch = this.createThrottledFetch(requestThrottle);
|
|
}
|
|
})
|
|
], DataService.prototype, "requestThrottle", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/fonts/fontManager.ts
|
|
var import_ag_charts_core62 = require("ag-charts-core");
|
|
var FontManager = class {
|
|
constructor(domManager, updateService) {
|
|
this.domManager = domManager;
|
|
this.updateService = updateService;
|
|
this.observers = [];
|
|
}
|
|
updateFonts(fonts) {
|
|
if (!fonts || fonts.size === 0)
|
|
return;
|
|
this.loadFonts(fonts);
|
|
for (const font of fonts) {
|
|
this.observeFontStatus(font);
|
|
}
|
|
}
|
|
destroy() {
|
|
for (const observer of this.observers) {
|
|
observer.disconnect();
|
|
}
|
|
this.observers = [];
|
|
}
|
|
loadFonts(fonts) {
|
|
const fontStrings = Array.from(fonts).map((font) => encodeURIComponent(font));
|
|
const fontStyle = ":wght@100;200;300;400;500;600;700;800;900";
|
|
const joinString = `${fontStyle}&family=`;
|
|
const css = `@import url('https://fonts.googleapis.com/css2?family=${fontStrings.join(joinString)}${fontStyle}&display=swap');
|
|
`;
|
|
this.domManager.addStyles(`google-font-${fontStrings.join("-")}`, css);
|
|
}
|
|
observeFontStatus(font) {
|
|
const ResizeObserverCtor = (0, import_ag_charts_core62.getResizeObserver)();
|
|
if (ResizeObserverCtor === void 0)
|
|
return;
|
|
const doc = (0, import_ag_charts_core62.getDocument)();
|
|
if (!doc)
|
|
return;
|
|
const fontCheckElement = doc.createElement("div");
|
|
fontCheckElement.style.setProperty("position", "absolute");
|
|
fontCheckElement.style.setProperty("top", "0");
|
|
fontCheckElement.style.setProperty("margin", "0");
|
|
fontCheckElement.style.setProperty("padding", "0");
|
|
fontCheckElement.style.setProperty("overflow", "hidden");
|
|
fontCheckElement.style.setProperty("visibility", "hidden");
|
|
fontCheckElement.style.setProperty("width", "auto");
|
|
fontCheckElement.style.setProperty("max-width", "none");
|
|
fontCheckElement.style.setProperty("font-synthesis", "none");
|
|
fontCheckElement.style.setProperty("font-family", font);
|
|
fontCheckElement.style.setProperty("font-size", "16px");
|
|
fontCheckElement.style.setProperty("white-space", "nowrap");
|
|
fontCheckElement.textContent = "UVWxyz";
|
|
this.domManager.addChild("canvas-container", `font-check-${encodeURIComponent(font)}`, fontCheckElement);
|
|
const fontCheckObserver = new ResizeObserverCtor((entries7) => {
|
|
const width = entries7?.at(0)?.contentBoxSize.at(0)?.inlineSize;
|
|
if (width != null && width > 0) {
|
|
import_ag_charts_core62.cachedTextMeasurer.clear();
|
|
this.updateService.update(import_ag_charts_core62.ChartUpdateType.PERFORM_LAYOUT);
|
|
}
|
|
});
|
|
fontCheckObserver.observe(fontCheckElement);
|
|
this.observers.push(fontCheckObserver);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/formatter/formatManager.ts
|
|
var import_ag_charts_core64 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/util/listeners.ts
|
|
var import_ag_charts_core63 = require("ag-charts-core");
|
|
var Listeners = class {
|
|
constructor() {
|
|
this.registeredListeners = /* @__PURE__ */ new Map();
|
|
}
|
|
addListener(eventType, handler) {
|
|
const record = { symbol: Symbol(eventType), handler };
|
|
if (this.registeredListeners.has(eventType)) {
|
|
this.registeredListeners.get(eventType).push(record);
|
|
} else {
|
|
this.registeredListeners.set(eventType, [record]);
|
|
}
|
|
return () => this.removeListener(record.symbol);
|
|
}
|
|
removeListener(eventSymbol) {
|
|
for (const [type, listeners] of this.registeredListeners.entries()) {
|
|
const matchIndex = listeners.findIndex((listener) => listener.symbol === eventSymbol);
|
|
if (matchIndex >= 0) {
|
|
listeners.splice(matchIndex, 1);
|
|
if (listeners.length === 0) {
|
|
this.registeredListeners.delete(type);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
dispatch(eventType, ...params) {
|
|
for (const listener of this.getListenersByType(eventType)) {
|
|
try {
|
|
listener.handler(...params);
|
|
} catch (e) {
|
|
import_ag_charts_core63.Logger.errorOnce(e);
|
|
}
|
|
}
|
|
}
|
|
getListenersByType(eventType) {
|
|
return this.registeredListeners.get(eventType) ?? [];
|
|
}
|
|
destroy() {
|
|
this.registeredListeners.clear();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/axis/timeFormatUtil.ts
|
|
var defaultTimeFormats = {
|
|
millisecond: "%H:%M:%S.%L",
|
|
second: "%H:%M:%S",
|
|
minute: "%H:%M",
|
|
hour: "%H:%M",
|
|
day: "%e",
|
|
month: "%b",
|
|
year: "%Y"
|
|
};
|
|
var hardCodedTimeFormats = {
|
|
millisecond: "%Y %b %e %H:%M:%S.%L",
|
|
second: "%Y %b %e %H:%M:%S",
|
|
minute: "%Y %b %e %H:%M",
|
|
hour: "%Y %b %e %H:%M",
|
|
day: "%Y %b %e",
|
|
month: "%Y %b",
|
|
year: "%Y"
|
|
};
|
|
var FORMAT_ORDERS = {
|
|
year: 0,
|
|
month: 1,
|
|
day: 2,
|
|
hour: 3,
|
|
minute: 4,
|
|
second: 5,
|
|
millisecond: 6
|
|
};
|
|
var MILLISECOND_FORMAT = /%[-_0]?L/;
|
|
var SECOND_FORMAT = /%[-_0]?S/;
|
|
var MINUTE_FORMAT = /%[-_0]?M/;
|
|
var HOUR_FORMAT = /%[-_0]?[HI]/;
|
|
var DAY_FORMAT = /^%[-_0]?[de]$/;
|
|
var MONTH_FORMAT = /^%[-_0]?[Bbm]$/;
|
|
var YEAR_FORMAT = /^%[-_0]?[Yy]$/;
|
|
function deriveTimeSpecifier(format, unit, truncateDate) {
|
|
if (typeof format === "string")
|
|
return format;
|
|
format ?? (format = defaultTimeFormats);
|
|
const {
|
|
millisecond = defaultTimeFormats.millisecond,
|
|
second = defaultTimeFormats.second,
|
|
minute = defaultTimeFormats.minute,
|
|
hour = defaultTimeFormats.hour,
|
|
day = defaultTimeFormats.day,
|
|
month = defaultTimeFormats.month,
|
|
year = defaultTimeFormats.year
|
|
} = format;
|
|
const formatOrder = FORMAT_ORDERS[unit];
|
|
const hardcodedTimeFormat = hardCodedTimeFormats[unit];
|
|
const truncationOrder = truncateDate ? FORMAT_ORDERS[truncateDate] : -1;
|
|
if (truncationOrder < FORMAT_ORDERS.year && formatOrder >= FORMAT_ORDERS.year && !YEAR_FORMAT.test(year) || truncationOrder < FORMAT_ORDERS.month && formatOrder >= FORMAT_ORDERS.month && !MONTH_FORMAT.test(month) || truncationOrder < FORMAT_ORDERS.day && formatOrder >= FORMAT_ORDERS.day && !DAY_FORMAT.test(day)) {
|
|
return hardcodedTimeFormat;
|
|
}
|
|
let timeFormat;
|
|
switch (unit) {
|
|
case "year":
|
|
return year;
|
|
case "month":
|
|
return truncationOrder < FORMAT_ORDERS.year ? `${month} ${year}` : month;
|
|
case "day":
|
|
return truncationOrder < FORMAT_ORDERS.year ? `${month} ${day} ${year}` : `${month} ${day}`;
|
|
case "hour":
|
|
timeFormat = hour;
|
|
break;
|
|
case "minute":
|
|
timeFormat = minute;
|
|
break;
|
|
case "second":
|
|
timeFormat = second;
|
|
break;
|
|
case "millisecond":
|
|
timeFormat = millisecond;
|
|
break;
|
|
default:
|
|
return hardcodedTimeFormat;
|
|
}
|
|
if (formatOrder >= FORMAT_ORDERS.hour && !HOUR_FORMAT.test(timeFormat) || formatOrder >= FORMAT_ORDERS.minute && !MINUTE_FORMAT.test(timeFormat) || formatOrder >= FORMAT_ORDERS.second && !SECOND_FORMAT.test(timeFormat) || formatOrder >= FORMAT_ORDERS.millisecond && !MILLISECOND_FORMAT.test(timeFormat)) {
|
|
return hardcodedTimeFormat;
|
|
}
|
|
let dateFormat;
|
|
if (truncationOrder < FORMAT_ORDERS.year) {
|
|
dateFormat = `${month} ${day} ${year}`;
|
|
} else if (truncationOrder < FORMAT_ORDERS.month) {
|
|
dateFormat = `${month} ${day}`;
|
|
}
|
|
return dateFormat ? `${timeFormat} ${dateFormat}` : timeFormat;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/formatter/formatManager.ts
|
|
var FormatManager = class _FormatManager extends Listeners {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.formats = /* @__PURE__ */ new Map();
|
|
this.dateFormatter = (0, import_ag_charts_core64.simpleMemorize2)(
|
|
(propertyFormatter, specifier, unit, style, truncateDate) => {
|
|
const mergedFormatter = _FormatManager.mergeSpecifiers(propertyFormatter, specifier) ?? defaultTimeFormats;
|
|
return _FormatManager.getFormatter("date", mergedFormatter, unit, style, { truncateDate });
|
|
}
|
|
);
|
|
this.formatter = void 0;
|
|
}
|
|
static mergeSpecifiers(...specifiers) {
|
|
let out;
|
|
for (const specifier of specifiers) {
|
|
if ((0, import_ag_charts_core64.isPlainObject)(specifier) && (0, import_ag_charts_core64.isPlainObject)(out)) {
|
|
out = { ...out, ...specifier };
|
|
} else {
|
|
out = specifier;
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
static getFormatter(type, specifier, unit, style = "long", { truncateDate } = {}) {
|
|
if ((0, import_ag_charts_core64.isPlainObject)(specifier)) {
|
|
if (type !== "date") {
|
|
import_ag_charts_core64.Logger.warn("Date formatter configuration is not supported for non-date types.");
|
|
return;
|
|
}
|
|
unit ?? (unit = "millisecond");
|
|
const fullFormat = style === "component" ? specifier?.[unit] ?? defaultTimeFormats[unit] : deriveTimeSpecifier(specifier, unit, truncateDate);
|
|
return (0, import_ag_charts_core64.buildDateFormatter)(fullFormat);
|
|
}
|
|
switch (type) {
|
|
case "number": {
|
|
const options = (0, import_ag_charts_core64.parseNumberFormat)(specifier);
|
|
if (options == null)
|
|
return;
|
|
return (0, import_ag_charts_core64.createNumberFormatter)(options);
|
|
}
|
|
case "date":
|
|
return (0, import_ag_charts_core64.buildDateFormatter)(specifier);
|
|
case "category":
|
|
return (value) => specifier.replace("%s", String(value));
|
|
}
|
|
}
|
|
setFormatter(formatter) {
|
|
if (this.formatter !== formatter) {
|
|
this.formatter = formatter;
|
|
this.formats.clear();
|
|
this.dateFormatter.reset();
|
|
this.dispatch("format-changed");
|
|
}
|
|
}
|
|
format(formatInContext, params, { specifier, truncateDate, allowNull } = {}) {
|
|
if (params.value == null && !allowNull)
|
|
return;
|
|
const { formatter } = this;
|
|
if (formatter == null)
|
|
return;
|
|
if (typeof formatter === "function") {
|
|
const value = formatInContext(formatter, params);
|
|
return value == null ? void 0 : String(value);
|
|
}
|
|
const propertyFormatter = formatter[params.property];
|
|
if (propertyFormatter == null)
|
|
return;
|
|
if (typeof propertyFormatter === "function") {
|
|
const value = formatInContext(propertyFormatter, params);
|
|
return value == null ? value : (0, import_ag_charts_core64.toTextString)(value);
|
|
} else if (params.type === "date") {
|
|
const { unit, style } = params;
|
|
const dateFormatter = this.dateFormatter(propertyFormatter, specifier, unit, style, truncateDate);
|
|
return dateFormatter?.(params.value);
|
|
}
|
|
const valueSpecifier = specifier ?? propertyFormatter;
|
|
if (typeof valueSpecifier !== "string")
|
|
return;
|
|
let valueFormatter = this.formats.get(valueSpecifier);
|
|
if (valueFormatter == null) {
|
|
valueFormatter = _FormatManager.getFormatter(params.type, valueSpecifier);
|
|
this.formats.set(valueSpecifier, valueFormatter);
|
|
}
|
|
return valueFormatter?.(params.value, params.type === "number" ? params.fractionDigits : void 0);
|
|
}
|
|
defaultFormat(params, { specifier, truncateDate } = {}) {
|
|
const { formatter } = this;
|
|
const propertyFormatter = typeof formatter === "function" ? void 0 : formatter?.[params.property];
|
|
switch (params.type) {
|
|
case "date": {
|
|
const { unit, style } = params;
|
|
const propertySpecifier = propertyFormatter != null && typeof propertyFormatter !== "function" ? propertyFormatter : void 0;
|
|
const dateFormatter = this.dateFormatter(propertySpecifier, specifier, unit, style, truncateDate);
|
|
return dateFormatter?.(params.value) ?? String(params.value);
|
|
}
|
|
case "number":
|
|
return (0, import_ag_charts_core64.formatValue)(params.value, params.fractionDigits);
|
|
case "category":
|
|
if (params.value == null) {
|
|
return "";
|
|
} else if (Array.isArray(params.value)) {
|
|
return params.value.join(" - ");
|
|
} else if (typeof params.value === "string") {
|
|
return params.value;
|
|
} else if (typeof params.value === "number") {
|
|
return (0, import_ag_charts_core64.formatValue)(params.value);
|
|
} else {
|
|
return String(params.value);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/activeManager.ts
|
|
var import_ag_charts_core66 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/chartOptionsDefs.ts
|
|
var import_ag_charts_core65 = require("ag-charts-core");
|
|
var initialStatePickedOptionsDef = {
|
|
activeItem: {
|
|
type: (0, import_ag_charts_core65.required)((0, import_ag_charts_core65.strictUnion)()("series-node", "legend")),
|
|
seriesId: import_ag_charts_core65.string,
|
|
itemId: (0, import_ag_charts_core65.required)((0, import_ag_charts_core65.or)(import_ag_charts_core65.string, import_ag_charts_core65.positiveNumber))
|
|
}
|
|
};
|
|
initialStatePickedOptionsDef.frozen = (0, import_ag_charts_core65.undocumented)(import_ag_charts_core65.boolean);
|
|
var commonChartOptions = {
|
|
mode: (0, import_ag_charts_core65.undocumented)((0, import_ag_charts_core65.union)("integrated", "standalone")),
|
|
container: import_ag_charts_core65.htmlElement,
|
|
context: () => true,
|
|
theme: import_ag_charts_core65.defined,
|
|
series: import_ag_charts_core65.array,
|
|
annotations: import_ag_charts_core65.defined,
|
|
navigator: import_ag_charts_core65.defined,
|
|
scrollbar: import_ag_charts_core65.defined,
|
|
initialState: {
|
|
active: initialStatePickedOptionsDef,
|
|
chartType: import_ag_charts_core65.string,
|
|
annotations: import_ag_charts_core65.defined,
|
|
legend: (0, import_ag_charts_core65.arrayOfDefs)(
|
|
{
|
|
visible: import_ag_charts_core65.boolean,
|
|
seriesId: import_ag_charts_core65.string,
|
|
itemId: import_ag_charts_core65.string,
|
|
legendItemName: import_ag_charts_core65.string
|
|
},
|
|
"legend state array"
|
|
),
|
|
zoom: import_ag_charts_core65.defined
|
|
}
|
|
};
|
|
var cartesianChartOptionsDefs = {
|
|
...import_ag_charts_core65.commonChartOptionsDefs,
|
|
...commonChartOptions,
|
|
axes: import_ag_charts_core65.object,
|
|
data: import_ag_charts_core65.array
|
|
};
|
|
var polarChartOptionsDefs = {
|
|
...import_ag_charts_core65.commonChartOptionsDefs,
|
|
...commonChartOptions,
|
|
axes: import_ag_charts_core65.object,
|
|
data: import_ag_charts_core65.array
|
|
};
|
|
var topologyChartOptionsDefs = {
|
|
...import_ag_charts_core65.commonChartOptionsDefs,
|
|
...commonChartOptions,
|
|
data: import_ag_charts_core65.array,
|
|
topology: import_ag_charts_core65.geoJson
|
|
};
|
|
var standaloneChartOptionsDefs = {
|
|
...import_ag_charts_core65.commonChartOptionsDefs,
|
|
...commonChartOptions,
|
|
data: import_ag_charts_core65.array
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/interactionManager.ts
|
|
var InteractionState = /* @__PURE__ */ ((InteractionState2) => {
|
|
InteractionState2[InteractionState2["Default"] = 64] = "Default";
|
|
InteractionState2[InteractionState2["ZoomDrag"] = 32] = "ZoomDrag";
|
|
InteractionState2[InteractionState2["Annotations"] = 16] = "Annotations";
|
|
InteractionState2[InteractionState2["ContextMenu"] = 8] = "ContextMenu";
|
|
InteractionState2[InteractionState2["Animation"] = 4] = "Animation";
|
|
InteractionState2[InteractionState2["AnnotationsSelected"] = 2] = "AnnotationsSelected";
|
|
InteractionState2[InteractionState2["Frozen"] = 1] = "Frozen";
|
|
InteractionState2[InteractionState2["Clickable"] = 82] = "Clickable";
|
|
InteractionState2[InteractionState2["Focusable"] = 68] = "Focusable";
|
|
InteractionState2[InteractionState2["Keyable"] = 86] = "Keyable";
|
|
InteractionState2[InteractionState2["ContextMenuable"] = 72] = "ContextMenuable";
|
|
InteractionState2[InteractionState2["AnnotationsMoveable"] = 18] = "AnnotationsMoveable";
|
|
InteractionState2[InteractionState2["AnnotationsDraggable"] = 114] = "AnnotationsDraggable";
|
|
InteractionState2[InteractionState2["ZoomDraggable"] = 100] = "ZoomDraggable";
|
|
InteractionState2[InteractionState2["ZoomClickable"] = 68] = "ZoomClickable";
|
|
InteractionState2[InteractionState2["ZoomWheelable"] = 118] = "ZoomWheelable";
|
|
InteractionState2[InteractionState2["All"] = 126] = "All";
|
|
return InteractionState2;
|
|
})(InteractionState || {});
|
|
var InteractionManager = class {
|
|
constructor() {
|
|
this.stateQueue = 64 /* Default */ | 4 /* Animation */;
|
|
}
|
|
pushState(state) {
|
|
this.stateQueue |= state;
|
|
}
|
|
popState(state) {
|
|
this.stateQueue &= ~state;
|
|
}
|
|
isState(allowedStates) {
|
|
return !!(this.stateQueue & -this.stateQueue & allowedStates);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/activeManager.ts
|
|
var ActiveManager = class {
|
|
constructor(chartService, eventsHub, updateService, interactionManager, fireEvent) {
|
|
this.chartService = chartService;
|
|
this.eventsHub = eventsHub;
|
|
this.interactionManager = interactionManager;
|
|
this.fireEvent = fireEvent;
|
|
this.mementoOriginatorKey = "active";
|
|
this.updateable = true;
|
|
// FIXME: same pattern as `ZoomManager`. Perhaps an architectural rewrite is warranted.
|
|
this.didLayout = false;
|
|
this.pendingMemento = void 0;
|
|
const removeListener = updateService.addListener("pre-scene-render", () => {
|
|
this.didLayout = true;
|
|
const { pendingMemento } = this;
|
|
if (pendingMemento) {
|
|
this.restoreMemento(pendingMemento.version, pendingMemento.mementoVersion, pendingMemento.memento);
|
|
this.pendingMemento = void 0;
|
|
}
|
|
removeListener();
|
|
});
|
|
}
|
|
isFrozen() {
|
|
return this.interactionManager.isState(1 /* Frozen */);
|
|
}
|
|
clear() {
|
|
this.update(void 0, void 0);
|
|
}
|
|
update(newItemState, nodeDatum) {
|
|
this.performUpdate("user-interaction", newItemState, nodeDatum, false);
|
|
}
|
|
performUpdate(source, newItemState, nodeDatum, frozenChanged) {
|
|
if (!this.updateable)
|
|
return;
|
|
const oldItemState = this.currentItem;
|
|
this.currentItem = newItemState;
|
|
this.eventsHub.emit("active:update", newItemState);
|
|
if (frozenChanged || !(0, import_ag_charts_core66.objectsEqual)(oldItemState, newItemState)) {
|
|
const { activeItem } = this.createMemento();
|
|
const { datum } = nodeDatum ?? {};
|
|
this.fireEvent({ type: "activeChange", source, activeItem, datum });
|
|
}
|
|
}
|
|
createMemento() {
|
|
switch (this.currentItem?.type) {
|
|
case "series-node":
|
|
case "legend": {
|
|
const { type, seriesId, itemId } = this.currentItem;
|
|
return { activeItem: { type, seriesId, itemId } };
|
|
}
|
|
default:
|
|
this.currentItem?.type;
|
|
return {};
|
|
}
|
|
}
|
|
guardMemento(blob, messages) {
|
|
if (blob == void 0)
|
|
return true;
|
|
const validationResult = (0, import_ag_charts_core66.validate)(blob, commonChartOptions.initialState.active);
|
|
messages.push(...validationResult.invalid.map((err) => err.toString()));
|
|
return validationResult.invalid.length === 0;
|
|
}
|
|
restoreMemento(version, mementoVersion, memento) {
|
|
if (!this.didLayout) {
|
|
this.pendingMemento = { version, mementoVersion, memento };
|
|
return;
|
|
}
|
|
this.updateable = false;
|
|
const [activeItem, nodeDatum] = this.performRestoration(memento?.activeItem);
|
|
this.updateable = true;
|
|
const oldFrozen = this.isFrozen();
|
|
const newFrozen = memento?.frozen;
|
|
const frozenChanged = newFrozen === void 0 ? false : oldFrozen !== newFrozen;
|
|
if (newFrozen === true) {
|
|
this.interactionManager.pushState(1 /* Frozen */);
|
|
} else if (newFrozen === false) {
|
|
this.interactionManager.popState(1 /* Frozen */);
|
|
} else {
|
|
newFrozen;
|
|
}
|
|
this.performUpdate("state-change", activeItem, nodeDatum, frozenChanged);
|
|
}
|
|
performRestoration(activeItem) {
|
|
let rejection = false;
|
|
const reject = () => rejection = true;
|
|
let nodeDatum = void 0;
|
|
const setDatum = (d) => nodeDatum = d;
|
|
const initialState = this.pendingMemento !== void 0;
|
|
const chartId = this.chartService.id;
|
|
this.eventsHub.emit("active:load-memento", { initialState, chartId, activeItem, reject, setDatum });
|
|
return rejection ? [void 0, void 0] : [activeItem, nodeDatum];
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/animationManager.ts
|
|
var import_ag_charts_core82 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/motion/animation.ts
|
|
var import_ag_charts_core68 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/util/interpolate.ts
|
|
var import_ag_charts_core67 = require("ag-charts-core");
|
|
function interpolateNumber(a, b) {
|
|
return (d) => Number(a) * (1 - d) + Number(b) * d;
|
|
}
|
|
function interpolateColor(a, b) {
|
|
if (typeof a === "string") {
|
|
try {
|
|
a = import_ag_charts_core67.Color.fromString(a);
|
|
} catch {
|
|
a = import_ag_charts_core67.Color.fromArray([0, 0, 0]);
|
|
}
|
|
}
|
|
if (typeof b === "string") {
|
|
try {
|
|
b = import_ag_charts_core67.Color.fromString(b);
|
|
} catch {
|
|
b = import_ag_charts_core67.Color.fromArray([0, 0, 0]);
|
|
}
|
|
}
|
|
return (d) => import_ag_charts_core67.Color.mix(a, b, d).toRgbaString();
|
|
}
|
|
|
|
// packages/ag-charts-community/src/motion/animation.ts
|
|
var QUICK_TRANSITION = 0.2;
|
|
var PHASE_ORDER = ["initial", "remove", "update", "add", "trailing", "end", "none"];
|
|
var PHASE_METADATA = {
|
|
initial: {
|
|
animationDuration: 1,
|
|
animationDelay: 0
|
|
},
|
|
add: {
|
|
animationDuration: 0.25,
|
|
animationDelay: 0.75
|
|
},
|
|
remove: {
|
|
animationDuration: 0.25,
|
|
animationDelay: 0
|
|
},
|
|
update: {
|
|
animationDuration: 0.5,
|
|
animationDelay: 0.25
|
|
},
|
|
trailing: {
|
|
animationDuration: QUICK_TRANSITION,
|
|
animationDelay: 1,
|
|
skipIfNoEarlierAnimations: true
|
|
},
|
|
end: {
|
|
animationDelay: 1 + QUICK_TRANSITION,
|
|
animationDuration: 0,
|
|
skipIfNoEarlierAnimations: true
|
|
},
|
|
none: {
|
|
animationDuration: 0,
|
|
animationDelay: 0
|
|
}
|
|
};
|
|
function isNodeArray(array4) {
|
|
return array4.every((n) => n instanceof Node);
|
|
}
|
|
function deconstructSelectionsOrNodes(selectionsOrNodes) {
|
|
return isNodeArray(selectionsOrNodes) ? { nodes: selectionsOrNodes, selections: [] } : { nodes: [], selections: selectionsOrNodes };
|
|
}
|
|
function animationValuesEqual(a, b) {
|
|
if (a === b) {
|
|
return true;
|
|
} else if (Array.isArray(a) && Array.isArray(b)) {
|
|
return a.length === b.length && a.every((v, i) => animationValuesEqual(v, b[i]));
|
|
} else if (isInterpolating(a) && isInterpolating(b)) {
|
|
return a.equals(b);
|
|
} else if ((0, import_ag_charts_core68.isPlainObject)(a) && (0, import_ag_charts_core68.isPlainObject)(b)) {
|
|
return (0, import_ag_charts_core68.objectsEqualWith)(a, b, animationValuesEqual);
|
|
}
|
|
return false;
|
|
}
|
|
var Animation = class {
|
|
constructor(opts) {
|
|
this.isComplete = false;
|
|
this.elapsed = 0;
|
|
this.iteration = 0;
|
|
this.isPlaying = false;
|
|
this.isReverse = false;
|
|
this.id = opts.id;
|
|
this.groupId = opts.groupId;
|
|
this.autoplay = opts.autoplay ?? true;
|
|
this.ease = opts.ease ?? import_ag_charts_core68.linear;
|
|
this.phase = opts.phase;
|
|
const durationProportion = opts.duration ?? PHASE_METADATA[this.phase].animationDuration;
|
|
this.duration = durationProportion * opts.defaultDuration;
|
|
this.delay = (opts.delay ?? 0) * opts.defaultDuration;
|
|
this.onComplete = opts.onComplete;
|
|
this.onPlay = opts.onPlay;
|
|
this.onStop = opts.onStop;
|
|
this.onUpdate = opts.onUpdate;
|
|
this.interpolate = this.createInterpolator(opts.from, opts.to);
|
|
this.from = opts.from;
|
|
if (opts.skip === true) {
|
|
this.onUpdate?.(opts.to, false, this);
|
|
this.onStop?.(this);
|
|
this.onComplete?.(this);
|
|
this.isComplete = true;
|
|
}
|
|
if (opts.collapsable !== false) {
|
|
this.duration = this.checkCollapse(opts, this.duration);
|
|
}
|
|
}
|
|
checkCollapse(opts, calculatedDuration) {
|
|
return animationValuesEqual(opts.from, opts.to) ? 0 : calculatedDuration;
|
|
}
|
|
play(initialUpdate = false) {
|
|
if (this.isPlaying || this.isComplete)
|
|
return;
|
|
this.isPlaying = true;
|
|
this.onPlay?.(this);
|
|
if (!this.autoplay)
|
|
return;
|
|
this.autoplay = false;
|
|
if (!initialUpdate)
|
|
return;
|
|
this.onUpdate?.(this.from, true, this);
|
|
}
|
|
stop() {
|
|
this.isPlaying = false;
|
|
if (!this.isComplete) {
|
|
this.isComplete = true;
|
|
this.onStop?.(this);
|
|
}
|
|
}
|
|
update(time3) {
|
|
if (this.isComplete)
|
|
return time3;
|
|
if (!this.isPlaying && this.autoplay) {
|
|
this.play(true);
|
|
}
|
|
const previousElapsed = this.elapsed;
|
|
this.elapsed += time3;
|
|
if (this.delay > this.elapsed)
|
|
return 0;
|
|
const value = this.interpolate(this.isReverse ? 1 - this.delta : this.delta);
|
|
this.onUpdate?.(value, false, this);
|
|
const totalDuration = this.delay + this.duration;
|
|
if (this.elapsed >= totalDuration) {
|
|
this.stop();
|
|
this.isComplete = true;
|
|
this.onComplete?.(this);
|
|
return time3 - (totalDuration - previousElapsed);
|
|
}
|
|
return 0;
|
|
}
|
|
get delta() {
|
|
return this.ease((0, import_ag_charts_core68.clamp)(0, (this.elapsed - this.delay) / this.duration, 1));
|
|
}
|
|
createInterpolator(from, to) {
|
|
if (typeof to !== "object" || isInterpolating(to)) {
|
|
return this.interpolateValue(from, to);
|
|
} else if (Array.isArray(to)) {
|
|
const interpolatorValues = [];
|
|
for (let i = 0; i < to.length; i++) {
|
|
const interpolator = this.createInterpolator(from[i], to[i]);
|
|
if (interpolator != null) {
|
|
interpolatorValues.push(interpolator);
|
|
}
|
|
}
|
|
return (d) => {
|
|
const out = [];
|
|
for (const interpolator of interpolatorValues) {
|
|
out.push(interpolator(d));
|
|
}
|
|
return out;
|
|
};
|
|
}
|
|
const interpolatorEntries = [];
|
|
for (const key of Object.keys(to)) {
|
|
const interpolator = this.createInterpolator(from[key], to[key]);
|
|
if (interpolator != null) {
|
|
interpolatorEntries.push([key, interpolator]);
|
|
}
|
|
}
|
|
return (d) => {
|
|
const result = {};
|
|
for (const [key, interpolator] of interpolatorEntries) {
|
|
result[key] = interpolator(d);
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
interpolateValue(a, b) {
|
|
if (a == null || b == null) {
|
|
return;
|
|
} else if (isInterpolating(a)) {
|
|
return (d) => a[interpolate](b, d);
|
|
}
|
|
try {
|
|
switch (typeof a) {
|
|
case "number":
|
|
return interpolateNumber(a, b);
|
|
case "string":
|
|
return interpolateColor(a, b);
|
|
case "boolean":
|
|
if (a === b) {
|
|
return () => a;
|
|
}
|
|
break;
|
|
case "object":
|
|
return () => a;
|
|
default:
|
|
throw new Error(`Unable to interpolate values: ${a}, ${b}`);
|
|
}
|
|
} catch {
|
|
}
|
|
throw new Error(`Unable to interpolate values: ${a}, ${b}`);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/processors.ts
|
|
var import_ag_charts_core80 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/data/aggregateFunctions.ts
|
|
var import_ag_charts_core69 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/utils/bandedStructure.ts
|
|
function adjustBandForInsertion(band, insertIndex, insertCount, isLastBand) {
|
|
if (insertIndex < band.startIndex) {
|
|
band.startIndex += insertCount;
|
|
band.endIndex += insertCount;
|
|
return false;
|
|
} else if (insertIndex < band.endIndex || insertIndex === band.endIndex && isLastBand) {
|
|
band.endIndex += insertCount;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function adjustBandForRemoval(band, removeIndex, removeCount) {
|
|
const removeEnd = removeIndex + removeCount;
|
|
if (removeEnd <= band.startIndex) {
|
|
band.startIndex = Math.max(0, band.startIndex - removeCount);
|
|
band.endIndex = Math.max(band.startIndex, band.endIndex - removeCount);
|
|
return false;
|
|
} else if (removeIndex >= band.endIndex) {
|
|
return false;
|
|
} else {
|
|
if (removeIndex <= band.startIndex && removeEnd >= band.endIndex) {
|
|
band.startIndex = removeIndex;
|
|
band.endIndex = removeIndex;
|
|
} else if (removeIndex <= band.startIndex) {
|
|
const deletedFromBand = removeEnd - band.startIndex;
|
|
const oldBandSize = band.endIndex - band.startIndex;
|
|
band.startIndex = removeIndex;
|
|
band.endIndex = band.startIndex + Math.max(0, oldBandSize - deletedFromBand);
|
|
} else if (removeEnd >= band.endIndex) {
|
|
band.endIndex = Math.max(band.startIndex, removeIndex);
|
|
} else {
|
|
band.endIndex = Math.max(band.startIndex, band.endIndex - removeCount);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
function calculateTargetBandCount(dataSize, minBandCount) {
|
|
const derivedCount = Math.ceil(dataSize / 1e3);
|
|
return Math.max(minBandCount, derivedCount);
|
|
}
|
|
function calculateIdealBandSize(dataSize, targetBandCount) {
|
|
return Math.max(1, Math.ceil(dataSize / targetBandCount));
|
|
}
|
|
function filterEmptyBands(bands) {
|
|
return bands.filter((band) => band.endIndex > band.startIndex);
|
|
}
|
|
function initializeBandArray(dataSize, config, bandFactory) {
|
|
if (!config.enableBanding || dataSize < config.minDataSizeForBanding) {
|
|
return [bandFactory(0, dataSize)];
|
|
}
|
|
const targetBandCount = calculateTargetBandCount(dataSize, config.targetBandCount);
|
|
const bandSize = calculateIdealBandSize(dataSize, targetBandCount);
|
|
const bands = [];
|
|
for (let startIndex = 0; startIndex < dataSize; startIndex += bandSize) {
|
|
const endIndex = Math.min(startIndex + bandSize, dataSize);
|
|
bands.push(bandFactory(startIndex, endIndex));
|
|
}
|
|
return bands;
|
|
}
|
|
function applySpliceOperations(bandHandler, spliceOps) {
|
|
for (const op of spliceOps) {
|
|
if (op.insertCount > 0) {
|
|
bandHandler.handleInsertion(op.index, op.insertCount);
|
|
}
|
|
if (op.deleteCount > 0) {
|
|
bandHandler.handleRemoval(op.index, op.deleteCount);
|
|
}
|
|
}
|
|
}
|
|
function markUpdatedIndices(bandHandler, updatedIndices) {
|
|
for (const index of updatedIndices) {
|
|
bandHandler.handleInsertion(index, 0);
|
|
}
|
|
}
|
|
function applyIndexMapToBandHandler(bandHandler, indexMap) {
|
|
applySpliceOperations(bandHandler, indexMap.spliceOps);
|
|
if (indexMap.updatedIndices.size > 0) {
|
|
markUpdatedIndices(bandHandler, indexMap.updatedIndices);
|
|
}
|
|
}
|
|
var DEFAULT_MIN_DATA_SIZE_FOR_BANDING = 1e3;
|
|
var DEFAULT_TARGET_BAND_COUNT = 10;
|
|
var BandedStructure = class {
|
|
constructor(config = {}) {
|
|
this.bands = [];
|
|
this.dataSize = 0;
|
|
this.config = {
|
|
minDataSizeForBanding: config.minDataSizeForBanding ?? DEFAULT_MIN_DATA_SIZE_FOR_BANDING,
|
|
targetBandCount: config.targetBandCount ?? DEFAULT_TARGET_BAND_COUNT,
|
|
maxBandSize: config.maxBandSize ?? Infinity,
|
|
enableBanding: config.enableBanding ?? true
|
|
};
|
|
}
|
|
applyIndexMap(indexMap) {
|
|
applyIndexMapToBandHandler(this, indexMap);
|
|
}
|
|
/**
|
|
* Initializes or rebalances bands based on current data size.
|
|
*/
|
|
initializeBands(dataSize) {
|
|
this.dataSize = Math.max(0, dataSize);
|
|
this.bands = initializeBandArray(
|
|
this.dataSize,
|
|
this.config,
|
|
(startIndex, endIndex) => this.createBand(startIndex, endIndex)
|
|
);
|
|
}
|
|
/**
|
|
* Returns the number of bands currently in this structure.
|
|
* Useful for checking if bands need initialization.
|
|
*/
|
|
getBandCount() {
|
|
return this.bands.length;
|
|
}
|
|
/**
|
|
* Handles insertion of new data by adjusting band indices.
|
|
* Uses proactive band splitting to maintain optimal band sizes.
|
|
*/
|
|
handleInsertion(insertIndex, insertCount) {
|
|
this.dataSize += insertCount;
|
|
if (this.bands.length === 0) {
|
|
this.initializeBands(this.dataSize);
|
|
return;
|
|
}
|
|
const targetBandCount = calculateTargetBandCount(this.dataSize, this.config.targetBandCount);
|
|
const idealBandSize = calculateIdealBandSize(this.dataSize, targetBandCount);
|
|
const maxBandSize = Math.ceil(idealBandSize * 1.1);
|
|
for (let i = 0; i < this.bands.length; i++) {
|
|
const band = this.bands[i];
|
|
const isLastBand = i === this.bands.length - 1;
|
|
if (insertIndex === band.endIndex && isLastBand && insertCount > 0) {
|
|
const currentBandSize = band.endIndex - band.startIndex;
|
|
if (currentBandSize >= idealBandSize) {
|
|
this.bands.push(this.createBand(insertIndex, insertIndex + insertCount));
|
|
} else {
|
|
band.endIndex += insertCount;
|
|
band.isDirty = true;
|
|
}
|
|
break;
|
|
}
|
|
const wasDirty = adjustBandForInsertion(band, insertIndex, insertCount, isLastBand);
|
|
if (wasDirty) {
|
|
band.isDirty = true;
|
|
if (insertCount > 0 && insertIndex < band.endIndex) {
|
|
const bandSize = band.endIndex - band.startIndex;
|
|
if (bandSize > maxBandSize) {
|
|
this.splitBand(i, idealBandSize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Handles removal of data by adjusting band indices.
|
|
* Uses shared utilities for consistent band manipulation.
|
|
*/
|
|
handleRemoval(removeIndex, removeCount) {
|
|
if (removeCount <= 0 || this.bands.length === 0)
|
|
return;
|
|
const effectiveRemoveCount = Math.min(removeCount, Math.max(0, this.dataSize - removeIndex));
|
|
if (effectiveRemoveCount <= 0)
|
|
return;
|
|
this.dataSize = Math.max(0, this.dataSize - effectiveRemoveCount);
|
|
for (const band of this.bands) {
|
|
const wasDirty = adjustBandForRemoval(band, removeIndex, effectiveRemoveCount);
|
|
if (wasDirty) {
|
|
band.isDirty = true;
|
|
}
|
|
}
|
|
this.bands = filterEmptyBands(this.bands);
|
|
}
|
|
/**
|
|
* Split an oversized band into two smaller bands.
|
|
* Called when a band exceeds maxBandSize during insertion.
|
|
*
|
|
* Strategy:
|
|
* - Split the band as evenly as possible
|
|
* - Both halves marked as dirty (need recalculation)
|
|
* - No cache preservation (splitting indicates data changed)
|
|
*/
|
|
splitBand(bandIndex, idealSize) {
|
|
const band = this.bands[bandIndex];
|
|
const bandSize = band.endIndex - band.startIndex;
|
|
const firstHalfSize = Math.min(idealSize, Math.floor(bandSize / 2));
|
|
const splitPoint = band.startIndex + firstHalfSize;
|
|
const band1 = this.createBand(band.startIndex, splitPoint);
|
|
const band2 = this.createBand(splitPoint, band.endIndex);
|
|
this.bands.splice(bandIndex, 1, band1, band2);
|
|
}
|
|
/**
|
|
* Returns statistics about the banded structure for debugging.
|
|
* Subclasses can override to add domain-specific stats.
|
|
*/
|
|
getStats() {
|
|
const dirtyBands = this.bands.filter((band) => band.isDirty);
|
|
return {
|
|
totalBands: this.bands.length,
|
|
dirtyBands: dirtyBands.length,
|
|
dataSize: this.dataSize
|
|
};
|
|
}
|
|
markRangeDirty(startIndex, endIndex) {
|
|
for (const band of this.bands) {
|
|
if (startIndex < band.endIndex && endIndex > band.startIndex) {
|
|
band.isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/dataDomain.ts
|
|
var DiscreteDomain = class _DiscreteDomain {
|
|
constructor() {
|
|
// Set-based storage (default mode)
|
|
this.domain = /* @__PURE__ */ new Set();
|
|
this.dateTimestamps = /* @__PURE__ */ new Set();
|
|
this.hasDateValues = false;
|
|
// Sorted array storage (optimized mode for sorted unique data)
|
|
this.sortedValues = null;
|
|
this.sortOrder = void 0;
|
|
this.isSortedUnique = false;
|
|
}
|
|
static is(value) {
|
|
return value instanceof _DiscreteDomain;
|
|
}
|
|
/**
|
|
* Configure domain for sorted unique mode.
|
|
* When enabled, uses a single array for O(1) append.
|
|
* Call this before extending with data.
|
|
*/
|
|
setSortedUniqueMode(sortOrder, isUnique) {
|
|
if (isUnique) {
|
|
this.isSortedUnique = true;
|
|
this.sortOrder = sortOrder;
|
|
this.sortedValues = [];
|
|
}
|
|
}
|
|
extend(val) {
|
|
if (this.isSortedUnique && this.sortedValues) {
|
|
this.sortedValues.push(val);
|
|
if (val instanceof Date) {
|
|
this.hasDateValues = true;
|
|
}
|
|
} else if (val instanceof Date) {
|
|
this.hasDateValues = true;
|
|
this.dateTimestamps.add(val.valueOf());
|
|
} else {
|
|
this.domain.add(val);
|
|
}
|
|
}
|
|
getDomain() {
|
|
if (this.isSortedUnique && this.sortedValues) {
|
|
let hasSeenInvalid = false;
|
|
return this.sortedValues.filter((v) => {
|
|
if (v == null) {
|
|
if (hasSeenInvalid)
|
|
return false;
|
|
hasSeenInvalid = true;
|
|
return true;
|
|
}
|
|
if (v instanceof Date && Number.isNaN(v.valueOf())) {
|
|
if (hasSeenInvalid)
|
|
return false;
|
|
hasSeenInvalid = true;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
if (this.hasDateValues) {
|
|
const dates = Array.from(this.dateTimestamps, (ts) => new Date(ts));
|
|
if (this.domain.size > 0) {
|
|
return [...dates, ...Array.from(this.domain)];
|
|
}
|
|
return dates;
|
|
}
|
|
return Array.from(this.domain);
|
|
}
|
|
/** Returns true if this domain contains Date values stored as timestamps */
|
|
isDateDomain() {
|
|
return this.hasDateValues;
|
|
}
|
|
/** Returns true if this domain is in sorted unique mode */
|
|
isSortedUniqueMode() {
|
|
return this.isSortedUnique;
|
|
}
|
|
/** Returns the sort order if in sorted mode, undefined otherwise */
|
|
getSortOrder() {
|
|
return this.sortOrder;
|
|
}
|
|
/** Merges another DiscreteDomain's values into this one */
|
|
mergeFrom(other) {
|
|
if (this.isSortedUnique && other.isSortedUnique && this.sortOrder === other.sortOrder && this.sortOrder !== void 0 && other.sortedValues) {
|
|
if (other.hasDateValues) {
|
|
this.hasDateValues = true;
|
|
}
|
|
this.sortedValues ?? (this.sortedValues = []);
|
|
this.sortedValues.push(...other.sortedValues);
|
|
return;
|
|
}
|
|
this.convertToSetMode();
|
|
if (other.hasDateValues) {
|
|
this.hasDateValues = true;
|
|
}
|
|
if (other.isSortedUnique && other.sortedValues) {
|
|
for (const val of other.sortedValues) {
|
|
if (val instanceof Date) {
|
|
this.dateTimestamps.add(val.valueOf());
|
|
} else {
|
|
this.domain.add(val);
|
|
}
|
|
}
|
|
} else {
|
|
for (const ts of other.dateTimestamps) {
|
|
this.dateTimestamps.add(ts);
|
|
}
|
|
for (const val of other.domain) {
|
|
this.domain.add(val);
|
|
}
|
|
}
|
|
}
|
|
/** Converts from sorted array mode to Set mode (one-way transition) */
|
|
convertToSetMode() {
|
|
if (!this.isSortedUnique)
|
|
return;
|
|
if (this.sortedValues) {
|
|
for (const val of this.sortedValues) {
|
|
if (val instanceof Date) {
|
|
this.dateTimestamps.add(val.valueOf());
|
|
} else {
|
|
this.domain.add(val);
|
|
}
|
|
}
|
|
this.sortedValues = null;
|
|
}
|
|
this.isSortedUnique = false;
|
|
this.sortOrder = void 0;
|
|
}
|
|
};
|
|
var ContinuousDomain = class _ContinuousDomain {
|
|
constructor() {
|
|
this.domain = [Infinity, -Infinity];
|
|
}
|
|
static is(value) {
|
|
return value instanceof _ContinuousDomain;
|
|
}
|
|
static extendDomain(values, domain = [Infinity, -Infinity]) {
|
|
for (const value of values) {
|
|
if (typeof value !== "number") {
|
|
continue;
|
|
}
|
|
if (domain[0] > value) {
|
|
domain[0] = value;
|
|
}
|
|
if (domain[1] < value) {
|
|
domain[1] = value;
|
|
}
|
|
}
|
|
return domain;
|
|
}
|
|
extend(value) {
|
|
if (typeof value !== "number" && !(value instanceof Date)) {
|
|
return;
|
|
}
|
|
if (this.domain[0] > value) {
|
|
this.domain[0] = value;
|
|
}
|
|
if (this.domain[1] < value) {
|
|
this.domain[1] = value;
|
|
}
|
|
}
|
|
getDomain() {
|
|
return [...this.domain];
|
|
}
|
|
};
|
|
var BandedDomain = class extends BandedStructure {
|
|
constructor(domainFactory, config = {}, isDiscrete = false) {
|
|
super(config);
|
|
this.fullDomainCache = null;
|
|
// Sort order metadata for optimization (set from KEY_SORT_ORDERS)
|
|
this.sortOrder = void 0;
|
|
this.isUnique = false;
|
|
this.domainFactory = domainFactory;
|
|
this.isDiscrete = isDiscrete;
|
|
}
|
|
/**
|
|
* Set sort order metadata from KEY_SORT_ORDERS.
|
|
* When data is sorted and unique, enables fast array concatenation in getDomain().
|
|
*/
|
|
setSortOrderMetadata(sortOrder, isUnique) {
|
|
this.sortOrder = sortOrder;
|
|
this.isUnique = isUnique;
|
|
}
|
|
/**
|
|
* Creates a new domain band with its own sub-domain instance.
|
|
* Configures sub-domain for sorted mode if applicable.
|
|
*/
|
|
createBand(startIndex, endIndex) {
|
|
const subDomain = this.domainFactory();
|
|
if (this.isDiscrete && this.sortOrder !== void 0 && this.isUnique) {
|
|
if (DiscreteDomain.is(subDomain)) {
|
|
subDomain.setSortedUniqueMode(this.sortOrder, this.isUnique);
|
|
}
|
|
}
|
|
return {
|
|
startIndex,
|
|
endIndex,
|
|
subDomain,
|
|
isDirty: true
|
|
};
|
|
}
|
|
/**
|
|
* Initializes bands and clears the full domain cache.
|
|
*/
|
|
initializeBands(dataSize) {
|
|
super.initializeBands(dataSize);
|
|
this.fullDomainCache = null;
|
|
}
|
|
/**
|
|
* Handles insertion and clears the full domain cache.
|
|
*/
|
|
handleInsertion(insertIndex, insertCount) {
|
|
super.handleInsertion(insertIndex, insertCount);
|
|
this.fullDomainCache = null;
|
|
}
|
|
/**
|
|
* Handles removal and clears the full domain cache.
|
|
*/
|
|
handleRemoval(removeIndex, removeCount) {
|
|
super.handleRemoval(removeIndex, removeCount);
|
|
this.fullDomainCache = null;
|
|
}
|
|
/**
|
|
* Split an oversized band into two smaller bands.
|
|
* Override to handle band splitting for large datasets where banding is beneficial.
|
|
*/
|
|
splitBand(bandIndex, idealSize) {
|
|
if (this.bands.length > 1) {
|
|
super.splitBand(bandIndex, idealSize);
|
|
}
|
|
}
|
|
/**
|
|
* Marks bands as dirty that need rescanning.
|
|
*/
|
|
markBandsDirty(startIndex, endIndex) {
|
|
this.markRangeDirty(startIndex, endIndex);
|
|
this.fullDomainCache = null;
|
|
}
|
|
/**
|
|
* Marks all bands as dirty, forcing a full rescan.
|
|
*/
|
|
markAllBandsDirty() {
|
|
for (const band of this.bands) {
|
|
band.isDirty = true;
|
|
}
|
|
this.fullDomainCache = null;
|
|
}
|
|
/**
|
|
* Extends the domain with values from specified bands.
|
|
* This is called after dirty bands have been rescanned.
|
|
*/
|
|
extendBandsFromData(data, invalidData) {
|
|
const dataLength = data.length;
|
|
for (const band of this.bands) {
|
|
if (!band.isDirty)
|
|
continue;
|
|
const subDomain = this.domainFactory();
|
|
if (this.isDiscrete && this.sortOrder !== void 0 && this.isUnique) {
|
|
if (DiscreteDomain.is(subDomain)) {
|
|
subDomain.setSortedUniqueMode(this.sortOrder, this.isUnique);
|
|
}
|
|
}
|
|
band.subDomain = subDomain;
|
|
const { startIndex, endIndex } = band;
|
|
for (let i = startIndex; i < endIndex && i < dataLength; i++) {
|
|
if (invalidData?.[i])
|
|
continue;
|
|
band.subDomain.extend(data[i]);
|
|
}
|
|
band.isDirty = false;
|
|
}
|
|
this.fullDomainCache = null;
|
|
}
|
|
/**
|
|
* Gets the bands that need rescanning.
|
|
*/
|
|
getDirtyBands() {
|
|
return this.bands.filter((band) => band.isDirty);
|
|
}
|
|
/**
|
|
* Standard IDataDomain interface - extends domain with a single value.
|
|
* Note: This is less efficient than batch operations with bands.
|
|
*/
|
|
extend(_value) {
|
|
this.markAllBandsDirty();
|
|
this.fullDomainCache = null;
|
|
}
|
|
/**
|
|
* Check if all sub-domains support fast sorted concatenation.
|
|
*/
|
|
canUseSortedConcatenation() {
|
|
if (!this.sortOrder || !this.isUnique || !this.isDiscrete)
|
|
return false;
|
|
for (const band of this.bands) {
|
|
if (!DiscreteDomain.is(band.subDomain))
|
|
return false;
|
|
if (!band.subDomain.isSortedUniqueMode())
|
|
return false;
|
|
if (band.subDomain.getSortOrder() !== this.sortOrder)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
/**
|
|
* Concatenate sorted domains efficiently.
|
|
* Only valid when canUseSortedConcatenation() returns true.
|
|
*/
|
|
concatenateSortedDomains() {
|
|
const combined = new DiscreteDomain();
|
|
combined.setSortedUniqueMode(this.sortOrder, this.isUnique);
|
|
for (const band of this.bands) {
|
|
if (DiscreteDomain.is(band.subDomain)) {
|
|
combined.mergeFrom(band.subDomain);
|
|
}
|
|
}
|
|
return combined.getDomain();
|
|
}
|
|
/**
|
|
* Deduplicate nulls and Invalid Dates in a domain result array.
|
|
* These represent invalid data and may appear from multiple bands.
|
|
*/
|
|
deduplicateNulls(result) {
|
|
let hasSeenInvalid = false;
|
|
return result.filter((v) => {
|
|
if (v == null) {
|
|
if (hasSeenInvalid)
|
|
return false;
|
|
hasSeenInvalid = true;
|
|
return true;
|
|
}
|
|
if (v instanceof Date && Number.isNaN(v.valueOf())) {
|
|
if (hasSeenInvalid)
|
|
return false;
|
|
hasSeenInvalid = true;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
/**
|
|
* Combines all band sub-domains to get the overall domain.
|
|
*/
|
|
getDomain() {
|
|
if (this.fullDomainCache !== null) {
|
|
return this.fullDomainCache;
|
|
}
|
|
if (this.bands.length === 0) {
|
|
this.fullDomainCache = [];
|
|
return [];
|
|
}
|
|
if (this.bands.length === 1) {
|
|
const result = this.bands[0].subDomain.getDomain();
|
|
this.fullDomainCache = this.isDiscrete ? this.deduplicateNulls(result) : result;
|
|
return this.fullDomainCache;
|
|
}
|
|
if (this.isDiscrete) {
|
|
const firstBand = this.bands[0].subDomain;
|
|
if (DiscreteDomain.is(firstBand)) {
|
|
if (this.canUseSortedConcatenation()) {
|
|
this.fullDomainCache = this.deduplicateNulls(this.concatenateSortedDomains());
|
|
} else {
|
|
const combined = new DiscreteDomain();
|
|
for (const band of this.bands) {
|
|
if (DiscreteDomain.is(band.subDomain)) {
|
|
combined.mergeFrom(band.subDomain);
|
|
}
|
|
}
|
|
this.fullDomainCache = this.deduplicateNulls(combined.getDomain());
|
|
}
|
|
} else {
|
|
const combined = /* @__PURE__ */ new Set();
|
|
for (const band of this.bands) {
|
|
for (const value of band.subDomain.getDomain()) {
|
|
combined.add(value);
|
|
}
|
|
}
|
|
this.fullDomainCache = Array.from(combined);
|
|
}
|
|
} else {
|
|
let min;
|
|
let max;
|
|
for (const band of this.bands) {
|
|
const bandDomain = band.subDomain.getDomain();
|
|
if (bandDomain.length === 2) {
|
|
const [bandMin, bandMax] = bandDomain;
|
|
if (min === void 0 || bandMin != null && min != null && bandMin < min) {
|
|
min = bandMin;
|
|
}
|
|
if (max === void 0 || bandMax != null && max != null && bandMax > max) {
|
|
max = bandMax;
|
|
}
|
|
}
|
|
}
|
|
if (min !== void 0 && max !== void 0) {
|
|
this.fullDomainCache = [min, max];
|
|
} else {
|
|
this.fullDomainCache = [];
|
|
}
|
|
}
|
|
return this.fullDomainCache;
|
|
}
|
|
/**
|
|
* Returns statistics about the banded domain for debugging.
|
|
*/
|
|
getStats() {
|
|
const dirtyCount = this.bands.filter((b) => b.isDirty).length;
|
|
const totalSize = this.bands.reduce((sum, b) => sum + (b.endIndex - b.startIndex), 0);
|
|
return {
|
|
bandCount: this.bands.length,
|
|
dirtyBandCount: dirtyCount,
|
|
averageBandSize: this.bands.length > 0 ? totalSize / this.bands.length : 0,
|
|
dataSize: this.dataSize
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/aggregateFunctions.ts
|
|
function sumValues(values, accumulator = [0, 0]) {
|
|
for (const value of values) {
|
|
if (typeof value !== "number") {
|
|
continue;
|
|
}
|
|
if (value < 0) {
|
|
accumulator[0] += value;
|
|
}
|
|
if (value > 0) {
|
|
accumulator[1] += value;
|
|
}
|
|
}
|
|
return accumulator;
|
|
}
|
|
function groupSum(id, opts) {
|
|
const visible = opts?.visible ?? true;
|
|
return {
|
|
id,
|
|
type: "aggregate",
|
|
matchGroupIds: opts?.matchGroupId ? [opts?.matchGroupId] : void 0,
|
|
aggregateFunction: (values) => sumValues(values),
|
|
groupAggregateFunction: (next, acc = [0, 0]) => {
|
|
if (visible) {
|
|
acc[0] += next?.[0] ?? 0;
|
|
acc[1] += next?.[1] ?? 0;
|
|
}
|
|
return acc;
|
|
}
|
|
};
|
|
}
|
|
function range(id, matchGroupId) {
|
|
const result = {
|
|
id,
|
|
matchGroupIds: [matchGroupId],
|
|
type: "aggregate",
|
|
aggregateFunction: (values) => ContinuousDomain.extendDomain(values)
|
|
};
|
|
return result;
|
|
}
|
|
function groupCount(id, opts) {
|
|
const visible = opts?.visible ?? true;
|
|
return {
|
|
id,
|
|
type: "aggregate",
|
|
aggregateFunction: () => [0, 1],
|
|
groupAggregateFunction: (next, acc = [0, 0]) => {
|
|
if (visible) {
|
|
acc[0] += next?.[0] ?? 0;
|
|
acc[1] += next?.[1] ?? 0;
|
|
}
|
|
return acc;
|
|
}
|
|
};
|
|
}
|
|
function groupAverage(id, opts) {
|
|
const visible = opts?.visible ?? true;
|
|
const def = {
|
|
id,
|
|
matchGroupIds: opts?.matchGroupId ? [opts?.matchGroupId] : void 0,
|
|
type: "aggregate",
|
|
aggregateFunction: (values) => sumValues(values),
|
|
groupAggregateFunction: (next, acc = [0, 0, -1]) => {
|
|
if (visible) {
|
|
acc[0] += next?.[0] ?? 0;
|
|
acc[2]++;
|
|
acc[1] += next?.[1] ?? 0;
|
|
}
|
|
return acc;
|
|
},
|
|
finalFunction: (acc = [0, 0, 0]) => {
|
|
const result = acc[0] + acc[1];
|
|
if (result >= 0) {
|
|
return [0, result / acc[2]];
|
|
}
|
|
return [result / acc[2], 0];
|
|
}
|
|
};
|
|
return def;
|
|
}
|
|
function area(id, aggFn, matchGroupId) {
|
|
const result = {
|
|
id,
|
|
matchGroupIds: matchGroupId ? [matchGroupId] : void 0,
|
|
type: "aggregate",
|
|
aggregateFunction: (values, keyRange = []) => {
|
|
const keyWidth = keyRange[1] - keyRange[0];
|
|
return aggFn.aggregateFunction(values).map((v) => v / keyWidth);
|
|
}
|
|
};
|
|
if (aggFn.groupAggregateFunction) {
|
|
result.groupAggregateFunction = aggFn.groupAggregateFunction;
|
|
}
|
|
return result;
|
|
}
|
|
function accumulatedValue(onlyPositive) {
|
|
return () => {
|
|
let value = 0;
|
|
return (datum) => {
|
|
if (!(0, import_ag_charts_core69.isFiniteNumber)(datum)) {
|
|
return datum;
|
|
}
|
|
value += onlyPositive ? Math.max(0, datum) : datum;
|
|
return value;
|
|
};
|
|
};
|
|
}
|
|
function trailingAccumulatedValue() {
|
|
return () => {
|
|
let value = 0;
|
|
return (datum) => {
|
|
if (!(0, import_ag_charts_core69.isFiniteNumber)(datum)) {
|
|
return datum;
|
|
}
|
|
const trailingValue = value;
|
|
value += datum;
|
|
return trailingValue;
|
|
};
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/data/dataModel.ts
|
|
var import_ag_charts_core79 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/aggregation/aggregator.ts
|
|
var import_ag_charts_core71 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/utils/helpers.ts
|
|
var import_ag_charts_core70 = require("ag-charts-core");
|
|
var NULL_KEY_STRING = "\0__AG_NULL__\0";
|
|
var UNDEFINED_KEY_STRING = "\0__AG_UNDEFINED__\0";
|
|
function keyToString(key) {
|
|
if (key === null)
|
|
return NULL_KEY_STRING;
|
|
if (key === void 0)
|
|
return UNDEFINED_KEY_STRING;
|
|
if (Array.isArray(key)) {
|
|
return "[" + key.map(keyToString).join(",") + "]";
|
|
}
|
|
return (0, import_ag_charts_core70.isObject)(key) ? JSON.stringify(key) : String(key);
|
|
}
|
|
function toKeyString(keys) {
|
|
return keys.map(keyToString).join("-");
|
|
}
|
|
function fixNumericExtent(extent6) {
|
|
const numberExtent = extent6?.map(Number);
|
|
return numberExtent?.every(Number.isFinite) ? numberExtent : [];
|
|
}
|
|
function getMissCount(scopeProvider, missMap) {
|
|
return missMap?.get(scopeProvider.id) ?? 0;
|
|
}
|
|
function isScoped(obj) {
|
|
return "scopes" in obj && Array.isArray(obj.scopes);
|
|
}
|
|
function createArray(length, value) {
|
|
const out = [];
|
|
for (let i = 0; i < length; i += 1) {
|
|
out[i] = value;
|
|
}
|
|
return out;
|
|
}
|
|
function uniqueChangeDescriptions(scopeChanges) {
|
|
const deduped = /* @__PURE__ */ new Set();
|
|
for (const changeDesc of scopeChanges.values()) {
|
|
if (changeDesc) {
|
|
deduped.add(changeDesc);
|
|
}
|
|
}
|
|
return deduped;
|
|
}
|
|
function datumKeys(keys, datumIndex, allowNull = false) {
|
|
const out = [];
|
|
for (const k of keys) {
|
|
const key = k?.[datumIndex];
|
|
if (key == null && !allowNull)
|
|
return;
|
|
out.push(key);
|
|
}
|
|
return out;
|
|
}
|
|
function getPathComponents(path) {
|
|
const components = [];
|
|
let matchIndex = 0;
|
|
let matchGroup;
|
|
const regExp = /((?:(?:^|\.)\s*\w+|\[\s*(?:'(?:[^']|(?<!\\)\\')*'|"(?:[^"]|(?<!\\)\\")*"|-?\d+)\s*\])\s*)/g;
|
|
while (matchGroup = regExp.exec(path)) {
|
|
if (matchGroup.index !== matchIndex) {
|
|
return;
|
|
}
|
|
matchIndex = matchGroup.index + matchGroup[0].length;
|
|
const match = matchGroup[1].trim();
|
|
if (match.startsWith(".")) {
|
|
components.push(match.slice(1).trim());
|
|
} else if (match.startsWith("[")) {
|
|
const accessor = match.slice(1, -1).trim();
|
|
if (accessor.startsWith(`'`)) {
|
|
components.push(accessor.slice(1, -1).replaceAll(/(?<!\\)\\'/g, `'`));
|
|
} else if (accessor.startsWith(`"`)) {
|
|
components.push(accessor.slice(1, -1).replaceAll(/(?<!\\)\\"/g, `"`));
|
|
} else {
|
|
components.push(accessor);
|
|
}
|
|
} else {
|
|
components.push(match);
|
|
}
|
|
}
|
|
if (matchIndex !== path.length)
|
|
return;
|
|
return components;
|
|
}
|
|
function createPathAccessor(components) {
|
|
return (datum) => {
|
|
let current = datum;
|
|
for (const component of components) {
|
|
current = current[component];
|
|
}
|
|
return current;
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/aggregation/aggregator.ts
|
|
var Aggregator = class {
|
|
constructor(ctx, scopeCacheManager, resolvers) {
|
|
this.ctx = ctx;
|
|
this.scopeCacheManager = scopeCacheManager;
|
|
this.resolvers = resolvers;
|
|
}
|
|
/**
|
|
* Aggregates data for ungrouped datasets.
|
|
* Each datum gets its own aggregation result.
|
|
*/
|
|
aggregateUngroupedData(processedData) {
|
|
const domainAggValues = this.ctx.aggregates.map(() => [Infinity, -Infinity]);
|
|
processedData.domain.aggValues = domainAggValues;
|
|
const { columns, dataSources } = processedData;
|
|
const onlyScope = (0, import_ag_charts_core71.first)(dataSources.keys());
|
|
const keys = processedData.keys.map((k) => k.get(onlyScope));
|
|
const rawData = dataSources.get(onlyScope)?.data ?? [];
|
|
const allowNull = this.ctx.keys.some((keyDef) => keyDef.allowNullKey === true);
|
|
processedData.aggregation = rawData?.map((_, datumIndex) => {
|
|
const aggregation = [];
|
|
for (const [index, def] of this.ctx.aggregates.entries()) {
|
|
const indices = this.valueGroupIdxLookup(def);
|
|
let groupAggValues = def.groupAggregateFunction?.() ?? [Infinity, -Infinity];
|
|
const valuesToAgg = indices.map((columnIndex) => columns[columnIndex][datumIndex]);
|
|
const k = datumKeys(keys, datumIndex, allowNull);
|
|
const valuesAgg = k == null ? void 0 : def.aggregateFunction(valuesToAgg, k);
|
|
if (valuesAgg) {
|
|
groupAggValues = def.groupAggregateFunction?.(valuesAgg, groupAggValues) ?? ContinuousDomain.extendDomain(valuesAgg, groupAggValues);
|
|
}
|
|
const finalValues = def.finalFunction?.(groupAggValues) ?? groupAggValues;
|
|
aggregation[index] = finalValues;
|
|
ContinuousDomain.extendDomain(finalValues, domainAggValues[index]);
|
|
}
|
|
return aggregation;
|
|
});
|
|
}
|
|
/**
|
|
* Aggregates data for grouped datasets.
|
|
* Multiple datums in a group share aggregation results.
|
|
*/
|
|
aggregateGroupedData(processedData) {
|
|
const domainAggValues = this.ctx.aggregates.map(() => [Infinity, -Infinity]);
|
|
processedData.domain.aggValues = domainAggValues;
|
|
const { columns } = processedData;
|
|
for (const [index, def] of this.ctx.aggregates.entries()) {
|
|
const indices = this.valueGroupIdxLookup(def);
|
|
for (let groupIndex = 0; groupIndex < processedData.groups.length; groupIndex++) {
|
|
const group = processedData.groups[groupIndex];
|
|
group.aggregation ?? (group.aggregation = []);
|
|
const groupKeys = group.keys;
|
|
let groupAggValues = def.groupAggregateFunction?.() ?? [Infinity, -Infinity];
|
|
const maxDatumIndex = Math.max(
|
|
...indices.map((columnIndex) => group.datumIndices[columnIndex]?.length ?? 0)
|
|
);
|
|
for (let datumIndex = 0; datumIndex < maxDatumIndex; datumIndex++) {
|
|
const valuesToAgg = indices.map((columnIndex) => {
|
|
const relativeDatumIndex = group.datumIndices[columnIndex]?.[datumIndex];
|
|
if (relativeDatumIndex == null) {
|
|
return void 0;
|
|
}
|
|
const absoluteDatumIndex = this.resolvers.resolveAbsoluteIndex(groupIndex, relativeDatumIndex);
|
|
return columns[columnIndex][absoluteDatumIndex];
|
|
});
|
|
const valuesAgg = def.aggregateFunction(valuesToAgg, groupKeys);
|
|
if (valuesAgg) {
|
|
groupAggValues = def.groupAggregateFunction?.(valuesAgg, groupAggValues) ?? ContinuousDomain.extendDomain(valuesAgg, groupAggValues);
|
|
}
|
|
}
|
|
const finalValues = def.finalFunction?.(groupAggValues) ?? groupAggValues;
|
|
group.aggregation[index] = finalValues;
|
|
ContinuousDomain.extendDomain(finalValues, domainAggValues[index]);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Post-processes groups after grouping is complete.
|
|
* Applies group value processors to adjust group values and recompute domains.
|
|
*/
|
|
postProcessGroups(processedData) {
|
|
const { groupProcessors } = this.ctx;
|
|
const { columnScopes, columns, invalidData } = processedData;
|
|
for (const processor of groupProcessors) {
|
|
const valueIndexes = this.valueGroupIdxLookup(processor);
|
|
const adjustFn = processor.adjust()();
|
|
for (let groupIndex = 0; groupIndex < processedData.groups.length; groupIndex++) {
|
|
const dataGroup = processedData.groups[groupIndex];
|
|
adjustFn(columns, valueIndexes, dataGroup, groupIndex);
|
|
}
|
|
for (const valueIndex of valueIndexes) {
|
|
const valueDef = this.ctx.values[valueIndex];
|
|
const isDiscrete = valueDef.valueType === "category";
|
|
const column = columns[valueIndex];
|
|
const columnScope = (0, import_ag_charts_core71.first)(columnScopes[valueIndex]);
|
|
const invalidDatums = invalidData?.get(columnScope);
|
|
const domain = isDiscrete ? new DiscreteDomain() : new ContinuousDomain();
|
|
for (let datumIndex = 0; datumIndex < column.length; datumIndex += 1) {
|
|
if (invalidDatums?.[datumIndex] === true)
|
|
continue;
|
|
domain.extend(column[datumIndex]);
|
|
}
|
|
processedData.domain.values[valueIndex] = domain.getDomain();
|
|
}
|
|
}
|
|
}
|
|
valueGroupIdxLookup(selector) {
|
|
return this.scopeCacheManager.valueGroupIdxLookup(selector);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/domain/domainInitializer.ts
|
|
var DomainInitializer = class {
|
|
constructor(ctx) {
|
|
this.ctx = ctx;
|
|
}
|
|
/**
|
|
* Sets up the appropriate domain type for a property definition.
|
|
* Returns a BandedDomain wrapping DiscreteDomain for category values,
|
|
* or a BandedDomain wrapping ContinuousDomain for continuous values.
|
|
* Falls back to non-banded domains when banding is disabled.
|
|
*
|
|
* @param sortOrderEntry Optional sort order metadata from KEY_SORT_ORDERS.
|
|
* When data is sorted and unique, enables fast array concatenation optimization.
|
|
*/
|
|
setupDomainForDefinition(def, bandedDomains, sortOrderEntry) {
|
|
const isDiscrete = def.valueType === "category";
|
|
let domain = bandedDomains.get(def);
|
|
if (!domain && this.ctx.bandingConfig?.enableBanding !== false) {
|
|
domain = new BandedDomain(
|
|
isDiscrete ? () => new DiscreteDomain() : () => new ContinuousDomain(),
|
|
this.ctx.bandingConfig,
|
|
isDiscrete
|
|
);
|
|
bandedDomains.set(def, domain);
|
|
}
|
|
if (domain && isDiscrete) {
|
|
domain.setSortOrderMetadata(
|
|
sortOrderEntry?.sortOrder,
|
|
sortOrderEntry?.isUnique ?? false
|
|
);
|
|
}
|
|
if (domain) {
|
|
return domain;
|
|
}
|
|
return isDiscrete ? new DiscreteDomain() : new ContinuousDomain();
|
|
}
|
|
/**
|
|
* Extends a domain from data array, using banded optimization if available.
|
|
* Note: For BandedDomain, bands should already be initialized before calling this method.
|
|
*/
|
|
extendDomainFromData(domain, data, invalidData) {
|
|
if (domain instanceof BandedDomain) {
|
|
domain.extendBandsFromData(data, invalidData);
|
|
} else {
|
|
for (let i = 0; i < data.length; i++) {
|
|
if (invalidData?.[i] === true)
|
|
continue;
|
|
domain.extend(data[i]);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Initializes a banded domain if needed based on data size and state.
|
|
* This is a memory optimization that divides large datasets into bands.
|
|
*/
|
|
initializeBandedDomain(domain, dataSize, propertyName) {
|
|
if (!(domain instanceof BandedDomain))
|
|
return;
|
|
const stats = domain.getStats();
|
|
const shouldReinit = stats.bandCount === 0 || stats.dataSize !== dataSize;
|
|
if (this.ctx.debug.check() && shouldReinit && propertyName) {
|
|
this.ctx.debug(
|
|
`Reinitializing bands for ${propertyName}: bandCount=${stats.bandCount}, dataSize=${stats.dataSize}, dataLength=${dataSize}`
|
|
);
|
|
}
|
|
if (shouldReinit) {
|
|
domain.initializeBands(dataSize);
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/domain/domainManager.ts
|
|
var import_ag_charts_core73 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/data/dataModelTypes.ts
|
|
var KEY_SORT_ORDERS = Symbol("key-sort-orders");
|
|
var COLUMN_SORT_ORDERS = Symbol("column-sort-orders");
|
|
var DOMAIN_RANGES = Symbol("domain-ranges");
|
|
var DOMAIN_BANDS = Symbol("domain-bands");
|
|
var REDUCER_BANDS = Symbol("reducer-bands");
|
|
var SHARED_ZERO_INDICES = Object.freeze([0]);
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/domain/processValueFactory.ts
|
|
var import_ag_charts_core72 = require("ag-charts-core");
|
|
function trackMissingValue(missing, valueScopes) {
|
|
if (typeof valueScopes === "string") {
|
|
missing.set(valueScopes, (missing.get(valueScopes) ?? 0) + 1);
|
|
} else {
|
|
for (const scope of valueScopes) {
|
|
missing.set(scope, (missing.get(scope) ?? 0) + 1);
|
|
}
|
|
}
|
|
}
|
|
function handleInvalidValue(meta, value) {
|
|
meta.reusableResult.valid = false;
|
|
if (meta.hasInvalidValue) {
|
|
meta.reusableResult.value = meta.invalidValue;
|
|
meta.domain.extend(meta.invalidValue);
|
|
return;
|
|
}
|
|
if (meta.mode !== "integrated") {
|
|
import_ag_charts_core72.Logger.warnOnce(
|
|
`invalid value of type [${typeof value}] for [${meta.def.scopes} / ${meta.def.id}] ignored:`,
|
|
`[${value}]`
|
|
);
|
|
}
|
|
meta.reusableResult.value = void 0;
|
|
}
|
|
function processValidationCheck(validation, valueInDatum, value, datum, idx, meta) {
|
|
if (validation && valueInDatum && validation(value, datum, idx) === false) {
|
|
meta.reusableResult.missing = false;
|
|
handleInvalidValue(meta, value);
|
|
return meta.reusableResult;
|
|
}
|
|
return null;
|
|
}
|
|
function handleMissingTracking(valueInDatum, hasMissingValue, missing, valueScopes, reusableResult) {
|
|
reusableResult.missing = !valueInDatum;
|
|
if (!valueInDatum && !hasMissingValue) {
|
|
trackMissingValue(missing, valueScopes);
|
|
}
|
|
}
|
|
function setValidResult(value, reusableResult, domain) {
|
|
reusableResult.valid = true;
|
|
reusableResult.value = value;
|
|
domain.extend(value);
|
|
return reusableResult;
|
|
}
|
|
var ProcessValueFactory = class {
|
|
constructor(ctx) {
|
|
this.ctx = ctx;
|
|
}
|
|
createProcessValueFn(def, accessor, domain, reusableResult, processorFns, domainMode) {
|
|
const context = {
|
|
def,
|
|
accessor,
|
|
domain,
|
|
reusableResult,
|
|
processorFns,
|
|
mode: this.ctx.mode
|
|
};
|
|
const specializedFn = domainMode === "extend" ? this.createSpecializedProcessValue(context, def.validation) : null;
|
|
return specializedFn ?? this.createGenericProcessValue(context, domainMode);
|
|
}
|
|
createSpecializedProcessValue(context, validation) {
|
|
if (context.def.forceValue != null) {
|
|
return this.createSpecializedProcessValueForceValue(context);
|
|
}
|
|
if (context.def.processor) {
|
|
return this.createSpecializedProcessValueProcessor(context, validation);
|
|
}
|
|
if (validation) {
|
|
return context.def.type === "key" ? this.createSpecializedProcessValueKeyValidation(context, validation) : this.createSpecializedProcessValueValueValidation(context, validation);
|
|
}
|
|
return null;
|
|
}
|
|
createValidationMeta(context) {
|
|
const { def, domain, reusableResult, mode } = context;
|
|
return {
|
|
reusableResult,
|
|
hasInvalidValue: "invalidValue" in def,
|
|
invalidValue: def.invalidValue,
|
|
domain,
|
|
def,
|
|
mode
|
|
};
|
|
}
|
|
/**
|
|
* Creates a specialized processValue function optimized for key properties with validation.
|
|
* Eliminates all branching for the most common key property case (~30% of calls).
|
|
*/
|
|
createSpecializedProcessValueKeyValidation(context, validation) {
|
|
const { def, accessor, domain, reusableResult } = context;
|
|
const property = def.property;
|
|
const hasMissingValue = "missingValue" in def;
|
|
const missingValue = def.missingValue;
|
|
const missing = def.missing;
|
|
const allowNullKey = def.allowNullKey ?? false;
|
|
const validationMeta = this.createValidationMeta(context);
|
|
if (accessor) {
|
|
const accessorFn = accessor;
|
|
return function processValueKeyValidationAccessor(datum, idx, valueScopes) {
|
|
let value;
|
|
try {
|
|
value = accessorFn(datum);
|
|
} catch {
|
|
}
|
|
const valueInDatum = value != null || allowNullKey && value == null;
|
|
const nullInvalid = !allowNullKey && value == null;
|
|
if (!valueInDatum || nullInvalid || validation(value, datum, idx) === false) {
|
|
reusableResult.missing = !valueInDatum;
|
|
if (!valueInDatum && !hasMissingValue) {
|
|
trackMissingValue(missing, valueScopes);
|
|
}
|
|
handleInvalidValue(validationMeta, value);
|
|
return reusableResult;
|
|
}
|
|
reusableResult.missing = false;
|
|
reusableResult.valid = true;
|
|
reusableResult.value = value;
|
|
domain.extend(value);
|
|
return reusableResult;
|
|
};
|
|
}
|
|
return function processValueKeyValidationDirect(datum, idx, valueScopes) {
|
|
const valueInDatum = property in datum;
|
|
const value = valueInDatum ? datum[property] : missingValue;
|
|
const nullInvalid = !allowNullKey && value == null;
|
|
if (!valueInDatum || nullInvalid || validation(value, datum, idx) === false) {
|
|
reusableResult.missing = !valueInDatum;
|
|
if (!valueInDatum && !hasMissingValue) {
|
|
trackMissingValue(missing, valueScopes);
|
|
}
|
|
handleInvalidValue(validationMeta, value);
|
|
return reusableResult;
|
|
}
|
|
reusableResult.missing = false;
|
|
reusableResult.valid = true;
|
|
reusableResult.value = value;
|
|
domain.extend(value);
|
|
return reusableResult;
|
|
};
|
|
}
|
|
/**
|
|
* Creates a specialized processValue function optimized for value properties with validation.
|
|
* Eliminates branching for the most common value property case (~50% of calls).
|
|
*/
|
|
createSpecializedProcessValueValueValidation(context, validation) {
|
|
const { def, accessor, domain, reusableResult } = context;
|
|
const property = def.property;
|
|
const hasMissingValue = "missingValue" in def;
|
|
const missingValue = def.missingValue;
|
|
const missing = def.missing;
|
|
const validationMeta = this.createValidationMeta(context);
|
|
if (accessor) {
|
|
const accessorFn = accessor;
|
|
return function processValueValueValidationAccessor(datum, idx, valueScopes) {
|
|
let value;
|
|
try {
|
|
value = accessorFn(datum);
|
|
} catch {
|
|
}
|
|
const valueInDatum = value != null;
|
|
const validationFailed = processValidationCheck(
|
|
validation,
|
|
valueInDatum,
|
|
value,
|
|
datum,
|
|
idx,
|
|
validationMeta
|
|
);
|
|
if (validationFailed !== null)
|
|
return validationFailed;
|
|
handleMissingTracking(valueInDatum, hasMissingValue, missing, valueScopes, reusableResult);
|
|
return setValidResult(value, reusableResult, domain);
|
|
};
|
|
}
|
|
return function processValueValueValidationDirect(datum, idx, valueScopes) {
|
|
const valueInDatum = property in datum;
|
|
const value = valueInDatum ? datum[property] : missingValue;
|
|
const validationFailed = processValidationCheck(
|
|
validation,
|
|
valueInDatum,
|
|
value,
|
|
datum,
|
|
idx,
|
|
validationMeta
|
|
);
|
|
if (validationFailed !== null)
|
|
return validationFailed;
|
|
handleMissingTracking(valueInDatum, hasMissingValue, missing, valueScopes, reusableResult);
|
|
return setValidResult(value, reusableResult, domain);
|
|
};
|
|
}
|
|
/**
|
|
* Creates a specialized processValue function for properties with forceValue.
|
|
* Optimized for invisible series (~5-10% of calls).
|
|
*/
|
|
createSpecializedProcessValueForceValue(context) {
|
|
const { def, accessor, domain, reusableResult } = context;
|
|
const property = def.property;
|
|
const forceValue = def.forceValue;
|
|
if (accessor) {
|
|
const accessorFn = accessor;
|
|
return function processValueForceValueAccessor(datum, _idx, _valueScopes) {
|
|
let value;
|
|
try {
|
|
value = accessorFn(datum);
|
|
} catch {
|
|
}
|
|
const valueInDatum = value != null;
|
|
const valueNegative = valueInDatum && (0, import_ag_charts_core72.isNegative)(value);
|
|
const forcedValue = valueNegative ? -1 * forceValue : forceValue;
|
|
reusableResult.missing = false;
|
|
reusableResult.valid = true;
|
|
reusableResult.value = forcedValue;
|
|
domain.extend(forcedValue);
|
|
return reusableResult;
|
|
};
|
|
}
|
|
return function processValueForceValueDirect(datum, _idx, _valueScopes) {
|
|
const valueInDatum = property in datum;
|
|
const value = valueInDatum ? datum[property] : void 0;
|
|
const valueNegative = valueInDatum && (0, import_ag_charts_core72.isNegative)(value);
|
|
const forcedValue = valueNegative ? -1 * forceValue : forceValue;
|
|
reusableResult.missing = false;
|
|
reusableResult.valid = true;
|
|
reusableResult.value = forcedValue;
|
|
domain.extend(forcedValue);
|
|
return reusableResult;
|
|
};
|
|
}
|
|
/**
|
|
* Creates a specialized processValue function for properties with processors.
|
|
* Optimized for data transformations (~5-10% of calls).
|
|
*/
|
|
createSpecializedProcessValueProcessor(context, validation) {
|
|
const { def, accessor, domain, reusableResult, processorFns } = context;
|
|
const property = def.property;
|
|
const hasMissingValue = "missingValue" in def;
|
|
const missingValue = def.missingValue;
|
|
const missing = def.missing;
|
|
const processor = def.processor;
|
|
const validationMeta = this.createValidationMeta(context);
|
|
if (accessor) {
|
|
const accessorFn = accessor;
|
|
return function processValueProcessorAccessor(datum, idx, valueScopes) {
|
|
let value;
|
|
try {
|
|
value = accessorFn(datum);
|
|
} catch {
|
|
}
|
|
const valueInDatum = value != null;
|
|
const validationFailed = processValidationCheck(
|
|
validation,
|
|
valueInDatum,
|
|
value,
|
|
datum,
|
|
idx,
|
|
validationMeta
|
|
);
|
|
if (validationFailed !== null)
|
|
return validationFailed;
|
|
handleMissingTracking(valueInDatum, hasMissingValue, missing, valueScopes, reusableResult);
|
|
let processorFn = processorFns.get(def);
|
|
if (processorFn == null) {
|
|
processorFn = processor();
|
|
processorFns.set(def, processorFn);
|
|
}
|
|
value = processorFn(value, idx);
|
|
return setValidResult(value, reusableResult, domain);
|
|
};
|
|
}
|
|
return function processValueProcessorDirect(datum, idx, valueScopes) {
|
|
const valueInDatum = property in datum;
|
|
let value = valueInDatum ? datum[property] : missingValue;
|
|
const validationFailed = processValidationCheck(
|
|
validation,
|
|
valueInDatum,
|
|
value,
|
|
datum,
|
|
idx,
|
|
validationMeta
|
|
);
|
|
if (validationFailed !== null)
|
|
return validationFailed;
|
|
handleMissingTracking(valueInDatum, hasMissingValue, missing, valueScopes, reusableResult);
|
|
let processorFn = processorFns.get(def);
|
|
if (processorFn == null) {
|
|
processorFn = processor();
|
|
processorFns.set(def, processorFn);
|
|
}
|
|
value = processorFn(value, idx);
|
|
return setValidResult(value, reusableResult, domain);
|
|
};
|
|
}
|
|
/**
|
|
* Creates the generic fallback processValue implementation used for edge cases
|
|
* and for skip mode (no domain extension). Generates a per-definition function
|
|
* so callers can resolve it once and reuse it without additional branching.
|
|
*/
|
|
createGenericProcessValue(context, domainMode) {
|
|
const { def, accessor, domain, processorFns } = context;
|
|
const property = def.property;
|
|
const hasMissingValue = "missingValue" in def;
|
|
const missingValue = def.missingValue;
|
|
const missing = def.missing;
|
|
const shouldExtendDomain = domainMode === "extend";
|
|
const reusableResult = context.reusableResult;
|
|
const validationMeta = this.createValidationMeta(context);
|
|
return function processValueGeneric(datum, idx, valueScopes) {
|
|
let value;
|
|
let valueInDatum;
|
|
if (accessor) {
|
|
try {
|
|
value = accessor(datum);
|
|
} catch {
|
|
}
|
|
valueInDatum = value != null;
|
|
} else {
|
|
valueInDatum = property in datum;
|
|
value = valueInDatum ? datum[property] : missingValue;
|
|
}
|
|
if (def.forceValue != null) {
|
|
const valueNegative = valueInDatum && (0, import_ag_charts_core72.isNegative)(value);
|
|
value = valueNegative ? -1 * def.forceValue : def.forceValue;
|
|
valueInDatum = true;
|
|
}
|
|
handleMissingTracking(valueInDatum, hasMissingValue, missing, valueScopes, reusableResult);
|
|
const allowNullKey = def.allowNullKey ?? false;
|
|
const isKeyWithNullValue = def.type === "key" && value == null && !allowNullKey;
|
|
if (isKeyWithNullValue) {
|
|
handleInvalidValue(validationMeta, value);
|
|
return reusableResult;
|
|
}
|
|
const validationFailed = processValidationCheck(
|
|
def.validation,
|
|
valueInDatum,
|
|
value,
|
|
datum,
|
|
idx,
|
|
validationMeta
|
|
);
|
|
if (validationFailed !== null)
|
|
return validationFailed;
|
|
reusableResult.valid = true;
|
|
if (def.processor) {
|
|
let processor = processorFns.get(def);
|
|
if (processor == null) {
|
|
processor = def.processor();
|
|
processorFns.set(def, processor);
|
|
}
|
|
value = processor(value, idx);
|
|
}
|
|
if (shouldExtendDomain) {
|
|
domain.extend(value);
|
|
}
|
|
reusableResult.value = value;
|
|
return reusableResult;
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/domain/domainManager.ts
|
|
function scopesOverlap(scopes1, scopes2) {
|
|
if (!scopes1 || !scopes2 || scopes1.length === 0 || scopes2.length === 0) {
|
|
return true;
|
|
}
|
|
return scopes1.some((s) => scopes2.includes(s));
|
|
}
|
|
function findMatchingKeyDef(valueDef, keyDefs) {
|
|
if (valueDef.valueType !== "category")
|
|
return void 0;
|
|
for (const keyDef of keyDefs) {
|
|
if (keyDef.property !== valueDef.property)
|
|
continue;
|
|
if (keyDef.valueType !== valueDef.valueType)
|
|
continue;
|
|
if (!scopesOverlap(keyDef.scopes, valueDef.scopes))
|
|
continue;
|
|
if (keyDef.validation !== valueDef.validation)
|
|
continue;
|
|
return keyDef;
|
|
}
|
|
return void 0;
|
|
}
|
|
var DomainManager = class {
|
|
constructor(ctx, initializer, scopeCacheManager) {
|
|
this.ctx = ctx;
|
|
this.initializer = initializer;
|
|
this.scopeCacheManager = scopeCacheManager;
|
|
this.processValueFactory = new ProcessValueFactory(ctx);
|
|
}
|
|
/**
|
|
* Recomputes all domains from processed data.
|
|
* Uses BandedDomain optimization for continuous domains to avoid full rescans.
|
|
* Shares domains between keys and values when they reference the same property.
|
|
*/
|
|
recomputeDomains(processedData) {
|
|
const startTime = this.ctx.debug.check() ? performance.now() : 0;
|
|
const bandedDomains = processedData[DOMAIN_BANDS];
|
|
let bandStats;
|
|
const keySortOrders = processedData[KEY_SORT_ORDERS];
|
|
const keyDomains = this.setupDefinitionDomains(this.ctx.keys, bandedDomains, keySortOrders);
|
|
const valueToKeyDef = /* @__PURE__ */ new Map();
|
|
for (const valueDef of this.ctx.values) {
|
|
const matchingKeyDef = findMatchingKeyDef(valueDef, this.ctx.keys);
|
|
if (matchingKeyDef) {
|
|
valueToKeyDef.set(valueDef, matchingKeyDef);
|
|
}
|
|
}
|
|
const valueDomains = this.setupValueDomainsWithSharing(
|
|
this.ctx.values,
|
|
bandedDomains,
|
|
keyDomains,
|
|
valueToKeyDef
|
|
);
|
|
const sharedDomains = /* @__PURE__ */ new Set();
|
|
for (const [, keyDef] of valueToKeyDef) {
|
|
const sharedDomain = keyDomains.get(keyDef);
|
|
if (sharedDomain) {
|
|
sharedDomains.add(sharedDomain);
|
|
}
|
|
}
|
|
this.initializeDomainBands(
|
|
this.ctx.keys,
|
|
keyDomains,
|
|
(defIndex) => {
|
|
const keysMap = processedData.keys[defIndex];
|
|
return Math.max(...Array.from(keysMap.values()).map((keys) => keys.length));
|
|
},
|
|
(def) => String(def.property)
|
|
);
|
|
this.initializeDomainBands(
|
|
this.ctx.values,
|
|
valueDomains,
|
|
(defIndex) => processedData.columns[defIndex].length,
|
|
(def) => String(def.property)
|
|
);
|
|
const preScanDomainStats = /* @__PURE__ */ new Map();
|
|
if (bandedDomains.size > 0) {
|
|
bandStats = {
|
|
totalBands: 0,
|
|
dirtyBands: 0,
|
|
totalData: 0
|
|
};
|
|
for (const domain of bandedDomains.values()) {
|
|
if (domain instanceof BandedDomain) {
|
|
const stats = domain.getStats();
|
|
preScanDomainStats.set(domain, stats);
|
|
bandStats.totalBands += stats.bandCount;
|
|
bandStats.dirtyBands += stats.dirtyBandCount;
|
|
bandStats.totalData = Math.max(bandStats.totalData, stats.dataSize);
|
|
}
|
|
}
|
|
}
|
|
this.extendDomainsFromData(
|
|
this.ctx.keys,
|
|
keyDomains,
|
|
(defIndex, scope) => processedData.keys[defIndex]?.get(scope),
|
|
(def) => def.scopes ?? [],
|
|
(scope) => processedData.invalidKeys?.get(scope)
|
|
);
|
|
this.extendDomainsFromData(
|
|
this.ctx.values,
|
|
valueDomains,
|
|
(defIndex, _scope) => processedData.columns[defIndex],
|
|
(def) => [(0, import_ag_charts_core73.first)(def.scopes)],
|
|
(scope) => processedData.invalidKeys?.get(scope),
|
|
sharedDomains
|
|
);
|
|
processedData.domain.keys = this.ctx.keys.map(function mapDomainKeys(keyDef) {
|
|
const domain = keyDomains.get(keyDef);
|
|
const result = domain.getDomain();
|
|
if (ContinuousDomain.is(domain) && result[0] > result[1]) {
|
|
return [];
|
|
}
|
|
return result;
|
|
});
|
|
processedData.domain.values = this.ctx.values.map(function mapDomainValues(valueDef) {
|
|
const domain = valueDomains.get(valueDef);
|
|
const result = domain.getDomain();
|
|
if (ContinuousDomain.is(domain) && result[0] > result[1]) {
|
|
return [];
|
|
}
|
|
return result;
|
|
});
|
|
if (processedData.type === "grouped") {
|
|
processedData.domain.groups = processedData.groups.map((group) => group.keys);
|
|
}
|
|
this.collectDomainBandingMetadata(processedData, keyDomains, valueDomains, bandedDomains, preScanDomainStats);
|
|
if (this.ctx.debug.check() && startTime > 0) {
|
|
const endTime = performance.now();
|
|
const duration = endTime - startTime;
|
|
if (bandStats && bandStats.totalBands > 0) {
|
|
const scanRatio = bandStats.dirtyBands / bandStats.totalBands;
|
|
const dataScanned = Math.round(scanRatio * bandStats.totalData);
|
|
this.ctx.debug(
|
|
`recomputeDomains with banding: ${duration.toFixed(2)}ms, bands: ${bandStats.dirtyBands}/${bandStats.totalBands} dirty, data scanned: ~${dataScanned}/${bandStats.totalData} (${(scanRatio * 100).toFixed(1)}%)`
|
|
);
|
|
} else {
|
|
this.ctx.debug(`recomputeDomains: ${duration.toFixed(2)}ms (no banding)`);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Creates domain instances for the given definitions, reusing banded domains when available.
|
|
* For key definitions, passes KEY_SORT_ORDERS metadata to enable fast array concatenation.
|
|
*/
|
|
setupDefinitionDomains(defs, bandedDomains, keySortOrders) {
|
|
const domains = /* @__PURE__ */ new Map();
|
|
for (const [defIndex, def] of defs.entries()) {
|
|
const sortOrderEntry = keySortOrders?.get(defIndex);
|
|
domains.set(def, this.initializer.setupDomainForDefinition(def, bandedDomains, sortOrderEntry));
|
|
}
|
|
return domains;
|
|
}
|
|
/**
|
|
* Initializes banded domains for each definition using the provided data length accessor.
|
|
*/
|
|
initializeDomainBands(defs, domains, getDataLength, getPropertyName) {
|
|
for (const [defIndex, def] of defs.entries()) {
|
|
const domain = domains.get(def);
|
|
if (!domain)
|
|
continue;
|
|
const dataLength = getDataLength(defIndex);
|
|
this.initializer.initializeBandedDomain(domain, dataLength, getPropertyName(def));
|
|
}
|
|
}
|
|
/**
|
|
* Extends domains from data sources using a shared traversal.
|
|
* @param skipDomains Optional set of domains to skip (already extended via shared key processing)
|
|
*/
|
|
extendDomainsFromData(defs, domains, getData, getScopes, getInvalid, skipDomains) {
|
|
for (const [defIndex, def] of defs.entries()) {
|
|
const domain = domains.get(def);
|
|
if (!domain)
|
|
continue;
|
|
if (skipDomains?.has(domain))
|
|
continue;
|
|
for (const scope of getScopes(def)) {
|
|
if (!scope)
|
|
continue;
|
|
const data = getData(defIndex, scope);
|
|
if (!data)
|
|
continue;
|
|
const invalid = getInvalid(scope);
|
|
this.initializer.extendDomainFromData(domain, data, invalid);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Sets up value domains, reusing key domains where properties match.
|
|
* This avoids duplicate domain computation for properties that appear as both key and value.
|
|
*/
|
|
setupValueDomainsWithSharing(defs, bandedDomains, keyDomains, valueToKeyDef) {
|
|
const domains = /* @__PURE__ */ new Map();
|
|
for (const def of defs) {
|
|
const matchingKeyDef = valueToKeyDef.get(def);
|
|
if (matchingKeyDef) {
|
|
const keyDomain = keyDomains.get(matchingKeyDef);
|
|
if (keyDomain) {
|
|
domains.set(def, keyDomain);
|
|
continue;
|
|
}
|
|
}
|
|
domains.set(def, this.initializer.setupDomainForDefinition(def, bandedDomains));
|
|
}
|
|
return domains;
|
|
}
|
|
/**
|
|
* Initializes domain processor for value processing during data transformation.
|
|
* Returns domain maps and processing functions used during data extraction.
|
|
* Uses specialized functions per property definition to eliminate branching in hot paths.
|
|
* Shares domains between keys and values when they reference the same property.
|
|
*/
|
|
initDataDomainProcessor(domainMode) {
|
|
const { keys: keyDefs, values: valueDefs } = this.ctx;
|
|
const scopes = /* @__PURE__ */ new Set();
|
|
for (const valueDef of valueDefs) {
|
|
if (!valueDef.scopes)
|
|
continue;
|
|
for (const scope of valueDef.scopes) {
|
|
scopes.add(scope);
|
|
}
|
|
}
|
|
const dataDomain = /* @__PURE__ */ new Map();
|
|
const processorFns = /* @__PURE__ */ new Map();
|
|
let allScopesHaveSameDefs = true;
|
|
const initDataDomain = () => {
|
|
for (const def of keyDefs) {
|
|
if (def.valueType === "category") {
|
|
dataDomain.set(def, new DiscreteDomain());
|
|
} else {
|
|
dataDomain.set(def, new ContinuousDomain());
|
|
}
|
|
}
|
|
for (const def of valueDefs) {
|
|
const matchingKeyDef = findMatchingKeyDef(def, keyDefs);
|
|
if (matchingKeyDef) {
|
|
const keyDomain = dataDomain.get(matchingKeyDef);
|
|
if (keyDomain) {
|
|
dataDomain.set(def, keyDomain);
|
|
allScopesHaveSameDefs && (allScopesHaveSameDefs = (def.scopes?.length ?? 0) === scopes.size);
|
|
continue;
|
|
}
|
|
}
|
|
if (def.valueType === "category") {
|
|
dataDomain.set(def, new DiscreteDomain());
|
|
} else {
|
|
dataDomain.set(def, new ContinuousDomain());
|
|
allScopesHaveSameDefs && (allScopesHaveSameDefs = (def.scopes?.length ?? 0) === scopes.size);
|
|
}
|
|
}
|
|
};
|
|
initDataDomain();
|
|
const accessors = this.scopeCacheManager.buildAccessors((0, import_ag_charts_core73.iterate)(keyDefs, valueDefs));
|
|
const processValueFns = /* @__PURE__ */ new WeakMap();
|
|
for (const def of (0, import_ag_charts_core73.iterate)(keyDefs, valueDefs)) {
|
|
const accessor = accessors.get(def.property);
|
|
const domain = dataDomain.get(def);
|
|
const reusableResult = {
|
|
value: void 0,
|
|
missing: false,
|
|
valid: false
|
|
};
|
|
const processFn = this.processValueFactory.createProcessValueFn(
|
|
def,
|
|
accessor,
|
|
domain,
|
|
reusableResult,
|
|
processorFns,
|
|
domainMode
|
|
);
|
|
processValueFns.set(def, processFn);
|
|
}
|
|
function getProcessValue(def) {
|
|
const processFn = processValueFns.get(def);
|
|
if (!processFn) {
|
|
throw new Error("AG Charts - missing processValue function for definition");
|
|
}
|
|
return processFn;
|
|
}
|
|
function processValue(def, datum, idx, valueScopes) {
|
|
return getProcessValue(def)(datum, idx, valueScopes);
|
|
}
|
|
return { dataDomain, processValue, getProcessValue, initDataDomain, scopes, allScopesHaveSameDefs };
|
|
}
|
|
/**
|
|
* Collects metadata about banded domain optimization for debugging and testing.
|
|
* Stores statistics about domain banding per key and value definition.
|
|
*/
|
|
collectDomainBandingMetadata(processedData, keyDomains, valueDomains, bandedDomains, preScanDomainStats) {
|
|
processedData.optimizations ?? (processedData.optimizations = {});
|
|
const collectDefs = (defs, domains) => {
|
|
return defs.map((def) => {
|
|
const domain = domains.get(def);
|
|
const bandedDomain = bandedDomains.get(def);
|
|
const isBanded = domain instanceof BandedDomain;
|
|
let reason;
|
|
if (!isBanded) {
|
|
reason = def.valueType === "category" ? "discrete domain" : "not configured";
|
|
}
|
|
let stats;
|
|
if (isBanded && bandedDomain) {
|
|
const domainStats = preScanDomainStats.get(bandedDomain) ?? bandedDomain.getStats();
|
|
const scanRatio = domainStats.bandCount > 0 ? domainStats.dirtyBandCount / domainStats.bandCount : 0;
|
|
stats = {
|
|
totalBands: domainStats.bandCount,
|
|
dirtyBands: domainStats.dirtyBandCount,
|
|
dataSize: domainStats.dataSize,
|
|
scanRatio
|
|
};
|
|
}
|
|
return {
|
|
property: String(def.property),
|
|
applied: isBanded,
|
|
reason,
|
|
stats
|
|
};
|
|
});
|
|
};
|
|
const keyDefs = collectDefs(this.ctx.keys, keyDomains);
|
|
const valueDefs = collectDefs(this.ctx.values, valueDomains);
|
|
processedData.optimizations.domainBanding = {
|
|
keyDefs,
|
|
valueDefs
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/extraction/dataExtractor.ts
|
|
var import_ag_charts_core74 = require("ag-charts-core");
|
|
function createKeyTracker() {
|
|
return { lastValue: void 0, sortOrder: 0, isUnique: true, isOrdered: true };
|
|
}
|
|
function updateKeyTracker(tracker, value) {
|
|
const numericValue = typeof value === "number" ? value : value?.valueOf?.();
|
|
if (typeof numericValue !== "number" || !Number.isFinite(numericValue))
|
|
return;
|
|
if (tracker.lastValue === void 0) {
|
|
tracker.lastValue = numericValue;
|
|
return;
|
|
}
|
|
const diff2 = numericValue - tracker.lastValue;
|
|
if (diff2 === 0) {
|
|
tracker.isUnique = false;
|
|
} else if (tracker.isOrdered) {
|
|
const direction = diff2 > 0 ? 1 : -1;
|
|
if (tracker.sortOrder === 0) {
|
|
tracker.sortOrder = direction;
|
|
} else if (tracker.sortOrder !== direction) {
|
|
tracker.isOrdered = false;
|
|
}
|
|
}
|
|
tracker.lastValue = numericValue;
|
|
}
|
|
function trackerToSortOrderEntry(tracker) {
|
|
return {
|
|
sortOrder: tracker.isOrdered && tracker.sortOrder !== 0 ? tracker.sortOrder : void 0,
|
|
isUnique: tracker.isUnique,
|
|
isDirty: false
|
|
};
|
|
}
|
|
var DataExtractor = class {
|
|
constructor(ctx, domainManager) {
|
|
this.ctx = ctx;
|
|
this.domainManager = domainManager;
|
|
this.markScopeDatumInvalid = function(scopes, data, datumIndex, invalidData, invalidDataCount) {
|
|
for (const scope of scopes) {
|
|
if (!invalidData.has(scope)) {
|
|
invalidData.set(scope, createArray(data.length, false));
|
|
invalidDataCount.set(scope, 0);
|
|
}
|
|
const scopeInvalidData = invalidData.get(scope);
|
|
if (!scopeInvalidData[datumIndex]) {
|
|
scopeInvalidData[datumIndex] = true;
|
|
invalidDataCount.set(scope, invalidDataCount.get(scope) + 1);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
extractData(sources) {
|
|
const { dataDomain, getProcessValue, allScopesHaveSameDefs } = this.domainManager.initDataDomainProcessor("extend");
|
|
const { keys: keyDefs, values: valueDefs } = this.ctx;
|
|
const { invalidData, invalidKeys, invalidKeyCount, invalidDataCount, allKeyMappings, keySortOrders } = this.extractKeys(keyDefs, sources, getProcessValue);
|
|
const { columns, columnScopes, columnNeedValueOf, partialValidDataCount, maxDataLength } = this.extractValues(
|
|
invalidData,
|
|
invalidDataCount,
|
|
valueDefs,
|
|
sources,
|
|
invalidKeys,
|
|
getProcessValue
|
|
);
|
|
const propertyDomain = (def) => {
|
|
const defDomain = dataDomain.get(def);
|
|
const result = defDomain.getDomain();
|
|
if (ContinuousDomain.is(defDomain) && result[0] > result[1]) {
|
|
return [];
|
|
}
|
|
return result;
|
|
};
|
|
return {
|
|
type: "ungrouped",
|
|
input: { count: maxDataLength },
|
|
scopes: new Set(sources.keys()),
|
|
dataSources: sources,
|
|
aggregation: void 0,
|
|
keys: [...allKeyMappings.values()],
|
|
columns,
|
|
columnScopes,
|
|
columnNeedValueOf,
|
|
invalidKeys,
|
|
invalidKeyCount,
|
|
invalidData,
|
|
invalidDataCount,
|
|
domain: {
|
|
keys: keyDefs.map(propertyDomain),
|
|
values: valueDefs.map(propertyDomain)
|
|
},
|
|
defs: {
|
|
allScopesHaveSameDefs,
|
|
keys: keyDefs,
|
|
values: valueDefs
|
|
},
|
|
partialValidDataCount,
|
|
time: 0,
|
|
version: 0,
|
|
[DOMAIN_RANGES]: /* @__PURE__ */ new Map(),
|
|
[KEY_SORT_ORDERS]: keySortOrders,
|
|
[COLUMN_SORT_ORDERS]: /* @__PURE__ */ new Map(),
|
|
[DOMAIN_BANDS]: /* @__PURE__ */ new Map(),
|
|
[REDUCER_BANDS]: /* @__PURE__ */ new Map()
|
|
};
|
|
}
|
|
extractKeys(keyDefs, sources, getProcessValue) {
|
|
const invalidKeys = /* @__PURE__ */ new Map();
|
|
const invalidData = /* @__PURE__ */ new Map();
|
|
const invalidKeyCount = /* @__PURE__ */ new Map();
|
|
const invalidDataCount = /* @__PURE__ */ new Map();
|
|
const allKeys = /* @__PURE__ */ new Map();
|
|
const keySortOrders = /* @__PURE__ */ new Map();
|
|
let keyDefKeys;
|
|
let scopeDataProcessed;
|
|
const keyProcessors = keyDefs.map((def) => getProcessValue(def));
|
|
const cloneScope = (source, target) => {
|
|
const sourceScope = scopeDataProcessed.get(source);
|
|
keyDefKeys.set(target, keyDefKeys.get(sourceScope));
|
|
if (invalidKeys.has(sourceScope)) {
|
|
invalidKeys.set(target, invalidKeys.get(sourceScope));
|
|
invalidData.set(target, invalidData.get(sourceScope));
|
|
invalidDataCount.set(target, invalidDataCount.get(sourceScope));
|
|
}
|
|
};
|
|
for (const [keyDefIndex, keyDef] of keyDefs.entries()) {
|
|
const { invalidValue, scopes: keyScopes } = keyDef;
|
|
const processKeyValue = keyProcessors[keyDefIndex];
|
|
keyDefKeys = /* @__PURE__ */ new Map();
|
|
scopeDataProcessed = /* @__PURE__ */ new Map();
|
|
allKeys.set(keyDef, keyDefKeys);
|
|
const tracker = createKeyTracker();
|
|
for (const scope of keyScopes ?? []) {
|
|
const data = sources.get(scope)?.data ?? [];
|
|
if (scopeDataProcessed.has(data)) {
|
|
cloneScope(data, scope);
|
|
continue;
|
|
}
|
|
const keys = [];
|
|
keyDefKeys.set(scope, keys);
|
|
scopeDataProcessed.set(data, scope);
|
|
let invalidScopeKeys;
|
|
let invalidScopeData;
|
|
let missingKeys = 0;
|
|
for (let datumIndex = 0; datumIndex < data.length; datumIndex++) {
|
|
if (data[datumIndex] == null || typeof data[datumIndex] !== "object") {
|
|
invalidScopeKeys ?? (invalidScopeKeys = createArray(data.length, false));
|
|
invalidScopeData ?? (invalidScopeData = createArray(data.length, false));
|
|
missingKeys += 1;
|
|
invalidScopeKeys[datumIndex] = true;
|
|
invalidScopeData[datumIndex] = true;
|
|
keys.push(invalidValue);
|
|
continue;
|
|
}
|
|
const result = processKeyValue(data[datumIndex], datumIndex, scope);
|
|
if (result.valid) {
|
|
keys.push(result.value);
|
|
updateKeyTracker(tracker, result.value);
|
|
continue;
|
|
}
|
|
keys.push(invalidValue);
|
|
invalidScopeKeys ?? (invalidScopeKeys = createArray(data.length, false));
|
|
invalidScopeData ?? (invalidScopeData = createArray(data.length, false));
|
|
missingKeys += 1;
|
|
invalidScopeKeys[datumIndex] = true;
|
|
invalidScopeData[datumIndex] = true;
|
|
}
|
|
if (invalidScopeKeys && invalidScopeData) {
|
|
invalidKeys.set(scope, invalidScopeKeys);
|
|
invalidData.set(scope, invalidScopeData);
|
|
invalidKeyCount.set(scope, missingKeys);
|
|
invalidDataCount.set(scope, missingKeys);
|
|
}
|
|
}
|
|
keySortOrders.set(keyDefIndex, trackerToSortOrderEntry(tracker));
|
|
}
|
|
return { invalidData, invalidKeys, invalidKeyCount, invalidDataCount, allKeyMappings: allKeys, keySortOrders };
|
|
}
|
|
extractValues(invalidData, invalidDataCount, valueDefs, sources, scopeInvalidKeys, getProcessValue) {
|
|
let partialValidDataCount = 0;
|
|
const columns = [];
|
|
const allColumnScopes = [];
|
|
const columnNeedValueOf = [];
|
|
let maxDataLength = 0;
|
|
const valueProcessors = valueDefs.map((def) => getProcessValue(def));
|
|
for (const [valueDefIndex, def] of valueDefs.entries()) {
|
|
const { invalidValue } = def;
|
|
const processValueForDef = valueProcessors[valueDefIndex];
|
|
const valueSources = new Set(def.scopes.map((s) => sources.get(s)));
|
|
if (valueSources.size > 1) {
|
|
throw new Error(`AG Charts - more than one data source for: ${JSON.stringify(def)}`);
|
|
}
|
|
const columnScopes = new Set(def.scopes);
|
|
const columnScope = (0, import_ag_charts_core74.first)(def.scopes);
|
|
const columnSource = sources.get(columnScope)?.data ?? [];
|
|
const column = new Array();
|
|
const invalidKeys = scopeInvalidKeys.get(columnScope);
|
|
let needsValueOf = false;
|
|
for (let datumIndex = 0; datumIndex < columnSource.length; datumIndex++) {
|
|
if (columnSource[datumIndex] == null || typeof columnSource[datumIndex] !== "object") {
|
|
this.markScopeDatumInvalid(def.scopes, columnSource, datumIndex, invalidData, invalidDataCount);
|
|
column[datumIndex] = invalidValue;
|
|
continue;
|
|
}
|
|
const valueDatum = columnSource[datumIndex];
|
|
const invalidKey = invalidKeys == null ? false : invalidKeys[datumIndex];
|
|
const result = processValueForDef(valueDatum, datumIndex, def.scopes);
|
|
let value = result.value;
|
|
if (invalidKey || !result.valid) {
|
|
this.markScopeDatumInvalid(def.scopes, columnSource, datumIndex, invalidData, invalidDataCount);
|
|
}
|
|
if (invalidKey) {
|
|
value = invalidValue;
|
|
} else if (!result.valid) {
|
|
partialValidDataCount += 1;
|
|
value = invalidValue;
|
|
}
|
|
if (!needsValueOf && value != null && typeof value === "object") {
|
|
needsValueOf = true;
|
|
}
|
|
column[datumIndex] = value;
|
|
}
|
|
columns.push(column);
|
|
allColumnScopes.push(columnScopes);
|
|
columnNeedValueOf.push(needsValueOf);
|
|
maxDataLength = Math.max(maxDataLength, column.length);
|
|
}
|
|
return { columns, columnScopes: allColumnScopes, columnNeedValueOf, partialValidDataCount, maxDataLength };
|
|
}
|
|
warnDataMissingProperties(sources) {
|
|
if (sources.size === 0)
|
|
return;
|
|
for (const def of (0, import_ag_charts_core74.iterate)(this.ctx.keys, this.ctx.values)) {
|
|
for (const [scope, missCount] of def.missing) {
|
|
if (missCount < (sources.get(scope)?.data.length ?? Infinity))
|
|
continue;
|
|
const scopeHint = scope == null ? "" : ` for ${scope}`;
|
|
import_ag_charts_core74.Logger.warnOnce(`the key '${def.property}' was not found in any data element${scopeHint}.`);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/grouping/dataGrouper.ts
|
|
var import_ag_charts_core75 = require("ag-charts-core");
|
|
var DataGrouper = class {
|
|
constructor(ctx) {
|
|
this.ctx = ctx;
|
|
}
|
|
/**
|
|
* Groups data by keys or custom grouping function.
|
|
*
|
|
* GROUPED DATA STRUCTURE AND INVARIANTS:
|
|
*
|
|
* When groupsUnique=true (each datum has distinct keys):
|
|
* - groups.length === columns[i].length for all columns
|
|
* - groups[i] corresponds to datum at columns[j][i]
|
|
* - All datumIndices arrays contain [0] (shared memory optimization)
|
|
* - Relative indexing: datumIndices contains offsets from group start
|
|
* - Absolute indexing: groupIndex + relativeDatumIndex gives column position
|
|
*
|
|
* When groupsUnique=false (data is aggregated):
|
|
* - groups.length <= columns[i].length
|
|
* - Multiple datums may map to same group
|
|
* - datumIndices contain actual relative offsets
|
|
*
|
|
* This design optimizes memory usage for high-frequency data updates
|
|
* where each datum typically has unique keys (e.g., time series data).
|
|
*/
|
|
groupData(data, customGroupingFn) {
|
|
var _a;
|
|
const { keys: dataKeys, columns: allColumns, columnScopes, invalidKeys, invalidData } = data;
|
|
const allScopes = data.scopes;
|
|
const resultGroups = [];
|
|
const resultData = [];
|
|
const groups = allScopes.size !== 1 || customGroupingFn != null ? /* @__PURE__ */ new Map() : void 0;
|
|
let groupsUnique = true;
|
|
let groupIndex = 0;
|
|
const rawBatchCount = allScopes.size;
|
|
const columnBatches = this.groupBatches(
|
|
allScopes,
|
|
allColumns,
|
|
columnScopes,
|
|
dataKeys,
|
|
invalidData,
|
|
invalidKeys
|
|
);
|
|
const mergedBatchCount = columnBatches.length;
|
|
if (this.ctx.debug?.check() && !data.optimizations) {
|
|
data.optimizations = {};
|
|
}
|
|
if (this.ctx.debug?.check()) {
|
|
const mergeRatio = rawBatchCount > 0 ? 1 - mergedBatchCount / rawBatchCount : 0;
|
|
data.optimizations.batchMerging = {
|
|
originalBatchCount: rawBatchCount,
|
|
mergedBatchCount,
|
|
mergeRatio
|
|
};
|
|
}
|
|
const singleBatch = columnBatches.length === 1;
|
|
const allZeroDatumIndices = Object.freeze(createArray(columnBatches[0][1].length, SHARED_ZERO_INDICES));
|
|
for (const [
|
|
scopes,
|
|
scopeColumnIndexes,
|
|
scopeKeys,
|
|
siblingScopes,
|
|
scopeInvalidData,
|
|
scopeInvalidKeys
|
|
] of columnBatches) {
|
|
const firstColumn = allColumns[(0, import_ag_charts_core75.first)(scopeColumnIndexes)];
|
|
for (let datumIndex = 0; datumIndex < firstColumn.length; datumIndex++) {
|
|
if (scopeInvalidKeys?.[datumIndex] === true)
|
|
continue;
|
|
const keys = scopeKeys.map((k) => k[datumIndex]);
|
|
if (keys == null || keys.length === 0) {
|
|
throw new Error("AG Charts - no keys found for scope(s): " + scopes.join(", "));
|
|
}
|
|
const group = customGroupingFn?.(keys) ?? keys;
|
|
const groupStr = groups == null ? void 0 : toKeyString(group);
|
|
let outputGroup = groups?.get(groupStr);
|
|
let currentGroup;
|
|
let currentGroupIndex;
|
|
let isNewGroup = false;
|
|
if (outputGroup == null) {
|
|
currentGroup = {
|
|
keys: group,
|
|
datumIndices: [],
|
|
aggregation: [],
|
|
validScopes: allScopes
|
|
};
|
|
currentGroupIndex = groupIndex++;
|
|
outputGroup = [currentGroupIndex, currentGroup];
|
|
isNewGroup = true;
|
|
groups?.set(groupStr, outputGroup);
|
|
resultGroups.push(currentGroup.keys);
|
|
resultData.push(currentGroup);
|
|
} else {
|
|
[currentGroupIndex, currentGroup] = outputGroup;
|
|
groupsUnique = false;
|
|
}
|
|
if (scopeInvalidData?.[datumIndex] === true) {
|
|
if (currentGroup.validScopes === allScopes) {
|
|
currentGroup.validScopes = new Set(allScopes.values());
|
|
}
|
|
for (const invalidScope of siblingScopes) {
|
|
currentGroup.validScopes.delete(invalidScope);
|
|
}
|
|
}
|
|
if (isNewGroup && datumIndex === currentGroupIndex && singleBatch) {
|
|
currentGroup.datumIndices = allZeroDatumIndices;
|
|
} else {
|
|
if (!isNewGroup && currentGroup.datumIndices === allZeroDatumIndices) {
|
|
currentGroup.datumIndices = allZeroDatumIndices.map((arr) => [...arr]);
|
|
}
|
|
for (const columnIdx of scopeColumnIndexes) {
|
|
(_a = currentGroup.datumIndices)[columnIdx] ?? (_a[columnIdx] = []);
|
|
currentGroup.datumIndices[columnIdx].push(datumIndex - currentGroupIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
...data,
|
|
type: "grouped",
|
|
domain: {
|
|
...data.domain,
|
|
groups: resultGroups
|
|
},
|
|
groups: resultData,
|
|
groupsUnique,
|
|
optimizations: data.optimizations,
|
|
[DOMAIN_BANDS]: data[DOMAIN_BANDS],
|
|
[REDUCER_BANDS]: data[REDUCER_BANDS]
|
|
};
|
|
}
|
|
/**
|
|
* Groups and merges column batches for efficient processing.
|
|
*
|
|
* BATCH MERGING OPTIMIZATION:
|
|
* - Identifies columns that share the same data characteristics
|
|
* - Merges compatible batches to reduce iteration overhead
|
|
* - Can reduce processing iterations by 30-50% for multi-scope datasets
|
|
*
|
|
* Compatibility criteria:
|
|
* - Same keys arrays (by reference)
|
|
* - Same invalidity arrays (by reference)
|
|
* - Scopes can be safely processed together
|
|
*/
|
|
groupBatches(allScopes, allColumns, columnScopes, dataKeys, invalidData, invalidKeys) {
|
|
const columnBatches = [];
|
|
const processedColumnIndexes = /* @__PURE__ */ new Set();
|
|
for (const scope of allScopes) {
|
|
const scopeColumnIndexes = allColumns.map((_, idx) => idx).filter((idx) => !processedColumnIndexes.has(idx) && columnScopes[idx].has(scope));
|
|
if (scopeColumnIndexes.length === 0)
|
|
continue;
|
|
for (const idx of scopeColumnIndexes) {
|
|
processedColumnIndexes.add(idx);
|
|
}
|
|
const siblingScopes = /* @__PURE__ */ new Set();
|
|
for (const columnIdx of scopeColumnIndexes) {
|
|
for (const columnScope of columnScopes[columnIdx]) {
|
|
siblingScopes.add(columnScope);
|
|
}
|
|
}
|
|
const scopeKeys = dataKeys.map((k) => k.get(scope)).filter((k) => k != null);
|
|
const scopeInvalidData = invalidData?.get(scope);
|
|
const scopeInvalidKeys = invalidKeys?.get(scope);
|
|
columnBatches.push([
|
|
scope,
|
|
scopeColumnIndexes,
|
|
scopeKeys,
|
|
siblingScopes,
|
|
scopeInvalidData,
|
|
scopeInvalidKeys
|
|
]);
|
|
}
|
|
return this.mergeCompatibleBatches(columnBatches);
|
|
}
|
|
/**
|
|
* Checks if two column batches can be merged based on shared data characteristics.
|
|
*/
|
|
areBatchesCompatible(batch1, batch2) {
|
|
const [, , keys1, , invalidData1, invalidKeys1] = batch1;
|
|
const [, , keys2, , invalidData2, invalidKeys2] = batch2;
|
|
return keys1.every((k, i) => k === keys2[i]) && invalidKeys1 === invalidKeys2 && invalidData1 === invalidData2;
|
|
}
|
|
mergeCompatibleBatches(columnBatches) {
|
|
const merged = [];
|
|
const processed = /* @__PURE__ */ new Set();
|
|
for (let i = 0; i < columnBatches.length; i++) {
|
|
if (processed.has(i))
|
|
continue;
|
|
const [scope, columnIndexes, keys, siblingScopes, invalidData, invalidKeys] = columnBatches[i];
|
|
const mergedBatch = [
|
|
[scope],
|
|
[...columnIndexes],
|
|
keys,
|
|
new Set(siblingScopes),
|
|
invalidData,
|
|
invalidKeys
|
|
];
|
|
this.findAndMergeCompatibleBatches(columnBatches, i, mergedBatch, processed);
|
|
merged.push(mergedBatch);
|
|
processed.add(i);
|
|
}
|
|
return merged;
|
|
}
|
|
findAndMergeCompatibleBatches(columnBatches, startIndex, mergedBatch, processed) {
|
|
const firstBatch = columnBatches[startIndex];
|
|
for (let j = startIndex + 1; j < columnBatches.length; j++) {
|
|
if (processed.has(j))
|
|
continue;
|
|
const otherBatch = columnBatches[j];
|
|
const [scope, otherColumnIndexes, , otherSiblingScopes] = otherBatch;
|
|
if (!this.areBatchesCompatible(firstBatch, otherBatch))
|
|
continue;
|
|
mergedBatch[0].push(scope);
|
|
mergedBatch[1].push(...otherColumnIndexes);
|
|
for (const siblingScope of otherSiblingScopes) {
|
|
mergedBatch[3].add(siblingScope);
|
|
}
|
|
processed.add(j);
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/incremental/incrementalProcessor.ts
|
|
var import_ag_charts_core77 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/data/dataChangeDescription.ts
|
|
function isAppendOnly(indexMap) {
|
|
return indexMap.removedIndices.size === 0 && indexMap.totalPrependCount === 0 && indexMap.totalAppendCount > 0;
|
|
}
|
|
function isPrependOnly(indexMap) {
|
|
return indexMap.removedIndices.size === 0 && indexMap.totalAppendCount === 0 && indexMap.totalPrependCount > 0;
|
|
}
|
|
function hasNoRemovals(indexMap) {
|
|
return indexMap.removedIndices.size === 0;
|
|
}
|
|
function isUpdateOnly(indexMap) {
|
|
return indexMap.removedIndices.size === 0 && indexMap.totalPrependCount === 0 && indexMap.totalAppendCount === 0 && indexMap.spliceOps.every((op) => op.insertCount === 0 && op.deleteCount === 0);
|
|
}
|
|
function hasOnlyRemovals(indexMap) {
|
|
return indexMap.removedIndices.size > 0 && indexMap.totalPrependCount === 0 && indexMap.totalAppendCount === 0 && indexMap.spliceOps.every((op) => op.insertCount === 0);
|
|
}
|
|
function hasContiguousRemovalsAtStart(indexMap) {
|
|
const { removedIndices } = indexMap;
|
|
if (removedIndices.size === 0)
|
|
return false;
|
|
const sorted = Array.from(removedIndices).sort((a, b) => a - b);
|
|
if (sorted[0] !== 0)
|
|
return false;
|
|
for (let i = 0; i < sorted.length; i++) {
|
|
if (sorted[i] !== i)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function isRollingWindow(indexMap) {
|
|
return hasContiguousRemovalsAtStart(indexMap) && indexMap.totalAppendCount > 0 && indexMap.totalPrependCount === 0;
|
|
}
|
|
var DataChangeDescription = class {
|
|
constructor(indexMap, insertions) {
|
|
this.indexMap = indexMap;
|
|
this.prependValues = insertions.prependValues;
|
|
this.appendValues = insertions.appendValues;
|
|
this.insertionValues = insertions.insertionValues;
|
|
}
|
|
/**
|
|
* Get all indices that were removed from the original array, sorted ascending.
|
|
*
|
|
* @returns Array of removed indices (e.g., [2, 5, 8])
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const removed = changeDesc.getRemovedIndices();
|
|
* console.log(`Removed ${removed.length} items at indices: ${removed}`);
|
|
* ```
|
|
*/
|
|
getRemovedIndices() {
|
|
return Array.from(this.indexMap.removedIndices).sort((a, b) => a - b);
|
|
}
|
|
/**
|
|
* Get all indices that were updated in the final array, sorted ascending.
|
|
*
|
|
* @returns Array of updated indices (e.g., [1, 3, 7])
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const updated = changeDesc.getUpdatedIndices();
|
|
* console.log(`Updated ${updated.length} items at indices: ${updated}`);
|
|
* ```
|
|
*/
|
|
getUpdatedIndices() {
|
|
return Array.from(this.indexMap.updatedIndices).sort((a, b) => a - b);
|
|
}
|
|
/**
|
|
* Iterate over preserved elements, mapping source index to destination index.
|
|
* Only calls callback for elements that were NOT removed.
|
|
*
|
|
* **Use this for:**
|
|
* - Tracking which elements moved (when sourceIndex !== destIndex)
|
|
* - Generating diff metadata (added/removed/moved items)
|
|
* - Understanding index shifts caused by prepends/removes
|
|
*
|
|
* @param callback - Called for each preserved element with (sourceIndex, destIndex)
|
|
*
|
|
* @example Detecting moved items
|
|
* ```typescript
|
|
* const movedItems = new Set<number>();
|
|
* changeDesc.forEachPreservedIndex((srcIdx, destIdx) => {
|
|
* if (srcIdx !== destIdx) {
|
|
* movedItems.add(destIdx);
|
|
* }
|
|
* });
|
|
* ```
|
|
*/
|
|
forEachPreservedIndex(callback4) {
|
|
const { originalLength, removedIndices, totalPrependCount } = this.indexMap;
|
|
let removalsBeforeCount = 0;
|
|
const sortedRemovals = Array.from(removedIndices).sort((a, b) => a - b);
|
|
let removalIdx = 0;
|
|
for (let srcIdx = 0; srcIdx < originalLength; srcIdx++) {
|
|
while (removalIdx < sortedRemovals.length && sortedRemovals[removalIdx] < srcIdx) {
|
|
removalsBeforeCount++;
|
|
removalIdx++;
|
|
}
|
|
if (!removedIndices.has(srcIdx)) {
|
|
const destIdx = srcIdx + totalPrependCount - removalsBeforeCount;
|
|
callback4(srcIdx, destIdx);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Get the values that were prepended to the beginning of the array.
|
|
*
|
|
* These values are stored during change description construction and can be used
|
|
* to avoid reprocessing prepended data.
|
|
*
|
|
* @returns Array of prepended values in order
|
|
*
|
|
* @example Processing prepended data
|
|
* ```typescript
|
|
* const prependedData = changeDesc.getPrependedValues<DataRow>();
|
|
* for (const row of prependedData) {
|
|
* processRow(row);
|
|
* }
|
|
* ```
|
|
*/
|
|
getPrependedValues() {
|
|
return this.prependValues;
|
|
}
|
|
/**
|
|
* Get the values that were appended to the end of the array.
|
|
*
|
|
* These values are stored during change description construction and can be used
|
|
* to avoid reprocessing appended data.
|
|
*
|
|
* @returns Array of appended values in order
|
|
*
|
|
* @example Processing appended data
|
|
* ```typescript
|
|
* const appendedData = changeDesc.getAppendedValues<DataRow>();
|
|
* for (const row of appendedData) {
|
|
* processRow(row);
|
|
* }
|
|
* ```
|
|
*/
|
|
getAppendedValues() {
|
|
return this.appendValues;
|
|
}
|
|
/**
|
|
* Get the values that were inserted at arbitrary indices.
|
|
*
|
|
* These values are stored during change description construction and can be used
|
|
* to avoid reprocessing inserted data.
|
|
*
|
|
* @returns Array of insertion values in the order they appear in splice operations
|
|
*
|
|
* @example Processing inserted data
|
|
* ```typescript
|
|
* const insertedData = changeDesc.getInsertionValues<DataRow>();
|
|
* for (const row of insertedData) {
|
|
* processRow(row);
|
|
* }
|
|
* ```
|
|
*/
|
|
getInsertionValues() {
|
|
return this.insertionValues;
|
|
}
|
|
/**
|
|
* Applies the transformation to an array in-place using native Array operations.
|
|
* This is a zero-copy operation that mutates the array directly.
|
|
*
|
|
* **Use this for:**
|
|
* - Transforming processed data arrays (keys, columns, invalidity)
|
|
* - Applying prepends, removals, and appends in a single pass
|
|
* - Maintaining synchronization between data and processed arrays
|
|
*
|
|
* **How it works:**
|
|
* 1. Applies splice operations in order (prepends, removals, appends)
|
|
* 2. Calls processInsertion callback for each inserted element
|
|
* 3. Mutates the array in-place for zero-copy efficiency
|
|
*
|
|
* @param array - The array to transform in-place (will be mutated)
|
|
* @param processInsertion - Callback to generate values for inserted indices
|
|
*
|
|
* @example Transforming a column array
|
|
* ```typescript
|
|
* // Transform processed column to match new data layout
|
|
* const insertionCache = new Map(); // Pre-computed processed values
|
|
* changeDesc.applyToArray(columnArray, (destIndex) => {
|
|
* return insertionCache.get(destIndex) ?? defaultValue;
|
|
* });
|
|
* ```
|
|
*
|
|
* @example Transforming an invalidity array
|
|
* ```typescript
|
|
* // Transform invalidity flags to match new data
|
|
* changeDesc.applyToArray(invalidityArray, (destIndex) => {
|
|
* const cached = insertionCache.get(destIndex);
|
|
* return cached?.hasInvalidKey ?? false;
|
|
* });
|
|
* ```
|
|
*/
|
|
applyToArray(array4, processInsertion, onRemove) {
|
|
const { spliceOps, finalLength, originalLength } = this.indexMap;
|
|
if (originalLength === finalLength && spliceOps.length === 0) {
|
|
return;
|
|
}
|
|
for (const op of spliceOps) {
|
|
const insertElements = op.insertCount > 0 ? Array.from({ length: op.insertCount }, function processOpInsertion(_, j) {
|
|
return processInsertion(op.index + j);
|
|
}) : [];
|
|
const removed = array4.splice(op.index, op.deleteCount, ...insertElements);
|
|
if (onRemove && removed.length > 0) {
|
|
onRemove(removed, op);
|
|
}
|
|
}
|
|
if (array4.length !== finalLength) {
|
|
array4.length = finalLength;
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/reducers/reducerManager.ts
|
|
var import_ag_charts_core76 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/reducers/bandedReducer.ts
|
|
var BandedReducer = class extends BandedStructure {
|
|
constructor(config = {}) {
|
|
super(config);
|
|
this.lastDirtyBandCount = 0;
|
|
this.lastScanRatio = 0;
|
|
this.statsCaptured = false;
|
|
}
|
|
/**
|
|
* Creates a new reducer band with undefined cached result.
|
|
*/
|
|
createBand(startIndex, endIndex) {
|
|
return {
|
|
startIndex,
|
|
endIndex,
|
|
cachedResult: void 0,
|
|
isDirty: true
|
|
};
|
|
}
|
|
/**
|
|
* Initializes bands and resets stats capture flag.
|
|
*/
|
|
initializeBands(dataSize) {
|
|
super.initializeBands(dataSize);
|
|
this.statsCaptured = false;
|
|
}
|
|
/**
|
|
* Gets the array of bands for direct access.
|
|
* For production code, prefer using evaluateFromData() and getResult() for symmetry with BandedDomain.
|
|
* This method is primarily for testing and debugging band structure.
|
|
*/
|
|
getBands() {
|
|
return this.bands;
|
|
}
|
|
/**
|
|
* Evaluates a reducer across all bands, reusing cached results for clean bands.
|
|
* Symmetrical to BandedDomain.extendBandsFromData().
|
|
*
|
|
* @param def Reducer definition with reducer function, initial value, and overlap settings
|
|
* @param context Reducer context containing raw data and key columns
|
|
* @param reuseCleanBands Whether to reuse cached results for clean bands (default: false)
|
|
*/
|
|
evaluateFromData(def, context, reuseCleanBands = false) {
|
|
const reducerFn = def.reducer();
|
|
for (const band of this.bands) {
|
|
if (reuseCleanBands && !band.isDirty) {
|
|
continue;
|
|
}
|
|
const startIndex = def.needsOverlap && band.startIndex > 0 ? Math.max(0, band.startIndex - 1) : band.startIndex;
|
|
const result = this.evaluateRange(def, reducerFn, context, startIndex, band.endIndex);
|
|
band.cachedResult = result;
|
|
band.isDirty = false;
|
|
}
|
|
}
|
|
/**
|
|
* Combines all band results to get the final aggregated value.
|
|
* Symmetrical to BandedDomain.getDomain().
|
|
*
|
|
* @param def Reducer definition with combineResults function
|
|
* @returns Combined result from all bands
|
|
*/
|
|
getResult(def) {
|
|
const bandResults = this.bands.map((band) => band.cachedResult);
|
|
return def.combineResults(bandResults);
|
|
}
|
|
/**
|
|
* Evaluates a reducer over a specific range of data indices.
|
|
* Symmetrical to BandedDomain's band scanning loop in extendBandsFromData().
|
|
*
|
|
* @param def Reducer definition with initial value
|
|
* @param reducer Reducer function to apply
|
|
* @param context Reducer context with data and keys
|
|
* @param startIndex Starting index (inclusive)
|
|
* @param endIndex Ending index (exclusive)
|
|
* @returns Accumulated reducer result for the range
|
|
*/
|
|
evaluateRange(def, reducer, context, startIndex, endIndex) {
|
|
let accValue = def.initialValue;
|
|
const { keyColumns, keysParam, rawData } = context;
|
|
const clampedEnd = Math.min(endIndex, rawData.length);
|
|
for (let datumIndex = startIndex; datumIndex < clampedEnd; datumIndex += 1) {
|
|
for (let keyIdx = 0; keyIdx < keysParam.length; keyIdx++) {
|
|
keysParam[keyIdx] = keyColumns[keyIdx]?.[datumIndex];
|
|
}
|
|
accValue = reducer(accValue, keysParam);
|
|
}
|
|
return accValue;
|
|
}
|
|
/**
|
|
* Capture the current dirty state before processing.
|
|
* Call this before marking bands as clean to preserve stats for reporting.
|
|
*/
|
|
captureStatsBeforeProcessing() {
|
|
const dirtyBands = this.bands.filter((band) => band.isDirty);
|
|
const dirtySpan = dirtyBands.reduce((sum, band) => sum + (band.endIndex - band.startIndex), 0);
|
|
this.lastDirtyBandCount = dirtyBands.length;
|
|
this.lastScanRatio = this.dataSize > 0 ? dirtySpan / this.dataSize : 0;
|
|
this.statsCaptured = true;
|
|
}
|
|
/**
|
|
* Returns reducer-specific statistics including cache hits and scan ratio.
|
|
*/
|
|
getStats() {
|
|
const cleanBands = this.bands.filter((band) => !band.isDirty && band.cachedResult !== void 0);
|
|
let dirtyBands;
|
|
let scanRatio;
|
|
if (this.statsCaptured) {
|
|
dirtyBands = this.lastDirtyBandCount;
|
|
scanRatio = this.lastScanRatio;
|
|
} else {
|
|
const currentDirtyBands = this.bands.filter((band) => band.isDirty);
|
|
const dirtySpan = currentDirtyBands.reduce((sum, band) => sum + (band.endIndex - band.startIndex), 0);
|
|
dirtyBands = currentDirtyBands.length;
|
|
scanRatio = this.dataSize > 0 ? dirtySpan / this.dataSize : 0;
|
|
}
|
|
return {
|
|
totalBands: this.bands.length,
|
|
dirtyBands,
|
|
dataSize: this.dataSize,
|
|
scanRatio,
|
|
cacheHits: cleanBands.length
|
|
};
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/reducers/reducerManager.ts
|
|
var ReducerManager = class {
|
|
constructor(bandingConfig = {}) {
|
|
this.bandingConfig = bandingConfig;
|
|
}
|
|
/**
|
|
* Evaluates a reducer over a specific range of data indices.
|
|
* Used for non-banded reducer evaluation (fallback path).
|
|
*
|
|
* This is a static utility method for cases where banding is not applicable
|
|
* (e.g., grouped data, small datasets, reducers that don't support banding).
|
|
*
|
|
* @param def Reducer definition with initial value
|
|
* @param reducer Reducer function to apply
|
|
* @param context Reducer context with data and keys
|
|
* @param startIndex Starting index (inclusive)
|
|
* @param endIndex Ending index (exclusive)
|
|
* @returns Accumulated reducer result for the range
|
|
*/
|
|
static evaluateRange(def, reducer, context, startIndex, endIndex) {
|
|
let accValue = def.initialValue;
|
|
const { keyColumns, keysParam, rawData } = context;
|
|
const clampedEnd = Math.min(endIndex, rawData.length);
|
|
for (let datumIndex = startIndex; datumIndex < clampedEnd; datumIndex += 1) {
|
|
for (let keyIdx = 0; keyIdx < keysParam.length; keyIdx++) {
|
|
keysParam[keyIdx] = keyColumns[keyIdx]?.[datumIndex];
|
|
}
|
|
accValue = reducer(accValue, keysParam);
|
|
}
|
|
return accValue;
|
|
}
|
|
/**
|
|
* Evaluates a banded reducer and returns the aggregated result.
|
|
* Symmetrical to DomainManager.recomputeDomains().
|
|
*
|
|
* @param def Reducer definition
|
|
* @param processedData Processed data containing raw data and keys
|
|
* @param options Evaluation options including band reuse settings
|
|
* @returns Aggregated reducer result
|
|
*/
|
|
evaluate(def, processedData, options = {}) {
|
|
var _a;
|
|
const context = this.createContext(def, processedData);
|
|
if (!context) {
|
|
return void 0;
|
|
}
|
|
processedData[_a = REDUCER_BANDS] ?? (processedData[_a] = /* @__PURE__ */ new Map());
|
|
const reducerBands = processedData[REDUCER_BANDS];
|
|
const property = def.property;
|
|
let bandManager = reducerBands.get(property);
|
|
if (!bandManager) {
|
|
bandManager = new BandedReducer(this.bandingConfig);
|
|
reducerBands.set(property, bandManager);
|
|
}
|
|
if (bandManager.getBandCount() === 0) {
|
|
bandManager.initializeBands(context.rawData.length);
|
|
}
|
|
options.beforeEvaluate?.(bandManager, context);
|
|
bandManager.captureStatsBeforeProcessing();
|
|
bandManager.evaluateFromData(def, context, options.reuseCleanBands ?? false);
|
|
return bandManager.getResult(def);
|
|
}
|
|
/**
|
|
* Applies index map transformations to all reducer bands.
|
|
* Symmetrical to DomainManager's band update logic.
|
|
*
|
|
* @param processedData Processed data containing reducer bands
|
|
* @param indexMap Index map with splice operations and updated indices
|
|
*/
|
|
applyIndexMap(processedData, indexMap) {
|
|
const reducerBands = processedData[REDUCER_BANDS];
|
|
if (!reducerBands)
|
|
return;
|
|
for (const bandManager of reducerBands.values()) {
|
|
bandManager.applyIndexMap(indexMap);
|
|
}
|
|
}
|
|
/**
|
|
* Creates a reducer context from processed data.
|
|
* Extracts raw data and key columns for the appropriate scope.
|
|
* Symmetrical to domain context creation in DomainManager.
|
|
*
|
|
* @param def Reducer definition
|
|
* @param processedData Processed data
|
|
* @returns Reducer context with scope information, or undefined if not applicable
|
|
*/
|
|
createContext(def, processedData) {
|
|
if (processedData.type !== "ungrouped") {
|
|
return void 0;
|
|
}
|
|
const scopeId = isScoped(def) ? def.scopes[0] : (0, import_ag_charts_core76.first)(processedData.dataSources.keys());
|
|
if (scopeId == null) {
|
|
return void 0;
|
|
}
|
|
const rawData = processedData.dataSources.get(scopeId)?.data ?? [];
|
|
const keyColumns = processedData.keys.map((column) => column.get(scopeId)).filter((column) => column != null);
|
|
const keysParam = keyColumns.map(() => void 0);
|
|
return { scopeId, rawData, keyColumns, keysParam };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/incremental/incrementalProcessor.ts
|
|
var IncrementalProcessor = class {
|
|
constructor(ctx, reducerManager) {
|
|
this.ctx = ctx;
|
|
this.reducerManager = reducerManager;
|
|
}
|
|
/**
|
|
* Checks if incremental reprocessing is supported for the given data configuration.
|
|
*/
|
|
isReprocessingSupported(processedData) {
|
|
if (processedData.type === "grouped") {
|
|
if (!processedData.groupsUnique)
|
|
return false;
|
|
const uniqueDataSets = this.getUniqueDataSets(processedData);
|
|
if (uniqueDataSets.size !== 1)
|
|
return false;
|
|
const scope = (0, import_ag_charts_core77.first)(processedData.scopes);
|
|
const invalidKeys = processedData.invalidKeys?.get(scope);
|
|
if (invalidKeys?.some((invalid) => invalid))
|
|
return false;
|
|
}
|
|
if (this.ctx.aggregates.length > 0)
|
|
return false;
|
|
const hasUnsupportedReducers = this.ctx.reducers.some(
|
|
(reducer) => reducer.supportsBanding !== true || typeof reducer.combineResults !== "function"
|
|
);
|
|
if (hasUnsupportedReducers)
|
|
return false;
|
|
const hasUnsupportedProcessors = this.ctx.processors.some(
|
|
(processor) => processor.incrementalCalculate === void 0
|
|
);
|
|
if (hasUnsupportedProcessors)
|
|
return false;
|
|
if (this.ctx.propertyProcessors.length > 0)
|
|
return false;
|
|
return this.ctx.groupProcessors.every((p) => p.supportsReprocessing ?? false);
|
|
}
|
|
/**
|
|
* Performs incremental reprocessing of data based on change descriptions.
|
|
*/
|
|
reprocessData(processedData, dataSets, getProcessValue, reprocessGroupProcessorsFn, recomputeDomainsFn, collectOptimizationMetadataFn) {
|
|
const start = performance.now();
|
|
const scopeChanges = this.collectScopeChanges(processedData, dataSets);
|
|
if (scopeChanges.size === 0) {
|
|
return processedData;
|
|
}
|
|
this.commitPendingTransactions(processedData);
|
|
const keyProcessors = this.buildDefinitionProcessors(this.ctx.keys, getProcessValue);
|
|
const valueProcessors = this.buildDefinitionProcessors(this.ctx.values, getProcessValue);
|
|
const insertionCaches = this.processAllInsertions(processedData, scopeChanges, keyProcessors, valueProcessors);
|
|
this.processAllUpdates(processedData, scopeChanges, keyProcessors, valueProcessors, insertionCaches);
|
|
this.updateBandsForChanges(processedData, scopeChanges);
|
|
const removedKeys = this.transformKeysArrays(processedData, scopeChanges, insertionCaches);
|
|
this.transformColumnsArrays(processedData, scopeChanges, insertionCaches);
|
|
this.transformInvalidityArrays(processedData, scopeChanges, insertionCaches);
|
|
this.reprocessBandedReducers(processedData, scopeChanges);
|
|
if (processedData.type === "grouped") {
|
|
this.transformGroupsArray(processedData, scopeChanges, insertionCaches);
|
|
if (this.ctx.groupProcessors.length > 0) {
|
|
reprocessGroupProcessorsFn(processedData, scopeChanges);
|
|
}
|
|
}
|
|
this.invalidateSortOrdersForChanges(processedData, scopeChanges);
|
|
recomputeDomainsFn(processedData);
|
|
this.reprocessProcessors(processedData);
|
|
if (processedData.reduced?.diff != null && scopeChanges.size > 0) {
|
|
this.generateDiffMetadata(processedData, scopeChanges, removedKeys);
|
|
}
|
|
this.updateProcessedDataMetadata(processedData);
|
|
const end2 = performance.now();
|
|
processedData.time = end2 - start;
|
|
processedData.version += 1;
|
|
collectOptimizationMetadataFn(processedData, "reprocess");
|
|
const uniqueChanges = uniqueChangeDescriptions(scopeChanges);
|
|
processedData.changeDescription = uniqueChanges.size === 1 ? uniqueChanges.values().next().value : void 0;
|
|
return processedData;
|
|
}
|
|
/**
|
|
* Updates banded domains based on pending changes.
|
|
*
|
|
* BANDING OPTIMIZATION:
|
|
* - Divides large datasets into bands (default ~100 bands)
|
|
* - Tracks which bands are "dirty" and need recalculation
|
|
* - During updates, only dirty bands are reprocessed
|
|
* - Significantly reduces domain calculation overhead for large datasets
|
|
*
|
|
* Example: 1M data points → 100 bands of 10K points each
|
|
* Adding 1000 points only dirties 1-2 bands instead of scanning all 1M points
|
|
*
|
|
* This optimizes domain recalculation by only marking affected bands as dirty.
|
|
* Deduplicates change descriptions to avoid processing the same changes multiple times
|
|
* when multiple scopes share the same DataSet.
|
|
*/
|
|
updateBandsForChanges(processedData, scopeChanges) {
|
|
const bandedDomains = processedData[DOMAIN_BANDS];
|
|
if (bandedDomains.size === 0)
|
|
return;
|
|
const processedChangeDescs = uniqueChangeDescriptions(scopeChanges);
|
|
for (const changeDesc of processedChangeDescs) {
|
|
const { indexMap } = changeDesc;
|
|
for (const domain of bandedDomains.values()) {
|
|
domain.applyIndexMap(indexMap);
|
|
}
|
|
}
|
|
}
|
|
reprocessBandedReducers(processedData, scopeChanges) {
|
|
if (processedData.type !== "ungrouped")
|
|
return;
|
|
const bandedReducers = this.ctx.reducers.filter(
|
|
(reducer) => reducer.supportsBanding && typeof reducer.combineResults === "function"
|
|
);
|
|
if (bandedReducers.length === 0)
|
|
return;
|
|
processedData.reduced ?? (processedData.reduced = {});
|
|
for (const def of bandedReducers) {
|
|
const result = this.reducerManager.evaluate(def, processedData, {
|
|
reuseCleanBands: true,
|
|
beforeEvaluate: (bandManager, context) => {
|
|
if (!context.scopeId)
|
|
return;
|
|
const changeDesc = scopeChanges.get(context.scopeId);
|
|
if (changeDesc) {
|
|
bandManager.applyIndexMap(changeDesc.indexMap);
|
|
}
|
|
}
|
|
});
|
|
if (result !== void 0) {
|
|
processedData.reduced[def.property] = result;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Collects change descriptions from all DataSets before committing.
|
|
*/
|
|
collectScopeChanges(processedData, dataSets) {
|
|
const scopeChanges = /* @__PURE__ */ new Map();
|
|
for (const [scopeId, dataSet] of processedData.dataSources) {
|
|
const changeDesc = dataSets?.get(dataSet) ?? dataSet.getChangeDescription();
|
|
if (changeDesc) {
|
|
scopeChanges.set(scopeId, changeDesc);
|
|
}
|
|
}
|
|
return scopeChanges;
|
|
}
|
|
/**
|
|
* Commits all pending transactions to the data arrays.
|
|
* Deduplicates DataSets to avoid committing the same DataSet multiple times
|
|
* when multiple scopes share the same DataSet.
|
|
*/
|
|
commitPendingTransactions(processedData) {
|
|
const uniqueDataSets = this.getUniqueDataSets(processedData);
|
|
for (const dataSet of uniqueDataSets) {
|
|
dataSet.commitPendingTransactions();
|
|
}
|
|
}
|
|
buildDefinitionProcessors(defs, getProcessValue) {
|
|
return defs.map((def, index) => ({
|
|
def,
|
|
index,
|
|
processValue: getProcessValue(def)
|
|
}));
|
|
}
|
|
/**
|
|
* Pre-processes all insertions once per scope to avoid redundant computation.
|
|
*/
|
|
processAllInsertions(processedData, scopeChanges, keyProcessors, valueProcessors) {
|
|
const insertionCaches = /* @__PURE__ */ new Map();
|
|
for (const [scope, changeDesc] of scopeChanges) {
|
|
const dataSet = processedData.dataSources.get(scope);
|
|
if (!dataSet)
|
|
continue;
|
|
const cache = this.processInsertionsOnce(scope, changeDesc, dataSet, keyProcessors, valueProcessors);
|
|
insertionCaches.set(scope, cache);
|
|
}
|
|
return insertionCaches;
|
|
}
|
|
/**
|
|
* Processes all updated items once per scope, adding them to the insertion cache.
|
|
* This ensures updated values are available when transforming columns/keys arrays.
|
|
*/
|
|
processAllUpdates(processedData, scopeChanges, keyProcessors, valueProcessors, insertionCaches) {
|
|
for (const [scope, changeDesc] of scopeChanges) {
|
|
const dataSet = processedData.dataSources.get(scope);
|
|
if (!dataSet)
|
|
continue;
|
|
const updatedIndices = changeDesc.getUpdatedIndices();
|
|
if (updatedIndices.length === 0)
|
|
continue;
|
|
let cache = insertionCaches.get(scope);
|
|
if (!cache) {
|
|
cache = /* @__PURE__ */ new Map();
|
|
insertionCaches.set(scope, cache);
|
|
}
|
|
for (const destIndex of updatedIndices) {
|
|
if (destIndex < 0 || destIndex >= dataSet.data.length) {
|
|
continue;
|
|
}
|
|
const processed = this.processDatum(dataSet, destIndex, scope, keyProcessors, valueProcessors);
|
|
if (processed) {
|
|
cache.set(destIndex, processed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Processes all insertions for a given scope once, caching the results.
|
|
* Returns a map from ADJUSTED destIndex to processed values for all keys and values.
|
|
* The adjusted destIndex accounts for out-of-bounds insertions that need to be shifted.
|
|
*/
|
|
processInsertionsOnce(scope, changeDesc, dataSet, keyProcessors, valueProcessors) {
|
|
const cache = /* @__PURE__ */ new Map();
|
|
const { finalLength } = changeDesc.indexMap;
|
|
for (const op of changeDesc.indexMap.spliceOps) {
|
|
if (op.insertCount <= 0)
|
|
continue;
|
|
for (let i = 0; i < op.insertCount; i++) {
|
|
const destIndex = op.index + i;
|
|
if (destIndex < 0 || destIndex >= finalLength) {
|
|
continue;
|
|
}
|
|
const processed = this.processDatum(dataSet, destIndex, scope, keyProcessors, valueProcessors);
|
|
if (processed) {
|
|
cache.set(destIndex, processed);
|
|
}
|
|
}
|
|
}
|
|
return cache;
|
|
}
|
|
/**
|
|
* Processes a single datum for the given scope, returning cached key/value results.
|
|
* Shared between insert and update paths to keep behaviour consistent.
|
|
*/
|
|
processDatum(dataSet, destIndex, scope, keyProcessors, valueProcessors) {
|
|
const datum = dataSet.data[destIndex];
|
|
const keys = /* @__PURE__ */ new Map();
|
|
const values = /* @__PURE__ */ new Map();
|
|
let hasInvalidKey = false;
|
|
let hasInvalidValue = false;
|
|
if (datum == null || typeof datum !== "object") {
|
|
hasInvalidKey = true;
|
|
hasInvalidValue = true;
|
|
} else {
|
|
for (const { index: keyDefIndex, def: keyDef, processValue: processKeyValue } of keyProcessors) {
|
|
if (!keyDef.scopes?.includes(scope))
|
|
continue;
|
|
const result = processKeyValue(datum, destIndex, scope);
|
|
keys.set(keyDefIndex, { value: result.value, valid: result.valid });
|
|
if (!result.valid) {
|
|
hasInvalidKey = true;
|
|
}
|
|
}
|
|
for (const { index: valueDefIndex, def: valueDef, processValue: processValueForDef } of valueProcessors) {
|
|
if (!valueDef.scopes?.includes(scope))
|
|
continue;
|
|
const result = processValueForDef(datum, destIndex, valueDef.scopes);
|
|
values.set(valueDefIndex, { value: result.value, valid: result.valid });
|
|
if (!result.valid) {
|
|
hasInvalidValue = true;
|
|
}
|
|
}
|
|
}
|
|
return { keys, values, hasInvalidKey, hasInvalidValue };
|
|
}
|
|
/**
|
|
* Generic utility to transform arrays using cached insertion results.
|
|
* This reduces duplication across transformKeysArrays, transformColumnsArrays, and transformInvalidityArrays.
|
|
*/
|
|
transformArraysWithCache(definitions, scopeChanges, insertionCaches, getArray, getScopes, extractValue) {
|
|
for (const [defIndex, def] of definitions.entries()) {
|
|
for (const scope of getScopes(def)) {
|
|
const changeDesc = scopeChanges.get(scope);
|
|
if (!changeDesc)
|
|
continue;
|
|
const array4 = getArray(defIndex, scope);
|
|
if (!array4)
|
|
continue;
|
|
const insertionCache = insertionCaches.get(scope);
|
|
this.applyChangeDescWithCache(
|
|
changeDesc,
|
|
array4,
|
|
insertionCache,
|
|
(cached, _destIndex) => extractValue(cached, def, defIndex)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Transforms keys arrays using cached insertion results.
|
|
*/
|
|
transformKeysArrays(processedData, scopeChanges, insertionCaches) {
|
|
const removedByScope = /* @__PURE__ */ new Map();
|
|
const ensureRemovedMetadata = (scope) => {
|
|
let metadata = removedByScope.get(scope);
|
|
if (!metadata) {
|
|
metadata = { tuples: [] };
|
|
removedByScope.set(scope, metadata);
|
|
}
|
|
return metadata;
|
|
};
|
|
const processedArrays = /* @__PURE__ */ new WeakSet();
|
|
for (const [defIndex, def] of this.ctx.keys.entries()) {
|
|
for (const scope of def.scopes ?? []) {
|
|
const changeDesc = scopeChanges.get(scope);
|
|
if (!changeDesc)
|
|
continue;
|
|
const keysArray = processedData.keys[defIndex]?.get(scope);
|
|
if (!keysArray)
|
|
continue;
|
|
if (processedArrays.has(keysArray)) {
|
|
const sourceScope = Array.from(processedData.keys[defIndex].entries()).find(
|
|
([_, arr]) => arr === keysArray
|
|
)?.[0];
|
|
if (sourceScope && sourceScope !== scope && removedByScope.has(sourceScope)) {
|
|
removedByScope.set(scope, removedByScope.get(sourceScope));
|
|
}
|
|
continue;
|
|
}
|
|
processedArrays.add(keysArray);
|
|
const insertionCache = insertionCaches.get(scope);
|
|
const removedMetadata = ensureRemovedMetadata(scope);
|
|
let removalCursor = 0;
|
|
this.applyChangeDescWithCache(
|
|
changeDesc,
|
|
keysArray,
|
|
insertionCache,
|
|
(cached) => {
|
|
const keyResult = cached?.keys.get(defIndex);
|
|
return keyResult?.valid ? keyResult.value : def.invalidValue;
|
|
},
|
|
(removedValues) => {
|
|
for (const value of removedValues) {
|
|
if (!removedMetadata.tuples[removalCursor]) {
|
|
removedMetadata.tuples[removalCursor] = new Array(this.ctx.keys.length);
|
|
}
|
|
removedMetadata.tuples[removalCursor][defIndex] = value;
|
|
removalCursor += 1;
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
const removedKeyStrings = /* @__PURE__ */ new Map();
|
|
for (const [scope, { tuples }] of removedByScope) {
|
|
if (tuples.length === 0)
|
|
continue;
|
|
const scopeSet = /* @__PURE__ */ new Set();
|
|
for (const tuple of tuples) {
|
|
const keyValues = [];
|
|
for (const [defIndex, value] of tuple.entries()) {
|
|
const keyDef = this.ctx.keys[defIndex];
|
|
if (!keyDef.scopes?.includes(scope))
|
|
continue;
|
|
keyValues.push(value);
|
|
}
|
|
if (keyValues.length > 0) {
|
|
scopeSet.add(toKeyString(keyValues));
|
|
}
|
|
}
|
|
removedKeyStrings.set(scope, scopeSet);
|
|
}
|
|
return removedKeyStrings;
|
|
}
|
|
/**
|
|
* Transforms columns arrays using cached insertion results.
|
|
*/
|
|
transformColumnsArrays(processedData, scopeChanges, insertionCaches) {
|
|
this.transformArraysWithCache(
|
|
this.ctx.values,
|
|
scopeChanges,
|
|
insertionCaches,
|
|
(defIndex) => processedData.columns[defIndex],
|
|
(def) => [(0, import_ag_charts_core77.first)(def.scopes)],
|
|
(cached, def, defIndex) => {
|
|
if (cached) {
|
|
if (cached.hasInvalidKey) {
|
|
return def.invalidValue;
|
|
}
|
|
const valueResult = cached.values.get(defIndex);
|
|
return valueResult?.valid ? valueResult.value : def.invalidValue;
|
|
}
|
|
return def.invalidValue;
|
|
}
|
|
);
|
|
}
|
|
/**
|
|
* Helper to transform a scope-based invalidity map.
|
|
*/
|
|
transformInvalidityMap(invalidityMap, scopeChanges, insertionCaches, extractValue) {
|
|
const processedArrays = /* @__PURE__ */ new Set();
|
|
for (const [scope, changeDesc] of scopeChanges) {
|
|
let array4 = invalidityMap.get(scope);
|
|
if (!array4) {
|
|
const insertionCache2 = insertionCaches.get(scope);
|
|
const hasAnyInvalid = insertionCache2 && Array.from(insertionCache2.values()).some(extractValue);
|
|
if (hasAnyInvalid) {
|
|
array4 = createArray(changeDesc.indexMap.originalLength, false);
|
|
invalidityMap.set(scope, array4);
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
if (processedArrays.has(array4))
|
|
continue;
|
|
processedArrays.add(array4);
|
|
const insertionCache = insertionCaches.get(scope);
|
|
this.applyChangeDescWithCache(
|
|
changeDesc,
|
|
array4,
|
|
insertionCache,
|
|
(cached, _destIndex) => extractValue(cached)
|
|
);
|
|
}
|
|
}
|
|
/**
|
|
* Transforms invalidity arrays using cached insertion results.
|
|
*/
|
|
transformInvalidityArrays(processedData, scopeChanges, insertionCaches) {
|
|
if (processedData.invalidKeys) {
|
|
this.transformInvalidityMap(
|
|
processedData.invalidKeys,
|
|
scopeChanges,
|
|
insertionCaches,
|
|
(cached) => cached?.hasInvalidKey ?? false
|
|
);
|
|
}
|
|
if (processedData.invalidData) {
|
|
this.transformInvalidityMap(
|
|
processedData.invalidData,
|
|
scopeChanges,
|
|
insertionCaches,
|
|
(cached) => cached ? cached.hasInvalidKey || cached.hasInvalidValue : false
|
|
);
|
|
}
|
|
}
|
|
/**
|
|
* Applies a change description to an array using the provided cache-aware extractor.
|
|
* Shared by array transformation helpers to keep update logic consistent.
|
|
*/
|
|
applyChangeDescWithCache(changeDesc, target, insertionCache, extractValue, onRemove) {
|
|
changeDesc.applyToArray(
|
|
target,
|
|
(destIndex) => {
|
|
const cached = insertionCache?.get(destIndex);
|
|
return extractValue(cached, destIndex);
|
|
},
|
|
onRemove
|
|
);
|
|
const updatedIndices = changeDesc.getUpdatedIndices();
|
|
if (updatedIndices.length === 0)
|
|
return;
|
|
for (const destIndex of updatedIndices) {
|
|
if (destIndex < 0 || destIndex >= target.length) {
|
|
continue;
|
|
}
|
|
const cached = insertionCache?.get(destIndex);
|
|
target[destIndex] = extractValue(cached, destIndex);
|
|
}
|
|
}
|
|
/**
|
|
* Transforms the groups array for grouped data during reprocessing.
|
|
* Only called when groupsUnique=true and no invalid keys exist.
|
|
*
|
|
* This maintains the invariant: groups[i] corresponds to datum at columns[i].
|
|
*/
|
|
transformGroupsArray(processedData, scopeChanges, insertionCaches) {
|
|
const scope = (0, import_ag_charts_core77.first)(processedData.scopes);
|
|
const changeDesc = scopeChanges.get(scope);
|
|
if (!changeDesc)
|
|
return;
|
|
const insertionCache = insertionCaches.get(scope);
|
|
for (const [, cached] of insertionCache ?? []) {
|
|
if (cached.hasInvalidKey) {
|
|
throw new Error(
|
|
"AG Charts - reprocessing grouped data with invalid keys not supported. This typically indicates a data quality issue that requires full reprocessing."
|
|
);
|
|
}
|
|
}
|
|
changeDesc.applyToArray(processedData.groups, (destIndex) => {
|
|
return this.createDataGroupForInsertion(destIndex, processedData, scope, insertionCache);
|
|
});
|
|
const updatedIndices = changeDesc.getUpdatedIndices();
|
|
if (updatedIndices.length > 0) {
|
|
for (const destIndex of updatedIndices) {
|
|
if (destIndex < 0 || destIndex >= processedData.groups.length) {
|
|
continue;
|
|
}
|
|
processedData.groups[destIndex] = this.createDataGroupForInsertion(
|
|
destIndex,
|
|
processedData,
|
|
scope,
|
|
insertionCache
|
|
);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Creates a new DataGroup for an inserted datum during reprocessing.
|
|
*
|
|
* When groupsUnique=true and no invalid keys exist, each datum has:
|
|
* - A unique set of keys
|
|
* - datumIndices[columnIdx] = [0] (relative offset is always 0)
|
|
* - All scopes are valid initially (unless invalid value detected)
|
|
*/
|
|
createDataGroupForInsertion(datumIndex, processedData, scope, insertionCache) {
|
|
const keys = [];
|
|
for (const keysMap of processedData.keys) {
|
|
const scopeKeys = keysMap.get(scope);
|
|
if (scopeKeys) {
|
|
keys.push(scopeKeys[datumIndex]);
|
|
}
|
|
}
|
|
const firstGroup = processedData.groups[0];
|
|
const allZeroDatumIndices = () => Object.freeze(createArray(processedData.columnScopes.length, SHARED_ZERO_INDICES));
|
|
const datumIndices = firstGroup?.datumIndices ?? allZeroDatumIndices();
|
|
const cached = insertionCache?.get(datumIndex);
|
|
const hasInvalidValue = cached?.hasInvalidValue ?? false;
|
|
let validScopes;
|
|
if (hasInvalidValue) {
|
|
validScopes = new Set(processedData.scopes);
|
|
validScopes.delete(scope);
|
|
} else {
|
|
validScopes = processedData.scopes;
|
|
}
|
|
return {
|
|
keys,
|
|
datumIndices,
|
|
aggregation: [],
|
|
// Empty - we don't support aggregates in reprocessing yet
|
|
validScopes
|
|
};
|
|
}
|
|
/**
|
|
* Generates diff metadata for animations and incremental rendering.
|
|
* This is an opt-in feature - only runs if diff tracking is already initialized.
|
|
*/
|
|
generateDiffMetadata(processedData, scopeChanges, removedKeys) {
|
|
const getKeyString = (scope, datumIndex) => {
|
|
const keys = [];
|
|
for (const keysMap of processedData.keys) {
|
|
const scopeKeys = keysMap.get(scope);
|
|
if (!scopeKeys)
|
|
return void 0;
|
|
keys.push(scopeKeys[datumIndex]);
|
|
}
|
|
return keys.length > 0 ? toKeyString(keys) : void 0;
|
|
};
|
|
for (const [scope, changeDesc] of scopeChanges) {
|
|
const diff2 = {
|
|
changed: true,
|
|
added: /* @__PURE__ */ new Set(),
|
|
removed: removedKeys.get(scope) ?? /* @__PURE__ */ new Set(),
|
|
updated: /* @__PURE__ */ new Set(),
|
|
moved: /* @__PURE__ */ new Set()
|
|
};
|
|
for (const op of changeDesc.indexMap.spliceOps) {
|
|
if (op.insertCount > 0) {
|
|
for (let i = 0; i < op.insertCount; i++) {
|
|
const datumIndex = op.index + i;
|
|
const keyStr = getKeyString(scope, datumIndex);
|
|
if (keyStr) {
|
|
diff2.added.add(keyStr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const { originalLength, totalPrependCount } = changeDesc.indexMap;
|
|
if (isAppendOnly(changeDesc.indexMap)) {
|
|
} else if (isPrependOnly(changeDesc.indexMap) && originalLength > 0) {
|
|
for (let destIndex = totalPrependCount; destIndex < totalPrependCount + originalLength; destIndex++) {
|
|
const keyStr = getKeyString(scope, destIndex);
|
|
if (keyStr)
|
|
diff2.moved.add(keyStr);
|
|
}
|
|
} else if (hasNoRemovals(changeDesc.indexMap) && totalPrependCount > 0) {
|
|
for (let sourceIndex = 0; sourceIndex < originalLength; sourceIndex++) {
|
|
const destIndex = sourceIndex + totalPrependCount;
|
|
const keyStr = getKeyString(scope, destIndex);
|
|
if (keyStr)
|
|
diff2.moved.add(keyStr);
|
|
}
|
|
} else {
|
|
changeDesc.forEachPreservedIndex((sourceIndex, destIndex) => {
|
|
if (sourceIndex !== destIndex) {
|
|
const keyStr = getKeyString(scope, destIndex);
|
|
if (keyStr)
|
|
diff2.moved.add(keyStr);
|
|
}
|
|
});
|
|
}
|
|
processedData.reduced.diff[scope] = diff2;
|
|
}
|
|
}
|
|
/**
|
|
* Updates metadata after array transformations.
|
|
* Uses intelligent cache management based on change patterns.
|
|
*/
|
|
updateProcessedDataMetadata(processedData) {
|
|
let maxDataLength = 0;
|
|
for (const dataSet of processedData.dataSources.values()) {
|
|
maxDataLength = Math.max(maxDataLength, dataSet.data.length);
|
|
}
|
|
processedData.input.count = maxDataLength;
|
|
let partialValidDataCount = 0;
|
|
for (const [scope, invalidData] of processedData.invalidData ?? /* @__PURE__ */ new Map()) {
|
|
const invalidKeys = processedData.invalidKeys?.get(scope);
|
|
for (let i = 0; i < invalidData.length; i++) {
|
|
if (invalidData[i] && !invalidKeys?.[i]) {
|
|
partialValidDataCount += 1;
|
|
}
|
|
}
|
|
}
|
|
processedData.partialValidDataCount = partialValidDataCount;
|
|
this.recountInvalid(processedData.invalidKeys, processedData.invalidKeyCount);
|
|
this.recountInvalid(processedData.invalidData, processedData.invalidDataCount);
|
|
this.invalidateCachesForChanges(processedData);
|
|
}
|
|
/**
|
|
* Updates sort order entry incrementally for appended values.
|
|
* Checks if new values maintain the existing ordering/uniqueness.
|
|
*/
|
|
updateSortOrderForAppend(entry, lastExistingValue, appendedValues) {
|
|
if (appendedValues.length === 0)
|
|
return;
|
|
const toNumeric = (v) => {
|
|
if (typeof v === "number")
|
|
return v;
|
|
if (v instanceof Date)
|
|
return v.valueOf();
|
|
return void 0;
|
|
};
|
|
let lastValue = toNumeric(lastExistingValue);
|
|
const existingSortOrder = entry.sortOrder;
|
|
for (const value of appendedValues) {
|
|
const numericValue = toNumeric(value);
|
|
if (numericValue === void 0)
|
|
continue;
|
|
if (lastValue === void 0) {
|
|
lastValue = numericValue;
|
|
continue;
|
|
}
|
|
const diff2 = numericValue - lastValue;
|
|
if (diff2 === 0) {
|
|
entry.isUnique = false;
|
|
}
|
|
if (entry.sortOrder !== void 0) {
|
|
let direction = 0;
|
|
if (diff2 > 0) {
|
|
direction = 1;
|
|
} else if (diff2 < 0) {
|
|
direction = -1;
|
|
}
|
|
if (direction !== 0 && direction !== existingSortOrder) {
|
|
entry.sortOrder = void 0;
|
|
}
|
|
}
|
|
lastValue = numericValue;
|
|
}
|
|
}
|
|
/**
|
|
* Updates KEY_SORT_ORDERS incrementally after an append operation.
|
|
*/
|
|
updateKeySortOrdersForAppend(processedData, originalLength) {
|
|
for (const [keyDefIndex, keysMap] of processedData.keys.entries()) {
|
|
const sortOrderEntry = processedData[KEY_SORT_ORDERS].get(keyDefIndex);
|
|
if (!sortOrderEntry)
|
|
continue;
|
|
const keysArray = (0, import_ag_charts_core77.first)(keysMap.values());
|
|
if (!keysArray || keysArray.length <= originalLength)
|
|
continue;
|
|
const lastExistingValue = originalLength > 0 ? keysArray[originalLength - 1] : void 0;
|
|
const appendedValues = keysArray.slice(originalLength);
|
|
this.updateSortOrderForAppend(sortOrderEntry, lastExistingValue, appendedValues);
|
|
}
|
|
}
|
|
/**
|
|
* Invalidates sort order metadata BEFORE domain recomputation.
|
|
*
|
|
* This must be called BEFORE recomputeDomains() so that BandedDomain.setSortOrderMetadata()
|
|
* receives the correct (possibly cleared) metadata. Without this, rolling window operations
|
|
* would see stale sort order data and incorrectly configure sub-domains for sorted mode.
|
|
*
|
|
* @param anyKeyChanged - Whether any key values changed during update processing
|
|
*/
|
|
invalidateSortOrdersForChanges(processedData, scopeChanges) {
|
|
const changeDescs = uniqueChangeDescriptions(scopeChanges);
|
|
let preserveSortOrders = true;
|
|
let hasAppendOnly = false;
|
|
let hasRollingWindow = false;
|
|
let appendOriginalLength;
|
|
let rollingWindowInfo;
|
|
for (const changeDesc of changeDescs) {
|
|
const { indexMap } = changeDesc;
|
|
if (isUpdateOnly(indexMap)) {
|
|
} else if (isAppendOnly(indexMap)) {
|
|
hasAppendOnly = true;
|
|
appendOriginalLength = indexMap.originalLength;
|
|
} else if (hasOnlyRemovals(indexMap)) {
|
|
} else if (isRollingWindow(indexMap)) {
|
|
hasRollingWindow = true;
|
|
rollingWindowInfo = {
|
|
originalLength: indexMap.originalLength,
|
|
removedCount: indexMap.removedIndices.size
|
|
};
|
|
} else {
|
|
preserveSortOrders = false;
|
|
}
|
|
}
|
|
if (!preserveSortOrders) {
|
|
processedData[KEY_SORT_ORDERS].clear();
|
|
processedData[COLUMN_SORT_ORDERS].clear();
|
|
} else if (hasAppendOnly && appendOriginalLength !== void 0) {
|
|
this.updateKeySortOrdersForAppend(processedData, appendOriginalLength);
|
|
} else if (hasRollingWindow && rollingWindowInfo) {
|
|
this.updateKeySortOrdersForRollingWindow(processedData, rollingWindowInfo);
|
|
}
|
|
}
|
|
/**
|
|
* Updates KEY_SORT_ORDERS incrementally after a rolling window operation.
|
|
* Rolling window = contiguous removals at start + appends at end.
|
|
*/
|
|
updateKeySortOrdersForRollingWindow(processedData, info) {
|
|
const { originalLength, removedCount } = info;
|
|
for (const [keyDefIndex, keysMap] of processedData.keys.entries()) {
|
|
const sortOrderEntry = processedData[KEY_SORT_ORDERS].get(keyDefIndex);
|
|
if (!sortOrderEntry)
|
|
continue;
|
|
const keysArray = (0, import_ag_charts_core77.first)(keysMap.values());
|
|
if (!keysArray || keysArray.length === 0)
|
|
continue;
|
|
const appendStartIndex = originalLength - removedCount;
|
|
const lastRemainingValue = appendStartIndex > 0 ? keysArray[appendStartIndex - 1] : void 0;
|
|
const appendedValues = keysArray.slice(appendStartIndex);
|
|
this.updateSortOrderForAppend(sortOrderEntry, lastRemainingValue, appendedValues);
|
|
}
|
|
}
|
|
/**
|
|
* Invalidates domain range caches after domain recomputation.
|
|
*
|
|
* Called AFTER recomputeDomains() to mark domain ranges as dirty for lazy rebuild.
|
|
* Sort order invalidation is handled separately by invalidateSortOrdersForChanges().
|
|
*/
|
|
invalidateCachesForChanges(processedData) {
|
|
this.markDomainRangesDirty(processedData[DOMAIN_RANGES]);
|
|
}
|
|
/**
|
|
* Marks all RangeLookup entries as dirty for lazy rebuild.
|
|
*/
|
|
markDomainRangesDirty(domainRanges) {
|
|
for (const rangeLookup of domainRanges.values()) {
|
|
rangeLookup.isDirty = true;
|
|
}
|
|
}
|
|
/**
|
|
* Recounts invalid entries for the given map into the provided counts map.
|
|
*/
|
|
recountInvalid(invalidMap, counts) {
|
|
if (!invalidMap || !counts)
|
|
return;
|
|
for (const [scope, invalidArray] of invalidMap) {
|
|
const invalidCount = invalidArray.filter(Boolean).length;
|
|
if (invalidCount === 0) {
|
|
invalidMap.delete(scope);
|
|
counts.delete(scope);
|
|
} else {
|
|
counts.set(scope, invalidCount);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Recomputes processor outputs using their incrementalCalculate hook when available.
|
|
* Falls back to calculate to avoid stale reducer outputs if a processor lacks the hook.
|
|
*/
|
|
reprocessProcessors(processedData) {
|
|
if (this.ctx.processors.length === 0)
|
|
return;
|
|
processedData.reduced ?? (processedData.reduced = {});
|
|
for (const def of this.ctx.processors) {
|
|
const previousValue = processedData.reduced[def.property];
|
|
const nextValue = def.incrementalCalculate?.(processedData, previousValue) ?? def.calculate(processedData, previousValue);
|
|
processedData.reduced[def.property] = nextValue;
|
|
}
|
|
}
|
|
/**
|
|
* Helper to get unique DataSets from processed data.
|
|
*/
|
|
getUniqueDataSets(processedData) {
|
|
return new Set(processedData.dataSources.values());
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/rangeLookup.ts
|
|
var MIN = 0;
|
|
var MAX = 1;
|
|
var SPAN = 2;
|
|
var RangeLookup = class _RangeLookup {
|
|
constructor(allValues) {
|
|
/** When true, the lookup needs to be rebuilt before use */
|
|
this.isDirty = false;
|
|
const dataLength = allValues.reduce((acc, v) => Math.max(acc, v.length), 0);
|
|
const { maxLevelSize, buffer } = _RangeLookup.createBuffer(dataLength);
|
|
this.maxLevelSize = maxLevelSize;
|
|
this.buffer = buffer;
|
|
this.dataLength = dataLength;
|
|
this.populateBuffer(allValues);
|
|
}
|
|
static computeMaxLevelSize(dataLength) {
|
|
const sizePower = 32 - Math.clz32(dataLength);
|
|
let maxLevelSize = 1 << sizePower;
|
|
if (dataLength === maxLevelSize / 2) {
|
|
maxLevelSize = maxLevelSize >>> 1;
|
|
}
|
|
return maxLevelSize;
|
|
}
|
|
static createBuffer(dataLength) {
|
|
const maxLevelSize = _RangeLookup.computeMaxLevelSize(dataLength);
|
|
const buffer = new Float64Array((maxLevelSize * 2 - 1) * 2).fill(Number.NaN);
|
|
return { maxLevelSize, buffer };
|
|
}
|
|
populateBuffer(allValues) {
|
|
const { maxLevelSize, buffer } = this;
|
|
const leafOffset = maxLevelSize - 1;
|
|
for (const values of allValues) {
|
|
const valuesLength = values.length;
|
|
for (let i = 0; i < valuesLength; i += 1) {
|
|
const value = Number(values[i]);
|
|
if (value !== value)
|
|
continue;
|
|
const bufferOffset = leafOffset + i << 1;
|
|
const prevMin = buffer[bufferOffset];
|
|
const prevMax = buffer[bufferOffset + 1];
|
|
if (prevMin !== prevMin || value < prevMin) {
|
|
buffer[bufferOffset] = value;
|
|
}
|
|
if (prevMax !== prevMax || value > prevMax) {
|
|
buffer[bufferOffset + 1] = value;
|
|
}
|
|
}
|
|
}
|
|
for (let size = maxLevelSize >>> 1; size >= 1; size >>>= 1) {
|
|
const start = size - 1;
|
|
const childStart = start + size << 1;
|
|
let nodeOffset = start << 1;
|
|
let leftOffset = childStart;
|
|
for (let i = 0; i < size; i += 1) {
|
|
const rightOffset = leftOffset + 2;
|
|
const aMin = buffer[leftOffset];
|
|
const bMin = buffer[rightOffset];
|
|
buffer[nodeOffset] = bMin !== bMin || aMin < bMin ? aMin : bMin;
|
|
const aMax = buffer[leftOffset + 1];
|
|
const bMax = buffer[rightOffset + 1];
|
|
buffer[nodeOffset + 1] = bMax !== bMax || aMax > bMax ? aMax : bMax;
|
|
nodeOffset += 2;
|
|
leftOffset += 4;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Rebuild the segment tree with new values, reusing the buffer if possible.
|
|
* Only allocates a new buffer if the data length requires a different maxLevelSize.
|
|
*/
|
|
rebuild(allValues) {
|
|
const dataLength = allValues.reduce((acc, v) => Math.max(acc, v.length), 0);
|
|
const requiredMaxLevelSize = _RangeLookup.computeMaxLevelSize(dataLength);
|
|
if (requiredMaxLevelSize === this.maxLevelSize) {
|
|
this.buffer.fill(Number.NaN);
|
|
} else {
|
|
const { maxLevelSize, buffer } = _RangeLookup.createBuffer(dataLength);
|
|
this.maxLevelSize = maxLevelSize;
|
|
this.buffer = buffer;
|
|
}
|
|
this.dataLength = dataLength;
|
|
this.populateBuffer(allValues);
|
|
}
|
|
/**
|
|
* Update values at a specific data index - O(k log n) where k is number of columns.
|
|
* After updating the leaf, propagates changes up to the root.
|
|
*
|
|
* @param dataIndex - Index in the data array (0-based)
|
|
* @param newValues - New values for this index from all columns
|
|
*/
|
|
updateValue(dataIndex, newValues) {
|
|
const { maxLevelSize, buffer } = this;
|
|
const bufferIndex = maxLevelSize + dataIndex - 1;
|
|
const bufferMinIndex = Math.trunc(bufferIndex * SPAN) + MIN;
|
|
const bufferMaxIndex = Math.trunc(bufferIndex * SPAN) + MAX;
|
|
buffer[bufferMinIndex] = Number.NaN;
|
|
buffer[bufferMaxIndex] = Number.NaN;
|
|
for (const value of newValues) {
|
|
const numValue = Number(value);
|
|
const prevMin = buffer[bufferMinIndex];
|
|
const prevMax = buffer[bufferMaxIndex];
|
|
if (!Number.isFinite(prevMin) || numValue < prevMin) {
|
|
buffer[bufferMinIndex] = numValue;
|
|
}
|
|
if (!Number.isFinite(prevMax) || numValue > prevMax) {
|
|
buffer[bufferMaxIndex] = numValue;
|
|
}
|
|
}
|
|
this.propagateUp(bufferIndex);
|
|
}
|
|
/**
|
|
* Batch update multiple values - O(k log n) per update.
|
|
* More efficient than individual updateValue calls when tracking dirty nodes.
|
|
*
|
|
* @param updates - Array of {index, values} pairs to update
|
|
*/
|
|
updateValues(updates) {
|
|
for (const { index, values } of updates) {
|
|
this.updateValue(index, values);
|
|
}
|
|
}
|
|
/**
|
|
* Propagate min/max changes from a leaf up to the root.
|
|
* Each level recalculates its min/max from its children.
|
|
*/
|
|
propagateUp(bufferIndex) {
|
|
const { buffer } = this;
|
|
while (bufferIndex > 0) {
|
|
const parentIndex = Math.trunc((bufferIndex - 1) / 2);
|
|
const leftChild = 2 * parentIndex + 1;
|
|
const rightChild = 2 * parentIndex + 2;
|
|
const leftMin = buffer[Math.trunc(leftChild * SPAN) + MIN];
|
|
const leftMax = buffer[Math.trunc(leftChild * SPAN) + MAX];
|
|
const rightMin = buffer[Math.trunc(rightChild * SPAN) + MIN];
|
|
const rightMax = buffer[Math.trunc(rightChild * SPAN) + MAX];
|
|
buffer[Math.trunc(parentIndex * SPAN) + MIN] = !Number.isFinite(rightMin) || leftMin < rightMin ? leftMin : rightMin;
|
|
buffer[Math.trunc(parentIndex * SPAN) + MAX] = !Number.isFinite(rightMax) || leftMax > rightMax ? leftMax : rightMax;
|
|
bufferIndex = parentIndex;
|
|
}
|
|
}
|
|
computeRangeInto(buffer, start, end2, bufferIndex, currentStart, step, into) {
|
|
const currentEnd = currentStart + step - 1;
|
|
if (currentEnd < start || currentStart >= end2)
|
|
return into;
|
|
if (currentStart >= start && currentEnd < end2) {
|
|
const min = buffer[Math.trunc(bufferIndex * SPAN) + MIN];
|
|
const max = buffer[Math.trunc(bufferIndex * SPAN) + MAX];
|
|
if (Number.isFinite(min))
|
|
into[0] = Math.min(into[0], min);
|
|
if (Number.isFinite(max))
|
|
into[1] = Math.max(into[1], max);
|
|
} else if (step > 1) {
|
|
bufferIndex = Math.trunc(bufferIndex * 2);
|
|
step = Math.trunc(step / 2);
|
|
this.computeRangeInto(buffer, start, end2, Math.trunc(bufferIndex + 1), currentStart, step, into);
|
|
this.computeRangeInto(buffer, start, end2, Math.trunc(bufferIndex + 2), currentStart + step, step, into);
|
|
}
|
|
return into;
|
|
}
|
|
rangeBetween(start, end2, into) {
|
|
const result = into ?? [0, 0];
|
|
if (start > end2) {
|
|
result[0] = Number.NaN;
|
|
result[1] = Number.NaN;
|
|
return result;
|
|
}
|
|
const { maxLevelSize, buffer } = this;
|
|
result[0] = Infinity;
|
|
result[1] = -Infinity;
|
|
this.computeRangeInto(buffer, start, end2, 0, 0, maxLevelSize, result);
|
|
return result;
|
|
}
|
|
getRange(into) {
|
|
const { buffer } = this;
|
|
const result = into ?? [0, 0];
|
|
result[0] = buffer[MIN];
|
|
result[1] = buffer[MAX];
|
|
return result;
|
|
}
|
|
get range() {
|
|
const { buffer } = this;
|
|
return [buffer[MIN], buffer[MAX]];
|
|
}
|
|
/** The number of data elements in the segment tree */
|
|
get length() {
|
|
return this.dataLength;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/sortOrder.ts
|
|
function valuesSortOrder(values, needsValueOf) {
|
|
const valuesLength = values.length;
|
|
if (values.length <= 1)
|
|
return 1;
|
|
let order = 0;
|
|
let v0 = values[0];
|
|
for (let i = 1; i < valuesLength; i++) {
|
|
const v1 = values[i];
|
|
if (v1 == null)
|
|
continue;
|
|
const primitive = needsValueOf ? v1.valueOf() : v1;
|
|
if (typeof primitive !== "number")
|
|
return;
|
|
const diff2 = Math.sign(v1 - v0);
|
|
if (diff2 !== 0) {
|
|
if (order !== 0 && order !== diff2)
|
|
return;
|
|
order = diff2;
|
|
}
|
|
v0 = v1;
|
|
}
|
|
return order === 0 ? 1 : order;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/utils/resolvers.ts
|
|
var DataModelResolvers = class {
|
|
constructor(ctx) {
|
|
this.ctx = ctx;
|
|
this.rangeBetweenBuffer = [0, 0];
|
|
}
|
|
resolveMissingDataCount(scope) {
|
|
let missingDataCount = 0;
|
|
for (const value of this.ctx.values) {
|
|
missingDataCount = Math.max(missingDataCount, value.missing.get(scope.id) ?? 0);
|
|
}
|
|
return missingDataCount;
|
|
}
|
|
resolveProcessedDataDefById(scope, searchId) {
|
|
const def = this.ctx.scopeCache.get(scope.id)?.get(searchId);
|
|
if (!def) {
|
|
throw new Error(`AG Charts - didn't find property definition for [${searchId}, ${scope.id}]`);
|
|
}
|
|
return { index: def.index, def };
|
|
}
|
|
resolveProcessedDataIndexById(scope, searchId) {
|
|
return this.resolveProcessedDataDefById(scope, searchId).index;
|
|
}
|
|
resolveKeysById(scope, searchId, processedData) {
|
|
const index = this.resolveProcessedDataIndexById(scope, searchId);
|
|
const keys = processedData.keys[index];
|
|
if (keys == null) {
|
|
throw new Error(`AG Charts - didn't find keys for [${searchId}, ${scope.id}]`);
|
|
}
|
|
return keys.get(scope.id);
|
|
}
|
|
hasColumnById(scope, searchId) {
|
|
return this.ctx.scopeCache.get(scope.id)?.get(searchId) != null;
|
|
}
|
|
resolveColumnById(scope, searchId, processedData) {
|
|
const index = this.resolveProcessedDataIndexById(scope, searchId);
|
|
const column = processedData.columns?.[index];
|
|
if (column == null) {
|
|
throw new Error(`AG Charts - didn't find column for [${searchId}, ${scope.id}]`);
|
|
}
|
|
return column;
|
|
}
|
|
resolveColumnNeedsValueOf(scope, searchId, processedData) {
|
|
const index = this.resolveProcessedDataIndexById(scope, searchId);
|
|
return processedData.columnNeedValueOf?.[index] ?? true;
|
|
}
|
|
/**
|
|
* Converts a relative datum index to an absolute column index.
|
|
*
|
|
* INDEXING STRATEGY:
|
|
* - Relative index: Offset from the start of a group (stored in datumIndices)
|
|
* - Absolute index: Position in the full column array
|
|
* - Conversion: absoluteIndex = groupIndex + relativeIndex
|
|
*
|
|
* When groupsUnique=true, relativeIndex is always 0, making this a simple
|
|
* identity mapping. This optimization reduces memory usage significantly
|
|
* for large datasets with unique keys.
|
|
*
|
|
* @param groupIndex index of the group in ProcessedData.groups
|
|
* @param relativeDatumIndex relative index stored in group.datumIndices
|
|
* @returns absolute index for accessing columns
|
|
*/
|
|
resolveAbsoluteIndex(groupIndex, relativeDatumIndex) {
|
|
return groupIndex + relativeDatumIndex;
|
|
}
|
|
getDomain(scope, searchId, type, processedData) {
|
|
const domains = this.getDomainsByType(type ?? "value", processedData);
|
|
return domains?.[this.resolveProcessedDataIndexById(scope, searchId)] ?? [];
|
|
}
|
|
getDomainBetweenRange(scope, searchIds, [i0, i1], processedData) {
|
|
const columnIndices = searchIds.map((searchId) => this.resolveProcessedDataIndexById(scope, searchId));
|
|
const dataLength = processedData.input.count;
|
|
if (i0 <= 0 && i1 >= dataLength) {
|
|
const domains = processedData.domain.values;
|
|
let min = Infinity;
|
|
let max = -Infinity;
|
|
for (const columnIndex of columnIndices) {
|
|
const domain = domains[columnIndex];
|
|
if (domain != null) {
|
|
if (domain[0] < min)
|
|
min = domain[0];
|
|
if (domain[1] > max)
|
|
max = domain[1];
|
|
}
|
|
}
|
|
this.rangeBetweenBuffer[0] = min;
|
|
this.rangeBetweenBuffer[1] = max;
|
|
return this.rangeBetweenBuffer;
|
|
}
|
|
const cacheKey = columnIndices.join(":");
|
|
const domainRanges = processedData[DOMAIN_RANGES];
|
|
const values = columnIndices.map((columnIndex) => processedData.columns[columnIndex]);
|
|
let rangeLookup = domainRanges.get(cacheKey);
|
|
if (rangeLookup == null) {
|
|
rangeLookup = new RangeLookup(values);
|
|
domainRanges.set(cacheKey, rangeLookup);
|
|
} else if (rangeLookup.isDirty) {
|
|
rangeLookup.rebuild(values);
|
|
rangeLookup.isDirty = false;
|
|
}
|
|
return rangeLookup.rangeBetween(i0, i1, this.rangeBetweenBuffer);
|
|
}
|
|
getSortOrder(values, index, sortOrders, needsValueOf) {
|
|
const entry = sortOrders.get(index);
|
|
if (entry == null || entry.isDirty) {
|
|
const newEntry = { sortOrder: valuesSortOrder(values, needsValueOf) };
|
|
sortOrders.set(index, newEntry);
|
|
return newEntry.sortOrder;
|
|
}
|
|
return entry.sortOrder;
|
|
}
|
|
getKeySortOrder(scope, searchId, processedData) {
|
|
const columnIndex = this.resolveProcessedDataIndexById(scope, searchId);
|
|
const keys = processedData.keys[columnIndex]?.get(scope.id);
|
|
return keys ? this.getSortOrder(keys, columnIndex, processedData[KEY_SORT_ORDERS], true) : void 0;
|
|
}
|
|
getKeySortEntry(scope, searchId, processedData) {
|
|
const columnIndex = this.resolveProcessedDataIndexById(scope, searchId);
|
|
const entry = processedData[KEY_SORT_ORDERS].get(columnIndex);
|
|
return entry?.isDirty ? void 0 : entry;
|
|
}
|
|
getColumnSortOrder(scope, searchId, processedData) {
|
|
const columnIndex = this.resolveProcessedDataIndexById(scope, searchId);
|
|
const needsValueOf = processedData.columnNeedValueOf?.[columnIndex] ?? true;
|
|
return this.getSortOrder(
|
|
processedData.columns[columnIndex],
|
|
columnIndex,
|
|
processedData[COLUMN_SORT_ORDERS],
|
|
needsValueOf
|
|
);
|
|
}
|
|
getDomainsByType(type, processedData) {
|
|
switch (type) {
|
|
case "key":
|
|
return processedData.domain.keys;
|
|
case "value":
|
|
return processedData.domain.values;
|
|
case "aggregate":
|
|
return processedData.domain.aggValues;
|
|
case "group-value-processor":
|
|
return processedData.domain.groups;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/data-model/utils/scopeCache.ts
|
|
var import_ag_charts_core78 = require("ag-charts-core");
|
|
var ScopeCacheManager = class {
|
|
constructor(ctx) {
|
|
this.ctx = ctx;
|
|
}
|
|
processScopeCache() {
|
|
this.ctx.scopeCache.clear();
|
|
for (const def of (0, import_ag_charts_core78.iterate)(this.ctx.keys, this.ctx.values, this.ctx.aggregates)) {
|
|
if (!def.idsMap)
|
|
continue;
|
|
for (const [scope, ids] of def.idsMap) {
|
|
for (const id of ids) {
|
|
if (!this.ctx.scopeCache.has(scope)) {
|
|
this.ctx.scopeCache.set(scope, /* @__PURE__ */ new Map([[id, def]]));
|
|
} else if (this.ctx.scopeCache.get(scope)?.has(id)) {
|
|
throw new Error("duplicate definition ids on the same scope are not allowed.");
|
|
} else {
|
|
this.ctx.scopeCache.get(scope).set(id, def);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
valueGroupIdxLookup({ matchGroupIds }) {
|
|
const result = [];
|
|
for (const [index, def] of this.ctx.values.entries()) {
|
|
if (!matchGroupIds || def.groupId && matchGroupIds.includes(def.groupId)) {
|
|
result.push(index);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
valueIdxLookup(scopes, prop) {
|
|
const noScopesToMatch = scopes == null || scopes.length === 0;
|
|
const propId = typeof prop === "string" ? prop : prop.id;
|
|
const hasMatchingScopeId = (def) => {
|
|
if (def.idsMap) {
|
|
for (const [scope, ids] of def.idsMap) {
|
|
if (scopes?.includes(scope) && ids.has(propId)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
const result = this.ctx.values.reduce((res, def, index) => {
|
|
const validDefScopes = def.scopes == null || noScopesToMatch && !def.scopes.length || def.scopes.some((s) => scopes?.includes(s));
|
|
if (validDefScopes && (def.property === propId || def.id === propId || hasMatchingScopeId(def))) {
|
|
res.push(index);
|
|
}
|
|
return res;
|
|
}, []);
|
|
if (result.length === 0) {
|
|
throw new Error(
|
|
`AG Charts - configuration error, unknown property ${JSON.stringify(prop)} in scope(s) ${JSON.stringify(
|
|
scopes
|
|
)}`
|
|
);
|
|
}
|
|
return result;
|
|
}
|
|
buildAccessors(defs) {
|
|
const result = /* @__PURE__ */ new Map();
|
|
if (this.ctx.suppressFieldDotNotation) {
|
|
return result;
|
|
}
|
|
for (const def of defs) {
|
|
const isPath = def.property.includes(".") || def.property.includes("[");
|
|
if (!isPath)
|
|
continue;
|
|
const components = getPathComponents(def.property);
|
|
if (components == null) {
|
|
import_ag_charts_core78.Logger.warnOnce("Invalid property path [%s]", def.property);
|
|
continue;
|
|
}
|
|
const accessor = createPathAccessor(components);
|
|
result.set(def.property, accessor);
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/data/dataModel.ts
|
|
var DataModel = class {
|
|
constructor(opts, mode = "standalone", suppressFieldDotNotation = false, eventsHub) {
|
|
this.opts = opts;
|
|
this.mode = mode;
|
|
this.suppressFieldDotNotation = suppressFieldDotNotation;
|
|
this.eventsHub = eventsHub;
|
|
this.debug = import_ag_charts_core79.Debug.create(true, "data-model");
|
|
this.scopeCache = /* @__PURE__ */ new Map();
|
|
this.keys = [];
|
|
this.values = [];
|
|
this.aggregates = [];
|
|
this.groupProcessors = [];
|
|
this.propertyProcessors = [];
|
|
this.reducers = [];
|
|
this.processors = [];
|
|
let keys = true;
|
|
for (const next of opts.props) {
|
|
if (next.type === "key" && !keys) {
|
|
throw new Error("AG Charts - internal config error: keys must come before values.");
|
|
}
|
|
if (next.type === "value" && keys) {
|
|
keys = false;
|
|
}
|
|
}
|
|
const verifyMatchGroupId = ({ matchGroupIds = [] }) => {
|
|
for (const matchGroupId of matchGroupIds) {
|
|
if (this.values.every((def) => def.groupId !== matchGroupId)) {
|
|
throw new Error(
|
|
`AG Charts - internal config error: matchGroupIds properties must match defined groups (${matchGroupId}).`
|
|
);
|
|
}
|
|
}
|
|
};
|
|
const keyScopes = /* @__PURE__ */ new Set();
|
|
const valueScopes = /* @__PURE__ */ new Set();
|
|
for (const def of opts.props) {
|
|
const scopes = def.type === "key" ? keyScopes : valueScopes;
|
|
if (isScoped(def)) {
|
|
if (def.scopes) {
|
|
for (const s of def.scopes) {
|
|
scopes.add(s);
|
|
}
|
|
}
|
|
}
|
|
switch (def.type) {
|
|
case "key":
|
|
this.keys.push({ ...def, index: this.keys.length, missing: /* @__PURE__ */ new Map() });
|
|
break;
|
|
case "value":
|
|
if (def.property == null) {
|
|
throw new Error(
|
|
`AG Charts - internal config error: no properties specified for value definitions: ${JSON.stringify(
|
|
def
|
|
)}`
|
|
);
|
|
}
|
|
this.values.push({ ...def, index: this.values.length, missing: /* @__PURE__ */ new Map() });
|
|
break;
|
|
case "aggregate":
|
|
verifyMatchGroupId(def);
|
|
this.aggregates.push({ ...def, index: this.aggregates.length });
|
|
break;
|
|
case "group-value-processor":
|
|
verifyMatchGroupId(def);
|
|
this.groupProcessors.push({ ...def, index: this.groupProcessors.length });
|
|
break;
|
|
case "property-value-processor":
|
|
this.propertyProcessors.push({ ...def, index: this.propertyProcessors.length });
|
|
break;
|
|
case "reducer":
|
|
this.reducers.push({ ...def, index: this.reducers.length });
|
|
break;
|
|
case "processor":
|
|
this.processors.push({ ...def, index: this.processors.length });
|
|
break;
|
|
}
|
|
}
|
|
if (!!this.opts.groupByKeys || this.opts.groupByFn != null) {
|
|
const ungroupedScopes = new Set(valueScopes.values());
|
|
for (const s of keyScopes) {
|
|
ungroupedScopes.delete(s);
|
|
}
|
|
if (ungroupedScopes.size > 0) {
|
|
throw new Error(
|
|
`AG Charts - scopes missing key for grouping, illegal configuration: ${[...ungroupedScopes.values()]}`
|
|
);
|
|
}
|
|
}
|
|
const ctx = {
|
|
keys: this.keys,
|
|
values: this.values,
|
|
aggregates: this.aggregates,
|
|
groupProcessors: this.groupProcessors,
|
|
propertyProcessors: this.propertyProcessors,
|
|
reducers: this.reducers,
|
|
processors: this.processors,
|
|
debug: this.debug,
|
|
mode: this.mode,
|
|
bandingConfig: this.opts.domainBandingConfig,
|
|
suppressFieldDotNotation: this.suppressFieldDotNotation,
|
|
scopeCache: this.scopeCache
|
|
};
|
|
this.resolvers = new DataModelResolvers(ctx);
|
|
this.scopeCacheManager = new ScopeCacheManager(ctx);
|
|
this.domainInitializer = new DomainInitializer(ctx);
|
|
this.domainManager = new DomainManager(ctx, this.domainInitializer, this.scopeCacheManager);
|
|
this.reducerManager = new ReducerManager(this.opts.domainBandingConfig);
|
|
this.dataExtractor = new DataExtractor(ctx, this.domainManager);
|
|
this.dataGrouper = new DataGrouper(ctx);
|
|
this.aggregator = new Aggregator(ctx, this.scopeCacheManager, this.resolvers);
|
|
this.incrementalProcessor = new IncrementalProcessor(ctx, this.reducerManager);
|
|
}
|
|
resolveProcessedDataDefById(scope, searchId) {
|
|
return this.resolvers.resolveProcessedDataDefById(scope, searchId);
|
|
}
|
|
resolveProcessedDataIndexById(scope, searchId) {
|
|
return this.resolvers.resolveProcessedDataIndexById(scope, searchId);
|
|
}
|
|
resolveKeysById(scope, searchId, processedData) {
|
|
return this.resolvers.resolveKeysById(scope, searchId, processedData);
|
|
}
|
|
hasColumnById(scope, searchId) {
|
|
return this.resolvers.hasColumnById(scope, searchId);
|
|
}
|
|
resolveColumnById(scope, searchId, processedData) {
|
|
return this.resolvers.resolveColumnById(scope, searchId, processedData);
|
|
}
|
|
resolveColumnNeedsValueOf(scope, searchId, processedData) {
|
|
return this.resolvers.resolveColumnNeedsValueOf(scope, searchId, processedData);
|
|
}
|
|
resolveMissingDataCount(scope) {
|
|
return this.resolvers.resolveMissingDataCount(scope);
|
|
}
|
|
/**
|
|
* Provides a convenience iterator to iterate over all of the extract datum values in a
|
|
* specific DataGroup.
|
|
*
|
|
* @param scope to which datums should belong
|
|
* @param group containing the datums
|
|
* @param processedData containing the group
|
|
* @param groupIndex index of the group in processedData.groups
|
|
*/
|
|
*forEachDatum(scope, processedData, group, groupIndex) {
|
|
const columnIndex = processedData.columnScopes.findIndex((s) => s.has(scope.id));
|
|
for (const relativeDatumIndex of group.datumIndices[columnIndex] ?? []) {
|
|
const absoluteDatumIndex = this.resolvers.resolveAbsoluteIndex(groupIndex, relativeDatumIndex);
|
|
yield processedData.columns[columnIndex][absoluteDatumIndex];
|
|
}
|
|
}
|
|
getUniqueDataSets(processedData) {
|
|
return new Set(processedData.dataSources.values());
|
|
}
|
|
/**
|
|
* Provides a convenience iterator to iterate over all of the extracted datum values in a
|
|
* GroupedData.
|
|
*
|
|
* @param scope to which datums should belong
|
|
* @param processedData to iterate through
|
|
*/
|
|
*forEachGroupDatum(scope, processedData) {
|
|
const columnIndex = processedData.columnScopes.findIndex((s) => s.has(scope.id));
|
|
const output = {
|
|
groupIndex: 0,
|
|
columnIndex
|
|
};
|
|
const empty = [];
|
|
for (const group of processedData.groups) {
|
|
output.group = group;
|
|
for (const relativeDatumIndex of group.datumIndices[columnIndex] ?? empty) {
|
|
output.datumIndex = this.resolvers.resolveAbsoluteIndex(output.groupIndex, relativeDatumIndex);
|
|
yield output;
|
|
}
|
|
output.groupIndex++;
|
|
}
|
|
}
|
|
getDomain(scope, searchId, type, processedData) {
|
|
const domain = this.resolvers.getDomain(scope, searchId, type, processedData);
|
|
if (type === "key" && domain.length > 0) {
|
|
const sortMetadata = this.getKeySortMetadata(scope, searchId, processedData);
|
|
return { domain, sortMetadata };
|
|
}
|
|
return { domain };
|
|
}
|
|
getDomainBetweenRange(scope, searchIds, [i0, i1], processedData) {
|
|
return this.resolvers.getDomainBetweenRange(scope, searchIds, [i0, i1], processedData);
|
|
}
|
|
getKeySortOrder(scope, searchId, processedData) {
|
|
return this.resolvers.getKeySortOrder(scope, searchId, processedData);
|
|
}
|
|
getColumnSortOrder(scope, searchId, processedData) {
|
|
return this.resolvers.getColumnSortOrder(scope, searchId, processedData);
|
|
}
|
|
/**
|
|
* Get sort metadata for a key column if available.
|
|
* Returns undefined if metadata is not available, is dirty, or data is unsorted.
|
|
*/
|
|
getKeySortMetadata(scope, searchId, processedData) {
|
|
const entry = this.resolvers.getKeySortEntry(scope, searchId, processedData);
|
|
if (entry?.sortOrder != null) {
|
|
return { sortOrder: entry.sortOrder, isUnique: entry.isUnique };
|
|
}
|
|
return void 0;
|
|
}
|
|
processData(sources) {
|
|
const {
|
|
opts: { groupByKeys, groupByFn },
|
|
aggregates,
|
|
groupProcessors,
|
|
reducers,
|
|
processors,
|
|
propertyProcessors
|
|
} = this;
|
|
const start = performance.now();
|
|
if (groupByKeys && this.keys.length === 0) {
|
|
return;
|
|
}
|
|
let processedData = this.extractData(sources);
|
|
if (groupByKeys) {
|
|
processedData = this.dataGrouper.groupData(processedData);
|
|
} else if (groupByFn) {
|
|
processedData = this.dataGrouper.groupData(processedData, groupByFn(processedData));
|
|
}
|
|
if (groupProcessors.length > 0 && processedData.type === "grouped") {
|
|
this.aggregator.postProcessGroups(processedData);
|
|
}
|
|
if (aggregates.length > 0 && processedData.type === "ungrouped") {
|
|
this.aggregator.aggregateUngroupedData(processedData);
|
|
} else if (aggregates.length > 0 && processedData.type === "grouped") {
|
|
this.aggregator.aggregateGroupedData(processedData);
|
|
}
|
|
if (propertyProcessors.length > 0) {
|
|
this.postProcessProperties(processedData);
|
|
}
|
|
if (reducers.length > 0) {
|
|
this.reduceData(processedData);
|
|
}
|
|
if (processors.length > 0) {
|
|
this.postProcessData(processedData);
|
|
}
|
|
this.warnDataMissingProperties(sources);
|
|
const end2 = performance.now();
|
|
processedData.time = end2 - start;
|
|
processedData.version += 1;
|
|
this.collectOptimizationMetadata(processedData, "full-process");
|
|
if (this.debug.check()) {
|
|
logProcessedData(processedData);
|
|
}
|
|
this.processScopeCache();
|
|
return processedData;
|
|
}
|
|
/**
|
|
* Determines if incremental reprocessing is supported for the given data.
|
|
*
|
|
* Reprocessing is supported when:
|
|
* - For ungrouped data: No aggregates, reducers, processors, or property processors
|
|
* - For grouped data: Additionally requires:
|
|
* - groupsUnique=true (each datum has unique keys)
|
|
* - Single data source (all scopes share same DataSet)
|
|
* - No invalid keys (to maintain groups.length === columns.length invariant)
|
|
* - All group processors support reprocessing
|
|
*
|
|
* When unsupported, falls back to full reprocessing automatically.
|
|
*
|
|
* @returns true if incremental reprocessing can be used, false otherwise
|
|
*/
|
|
isReprocessingSupported(processedData) {
|
|
return this.incrementalProcessor.isReprocessingSupported(processedData);
|
|
}
|
|
reprocessData(processedData, dataSets) {
|
|
if (!this.isReprocessingSupported(processedData)) {
|
|
if (this.debug.check()) {
|
|
this.debug("Falling back to full reprocessing - incremental not supported for current configuration");
|
|
}
|
|
const uniqueDataSets = this.getUniqueDataSets(processedData);
|
|
for (const dataSet of uniqueDataSets) {
|
|
dataSet.commitPendingTransactions();
|
|
}
|
|
return this.processData(processedData.dataSources);
|
|
}
|
|
const { getProcessValue } = this.initDataDomainProcessor("skip");
|
|
return this.incrementalProcessor.reprocessData(
|
|
processedData,
|
|
dataSets,
|
|
getProcessValue,
|
|
this.reprocessGroupProcessors.bind(this),
|
|
this.recomputeDomains.bind(this),
|
|
this.collectOptimizationMetadata.bind(this)
|
|
);
|
|
}
|
|
/**
|
|
* Recomputes domains from transformed arrays.
|
|
* Uses BandedDomain optimization for continuous domains to avoid full rescans.
|
|
*/
|
|
recomputeDomains(processedData) {
|
|
this.domainManager.recomputeDomains(processedData);
|
|
}
|
|
warnDataMissingProperties(sources) {
|
|
this.dataExtractor.warnDataMissingProperties(sources);
|
|
}
|
|
processScopeCache() {
|
|
this.scopeCacheManager.processScopeCache();
|
|
}
|
|
valueGroupIdxLookup(selector) {
|
|
return this.scopeCacheManager.valueGroupIdxLookup(selector);
|
|
}
|
|
valueIdxLookup(scopes, prop) {
|
|
return this.scopeCacheManager.valueIdxLookup(scopes, prop);
|
|
}
|
|
extractData(sources) {
|
|
return this.dataExtractor.extractData(sources);
|
|
}
|
|
/**
|
|
* Reprocesses group processors for incremental updates.
|
|
* Only processes newly inserted groups to avoid double-processing.
|
|
* This is safe only when all group processors support reprocessing.
|
|
* Deduplicates change descriptions to avoid processing the same groups multiple times
|
|
* when multiple scopes share the same DataSet.
|
|
*/
|
|
reprocessGroupProcessors(processedData, scopeChanges) {
|
|
const { groupProcessors } = this;
|
|
const { columns } = processedData;
|
|
for (const processor of groupProcessors) {
|
|
if (!processor.supportsReprocessing) {
|
|
throw new Error(
|
|
"AG Charts - attempted to reprocess group processor that does not support reprocessing. This is an internal error that should not occur."
|
|
);
|
|
}
|
|
}
|
|
const processedChangeDescs = uniqueChangeDescriptions(scopeChanges);
|
|
for (const processor of groupProcessors) {
|
|
const valueIndexes = this.valueGroupIdxLookup(processor);
|
|
const adjustFn = processor.adjust()();
|
|
for (const changeDesc of processedChangeDescs) {
|
|
const { indexMap } = changeDesc;
|
|
for (const op of indexMap.spliceOps) {
|
|
if (op.insertCount > 0) {
|
|
for (let i = 0; i < op.insertCount; i++) {
|
|
const groupIndex = op.index + i;
|
|
const dataGroup = processedData.groups[groupIndex];
|
|
adjustFn(columns, valueIndexes, dataGroup, groupIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
postProcessProperties(processedData) {
|
|
for (const { adjust, property, scopes } of this.propertyProcessors) {
|
|
for (const idx of this.valueIdxLookup(scopes, property)) {
|
|
adjust()(processedData, idx);
|
|
}
|
|
}
|
|
}
|
|
reduceData(processedData) {
|
|
processedData.reduced ?? (processedData.reduced = {});
|
|
for (const def of this.reducers) {
|
|
if (this.shouldUseReducerBanding(def, processedData)) {
|
|
processedData.reduced[def.property] = this.reduceWithBands(
|
|
def,
|
|
processedData
|
|
);
|
|
} else {
|
|
processedData.reduced[def.property] = this.reduceStandard(
|
|
def,
|
|
processedData
|
|
);
|
|
}
|
|
}
|
|
}
|
|
shouldUseReducerBanding(def, processedData) {
|
|
return processedData.type === "ungrouped" && def.supportsBanding === true && typeof def.combineResults === "function";
|
|
}
|
|
reduceWithBands(def, processedData) {
|
|
const result = this.reducerManager.evaluate(def, processedData, {
|
|
reuseCleanBands: false
|
|
});
|
|
if (result === void 0) {
|
|
return this.reduceStandard(def, processedData);
|
|
}
|
|
return result;
|
|
}
|
|
reduceStandard(def, processedData) {
|
|
const reducer = def.reducer();
|
|
if (processedData.type === "grouped") {
|
|
let accValue = def.initialValue;
|
|
for (const group of processedData.groups) {
|
|
accValue = reducer(accValue, group.keys);
|
|
}
|
|
return accValue;
|
|
}
|
|
const scopeId = isScoped(def) ? def.scopes[0] : (0, import_ag_charts_core79.first)(processedData.scopes);
|
|
if (scopeId == null) {
|
|
return def.initialValue;
|
|
}
|
|
const rawData = processedData.dataSources.get(scopeId)?.data ?? [];
|
|
const keyColumns = processedData.keys.map((column) => column.get(scopeId)).filter((column) => column != null);
|
|
const keysParam = keyColumns.map(() => void 0);
|
|
return ReducerManager.evaluateRange(def, reducer, { rawData, keyColumns, keysParam }, 0, rawData.length);
|
|
}
|
|
postProcessData(processedData) {
|
|
processedData.reduced ?? (processedData.reduced = {});
|
|
for (const def of this.processors) {
|
|
processedData.reduced[def.property] = def.calculate(
|
|
processedData,
|
|
processedData.reduced[def.property]
|
|
);
|
|
}
|
|
const { diff: diff2 } = processedData.reduced;
|
|
if (diff2) {
|
|
this.eventsHub?.emit("datamodel:diff", { diff: diff2 });
|
|
}
|
|
}
|
|
initDataDomainProcessor(domainMode) {
|
|
return this.domainManager.initDataDomainProcessor(domainMode);
|
|
}
|
|
/**
|
|
* Collects optimization metadata for debugging purposes.
|
|
* Only called when debug mode is enabled.
|
|
*/
|
|
collectOptimizationMetadata(processedData, pathTaken) {
|
|
const existingDomainBanding = processedData.optimizations?.domainBanding;
|
|
const reducerBands = processedData[REDUCER_BANDS];
|
|
if (this.reducers.length > 0 && reducerBands) {
|
|
this.collectReducerBandingMetadata(processedData, reducerBands);
|
|
}
|
|
const reducerBanding = processedData.optimizations?.reducerBanding;
|
|
processedData.optimizations = {
|
|
performance: {
|
|
processingTime: processedData.time,
|
|
pathTaken
|
|
},
|
|
...existingDomainBanding && { domainBanding: existingDomainBanding },
|
|
...reducerBanding && { reducerBanding }
|
|
};
|
|
const reprocessingSupported = this.isReprocessingSupported(processedData);
|
|
const reprocessingApplied = pathTaken === "reprocess";
|
|
let reprocessingReason;
|
|
if (!reprocessingSupported) {
|
|
const reasons = [];
|
|
if (processedData.type === "grouped") {
|
|
if (!processedData.groupsUnique) {
|
|
reasons.push("groupsUnique=false");
|
|
}
|
|
const uniqueDataSets = this.getUniqueDataSets(processedData);
|
|
if (uniqueDataSets.size !== 1) {
|
|
reasons.push("multiple data sources");
|
|
}
|
|
const scope = (0, import_ag_charts_core79.first)(processedData.scopes);
|
|
const invalidKeys = processedData.invalidKeys?.get(scope);
|
|
if (invalidKeys?.some((invalid) => invalid)) {
|
|
reasons.push("has invalid keys");
|
|
}
|
|
}
|
|
if (this.aggregates.length > 0) {
|
|
reasons.push("has aggregates");
|
|
}
|
|
if (this.reducers.filter((r) => !r.supportsBanding).length > 0) {
|
|
reasons.push("has reducers");
|
|
}
|
|
if (this.processors.filter((p) => p.incrementalCalculate === void 0).length > 0) {
|
|
reasons.push("has processors");
|
|
}
|
|
if (this.propertyProcessors.length > 0) {
|
|
reasons.push("has property processors");
|
|
}
|
|
reprocessingReason = reasons.length > 0 ? reasons.join(", ") : void 0;
|
|
}
|
|
processedData.optimizations.reprocessing = {
|
|
applied: reprocessingApplied,
|
|
reason: reprocessingReason
|
|
};
|
|
if (processedData.type === "grouped") {
|
|
let sharedGroupCount = 0;
|
|
const firstGroup = processedData.groups[0];
|
|
if (firstGroup) {
|
|
const sharedDatumIndices = firstGroup.datumIndices;
|
|
for (const group of processedData.groups) {
|
|
if (group.datumIndices === sharedDatumIndices) {
|
|
sharedGroupCount++;
|
|
}
|
|
}
|
|
}
|
|
processedData.optimizations.sharedDatumIndices = {
|
|
applied: sharedGroupCount > 0,
|
|
sharedGroupCount,
|
|
totalGroupCount: processedData.groups.length
|
|
};
|
|
}
|
|
}
|
|
/**
|
|
* Collects reducer banding metadata for debugging purposes.
|
|
* Tracks which reducers used banding and their performance stats.
|
|
*/
|
|
collectReducerBandingMetadata(processedData, reducerBands) {
|
|
if (this.reducers.length === 0)
|
|
return;
|
|
processedData.optimizations ?? (processedData.optimizations = {});
|
|
const reducerMetadata = [];
|
|
for (const def of this.reducers) {
|
|
const bandManager = reducerBands.get(def.property);
|
|
const isBanded = this.shouldUseReducerBanding(def, processedData) && bandManager != null;
|
|
let reason;
|
|
if (!isBanded) {
|
|
if (def.supportsBanding !== true) {
|
|
reason = "reducer does not support banding";
|
|
} else if (processedData.type !== "ungrouped") {
|
|
reason = "grouped data not supported";
|
|
} else if (def.combineResults === void 0) {
|
|
reason = "missing combineResults function";
|
|
} else {
|
|
reason = "banding not applied";
|
|
}
|
|
}
|
|
let stats;
|
|
if (isBanded && bandManager) {
|
|
stats = bandManager.getStats();
|
|
}
|
|
reducerMetadata.push({
|
|
property: String(def.property),
|
|
applied: isBanded,
|
|
reason,
|
|
stats
|
|
});
|
|
}
|
|
processedData.optimizations.reducerBanding = {
|
|
reducers: reducerMetadata
|
|
};
|
|
}
|
|
buildAccessors(defs) {
|
|
return this.scopeCacheManager.buildAccessors(defs);
|
|
}
|
|
};
|
|
function logProcessedData(processedData) {
|
|
const logValues = (name, data) => {
|
|
if (data.length > 0) {
|
|
import_ag_charts_core79.Logger.log(`DataModel.processData() - ${name}`);
|
|
import_ag_charts_core79.Logger.table(data);
|
|
}
|
|
};
|
|
import_ag_charts_core79.Logger.log("DataModel.processData() - processedData", processedData);
|
|
logValues("Key Domains", processedData.domain.keys);
|
|
logValues("Value Domains", processedData.domain.values);
|
|
logValues("Aggregate Domains", processedData.domain.aggValues ?? []);
|
|
if (processedData.optimizations) {
|
|
import_ag_charts_core79.Logger.log("DataModel.processData() - Optimization Summary");
|
|
const opt = processedData.optimizations;
|
|
if (opt.performance) {
|
|
import_ag_charts_core79.Logger.log(` Performance: ${opt.performance.processingTime.toFixed(2)}ms (${opt.performance.pathTaken})`);
|
|
}
|
|
if (opt.reprocessing) {
|
|
const symbol = opt.reprocessing.applied ? "\u2713" : "\u2717";
|
|
const reason = opt.reprocessing.reason ? ` (${opt.reprocessing.reason})` : "";
|
|
import_ag_charts_core79.Logger.log(` Reprocessing: ${symbol}${reason}`);
|
|
}
|
|
if (opt.domainBanding) {
|
|
const keyStats = opt.domainBanding.keyDefs.filter((d) => d.applied);
|
|
const valueStats = opt.domainBanding.valueDefs.filter((d) => d.applied);
|
|
const totalApplied = keyStats.length + valueStats.length;
|
|
const totalDefs = opt.domainBanding.keyDefs.length + opt.domainBanding.valueDefs.length;
|
|
if (totalApplied > 0) {
|
|
import_ag_charts_core79.Logger.log(` Domain Banding: \u2713 (${totalApplied}/${totalDefs} definitions)`);
|
|
for (const def of [...keyStats, ...valueStats]) {
|
|
if (def.stats) {
|
|
const pct2 = (def.stats.scanRatio * 100).toFixed(1);
|
|
import_ag_charts_core79.Logger.log(
|
|
` ${def.property}: scanned ${def.stats.dirtyBands}/${def.stats.totalBands} bands (${pct2}%)`
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
const reasons = [
|
|
...opt.domainBanding.keyDefs.filter((d) => !d.applied).map((d) => d.reason),
|
|
...opt.domainBanding.valueDefs.filter((d) => !d.applied).map((d) => d.reason)
|
|
];
|
|
const uniqueReasons = [...new Set(reasons)].join(", ");
|
|
import_ag_charts_core79.Logger.log(` Domain Banding: \u2717 (${uniqueReasons})`);
|
|
}
|
|
}
|
|
if (opt.sharedDatumIndices) {
|
|
const symbol = opt.sharedDatumIndices.applied ? "\u2713" : "\u2717";
|
|
const ratio10 = `${opt.sharedDatumIndices.sharedGroupCount}/${opt.sharedDatumIndices.totalGroupCount}`;
|
|
import_ag_charts_core79.Logger.log(` Shared DatumIndices: ${symbol} (${ratio10} groups)`);
|
|
}
|
|
if (opt.batchMerging) {
|
|
const pct2 = (opt.batchMerging.mergeRatio * 100).toFixed(0);
|
|
const reduction = `${opt.batchMerging.originalBatchCount} \u2192 ${opt.batchMerging.mergedBatchCount}`;
|
|
import_ag_charts_core79.Logger.log(` Batch Merging: ${reduction} (${pct2}% reduction)`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/data/processors.ts
|
|
var MAX_ANIMATABLE_NODES = 1e3;
|
|
function combineIntervalBandResults(bandResults, fallback, combiner) {
|
|
const validResults = bandResults.filter(
|
|
(result) => typeof result === "number" && Number.isFinite(result)
|
|
);
|
|
return validResults.length > 0 ? combiner(validResults) : fallback;
|
|
}
|
|
function processedDataIsAnimatable(processedData) {
|
|
return processedData.input.count <= MAX_ANIMATABLE_NODES;
|
|
}
|
|
function basicContinuousCheckDatumValidation(value) {
|
|
return value != null && (0, import_ag_charts_core80.isContinuous)(value);
|
|
}
|
|
function basicDiscreteCheckDatumValidation(value) {
|
|
return value != null;
|
|
}
|
|
function basicDiscreteCheckDatumValidationAllowNull(_value) {
|
|
return true;
|
|
}
|
|
function getValidationFn(scaleType, allowNullKey) {
|
|
switch (scaleType) {
|
|
case "number":
|
|
case "log":
|
|
case "time":
|
|
case "unit-time":
|
|
case "ordinal-time":
|
|
case "color":
|
|
return basicContinuousCheckDatumValidation;
|
|
default:
|
|
return allowNullKey ? basicDiscreteCheckDatumValidationAllowNull : basicDiscreteCheckDatumValidation;
|
|
}
|
|
}
|
|
function getValueType(scaleType) {
|
|
switch (scaleType) {
|
|
case "number":
|
|
case "log":
|
|
case "time":
|
|
case "color":
|
|
return "range";
|
|
default:
|
|
return "category";
|
|
}
|
|
}
|
|
function keyProperty(propName, scaleType, opts = {}) {
|
|
const allowNullKey = opts.allowNullKey ?? false;
|
|
const result = {
|
|
property: propName,
|
|
type: "key",
|
|
valueType: getValueType(scaleType),
|
|
validation: opts.validation ?? getValidationFn(scaleType, allowNullKey),
|
|
...opts
|
|
};
|
|
return result;
|
|
}
|
|
function valueProperty(propName, scaleType, opts = {}) {
|
|
const allowNullKey = opts.allowNullKey ?? false;
|
|
const result = {
|
|
property: propName,
|
|
type: "value",
|
|
valueType: getValueType(scaleType),
|
|
validation: opts.validation ?? getValidationFn(scaleType, allowNullKey),
|
|
...opts
|
|
};
|
|
return result;
|
|
}
|
|
function rowCountProperty(propName, opts = {}) {
|
|
const result = {
|
|
property: propName,
|
|
type: "value",
|
|
valueType: "range",
|
|
missingValue: 1,
|
|
processor: function rowCountResetFn() {
|
|
return function rowCountGroupResetFn() {
|
|
return 1;
|
|
};
|
|
},
|
|
...opts
|
|
};
|
|
return result;
|
|
}
|
|
var noopProcessor = function(v) {
|
|
return v;
|
|
};
|
|
function processorChain(...chain) {
|
|
const filteredChain = chain.filter((fn) => fn != null);
|
|
if (filteredChain.length === 0) {
|
|
return () => noopProcessor;
|
|
}
|
|
if (filteredChain.length === 1) {
|
|
return filteredChain[0];
|
|
}
|
|
return function processorChainFn() {
|
|
const processorInstances = filteredChain.map((fn) => fn());
|
|
return function processorChainResultFn(value, index) {
|
|
return processorInstances.reduce((r, p) => p(r, index), value);
|
|
};
|
|
};
|
|
}
|
|
function rangedValueProperty(propName, opts = {}) {
|
|
const { min = -Infinity, max = Infinity, processor, ...defOpts } = opts;
|
|
return {
|
|
type: "value",
|
|
property: propName,
|
|
valueType: "range",
|
|
validation: basicContinuousCheckDatumValidation,
|
|
processor: processorChain(processor, function clampFnBuilder() {
|
|
return function clampFn(datum) {
|
|
return (0, import_ag_charts_core80.isFiniteNumber)(datum) ? (0, import_ag_charts_core80.clamp)(min, datum, max) : datum;
|
|
};
|
|
}),
|
|
...defOpts
|
|
};
|
|
}
|
|
function accumulativeValueProperty(propName, scaleType, opts = {}) {
|
|
const { onlyPositive, processor, ...defOpts } = opts;
|
|
const result = {
|
|
...valueProperty(propName, scaleType, defOpts),
|
|
processor: processorChain(processor, accumulatedValue(onlyPositive))
|
|
};
|
|
return result;
|
|
}
|
|
function trailingAccumulatedValueProperty(propName, scaleType, opts = {}) {
|
|
const result = {
|
|
...valueProperty(propName, scaleType, opts),
|
|
processor: trailingAccumulatedValue()
|
|
};
|
|
return result;
|
|
}
|
|
function groupAccumulativeValueProperty(propName, mode, opts, scaleType) {
|
|
return [
|
|
valueProperty(propName, scaleType, opts),
|
|
accumulateGroup(opts.groupId, mode, opts.separateNegative),
|
|
...opts.rangeId == null ? [] : [range(opts.rangeId, opts.groupId)]
|
|
];
|
|
}
|
|
var SMALLEST_KEY_INTERVAL = {
|
|
type: "reducer",
|
|
property: "smallestKeyInterval",
|
|
initialValue: Infinity,
|
|
reducer() {
|
|
let prevX = Number.NaN;
|
|
return function smallestKeyIntervalReducerFn(smallestSoFar, keys) {
|
|
const key = keys[0];
|
|
const nextX = typeof key === "number" ? key : Number(key);
|
|
if (!Number.isFinite(nextX))
|
|
return smallestSoFar;
|
|
const prevX2 = prevX;
|
|
prevX = nextX;
|
|
if (!Number.isFinite(prevX))
|
|
return smallestSoFar;
|
|
const interval = Math.abs(nextX - prevX2);
|
|
const currentSmallest = smallestSoFar ?? Infinity;
|
|
if (interval > 0 && interval < currentSmallest) {
|
|
return interval;
|
|
}
|
|
return currentSmallest;
|
|
};
|
|
},
|
|
supportsBanding: true,
|
|
combineResults(bandResults) {
|
|
return combineIntervalBandResults(bandResults, Infinity, (values) => Math.min(...values));
|
|
},
|
|
needsOverlap: true
|
|
};
|
|
var LARGEST_KEY_INTERVAL = {
|
|
type: "reducer",
|
|
property: "largestKeyInterval",
|
|
initialValue: -Infinity,
|
|
reducer() {
|
|
let prevX = Number.NaN;
|
|
return function largestKeyIntervalReducerFn(largestSoFar, keys) {
|
|
const key = keys[0];
|
|
const nextX = typeof key === "number" ? key : Number(key);
|
|
if (!Number.isFinite(nextX))
|
|
return largestSoFar;
|
|
const prevX2 = prevX;
|
|
prevX = nextX;
|
|
if (!Number.isFinite(prevX))
|
|
return largestSoFar;
|
|
const interval = Math.abs(nextX - prevX2);
|
|
const currentLargest = largestSoFar ?? -Infinity;
|
|
if (interval > 0 && interval > currentLargest) {
|
|
return interval;
|
|
}
|
|
return currentLargest;
|
|
};
|
|
},
|
|
supportsBanding: true,
|
|
combineResults(bandResults) {
|
|
return combineIntervalBandResults(bandResults, -Infinity, (values) => Math.max(...values));
|
|
},
|
|
needsOverlap: true
|
|
};
|
|
var SORT_DOMAIN_GROUPS = {
|
|
type: "processor",
|
|
property: "sortedGroupDomain",
|
|
calculate: function sortedGroupDomainFn({ domain: { groups } }) {
|
|
return groups?.slice().sort((a, b) => {
|
|
for (let i = 0; i < a.length; i++) {
|
|
const result = a[i] - b[i];
|
|
if (result !== 0) {
|
|
return result;
|
|
}
|
|
}
|
|
return 0;
|
|
});
|
|
}
|
|
};
|
|
function normaliseFnBuilder({ normaliseTo }) {
|
|
const normalise = (val, extent6) => {
|
|
if (extent6 === 0)
|
|
return 0;
|
|
const result = (val ?? 0) * normaliseTo / extent6;
|
|
if (result >= 0) {
|
|
return Math.min(normaliseTo, result);
|
|
}
|
|
return Math.max(-normaliseTo, result);
|
|
};
|
|
return () => () => (columns, valueIndexes, dataGroup, groupIndex) => {
|
|
const extent6 = normaliseFindExtent(columns, valueIndexes, dataGroup, groupIndex);
|
|
for (const valueIdx of valueIndexes) {
|
|
const datumIndices = dataGroup.datumIndices[valueIdx];
|
|
if (datumIndices == null)
|
|
continue;
|
|
for (const relativeDatumIndex of datumIndices) {
|
|
const datumIndex = groupIndex + relativeDatumIndex;
|
|
const column = columns[valueIdx];
|
|
const value = column[datumIndex];
|
|
if (value == null) {
|
|
column[datumIndex] = void 0;
|
|
continue;
|
|
}
|
|
column[datumIndex] = normalise(value, extent6);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
function normaliseFindExtent(columns, valueIndexes, dataGroup, groupIndex) {
|
|
const valuesExtent = [0, 0];
|
|
for (const valueIdx of valueIndexes) {
|
|
const column = columns[valueIdx];
|
|
const datumIndices = dataGroup.datumIndices[valueIdx];
|
|
if (datumIndices == null)
|
|
continue;
|
|
for (const relativeDatumIndex of datumIndices) {
|
|
const datumIndex = groupIndex + relativeDatumIndex;
|
|
const value = column[datumIndex];
|
|
if (value == null)
|
|
continue;
|
|
const valueExtent = typeof value === "number" ? value : Math.max(...value.map((v) => v ?? 0));
|
|
const valIdx = valueExtent < 0 ? 0 : 1;
|
|
if (valIdx === 0) {
|
|
valuesExtent[valIdx] = Math.min(valuesExtent[valIdx], valueExtent);
|
|
} else {
|
|
valuesExtent[valIdx] = Math.max(valuesExtent[valIdx], valueExtent);
|
|
}
|
|
}
|
|
}
|
|
return Math.max(Math.abs(valuesExtent[0]), valuesExtent[1]);
|
|
}
|
|
function normaliseGroupTo(matchGroupIds, normaliseTo) {
|
|
return {
|
|
type: "group-value-processor",
|
|
matchGroupIds,
|
|
adjust: (0, import_ag_charts_core80.memo)({ normaliseTo }, normaliseFnBuilder)
|
|
};
|
|
}
|
|
function normalisePropertyFnBuilder({
|
|
normaliseTo,
|
|
zeroDomain,
|
|
rangeMin,
|
|
rangeMax
|
|
}) {
|
|
const normaliseSpan = normaliseTo[1] - normaliseTo[0];
|
|
const normalise = function normaliseFn(val, start, span) {
|
|
const result = normaliseTo[0] + (val - start) / span * normaliseSpan;
|
|
if (span === 0) {
|
|
return zeroDomain;
|
|
} else if (result >= normaliseTo[1]) {
|
|
return normaliseTo[1];
|
|
} else if (result < normaliseTo[0]) {
|
|
return normaliseTo[0];
|
|
}
|
|
return result;
|
|
};
|
|
return function normalisePropertyResetFn() {
|
|
return function normalisePropertyResultFn(pData, pIdx) {
|
|
let [start, end2] = pData.domain.values[pIdx];
|
|
if (rangeMin != null)
|
|
start = rangeMin;
|
|
if (rangeMax != null)
|
|
end2 = rangeMax;
|
|
const span = end2 - start;
|
|
pData.domain.values[pIdx] = [normaliseTo[0], normaliseTo[1]];
|
|
const column = pData.columns[pIdx];
|
|
for (let datumIndex = 0; datumIndex < column.length; datumIndex += 1) {
|
|
column[datumIndex] = normalise(column[datumIndex], start, span);
|
|
}
|
|
};
|
|
};
|
|
}
|
|
function normalisePropertyTo(property, normaliseTo, zeroDomain, rangeMin, rangeMax) {
|
|
return {
|
|
type: "property-value-processor",
|
|
property,
|
|
adjust: (0, import_ag_charts_core80.memo)({ normaliseTo, rangeMin, rangeMax, zeroDomain }, normalisePropertyFnBuilder)
|
|
};
|
|
}
|
|
var ANIMATION_VALIDATION_UNIQUE_KEYS = 1;
|
|
var ANIMATION_VALIDATION_ORDERED_KEYS = 2;
|
|
function animationValidationProcessValue(def, domainValues, column) {
|
|
let validation = ANIMATION_VALIDATION_UNIQUE_KEYS | ANIMATION_VALIDATION_ORDERED_KEYS;
|
|
if (def.valueType === "category") {
|
|
if (domainValues.length < column.length)
|
|
validation &= ~ANIMATION_VALIDATION_UNIQUE_KEYS;
|
|
return validation;
|
|
}
|
|
let lastValue = column[0]?.valueOf();
|
|
for (let d = 1; validation !== 0 && d < column.length; d++) {
|
|
const keyValue = column[d]?.valueOf();
|
|
if (!Number.isFinite(keyValue) || lastValue > keyValue)
|
|
validation &= ~ANIMATION_VALIDATION_ORDERED_KEYS;
|
|
if (Number.isFinite(keyValue) && lastValue === keyValue)
|
|
validation &= ~ANIMATION_VALIDATION_UNIQUE_KEYS;
|
|
lastValue = keyValue;
|
|
}
|
|
return validation;
|
|
}
|
|
function buildAnimationValidationFn(valueKeyIds) {
|
|
return function calculate(result, _previousValue) {
|
|
if (!processedDataIsAnimatable(result))
|
|
return;
|
|
const { keys: keysDefs, values: valuesDef } = result.defs;
|
|
const {
|
|
input,
|
|
domain: { values: domainValues },
|
|
columns
|
|
} = result;
|
|
let uniqueKeys = true;
|
|
let orderedKeys = true;
|
|
if (input.count !== 0) {
|
|
const keySortOrders = result[KEY_SORT_ORDERS];
|
|
for (let i = 0; (uniqueKeys || orderedKeys) && i < keysDefs.length; i++) {
|
|
const def = keysDefs[i];
|
|
const entry = keySortOrders.get(i);
|
|
if (def.valueType === "category") {
|
|
const domainSize = result.domain.keys[i]?.length ?? 0;
|
|
const dataSize = result.keys[i]?.values().next().value?.length ?? 0;
|
|
if (domainSize < dataSize)
|
|
uniqueKeys = false;
|
|
} else if (entry) {
|
|
if (entry.isUnique === false)
|
|
uniqueKeys = false;
|
|
if (entry.sortOrder !== 1)
|
|
orderedKeys = false;
|
|
}
|
|
}
|
|
if (valueKeyIds && valueKeyIds.length > 0) {
|
|
let validation = ANIMATION_VALIDATION_UNIQUE_KEYS | ANIMATION_VALIDATION_ORDERED_KEYS;
|
|
for (let i = 0; validation !== 0 && i < valuesDef.length; i++) {
|
|
const value = valuesDef[i];
|
|
if (!valueKeyIds.includes(value.id))
|
|
continue;
|
|
validation &= animationValidationProcessValue(value, domainValues[i], columns[i]);
|
|
}
|
|
if ((validation & ANIMATION_VALIDATION_UNIQUE_KEYS) === 0)
|
|
uniqueKeys = false;
|
|
if ((validation & ANIMATION_VALIDATION_ORDERED_KEYS) === 0)
|
|
orderedKeys = false;
|
|
}
|
|
}
|
|
return { uniqueKeys, orderedKeys };
|
|
};
|
|
}
|
|
function incrementalCalculateAnimationValidation() {
|
|
return {
|
|
uniqueKeys: true,
|
|
orderedKeys: false
|
|
};
|
|
}
|
|
function animationValidation(valueKeyIds) {
|
|
const calculate = (0, import_ag_charts_core80.memo)(valueKeyIds, buildAnimationValidationFn);
|
|
return {
|
|
type: "processor",
|
|
property: "animationValidation",
|
|
calculate,
|
|
incrementalCalculate: incrementalCalculateAnimationValidation
|
|
};
|
|
}
|
|
function buildGroupAccFn({ mode, separateNegative }) {
|
|
return function buildGroupAccFnResetFn() {
|
|
return function buildGroupAccFnGroupResetFn() {
|
|
return function buildGroupAccFnResultFn(columns, valueIndexes, dataGroup, groupIndex) {
|
|
const acc = [0, 0];
|
|
for (const valueIdx of valueIndexes) {
|
|
const datumIndices = dataGroup.datumIndices[valueIdx];
|
|
if (datumIndices == null)
|
|
continue;
|
|
const stackNegative = acc[0];
|
|
const stackPositive = acc[1];
|
|
const column = columns[valueIdx];
|
|
let didAccumulate = false;
|
|
for (const relativeDatumIndex of datumIndices) {
|
|
const datumIndex = groupIndex + relativeDatumIndex;
|
|
const currentVal = column[datumIndex];
|
|
if (!(0, import_ag_charts_core80.isFiniteNumber)(currentVal))
|
|
continue;
|
|
const useNegative = separateNegative && (0, import_ag_charts_core80.isNegative)(currentVal);
|
|
const accValue = useNegative ? stackNegative : stackPositive;
|
|
if (mode === "normal") {
|
|
column[datumIndex] = accValue + currentVal;
|
|
} else {
|
|
column[datumIndex] = accValue;
|
|
}
|
|
if (!didAccumulate) {
|
|
const accIndex = useNegative ? 0 : 1;
|
|
acc[accIndex] = accValue + currentVal;
|
|
didAccumulate = true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
};
|
|
};
|
|
}
|
|
function accumulateGroup(matchGroupId, mode, separateNegative = false) {
|
|
const adjust = (0, import_ag_charts_core80.memo)({ mode, separateNegative }, buildGroupAccFn);
|
|
return {
|
|
type: "group-value-processor",
|
|
matchGroupIds: [matchGroupId],
|
|
adjust,
|
|
supportsReprocessing: true
|
|
};
|
|
}
|
|
function valueIdentifier(value) {
|
|
return value.id ?? value.property;
|
|
}
|
|
function valueIndices(id, previousData, processedData) {
|
|
const properties = /* @__PURE__ */ new Map();
|
|
const previousValues = previousData.defs.values;
|
|
for (let previousIndex = 0; previousIndex < previousValues.length; previousIndex += 1) {
|
|
const previousValue = previousValues[previousIndex];
|
|
if (previousValue.scopes?.includes(id) === false)
|
|
continue;
|
|
const valueId = valueIdentifier(previousValue);
|
|
if (properties.has(valueId))
|
|
return;
|
|
properties.set(valueId, previousIndex);
|
|
}
|
|
const indices = [];
|
|
const nextValues = processedData.defs.values;
|
|
for (let nextIndex = 0; nextIndex < nextValues.length; nextIndex += 1) {
|
|
const nextValue = nextValues[nextIndex];
|
|
if (nextValue.scopes?.includes(id) === false)
|
|
continue;
|
|
const valueId = valueIdentifier(nextValue);
|
|
const previousIndex = properties.get(valueId);
|
|
if (previousIndex == null)
|
|
return;
|
|
properties.delete(valueId);
|
|
indices.push({ previousIndex, nextIndex });
|
|
}
|
|
if (properties.size !== 0)
|
|
return;
|
|
return indices;
|
|
}
|
|
function columnsEqual(previousColumns, nextColumns, indices, previousDatumIndex, nextDatumIndex) {
|
|
for (const { previousIndex, nextIndex } of indices) {
|
|
const previousColumn = previousColumns[previousIndex];
|
|
const nextColumn = nextColumns[nextIndex];
|
|
const previousValue = previousColumn[previousDatumIndex];
|
|
const nextValue = nextColumn[nextDatumIndex];
|
|
if (previousValue !== nextValue) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function diff(id, previousData, updateMovedData = true) {
|
|
return {
|
|
type: "processor",
|
|
property: "diff",
|
|
calculate(processedData, previousValue) {
|
|
if (!processedDataIsAnimatable(processedData))
|
|
return;
|
|
const moved = /* @__PURE__ */ new Map();
|
|
const added = /* @__PURE__ */ new Map();
|
|
const updated = /* @__PURE__ */ new Map();
|
|
const removed = /* @__PURE__ */ new Map();
|
|
const previousKeys = previousData.keys.map((keyMap) => keyMap.get(id));
|
|
const keys = processedData.keys.map((keyMap) => keyMap.get(id));
|
|
const previousColumns = previousData.columns;
|
|
const columns = processedData.columns;
|
|
const indices = valueIndices(id, previousData, processedData);
|
|
if (indices == null)
|
|
return previousValue;
|
|
const length = Math.max(previousData.input.count, processedData.input.count);
|
|
const allowNull = processedData.defs.keys.some((def) => def.allowNullKey === true);
|
|
for (let i = 0; i < length; i++) {
|
|
const hasPreviousDatum = i < previousData.input.count;
|
|
const hasDatum = i < processedData.input.count;
|
|
const prevKeys = hasPreviousDatum ? datumKeys(previousKeys, i, allowNull) : void 0;
|
|
const prevId = prevKeys == null ? "" : createDatumId(...prevKeys);
|
|
const dKeys = hasDatum ? datumKeys(keys, i, allowNull) : void 0;
|
|
const datumId = dKeys == null ? "" : createDatumId(...dKeys);
|
|
if (hasDatum && hasPreviousDatum && prevId === datumId) {
|
|
if (!columnsEqual(previousColumns, columns, indices, i, i)) {
|
|
updated.set(datumId, i);
|
|
}
|
|
continue;
|
|
}
|
|
const removedIndex = removed.get(datumId);
|
|
if (removedIndex != null) {
|
|
if (updateMovedData || !columnsEqual(previousColumns, columns, indices, removedIndex, i)) {
|
|
updated.set(datumId, i);
|
|
moved.set(datumId, i);
|
|
}
|
|
removed.delete(datumId);
|
|
} else if (hasDatum) {
|
|
added.set(datumId, i);
|
|
}
|
|
const addedIndex = added.get(prevId);
|
|
if (addedIndex != null) {
|
|
if (updateMovedData || !columnsEqual(previousColumns, columns, indices, addedIndex, i)) {
|
|
updated.set(prevId, i);
|
|
moved.set(prevId, i);
|
|
}
|
|
added.delete(prevId);
|
|
} else if (hasPreviousDatum) {
|
|
updated.delete(prevId);
|
|
removed.set(prevId, i);
|
|
}
|
|
}
|
|
const changed = added.size > 0 || updated.size > 0 || removed.size > 0;
|
|
const value = {
|
|
changed,
|
|
added: new Set(added.keys()),
|
|
updated: new Set(updated.keys()),
|
|
removed: new Set(removed.keys()),
|
|
moved: new Set(moved.keys())
|
|
};
|
|
return {
|
|
...previousValue,
|
|
[id]: value
|
|
};
|
|
}
|
|
};
|
|
}
|
|
function createDatumId(...keys) {
|
|
if (keys.length === 1) {
|
|
const key = (0, import_ag_charts_core80.transformIntegratedCategoryValue)(keys[0]);
|
|
if (key === null)
|
|
return NULL_KEY_STRING;
|
|
if (key === void 0)
|
|
return UNDEFINED_KEY_STRING;
|
|
const isPrimitive = typeof key === "boolean" || typeof key === "number" || typeof key === "string";
|
|
if (isPrimitive)
|
|
return key;
|
|
}
|
|
return keys.map((key) => {
|
|
const transformed = (0, import_ag_charts_core80.transformIntegratedCategoryValue)(key);
|
|
if (transformed === null)
|
|
return NULL_KEY_STRING;
|
|
if (transformed === void 0)
|
|
return UNDEFINED_KEY_STRING;
|
|
return transformed;
|
|
}).join("___");
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/animationBatch.ts
|
|
var import_ag_charts_core81 = require("ag-charts-core");
|
|
var AnimationBatch = class {
|
|
constructor(maxAnimationTime) {
|
|
this.maxAnimationTime = maxAnimationTime;
|
|
this.debug = import_ag_charts_core81.Debug.create(true, "animation");
|
|
this.controllers = /* @__PURE__ */ new Map();
|
|
this.stoppedCbs = /* @__PURE__ */ new Set();
|
|
this.currentPhase = 0;
|
|
this.phases = new Map(PHASE_ORDER.map((p) => [p, []]));
|
|
this.skipAnimations = false;
|
|
this.animationTimeConsumed = 0;
|
|
/** Guard against premature animation execution. */
|
|
this.isReady = false;
|
|
}
|
|
get size() {
|
|
return this.controllers.size;
|
|
}
|
|
get consumedTimeMs() {
|
|
return this.animationTimeConsumed;
|
|
}
|
|
isActive() {
|
|
return this.controllers.size > 0;
|
|
}
|
|
getActiveControllers() {
|
|
return this.phases.get(PHASE_ORDER[this.currentPhase]) ?? [];
|
|
}
|
|
checkOverlappingId(id) {
|
|
if (id != null && this.controllers.has(id)) {
|
|
this.controllers.get(id).stop();
|
|
this.debug(`Skipping animation batch due to update of existing animation: ${id}`);
|
|
this.skip();
|
|
}
|
|
}
|
|
addAnimation(animation) {
|
|
if (animation.isComplete)
|
|
return;
|
|
const animationPhaseIdx = PHASE_ORDER.indexOf(animation.phase);
|
|
if (animationPhaseIdx < this.currentPhase) {
|
|
this.debug(`Skipping animation due to being for an earlier phase`, animation.id);
|
|
animation.stop();
|
|
return;
|
|
}
|
|
this.controllers.set(animation.id, animation);
|
|
this.phases.get(animation.phase)?.push(animation);
|
|
}
|
|
removeAnimation(animation) {
|
|
this.controllers.delete(animation.id);
|
|
const phase = this.phases.get(animation.phase);
|
|
const index = phase?.indexOf(animation);
|
|
if (index != null && index >= 0) {
|
|
phase?.splice(index, 1);
|
|
}
|
|
}
|
|
progress(deltaTime) {
|
|
if (!this.isReady)
|
|
return;
|
|
let unusedTime = deltaTime === 0 ? 0.01 : deltaTime;
|
|
const refresh = () => {
|
|
const phase2 = PHASE_ORDER[this.currentPhase];
|
|
return {
|
|
phaseControllers: [...this.getActiveControllers()],
|
|
phase: phase2,
|
|
phaseMeta: PHASE_METADATA[phase2]
|
|
};
|
|
};
|
|
let { phase, phaseControllers, phaseMeta } = refresh();
|
|
const arePhasesComplete = () => PHASE_ORDER[this.currentPhase] == null;
|
|
const progressPhase = () => {
|
|
({ phase, phaseControllers, phaseMeta } = refresh());
|
|
while (!arePhasesComplete() && phaseControllers.length === 0) {
|
|
this.currentPhase++;
|
|
({ phase, phaseControllers, phaseMeta } = refresh());
|
|
this.debug(`AnimationBatch - phase changing to ${phase}`, { unusedTime }, phaseControllers);
|
|
}
|
|
};
|
|
const total = this.controllers.size;
|
|
this.debug(`AnimationBatch - ${deltaTime}ms; phase ${phase} with ${phaseControllers?.length} of ${total}`);
|
|
do {
|
|
const phaseDeltaTime = unusedTime;
|
|
const skipPhase = phaseMeta.skipIfNoEarlierAnimations && this.animationTimeConsumed === 0;
|
|
let completeCount = 0;
|
|
for (const controller of phaseControllers) {
|
|
if (skipPhase) {
|
|
controller.stop();
|
|
} else {
|
|
unusedTime = Math.min(controller.update(phaseDeltaTime), unusedTime);
|
|
}
|
|
if (controller.isComplete) {
|
|
completeCount++;
|
|
this.removeAnimation(controller);
|
|
}
|
|
}
|
|
this.animationTimeConsumed += phaseDeltaTime - unusedTime;
|
|
this.debug(
|
|
`AnimationBatch - updated ${phaseControllers.length} controllers; ${completeCount} completed`,
|
|
phaseControllers
|
|
);
|
|
this.debug(`AnimationBatch - animationTimeConsumed: ${this.animationTimeConsumed}`);
|
|
progressPhase();
|
|
} while (unusedTime > 0 && !arePhasesComplete());
|
|
if (this.animationTimeConsumed > this.maxAnimationTime) {
|
|
this.debug(`Animation batch exceeded max animation time, skipping`, [...this.controllers]);
|
|
this.stop();
|
|
}
|
|
}
|
|
ready() {
|
|
if (this.isReady)
|
|
return;
|
|
this.isReady = true;
|
|
this.debug(`AnimationBatch - ready; skipped: ${this.skipAnimations}`, [...this.controllers]);
|
|
let skipAll = true;
|
|
for (const [, controller] of this.controllers) {
|
|
if (controller.duration > 0 && PHASE_METADATA[controller.phase].skipIfNoEarlierAnimations !== true) {
|
|
skipAll = false;
|
|
break;
|
|
}
|
|
}
|
|
if (!skipAll) {
|
|
for (const [, controller] of this.controllers) {
|
|
if (controller.autoplay) {
|
|
controller.play(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
skip(skip = true) {
|
|
if (this.skipAnimations === false && skip === true) {
|
|
for (const controller of this.controllers.values()) {
|
|
controller.stop();
|
|
}
|
|
this.controllers.clear();
|
|
}
|
|
this.skipAnimations = skip;
|
|
}
|
|
play() {
|
|
for (const controller of this.controllers.values()) {
|
|
controller.play();
|
|
}
|
|
}
|
|
stop() {
|
|
for (const controller of this.controllers.values()) {
|
|
try {
|
|
controller.stop();
|
|
this.removeAnimation(controller);
|
|
} catch (error) {
|
|
import_ag_charts_core81.Logger.error("Error during animation stop", error);
|
|
}
|
|
}
|
|
this.dispatchStopped();
|
|
}
|
|
stopByAnimationId(id) {
|
|
if (id != null && this.controllers.has(id)) {
|
|
const controller = this.controllers.get(id);
|
|
if (controller) {
|
|
controller.stop();
|
|
this.removeAnimation(controller);
|
|
}
|
|
}
|
|
}
|
|
stopByAnimationGroupId(id) {
|
|
for (const controller of this.controllers.values()) {
|
|
if (controller.groupId === id) {
|
|
this.stopByAnimationId(controller.id);
|
|
}
|
|
}
|
|
}
|
|
dispatchStopped() {
|
|
for (const cb of this.stoppedCbs) {
|
|
cb();
|
|
}
|
|
this.stoppedCbs.clear();
|
|
}
|
|
isSkipped() {
|
|
return this.skipAnimations;
|
|
}
|
|
getRemainingTime(restrictPhase) {
|
|
if (!this.isActive())
|
|
return 0;
|
|
let total = 0;
|
|
for (const [phase, controllers] of this.phases) {
|
|
if (controllers.length === 0)
|
|
continue;
|
|
if (restrictPhase != null && restrictPhase !== phase)
|
|
continue;
|
|
total += Math.max(...controllers.map((c) => c.isComplete ? 0 : c.delay + c.duration - (c.elapsed ?? 0)));
|
|
}
|
|
return total;
|
|
}
|
|
destroy() {
|
|
this.stop();
|
|
this.controllers.clear();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/animationManager.ts
|
|
function validAnimationDuration(testee) {
|
|
if (testee == null)
|
|
return true;
|
|
return !Number.isNaN(testee) && testee >= 0 && testee <= 2;
|
|
}
|
|
var AnimationManager = class {
|
|
constructor(interactionManager, chartUpdateMutex) {
|
|
this.interactionManager = interactionManager;
|
|
this.chartUpdateMutex = chartUpdateMutex;
|
|
this.defaultDuration = 1e3;
|
|
this.maxAnimatableItems = MAX_ANIMATABLE_NODES;
|
|
this.batch = new AnimationBatch(this.defaultDuration * 1.5);
|
|
this.debug = import_ag_charts_core82.Debug.create(true, "animation");
|
|
this.events = new import_ag_charts_core82.EventEmitter();
|
|
this.rafAvailable = typeof requestAnimationFrame !== "undefined";
|
|
this.isPlaying = true;
|
|
this.requestId = null;
|
|
this.skipAnimations = true;
|
|
this.currentAnonymousAnimationId = 0;
|
|
this.cumulativeAnimationTime = 0;
|
|
}
|
|
addListener(eventName, listener) {
|
|
return this.events.on(eventName, listener);
|
|
}
|
|
/**
|
|
* Create an animation to tween a value between the `from` and `to` properties. If an animation already exists
|
|
* with the same `id`, immediately stop it.
|
|
*/
|
|
animate(opts) {
|
|
const batch = this.batch;
|
|
try {
|
|
batch.checkOverlappingId(opts.id);
|
|
} catch (error) {
|
|
this.failsafeOnError(error);
|
|
return;
|
|
}
|
|
let { id } = opts;
|
|
if (id == null) {
|
|
id = `__${this.currentAnonymousAnimationId}`;
|
|
this.currentAnonymousAnimationId += 1;
|
|
}
|
|
const skip = this.isSkipped() || opts.phase === "none";
|
|
if (skip) {
|
|
this.debug("AnimationManager - skipping animation");
|
|
}
|
|
const { delay, duration } = opts;
|
|
if (!validAnimationDuration(delay)) {
|
|
throw new Error(`Animation delay of ${delay} is unsupported (${id})`);
|
|
}
|
|
if (!validAnimationDuration(duration)) {
|
|
throw new Error(`Animation duration of ${duration} is unsupported (${id})`);
|
|
}
|
|
const animation = new Animation({
|
|
...opts,
|
|
id,
|
|
skip,
|
|
autoplay: this.isPlaying ? opts.autoplay : false,
|
|
phase: opts.phase,
|
|
defaultDuration: this.defaultDuration
|
|
});
|
|
if (this.forceTimeJump(animation, this.defaultDuration)) {
|
|
return;
|
|
}
|
|
this.batch.addAnimation(animation);
|
|
return animation;
|
|
}
|
|
play() {
|
|
if (this.isPlaying) {
|
|
return;
|
|
}
|
|
this.isPlaying = true;
|
|
this.debug("AnimationManager.play()");
|
|
try {
|
|
this.batch.play();
|
|
} catch (error) {
|
|
this.failsafeOnError(error);
|
|
}
|
|
this.requestAnimation();
|
|
}
|
|
stop() {
|
|
this.isPlaying = false;
|
|
this.cancelAnimation();
|
|
this.debug("AnimationManager.stop()");
|
|
this.batch.stop();
|
|
}
|
|
stopByAnimationId(id) {
|
|
try {
|
|
this.batch.stopByAnimationId(id);
|
|
} catch (error) {
|
|
this.failsafeOnError(error);
|
|
}
|
|
}
|
|
stopByAnimationGroupId(id) {
|
|
try {
|
|
this.batch.stopByAnimationGroupId(id);
|
|
} catch (error) {
|
|
this.failsafeOnError(error);
|
|
}
|
|
}
|
|
reset() {
|
|
if (this.isPlaying) {
|
|
this.stop();
|
|
this.play();
|
|
} else {
|
|
this.stop();
|
|
}
|
|
}
|
|
skip(skip = true) {
|
|
this.skipAnimations = skip;
|
|
}
|
|
isSkipped() {
|
|
return !this.rafAvailable || this.skipAnimations || this.batch.isSkipped();
|
|
}
|
|
isActive() {
|
|
return this.isPlaying && this.batch.isActive();
|
|
}
|
|
getRemainingTime(phase) {
|
|
return this.batch.getRemainingTime(phase);
|
|
}
|
|
getCumulativeAnimationTime() {
|
|
return this.cumulativeAnimationTime;
|
|
}
|
|
skipCurrentBatch() {
|
|
if (this.debug.check()) {
|
|
this.debug(`AnimationManager - skipCurrentBatch()`, {
|
|
stack: new Error("Stack trace for animation skip tracking").stack
|
|
});
|
|
}
|
|
this.batch.skip();
|
|
}
|
|
/** Mocking point for tests to guarantee that animation updates happen. */
|
|
isSkippingFrames() {
|
|
return true;
|
|
}
|
|
/** Mocking point for tests to capture requestAnimationFrame callbacks. */
|
|
scheduleAnimationFrame(cb) {
|
|
this.requestId = (0, import_ag_charts_core82.getWindow)().requestAnimationFrame((t) => {
|
|
cb(t).catch((e) => import_ag_charts_core82.Logger.error(e));
|
|
});
|
|
}
|
|
/** Mocking point for tests to skip animations to a specific point in time. */
|
|
forceTimeJump(_animation, _defaultDuration) {
|
|
return false;
|
|
}
|
|
requestAnimation() {
|
|
if (!this.rafAvailable)
|
|
return;
|
|
if (!this.batch.isActive() || this.requestId !== null)
|
|
return;
|
|
let prevTime;
|
|
const onAnimationFrame = async (time3) => {
|
|
await this.debug.group("AnimationManager.onAnimationFrame()", async () => {
|
|
const executeAnimationFrame = () => {
|
|
const deltaTime = time3 - (prevTime ?? time3);
|
|
prevTime = time3;
|
|
this.debug("AnimationManager", {
|
|
controllersCount: this.batch.size,
|
|
deltaTime
|
|
});
|
|
this.interactionManager.pushState(4 /* Animation */);
|
|
try {
|
|
this.batch.progress(deltaTime);
|
|
this.cumulativeAnimationTime += deltaTime;
|
|
} catch (error) {
|
|
this.failsafeOnError(error);
|
|
}
|
|
this.events.emit("animation-frame", {
|
|
type: "animation-frame",
|
|
deltaMs: deltaTime
|
|
});
|
|
};
|
|
if (this.isSkippingFrames()) {
|
|
await this.chartUpdateMutex.acquireImmediately(executeAnimationFrame);
|
|
} else {
|
|
await this.chartUpdateMutex.acquire(executeAnimationFrame);
|
|
}
|
|
if (this.batch.isActive()) {
|
|
this.scheduleAnimationFrame(onAnimationFrame);
|
|
} else {
|
|
this.batch.stop();
|
|
this.events.emit("animation-stop", {
|
|
type: "animation-stop",
|
|
deltaMs: this.batch.consumedTimeMs
|
|
});
|
|
}
|
|
});
|
|
};
|
|
this.events.emit("animation-start", {
|
|
type: "animation-start",
|
|
deltaMs: 0
|
|
});
|
|
this.scheduleAnimationFrame(onAnimationFrame);
|
|
}
|
|
cancelAnimation() {
|
|
if (this.requestId === null)
|
|
return;
|
|
cancelAnimationFrame(this.requestId);
|
|
this.events.emit("animation-stop", {
|
|
type: "animation-stop",
|
|
deltaMs: this.batch.consumedTimeMs
|
|
});
|
|
this.requestId = null;
|
|
this.startBatch();
|
|
}
|
|
failsafeOnError(error, cancelAnimation = true) {
|
|
import_ag_charts_core82.Logger.error("Error during animation, skipping animations", error);
|
|
if (cancelAnimation) {
|
|
this.cancelAnimation();
|
|
}
|
|
}
|
|
startBatch(skipAnimations) {
|
|
this.debug(`AnimationManager - startBatch() with skipAnimations=${skipAnimations}.`);
|
|
this.reset();
|
|
this.batch.destroy();
|
|
this.batch = new AnimationBatch(this.defaultDuration * 1.5);
|
|
if (skipAnimations === true) {
|
|
this.batch.skip();
|
|
}
|
|
}
|
|
endBatch() {
|
|
if (this.batch.isActive()) {
|
|
this.batch.ready();
|
|
this.requestAnimation();
|
|
} else {
|
|
this.interactionManager.popState(4 /* Animation */);
|
|
if (this.batch.isSkipped()) {
|
|
this.batch.skip(false);
|
|
}
|
|
}
|
|
}
|
|
onBatchStop(cb) {
|
|
this.batch.stoppedCbs.add(cb);
|
|
}
|
|
destroy() {
|
|
this.stop();
|
|
this.events.clear();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/contextMenuTypes.ts
|
|
var ContextMenuBuiltinItems = class {
|
|
constructor() {
|
|
this.download = {
|
|
type: "action",
|
|
showOn: "always",
|
|
label: "contextMenuDownload",
|
|
enabled: true,
|
|
action: void 0,
|
|
items: void 0
|
|
};
|
|
this["zoom-to-cursor"] = {
|
|
type: "action",
|
|
showOn: "series-area",
|
|
label: "contextMenuZoomToCursor",
|
|
enabled: true,
|
|
action: void 0,
|
|
items: void 0
|
|
};
|
|
this["pan-to-cursor"] = {
|
|
type: "action",
|
|
showOn: "series-area",
|
|
label: "contextMenuPanToCursor",
|
|
enabled: true,
|
|
action: void 0,
|
|
items: void 0
|
|
};
|
|
this["reset-zoom"] = {
|
|
type: "action",
|
|
showOn: "series-area",
|
|
label: "contextMenuResetZoom",
|
|
enabled: true,
|
|
action: void 0,
|
|
items: void 0
|
|
};
|
|
this["toggle-series-visibility"] = {
|
|
type: "action",
|
|
showOn: "legend-item",
|
|
label: "contextMenuToggleSeriesVisibility",
|
|
enabled: true,
|
|
action: void 0,
|
|
items: void 0
|
|
};
|
|
this["toggle-other-series"] = {
|
|
type: "action",
|
|
showOn: "legend-item",
|
|
label: "contextMenuToggleOtherSeries",
|
|
enabled: true,
|
|
action: void 0,
|
|
items: void 0
|
|
};
|
|
this["separator"] = {
|
|
type: "separator",
|
|
showOn: "always",
|
|
label: "separator",
|
|
enabled: true,
|
|
action: void 0,
|
|
items: void 0
|
|
};
|
|
}
|
|
};
|
|
var ContextMenuBuiltinItemLists = class {
|
|
constructor() {
|
|
this.defaults = [
|
|
"download",
|
|
"zoom-to-cursor",
|
|
"pan-to-cursor",
|
|
"reset-zoom",
|
|
"toggle-series-visibility",
|
|
"toggle-other-series"
|
|
];
|
|
}
|
|
};
|
|
var ContextMenuBuiltins = class {
|
|
constructor() {
|
|
this.items = new ContextMenuBuiltinItems();
|
|
this.lists = new ContextMenuBuiltinItemLists();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/contextMenuRegistry.ts
|
|
var ContextMenuRegistry = class {
|
|
constructor(eventsHub) {
|
|
this.eventsHub = eventsHub;
|
|
this.builtins = new ContextMenuBuiltins();
|
|
this.hiddenActions = /* @__PURE__ */ new Set();
|
|
this.toggle("zoom-to-cursor", "hide");
|
|
this.toggle("pan-to-cursor", "hide");
|
|
this.toggle("reset-zoom", "hide");
|
|
}
|
|
static check(showOn, event) {
|
|
return event.showOn == showOn;
|
|
}
|
|
static checkCallback(desiredShowOn, showOn, _callback) {
|
|
return desiredShowOn === showOn;
|
|
}
|
|
dispatchContext(showOn, pointerEvent, context, position) {
|
|
const { widgetEvent } = pointerEvent;
|
|
if (widgetEvent.sourceEvent.defaultPrevented) {
|
|
return;
|
|
}
|
|
const x = position?.x ?? pointerEvent.canvasX;
|
|
const y = position?.y ?? pointerEvent.canvasY;
|
|
const event = { showOn, x, y, context, widgetEvent };
|
|
this.eventsHub.emit("context-menu:setup", event);
|
|
this.eventsHub.emit("context-menu:complete", event);
|
|
}
|
|
isVisible(id) {
|
|
return !this.hiddenActions.has(id);
|
|
}
|
|
toggle(id, action) {
|
|
action ?? (action = this.isVisible(id) ? "hide" : "show");
|
|
switch (action) {
|
|
case "show":
|
|
this.hiddenActions.delete(id);
|
|
break;
|
|
case "hide":
|
|
this.hiddenActions.add(id);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/highlightManager.ts
|
|
var import_ag_charts_core83 = require("ag-charts-core");
|
|
var _HighlightManager = class _HighlightManager {
|
|
constructor(eventsHub) {
|
|
this.eventsHub = eventsHub;
|
|
this.highlightStates = new StateTracker();
|
|
// Track pending unhighlights per caller
|
|
this.pendingUnhighlights = /* @__PURE__ */ new Map();
|
|
// Configurable delay (hardcoded for POC, will be user-configurable later)
|
|
this.unhighlightDelay = 100;
|
|
}
|
|
updateHighlight(callerId, highlightedDatum, delayed = false) {
|
|
if (highlightedDatum?.series?.isHighlightEnabled() === false) {
|
|
highlightedDatum = void 0;
|
|
}
|
|
const previousHighlight = this.getActiveHighlight();
|
|
if (highlightedDatum == null && delayed && this.unhighlightDelay > 0) {
|
|
if (!this.pendingUnhighlights.has(callerId)) {
|
|
const scheduler = debouncedCallback(() => {
|
|
this.applyPendingUnhighlight(callerId);
|
|
});
|
|
this.pendingUnhighlights.set(callerId, { scheduler });
|
|
scheduler.schedule(this.unhighlightDelay);
|
|
}
|
|
return;
|
|
}
|
|
const pending = this.pendingUnhighlights.get(callerId);
|
|
if (pending) {
|
|
pending.scheduler.cancel();
|
|
this.pendingUnhighlights.delete(callerId);
|
|
}
|
|
if (highlightedDatum) {
|
|
this.highlightStates.set(callerId, highlightedDatum);
|
|
} else {
|
|
this.highlightStates.delete(callerId);
|
|
}
|
|
this.maybeEmitChange(callerId, previousHighlight);
|
|
}
|
|
maybeEmitChange(callerId, previousHighlight) {
|
|
const currentHighlight = this.getActiveHighlight();
|
|
if (!this.isEqual(currentHighlight, previousHighlight)) {
|
|
this.eventsHub.emit(_HighlightManager.HIGHLIGHT_CHANGE_EVENT, {
|
|
callerId,
|
|
currentHighlight,
|
|
previousHighlight
|
|
});
|
|
}
|
|
}
|
|
applyPendingUnhighlight(callerId) {
|
|
if (!this.pendingUnhighlights.has(callerId)) {
|
|
return;
|
|
}
|
|
this.pendingUnhighlights.delete(callerId);
|
|
const previousHighlight = this.getActiveHighlight();
|
|
this.highlightStates.delete(callerId);
|
|
const currentHighlight = this.getActiveHighlight();
|
|
if (!this.isEqual(currentHighlight, previousHighlight)) {
|
|
this.eventsHub.emit(_HighlightManager.HIGHLIGHT_CHANGE_EVENT, {
|
|
callerId,
|
|
currentHighlight,
|
|
previousHighlight
|
|
});
|
|
}
|
|
}
|
|
getActiveHighlight() {
|
|
return this.highlightStates.stateValue();
|
|
}
|
|
destroy() {
|
|
for (const { scheduler } of this.pendingUnhighlights.values()) {
|
|
scheduler.cancel();
|
|
}
|
|
this.pendingUnhighlights.clear();
|
|
}
|
|
isEqual(a, b) {
|
|
return a === b || a != null && b != null && a.series === b.series && this.idsMatch(a, b) && a.datum === b.datum;
|
|
}
|
|
idsMatch(a, b) {
|
|
return a.itemId != null && b.itemId != null && a.itemId === b.itemId || a.datumIndex != null && b.datumIndex != null && (0, import_ag_charts_core83.objectsEqual)(a.datumIndex, b.datumIndex);
|
|
}
|
|
};
|
|
// milliseconds
|
|
_HighlightManager.HIGHLIGHT_CHANGE_EVENT = "highlight:change";
|
|
var HighlightManager = _HighlightManager;
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/tooltipManager.ts
|
|
var import_ag_charts_core86 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/util.ts
|
|
var import_ag_charts_core85 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/seriesProperties.ts
|
|
var import_ag_charts_core84 = require("ag-charts-core");
|
|
var HighlightState = /* @__PURE__ */ ((HighlightState3) => {
|
|
HighlightState3[HighlightState3["None"] = 0] = "None";
|
|
HighlightState3[HighlightState3["Item"] = 1] = "Item";
|
|
HighlightState3[HighlightState3["Series"] = 2] = "Series";
|
|
HighlightState3[HighlightState3["OtherSeries"] = 3] = "OtherSeries";
|
|
HighlightState3[HighlightState3["OtherItem"] = 4] = "OtherItem";
|
|
return HighlightState3;
|
|
})(HighlightState || {});
|
|
var highlightStates = [
|
|
0 /* None */,
|
|
1 /* Item */,
|
|
2 /* Series */,
|
|
3 /* OtherSeries */,
|
|
4 /* OtherItem */
|
|
];
|
|
function getHighlightStyleOptionKeys(highlightState) {
|
|
switch (highlightState) {
|
|
case 1 /* Item */:
|
|
return ["highlightedItem", "highlightedSeries"];
|
|
case 4 /* OtherItem */:
|
|
return ["unhighlightedItem", "highlightedSeries"];
|
|
case 2 /* Series */:
|
|
return ["highlightedSeries"];
|
|
case 3 /* OtherSeries */:
|
|
return ["unhighlightedSeries"];
|
|
case 0 /* None */:
|
|
return [];
|
|
}
|
|
}
|
|
function toHighlightString(state) {
|
|
const unreachable = (a) => a;
|
|
switch (state) {
|
|
case 1 /* Item */:
|
|
return "highlighted-item";
|
|
case 4 /* OtherItem */:
|
|
return "unhighlighted-item";
|
|
case 2 /* Series */:
|
|
return "highlighted-series";
|
|
case 3 /* OtherSeries */:
|
|
return "unhighlighted-series";
|
|
case 0 /* None */:
|
|
return "none";
|
|
default:
|
|
return unreachable(state);
|
|
}
|
|
}
|
|
var SeriesItemHighlightStyle = class extends import_ag_charts_core84.BaseProperties {
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesItemHighlightStyle.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesItemHighlightStyle.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesItemHighlightStyle.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesItemHighlightStyle.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesItemHighlightStyle.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesItemHighlightStyle.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesItemHighlightStyle.prototype, "lineDashOffset", 2);
|
|
var HighlightProperties = class extends import_ag_charts_core84.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.range = "tooltip";
|
|
this.bringToFront = true;
|
|
this.highlightedItem = {};
|
|
this.unhighlightedItem = {};
|
|
this.highlightedSeries = {};
|
|
this.unhighlightedSeries = {};
|
|
}
|
|
getStyle(highlightState) {
|
|
const keys = getHighlightStyleOptionKeys(highlightState);
|
|
if (keys.length === 0)
|
|
return {};
|
|
return (0, import_ag_charts_core84.mergeDefaults)(...keys.map((key) => this[key]));
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], HighlightProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], HighlightProperties.prototype, "range", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], HighlightProperties.prototype, "bringToFront", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], HighlightProperties.prototype, "highlightedItem", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], HighlightProperties.prototype, "unhighlightedItem", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], HighlightProperties.prototype, "highlightedSeries", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], HighlightProperties.prototype, "unhighlightedSeries", 2);
|
|
var SegmentOptions = class extends import_ag_charts_core84.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "#c16068";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "#874349";
|
|
this.strokeWidth = 2;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SegmentOptions.prototype, "start", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SegmentOptions.prototype, "stop", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SegmentOptions.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SegmentOptions.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SegmentOptions.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SegmentOptions.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SegmentOptions.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SegmentOptions.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SegmentOptions.prototype, "lineDashOffset", 2);
|
|
var Segmentation = class {
|
|
constructor() {
|
|
this.key = "x";
|
|
this.segments = new import_ag_charts_core84.PropertiesArray(SegmentOptions);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], Segmentation.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], Segmentation.prototype, "key", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], Segmentation.prototype, "segments", 2);
|
|
var FillGradientDefaults = class extends import_ag_charts_core84.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "gradient";
|
|
this.colorStops = [];
|
|
this.bounds = "item";
|
|
this.gradient = "linear";
|
|
this.rotation = 0;
|
|
this.reverse = false;
|
|
this.colorSpace = "rgb";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillGradientDefaults.prototype, "type", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillGradientDefaults.prototype, "colorStops", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillGradientDefaults.prototype, "bounds", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillGradientDefaults.prototype, "gradient", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillGradientDefaults.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillGradientDefaults.prototype, "reverse", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillGradientDefaults.prototype, "colorSpace", 2);
|
|
var FillPatternDefaults = class extends import_ag_charts_core84.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "pattern";
|
|
this.colorStops = [];
|
|
this.bounds = "item";
|
|
this.gradient = "linear";
|
|
this.rotation = 0;
|
|
this.scale = 1;
|
|
this.reverse = false;
|
|
this.pattern = "forward-slanted-lines";
|
|
this.width = 26;
|
|
this.height = 26;
|
|
this.padding = 6;
|
|
this.fill = "black";
|
|
this.fillOpacity = 1;
|
|
this.backgroundFill = "white";
|
|
this.backgroundFillOpacity = 1;
|
|
this.stroke = "black";
|
|
this.strokeOpacity = 1;
|
|
this.strokeWidth = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "type", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "colorStops", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "bounds", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "gradient", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "scale", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "reverse", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "path", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "pattern", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "width", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "height", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "padding", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "backgroundFill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "backgroundFillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillPatternDefaults.prototype, "strokeWidth", 2);
|
|
var FillImageDefaults = class extends import_ag_charts_core84.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "image";
|
|
this.url = "";
|
|
this.rotation = 0;
|
|
this.scale = 1;
|
|
this.backgroundFill = "black";
|
|
this.backgroundFillOpacity = 1;
|
|
this.repeat = "no-repeat";
|
|
this.fit = "contain";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillImageDefaults.prototype, "type", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillImageDefaults.prototype, "url", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillImageDefaults.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillImageDefaults.prototype, "scale", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillImageDefaults.prototype, "backgroundFill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillImageDefaults.prototype, "backgroundFillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillImageDefaults.prototype, "repeat", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], FillImageDefaults.prototype, "fit", 2);
|
|
var SeriesProperties = class extends import_ag_charts_core84.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.visible = true;
|
|
this.focusPriority = Infinity;
|
|
this.showInLegend = true;
|
|
this.cursor = "default";
|
|
this.nodeClickRange = "exact";
|
|
this.highlight = new HighlightProperties();
|
|
}
|
|
handleUnknownProperties(unknownKeys, properties) {
|
|
if ("context" in properties) {
|
|
this.context = properties.context;
|
|
unknownKeys.delete("context");
|
|
}
|
|
if ("allowNullKeys" in properties) {
|
|
this.allowNullKeys = properties.allowNullKeys;
|
|
unknownKeys.delete("allowNullKeys");
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesProperties.prototype, "id", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesProperties.prototype, "visible", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesProperties.prototype, "focusPriority", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesProperties.prototype, "showInLegend", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesProperties.prototype, "cursor", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesProperties.prototype, "nodeClickRange", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core84.Property
|
|
], SeriesProperties.prototype, "highlight", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/util.ts
|
|
function datumBoundaryPoints(datum, domain) {
|
|
if (domain.length === 0) {
|
|
return [false, false];
|
|
}
|
|
const d0 = domain[0];
|
|
const d1 = domain.at(-1);
|
|
if (typeof d0 === "string" || d0 === null || d0 === void 0) {
|
|
return [datum === d0, datum === d1];
|
|
}
|
|
if (datum == null) {
|
|
return [false, false];
|
|
}
|
|
const datumValue = datum.valueOf();
|
|
if (d0 == null || d1 == null) {
|
|
return [false, false];
|
|
}
|
|
let min = d0.valueOf();
|
|
let max = d1.valueOf();
|
|
if (min > max) {
|
|
[min, max] = [max, min];
|
|
}
|
|
return [datumValue === min, datumValue === max];
|
|
}
|
|
function datumStylerProperties(xValue, yValue, xKey, yKey, xDomain, yDomain) {
|
|
const [min, max] = datumBoundaryPoints(yValue, yDomain);
|
|
const [first8, last] = datumBoundaryPoints(xValue, xDomain);
|
|
return {
|
|
xKey,
|
|
yKey,
|
|
xValue,
|
|
yValue,
|
|
first: first8,
|
|
last,
|
|
min,
|
|
max
|
|
};
|
|
}
|
|
function visibleRangeIndices(sortOrder, length, [range0, range1], xRange) {
|
|
let xMinIndex = (0, import_ag_charts_core85.findMinIndex)(0, length - 1, (i) => {
|
|
const index = sortOrder === 1 ? i : length - i;
|
|
const x1 = xRange(index)?.[1] ?? Number.NaN;
|
|
return !Number.isFinite(x1) || x1 >= range0;
|
|
}) ?? 0;
|
|
let xMaxIndex = (0, import_ag_charts_core85.findMaxIndex)(0, length - 1, (i) => {
|
|
const index = sortOrder === 1 ? i : length - i;
|
|
const x0 = xRange(index)?.[0] ?? Number.NaN;
|
|
return !Number.isFinite(x0) || x0 <= range1;
|
|
}) ?? length - 1;
|
|
if (sortOrder === -1) {
|
|
[xMinIndex, xMaxIndex] = [length - xMaxIndex, length - xMinIndex];
|
|
}
|
|
xMinIndex = Math.max(xMinIndex, 0);
|
|
xMaxIndex = Math.min(xMaxIndex + 1, length);
|
|
return [xMinIndex, xMaxIndex];
|
|
}
|
|
function getDatumRefPoint(series, datum, movedBounds) {
|
|
if (movedBounds) {
|
|
const { x, y, width, height } = movedBounds;
|
|
return { canvasX: x + width / 2, canvasY: y + height / 2 };
|
|
}
|
|
const refPoint = datum.yBar?.upperPoint ?? datum.midPoint ?? series.datumMidPoint?.(datum);
|
|
if (refPoint) {
|
|
const { x, y } = Transformable.toCanvasPoint(series.contentGroup, refPoint.x, refPoint.y);
|
|
return { canvasX: Math.round(x), canvasY: Math.round(y) };
|
|
}
|
|
}
|
|
function countExpandingSearch(min, max, start, countUntil, iteratee) {
|
|
let i = -1;
|
|
let count = 0;
|
|
let shift = 0;
|
|
let reachedAnEnd = false;
|
|
while (count < countUntil && i <= max - min) {
|
|
i += 1;
|
|
const index = start + shift;
|
|
if (!reachedAnEnd)
|
|
shift *= -1;
|
|
if (shift >= 0)
|
|
shift += 1;
|
|
if (reachedAnEnd && shift < 0)
|
|
shift -= 1;
|
|
if (index < min || index > max) {
|
|
reachedAnEnd = true;
|
|
continue;
|
|
}
|
|
if (iteratee(index))
|
|
count += 1;
|
|
}
|
|
return count;
|
|
}
|
|
function getItemStyles(getItemStyle) {
|
|
const result = {};
|
|
for (const state of highlightStates) {
|
|
result[state] = getItemStyle(void 0, false, state);
|
|
}
|
|
return result;
|
|
}
|
|
function getItemStylesPerItemId(getItemStyle, ...itemIds) {
|
|
const result = {};
|
|
for (const itemId of itemIds ?? ["default"]) {
|
|
for (const state of highlightStates) {
|
|
const states = result[itemId] ?? (result[itemId] = {});
|
|
states[state] = getItemStyle(void 0, false, state, itemId);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function hasDimmedOpacity(style) {
|
|
return (style?.opacity ?? 1) < 1 || (style?.fillOpacity ?? 1) < 1 || (style?.strokeOpacity ?? 1) < 1;
|
|
}
|
|
var opaqueMarkerFillCache = /* @__PURE__ */ new Map();
|
|
function isOpaqueMarkerFillStyle(style) {
|
|
if (style == null)
|
|
return false;
|
|
const fill = style.fill;
|
|
if (!(0, import_ag_charts_core85.isString)(fill))
|
|
return false;
|
|
const fillString = fill.trim();
|
|
const fillLower = fillString.toLowerCase();
|
|
if (fillLower === "transparent" || fillLower === "none")
|
|
return false;
|
|
let cached = opaqueMarkerFillCache.get(fillString);
|
|
if (cached == null) {
|
|
try {
|
|
cached = import_ag_charts_core85.Color.fromString(fillString).a === 1;
|
|
} catch {
|
|
cached = false;
|
|
}
|
|
opaqueMarkerFillCache.set(fillString, cached);
|
|
}
|
|
return cached;
|
|
}
|
|
function resolveMarkerDrawingMode(baseDrawingMode, style) {
|
|
if (baseDrawingMode !== "cutout")
|
|
return baseDrawingMode;
|
|
return isOpaqueMarkerFillStyle(style) ? "cutout" : "overlay";
|
|
}
|
|
function findNodeDatumInArray(itemIdOrIndex, nodeData) {
|
|
for (const node of nodeData ?? []) {
|
|
switch (typeof itemIdOrIndex) {
|
|
case "string":
|
|
if (node.itemId === itemIdOrIndex) {
|
|
return node;
|
|
}
|
|
break;
|
|
case "number":
|
|
if (node.datumIndex === itemIdOrIndex) {
|
|
return node;
|
|
}
|
|
break;
|
|
default:
|
|
return itemIdOrIndex;
|
|
}
|
|
}
|
|
return void 0;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/tooltipManager.ts
|
|
var TooltipManager = class {
|
|
constructor(eventsHub, localeManager, domManager, tooltip) {
|
|
this.domManager = domManager;
|
|
this.tooltip = tooltip;
|
|
this.stateTracker = new StateTracker();
|
|
this.suppressState = new StateTracker(false);
|
|
this.appliedState = null;
|
|
// Track pending removals per caller
|
|
this.pendingRemovals = /* @__PURE__ */ new Map();
|
|
// Configurable delay (match highlights at 100ms)
|
|
this.removeDelay = 100;
|
|
// milliseconds
|
|
this.cleanup = new import_ag_charts_core86.CleanupRegistry();
|
|
this.cleanup.register(
|
|
tooltip.setup(localeManager, domManager),
|
|
eventsHub.on("dom:hidden", () => this.tooltip.hide())
|
|
);
|
|
}
|
|
destroy() {
|
|
for (const { scheduler } of this.pendingRemovals.values()) {
|
|
scheduler.cancel();
|
|
}
|
|
this.pendingRemovals.clear();
|
|
this.cleanup.flush();
|
|
}
|
|
updateTooltip(callerId, meta, content, pagination) {
|
|
const pending = this.pendingRemovals.get(callerId);
|
|
if (pending) {
|
|
pending.scheduler.cancel();
|
|
this.pendingRemovals.delete(callerId);
|
|
}
|
|
content ?? (content = this.stateTracker.get(callerId)?.content);
|
|
this.stateTracker.set(callerId, { meta, content, pagination });
|
|
this.applyStates();
|
|
}
|
|
removeTooltip(callerId, meta, delayed = false) {
|
|
if (delayed && this.removeDelay > 0) {
|
|
const existingPending = this.pendingRemovals.get(callerId);
|
|
if (existingPending) {
|
|
if (meta) {
|
|
existingPending.lastMeta = meta;
|
|
}
|
|
return;
|
|
}
|
|
const scheduler = debouncedCallback(() => {
|
|
this.applyPendingRemoval(callerId);
|
|
});
|
|
this.pendingRemovals.set(callerId, { scheduler, lastMeta: meta });
|
|
scheduler.schedule(this.removeDelay);
|
|
return;
|
|
}
|
|
const pending = this.pendingRemovals.get(callerId);
|
|
if (pending) {
|
|
pending.scheduler.cancel();
|
|
this.pendingRemovals.delete(callerId);
|
|
}
|
|
this.stateTracker.delete(callerId);
|
|
this.applyStates();
|
|
}
|
|
suppressTooltip(callerId) {
|
|
this.suppressState.set(callerId, true);
|
|
}
|
|
unsuppressTooltip(callerId) {
|
|
this.suppressState.delete(callerId);
|
|
}
|
|
applyPendingRemoval(callerId) {
|
|
if (!this.pendingRemovals.has(callerId)) {
|
|
return;
|
|
}
|
|
this.pendingRemovals.delete(callerId);
|
|
this.stateTracker.delete(callerId);
|
|
this.applyStates();
|
|
}
|
|
applyStates() {
|
|
const id = this.stateTracker.stateId();
|
|
const state = id ? this.stateTracker.get(id) : void 0;
|
|
if (this.suppressState.stateValue() || state?.meta == null || state?.content == null) {
|
|
this.appliedState = null;
|
|
this.tooltip.hide();
|
|
return;
|
|
}
|
|
const canvasRect = this.domManager.getBoundingClientRect();
|
|
const boundingRect = this.tooltip.bounds === "extended" ? this.domManager.getOverlayClientRect() : canvasRect;
|
|
if ((0, import_ag_charts_core86.objectsEqual)(this.appliedState?.content, state?.content) && (0, import_ag_charts_core86.objectsEqual)(this.appliedState?.pagination, state?.pagination)) {
|
|
const renderInstantly = this.tooltip.isVisible();
|
|
this.tooltip.show(boundingRect, canvasRect, state?.meta, null, void 0, renderInstantly);
|
|
} else {
|
|
this.tooltip.show(boundingRect, canvasRect, state?.meta, state?.content, state?.pagination);
|
|
}
|
|
this.appliedState = state;
|
|
}
|
|
static makeTooltipMeta(event, series, datum, movedBounds) {
|
|
const { canvasX, canvasY } = event;
|
|
const tooltip = series.properties.tooltip;
|
|
const { placement, anchorTo, xOffset, yOffset } = tooltip.position;
|
|
const refPoint = getDatumRefPoint(series, datum, movedBounds);
|
|
const meta = {
|
|
canvasX,
|
|
canvasY,
|
|
nodeCanvasX: refPoint?.canvasX ?? canvasX,
|
|
nodeCanvasY: refPoint?.canvasY ?? canvasY,
|
|
enableInteraction: tooltip.interaction?.enabled ?? false,
|
|
showArrow: tooltip.showArrow,
|
|
position: {
|
|
placement,
|
|
anchorTo,
|
|
xOffset,
|
|
yOffset
|
|
}
|
|
};
|
|
return meta;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/dragInterpreter.ts
|
|
var import_ag_charts_core87 = require("ag-charts-core");
|
|
var DRAG_THRESHOLD_PX = 3;
|
|
var DOUBLE_TAP_TIMER_MS = 505;
|
|
var DOUBLE_TAP_THRESHOLD_PX = 30;
|
|
function makeSynthetic(type, event) {
|
|
const { device, offsetX, offsetY, clientX, clientY, currentX, currentY, sourceEvent } = event;
|
|
return { type, device, offsetX, offsetY, clientX, clientY, currentX, currentY, sourceEvent };
|
|
}
|
|
function checkDragDistance(dx, dy) {
|
|
const distanceSquared = dx * dx + dy * dy;
|
|
const thresholdSquared = DRAG_THRESHOLD_PX * DRAG_THRESHOLD_PX;
|
|
return distanceSquared >= thresholdSquared;
|
|
}
|
|
function checkDoubleTapDistance(t1, t2) {
|
|
const dx = t1.clientX - t2.clientX;
|
|
const dy = t1.clientY - t2.clientY;
|
|
const distanceSquared = dx * dx + dy * dy;
|
|
const thresholdSquared = DOUBLE_TAP_THRESHOLD_PX * DOUBLE_TAP_THRESHOLD_PX;
|
|
return distanceSquared < thresholdSquared;
|
|
}
|
|
var DragInterpreter = class {
|
|
constructor(widget) {
|
|
this.cleanup = new import_ag_charts_core87.CleanupRegistry();
|
|
this.events = new import_ag_charts_core87.EventEmitter();
|
|
this.isDragging = false;
|
|
this.touch = { distanceTravelledX: 0, distanceTravelledY: 0, clientX: 0, clientY: 0 };
|
|
this.cleanup.register(
|
|
widget.addListener("touchstart", this.onTouchStart.bind(this)),
|
|
widget.addListener("touchmove", this.onTouchMove.bind(this)),
|
|
widget.addListener("touchend", this.onTouchEnd.bind(this)),
|
|
widget.addListener("mousemove", this.onMouseMove.bind(this)),
|
|
widget.addListener("dblclick", this.onDblClick.bind(this)),
|
|
widget.addListener("drag-start", this.onDragStart.bind(this)),
|
|
widget.addListener("drag-move", this.onDragMove.bind(this)),
|
|
widget.addListener("drag-end", this.onDragEnd.bind(this))
|
|
);
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
onTouchStart(e) {
|
|
const { clientX, clientY } = e.sourceEvent.targetTouches[0] ?? { clientX: Infinity, clientY: Infinity };
|
|
this.touch.distanceTravelledX = 0;
|
|
this.touch.distanceTravelledY = 0;
|
|
this.touch.clientX = clientX;
|
|
this.touch.clientY = clientY;
|
|
}
|
|
onTouchMove(e) {
|
|
const { clientX, clientY } = e.sourceEvent.targetTouches[0] ?? { clientX: Infinity, clientY: Infinity };
|
|
this.touch.distanceTravelledX += Math.abs(this.touch.clientX - clientX);
|
|
this.touch.distanceTravelledY += Math.abs(this.touch.clientY - clientY);
|
|
this.touch.clientX = clientX;
|
|
this.touch.clientY = clientY;
|
|
}
|
|
onTouchEnd(event) {
|
|
event.sourceEvent.preventDefault();
|
|
}
|
|
onMouseMove(event) {
|
|
this.events.emit("mousemove", event);
|
|
}
|
|
onDblClick(event) {
|
|
this.events.emit("dblclick", event);
|
|
}
|
|
onDragStart(event) {
|
|
this.dragStartEvent = event;
|
|
}
|
|
onDragMove(event) {
|
|
if (this.dragStartEvent != null) {
|
|
if (checkDragDistance(event.originDeltaX, event.originDeltaY)) {
|
|
this.events.emit("drag-start", this.dragStartEvent);
|
|
this.events.emit("drag-move", { ...this.dragStartEvent, type: "drag-move" });
|
|
this.dragStartEvent = void 0;
|
|
this.isDragging = true;
|
|
}
|
|
}
|
|
if (this.isDragging) {
|
|
this.events.emit("drag-move", event);
|
|
}
|
|
}
|
|
onDragEnd(event) {
|
|
if (this.isDragging) {
|
|
this.events.emit("drag-end", event);
|
|
this.isDragging = false;
|
|
return;
|
|
}
|
|
if (event.device === "mouse") {
|
|
const click = makeSynthetic("click", event);
|
|
this.events.emit("click", click);
|
|
} else if (event.sourceEvent.type === "touchend") {
|
|
if (checkDragDistance(this.touch.distanceTravelledX, this.touch.distanceTravelledY)) {
|
|
return;
|
|
}
|
|
const click = makeSynthetic("click", event);
|
|
this.events.emit("click", click);
|
|
const now = Date.now();
|
|
if (this.lastClick !== void 0 && now - this.lastClick.time <= DOUBLE_TAP_TIMER_MS && checkDoubleTapDistance(this.lastClick, event)) {
|
|
const dblClick = makeSynthetic("dblclick", event);
|
|
this.events.emit("dblclick", dblClick);
|
|
this.lastClick = void 0;
|
|
} else {
|
|
this.lastClick = { time: now, clientX: event.clientX, clientY: event.clientY };
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/widgetSet.ts
|
|
var DOMManagerWidget = class extends NativeWidget {
|
|
constructor(elem) {
|
|
super(elem);
|
|
}
|
|
addChildToDOM() {
|
|
}
|
|
removeChildFromDOM() {
|
|
}
|
|
};
|
|
var WidgetSet = class {
|
|
constructor(domManager, opts) {
|
|
this.seriesWidget = new DOMManagerWidget(domManager.getParent("series-area"));
|
|
this.chartWidget = new DOMManagerWidget(domManager.getParent("canvas-proxy"));
|
|
this.containerWidget = new DOMManagerWidget(domManager.getParent("canvas-container"));
|
|
this.containerWidget.addChild(this.chartWidget);
|
|
this.chartWidget.addChild(this.seriesWidget);
|
|
if (opts.withDragInterpretation) {
|
|
this.seriesDragInterpreter = new DragInterpreter(this.seriesWidget);
|
|
}
|
|
}
|
|
destroy() {
|
|
this.seriesDragInterpreter?.destroy();
|
|
this.seriesWidget.destroy();
|
|
this.chartWidget.destroy();
|
|
this.containerWidget.destroy();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/zoomManager.ts
|
|
var import_ag_charts_core93 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scale/continuousScale.ts
|
|
var import_ag_charts_core88 = require("ag-charts-core");
|
|
var _ContinuousScale = class _ContinuousScale extends AbstractScale {
|
|
constructor(domain = [], range4 = []) {
|
|
super();
|
|
this.range = range4;
|
|
this.defaultTickCount = _ContinuousScale.defaultTickCount;
|
|
this.defaultClamp = false;
|
|
// Domain caching to avoid repeated valueOf() calls in hot paths
|
|
this._domain = [];
|
|
this.domainNeedsValueOf = true;
|
|
// Safe default
|
|
this.d0Cache = Number.NaN;
|
|
this.d1Cache = Number.NaN;
|
|
this.domain = domain;
|
|
}
|
|
static is(value) {
|
|
return value instanceof _ContinuousScale;
|
|
}
|
|
get domain() {
|
|
return this._domain;
|
|
}
|
|
set domain(values) {
|
|
this._domain = values;
|
|
if (values && values.length >= 2) {
|
|
const sample = values[0];
|
|
this.domainNeedsValueOf = sample != null && typeof sample === "object";
|
|
if (this.domainNeedsValueOf) {
|
|
this.d0Cache = values[0].valueOf();
|
|
this.d1Cache = values[1].valueOf();
|
|
} else {
|
|
this.d0Cache = values[0];
|
|
this.d1Cache = values[1];
|
|
}
|
|
} else {
|
|
this.d0Cache = Number.NaN;
|
|
this.d1Cache = Number.NaN;
|
|
}
|
|
}
|
|
normalizeDomains(...domains) {
|
|
return normalizeContinuousDomains(...domains);
|
|
}
|
|
calcBandwidth(smallestInterval = 1, minWidth = 1) {
|
|
const { domain } = this;
|
|
const rangeDistance = this.getPixelRange();
|
|
if (domain.length === 0)
|
|
return rangeDistance;
|
|
const intervals = Math.abs(this.d1Cache - this.d0Cache) / smallestInterval + 1;
|
|
let bands = intervals;
|
|
if (minWidth !== 0) {
|
|
const maxBands = Math.floor(rangeDistance);
|
|
bands = Math.min(bands, maxBands);
|
|
}
|
|
return rangeDistance / Math.max(1, bands);
|
|
}
|
|
convert(value, options) {
|
|
const { domain } = this;
|
|
if (!domain || domain.length < 2 || value == null) {
|
|
return Number.NaN;
|
|
}
|
|
const { range: range4 } = this;
|
|
const clamp25 = options?.clamp ?? this.defaultClamp;
|
|
let d0 = this.d0Cache;
|
|
let d1 = this.d1Cache;
|
|
let x = typeof value === "number" ? value : value.valueOf();
|
|
if (this.transform) {
|
|
d0 = this.transform(d0);
|
|
d1 = this.transform(d1);
|
|
x = this.transform(x);
|
|
}
|
|
if (clamp25) {
|
|
const [start, stop] = (0, import_ag_charts_core88.findMinMax)([d0, d1]);
|
|
if (x < start) {
|
|
return range4[0];
|
|
} else if (x > stop) {
|
|
return range4[1];
|
|
}
|
|
}
|
|
if (d0 === d1) {
|
|
return (range4[0] + range4[1]) / 2;
|
|
} else if (x === d0) {
|
|
return range4[0];
|
|
} else if (x === d1) {
|
|
return range4[1];
|
|
}
|
|
const r0 = range4[0];
|
|
return r0 + (x - d0) / (d1 - d0) * (range4[1] - r0);
|
|
}
|
|
invert(x, _nearest) {
|
|
const { domain } = this;
|
|
if (domain.length < 2)
|
|
return;
|
|
let d0 = this.d0Cache;
|
|
let d1 = this.d1Cache;
|
|
if (this.transform) {
|
|
d0 = this.transform(d0);
|
|
d1 = this.transform(d1);
|
|
}
|
|
const { range: range4 } = this;
|
|
const [r0, r1] = range4;
|
|
let d;
|
|
if (r0 === r1) {
|
|
d = this.toDomain((d0 + d1) / 2);
|
|
} else {
|
|
d = this.toDomain(d0 + (x - r0) / (r1 - r0) * (d1 - d0));
|
|
}
|
|
return this.transformInvert ? this.transformInvert(d) : d;
|
|
}
|
|
getDomainMinMax() {
|
|
return unpackDomainMinMax(this.domain);
|
|
}
|
|
getPixelRange() {
|
|
const [a, b] = this.range;
|
|
return Math.abs(b - a);
|
|
}
|
|
};
|
|
_ContinuousScale.defaultTickCount = 5;
|
|
var ContinuousScale = _ContinuousScale;
|
|
function normalizeContinuousDomains(...domains) {
|
|
let min;
|
|
let minValue = Infinity;
|
|
let max;
|
|
let maxValue = -Infinity;
|
|
for (const input of domains) {
|
|
const domain = input.domain;
|
|
for (const d of domain) {
|
|
const value = d.valueOf();
|
|
if (value < minValue) {
|
|
minValue = value;
|
|
min = d;
|
|
}
|
|
if (value > maxValue) {
|
|
maxValue = value;
|
|
max = d;
|
|
}
|
|
}
|
|
}
|
|
if (min != null && max != null) {
|
|
const domain = [min, max];
|
|
return { domain, animatable: true };
|
|
} else {
|
|
return { domain: [], animatable: false };
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scale/discreteTimeScale.ts
|
|
var import_ag_charts_core90 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scale/bandScale.ts
|
|
var import_ag_charts_core89 = require("ag-charts-core");
|
|
var _BandScale = class _BandScale extends AbstractScale {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.invalid = true;
|
|
this.range = [0, 1];
|
|
this.round = false;
|
|
this._bandwidth = 1;
|
|
this._step = 1;
|
|
this._inset = 1;
|
|
this._rawBandwidth = 1;
|
|
/**
|
|
* The ratio of the range that is reserved for space between bands.
|
|
*/
|
|
this._paddingInner = 0;
|
|
/**
|
|
* The ratio of the range that is reserved for space before the first
|
|
* and after the last band.
|
|
*/
|
|
this._paddingOuter = 0;
|
|
}
|
|
static is(value) {
|
|
return value instanceof _BandScale;
|
|
}
|
|
get bandwidth() {
|
|
this.refresh();
|
|
return this._bandwidth;
|
|
}
|
|
get step() {
|
|
this.refresh();
|
|
return this._step;
|
|
}
|
|
get inset() {
|
|
this.refresh();
|
|
return this._inset;
|
|
}
|
|
get rawBandwidth() {
|
|
this.refresh();
|
|
return this._rawBandwidth;
|
|
}
|
|
set padding(value) {
|
|
value = (0, import_ag_charts_core89.clamp)(0, value, 1);
|
|
this._paddingInner = value;
|
|
this._paddingOuter = value;
|
|
}
|
|
get padding() {
|
|
return this._paddingInner;
|
|
}
|
|
set paddingInner(value) {
|
|
this.invalid = true;
|
|
this._paddingInner = (0, import_ag_charts_core89.clamp)(0, value, 1);
|
|
}
|
|
get paddingInner() {
|
|
return this._paddingInner;
|
|
}
|
|
set paddingOuter(value) {
|
|
this.invalid = true;
|
|
this._paddingOuter = (0, import_ag_charts_core89.clamp)(0, value, 1);
|
|
}
|
|
get paddingOuter() {
|
|
return this._paddingOuter;
|
|
}
|
|
/** Override in subclass to provide band count without triggering full band materialization */
|
|
getBandCountForUpdate() {
|
|
return this.bands.length;
|
|
}
|
|
refresh() {
|
|
if (!this.invalid)
|
|
return;
|
|
this.invalid = false;
|
|
this.update();
|
|
if (this.invalid) {
|
|
import_ag_charts_core89.Logger.warnOnce("Expected update to not invalidate scale");
|
|
}
|
|
}
|
|
convert(d, options) {
|
|
this.refresh();
|
|
const i = this.findIndex(d, options?.alignment);
|
|
if (i == null || i < 0 || i >= this.getBandCountForUpdate()) {
|
|
return Number.NaN;
|
|
}
|
|
return this.ordinalRange(i);
|
|
}
|
|
getDomainMinMax() {
|
|
return unpackDomainMinMax(this.domain);
|
|
}
|
|
invertNearestIndex(position) {
|
|
this.refresh();
|
|
const bandCount = this.getBandCountForUpdate();
|
|
if (bandCount === 0)
|
|
return -1;
|
|
let low = 0;
|
|
let high = bandCount - 1;
|
|
let closestDistance = Infinity;
|
|
let closestIndex = 0;
|
|
while (low <= high) {
|
|
const mid = Math.trunc((high + low) / 2);
|
|
const p = this.ordinalRange(mid);
|
|
const distance = Math.abs(p - position);
|
|
if (distance === 0)
|
|
return mid;
|
|
if (distance < closestDistance) {
|
|
closestDistance = distance;
|
|
closestIndex = mid;
|
|
}
|
|
if (p < position) {
|
|
low = mid + 1;
|
|
} else {
|
|
high = mid - 1;
|
|
}
|
|
}
|
|
return closestIndex;
|
|
}
|
|
update() {
|
|
const [r0, r1] = this.range;
|
|
let { _paddingInner: paddingInner } = this;
|
|
const { _paddingOuter: paddingOuter } = this;
|
|
const bandCount = this.getBandCountForUpdate();
|
|
if (bandCount === 0)
|
|
return;
|
|
const rangeDistance = r1 - r0;
|
|
let rawStep;
|
|
if (bandCount === 1) {
|
|
paddingInner = 0;
|
|
rawStep = rangeDistance * (1 - paddingOuter * 2);
|
|
} else {
|
|
rawStep = rangeDistance / Math.max(1, bandCount - paddingInner + paddingOuter * 2);
|
|
}
|
|
const round = this.round && Math.floor(rawStep) > 0;
|
|
const step = round ? Math.floor(rawStep) : rawStep;
|
|
let inset = r0 + (rangeDistance - step * (bandCount - paddingInner)) / 2;
|
|
let bandwidth = step * (1 - paddingInner);
|
|
if (round) {
|
|
inset = Math.round(inset);
|
|
bandwidth = Math.round(bandwidth);
|
|
}
|
|
this._step = step;
|
|
this._inset = inset;
|
|
this._bandwidth = bandwidth;
|
|
this._rawBandwidth = rawStep * (1 - paddingInner);
|
|
}
|
|
ordinalRange(i) {
|
|
const { _inset: inset, _step: step, range: range4 } = this;
|
|
const min = Math.min(range4[0], range4[1]);
|
|
const max = Math.max(range4[0], range4[1]);
|
|
return (0, import_ag_charts_core89.clamp)(min, inset + step * i, max);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
Invalidating
|
|
], _BandScale.prototype, "range", 2);
|
|
__decorateClass([
|
|
Invalidating
|
|
], _BandScale.prototype, "round", 2);
|
|
var BandScale = _BandScale;
|
|
|
|
// packages/ag-charts-community/src/scale/discreteTimeScale.ts
|
|
var APPROXIMATE_THRESHOLD = 1e3;
|
|
var SAMPLE_POINTS = 20;
|
|
function checkUniformityBySampling(bands, startIdx = 0, endIdx = bands.length - 1) {
|
|
const n = endIdx - startIdx + 1;
|
|
if (n < 2)
|
|
return { isUniform: false };
|
|
const indices = Array.from(
|
|
{ length: SAMPLE_POINTS },
|
|
(_, i) => startIdx + Math.floor(i * (n - 1) / (SAMPLE_POINTS - 1))
|
|
);
|
|
const samples = indices.map((i) => bands[i].valueOf());
|
|
const expectedInterval = (samples.at(-1) - samples[0]) / (n - 1);
|
|
if (!Number.isFinite(expectedInterval) || expectedInterval === 0) {
|
|
return { isUniform: false };
|
|
}
|
|
const tolerance = Math.abs(expectedInterval * 0.01);
|
|
for (let i = 1; i < samples.length; i++) {
|
|
const indexGap = indices[i] - indices[i - 1];
|
|
const actualInterval = (samples[i] - samples[i - 1]) / indexGap;
|
|
if (Math.abs(actualInterval - expectedInterval) > tolerance) {
|
|
return { isUniform: false };
|
|
}
|
|
}
|
|
return { isUniform: true, interval: expectedInterval };
|
|
}
|
|
var DiscreteTimeScale = class _DiscreteTimeScale extends BandScale {
|
|
static is(value) {
|
|
return value instanceof _DiscreteTimeScale;
|
|
}
|
|
toDomain(value) {
|
|
return new Date(value);
|
|
}
|
|
get reversed() {
|
|
const { domain } = this;
|
|
return domain.length > 0 && domain[0].valueOf() > domain.at(-1).valueOf();
|
|
}
|
|
/** Cached numeric band values for efficient binary search. Subclasses should override with a cached version. */
|
|
get numericBands() {
|
|
return this.bands.map((d) => d.valueOf());
|
|
}
|
|
convert(value, options) {
|
|
this.refresh();
|
|
if (!(value instanceof Date))
|
|
value = new Date(value);
|
|
const { domain, reversed } = this;
|
|
const numericBands = this.numericBands;
|
|
const bandCount = numericBands.length;
|
|
if (domain.length <= 0)
|
|
return Number.NaN;
|
|
const r0 = this.ordinalRange(0);
|
|
const r1 = this.ordinalRange(bandCount - 1);
|
|
if (bandCount === 0)
|
|
return r0;
|
|
if (options?.clamp === true) {
|
|
const { range: range4 } = this;
|
|
if (value.valueOf() < numericBands[0])
|
|
return range4[0];
|
|
if (value.valueOf() > numericBands.at(-1))
|
|
return range4[1];
|
|
}
|
|
const alignment = options?.alignment ?? import_ag_charts_core90.ScaleAlignment.Leading;
|
|
if (alignment !== import_ag_charts_core90.ScaleAlignment.Interpolate) {
|
|
const r2 = super.convert(value, options);
|
|
return reversed ? r1 - (r2 - r0) : r2;
|
|
}
|
|
const v = value.valueOf();
|
|
let bandIndex = this.findIndex(value) ?? 0;
|
|
let dIndex;
|
|
if (reversed) {
|
|
bandIndex = Math.min(Math.max(bandIndex, 1), bandCount - 1);
|
|
dIndex = -1;
|
|
} else {
|
|
bandIndex = Math.min(Math.max(bandIndex, 0), bandCount - 2);
|
|
dIndex = 1;
|
|
}
|
|
const v0 = numericBands[bandIndex];
|
|
const v1 = numericBands[bandIndex + dIndex];
|
|
const vr0 = this.ordinalRange(bandIndex);
|
|
const vr1 = this.ordinalRange(bandIndex + dIndex);
|
|
const ratio10 = (v - v0) / (v1 - v0);
|
|
const r = ratio10 * (vr1 - vr0) + vr0;
|
|
return reversed ? r1 - (r - r0) : r;
|
|
}
|
|
invert(position, nearest = false) {
|
|
this.refresh();
|
|
const { domain } = this;
|
|
if (domain.length <= 0)
|
|
return;
|
|
const bands = this.bands;
|
|
const bandCount = this.getBandCountForUpdate();
|
|
const reversed = domain[0].valueOf() > domain.at(-1).valueOf();
|
|
let index;
|
|
if (nearest) {
|
|
index = this.invertNearestIndex(position - this.bandwidth / 2);
|
|
} else {
|
|
const closestIndex = (0, import_ag_charts_core90.findMinIndex)(0, bandCount - 1, (i) => {
|
|
const p = this.ordinalRange(i);
|
|
return p >= position;
|
|
});
|
|
index = closestIndex ?? bandCount - 1;
|
|
}
|
|
return bands[reversed ? bandCount - 1 - index : index];
|
|
}
|
|
/** Override in subclass to provide cached uniformity check result */
|
|
getUniformityCache(_visibleRange) {
|
|
return void 0;
|
|
}
|
|
findIndex(value, alignment = import_ag_charts_core90.ScaleAlignment.Leading) {
|
|
if (value == null)
|
|
return void 0;
|
|
const numericBands = this.numericBands;
|
|
const n = numericBands.length;
|
|
if (n === 0)
|
|
return void 0;
|
|
if (n === 1)
|
|
return 0;
|
|
const target = value.valueOf();
|
|
if (alignment === import_ag_charts_core90.ScaleAlignment.Trailing) {
|
|
return (0, import_ag_charts_core90.findMinIndex)(0, n - 1, (index) => numericBands[index] >= target);
|
|
}
|
|
return (0, import_ag_charts_core90.findMaxIndex)(0, n - 1, (index) => numericBands[index] <= target);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/util/panToBBox.ts
|
|
var import_ag_charts_core91 = require("ag-charts-core");
|
|
function normalize(screenMin, min, screenMax, max, target) {
|
|
return min + (max - min) * ((target - screenMin) / (screenMax - screenMin));
|
|
}
|
|
function unnormalize(screenMin, min, screenMax, max, ratio10) {
|
|
return screenMin + (ratio10 - min) * ((screenMax - screenMin) / (max - min));
|
|
}
|
|
function calcWorldAxis(viewportMin, viewportMax, ratio10) {
|
|
return [
|
|
unnormalize(viewportMin, ratio10.min, viewportMax, ratio10.max, 0),
|
|
unnormalize(viewportMin, ratio10.min, viewportMax, ratio10.max, 1)
|
|
];
|
|
}
|
|
function calcWorldVec4(viewport, ratioX, ratioY) {
|
|
const [x1, x2] = calcWorldAxis(viewport.x1, viewport.x2, ratioX);
|
|
const [y1, y2] = calcWorldAxis(viewport.y1, viewport.y2, ratioY);
|
|
return { x1, x2, y1, y2 };
|
|
}
|
|
function panAxesUnnormalized(worldMin, worldMax, viewportMin, viewportMax, targetMin, targetMax) {
|
|
if (viewportMin <= targetMin && targetMax <= viewportMax)
|
|
return viewportMin;
|
|
const minDiff = targetMin - viewportMin;
|
|
const maxDiff = targetMax - viewportMax;
|
|
const diff2 = Math.abs(minDiff) < Math.abs(maxDiff) ? minDiff : maxDiff;
|
|
return (0, import_ag_charts_core91.clamp)(worldMin, viewportMin + diff2, worldMax);
|
|
}
|
|
function calcPanToBBoxRatios(viewportBBox, ratios, targetBBox) {
|
|
const { x: ratioX = { min: 0, max: 1 }, y: ratioY = { min: 0, max: 1 } } = ratios;
|
|
const target = import_ag_charts_core91.Vec4.from(targetBBox);
|
|
const viewport = import_ag_charts_core91.Vec4.from(viewportBBox);
|
|
const world = calcWorldVec4(viewport, ratioX, ratioY);
|
|
const x = panAxesUnnormalized(world.x1, world.x2, viewport.x1, viewport.x2, target.x1, target.x2);
|
|
const y = panAxesUnnormalized(world.y1, world.y2, viewport.y1, viewport.y2, target.y1, target.y2);
|
|
const result = {
|
|
x: {
|
|
min: normalize(viewport.x1, ratioX.min, viewport.x2, ratioX.max, x),
|
|
max: normalize(viewport.x1, ratioX.min, viewport.x2, ratioX.max, x + viewportBBox.width)
|
|
},
|
|
y: {
|
|
min: normalize(viewport.y1, ratioY.min, viewport.y2, ratioY.max, y),
|
|
max: normalize(viewport.y1, ratioY.min, viewport.y2, ratioY.max, y + viewportBBox.height)
|
|
}
|
|
};
|
|
const diffX = result.x.max - result.x.min;
|
|
const diffY = result.y.max - result.y.min;
|
|
result.x.min = (0, import_ag_charts_core91.clamp)(0, result.x.min, 1 - diffX);
|
|
result.x.max = result.x.min + diffX;
|
|
result.y.min = (0, import_ag_charts_core91.clamp)(0, result.y.min, 1 - diffY);
|
|
result.y.max = result.y.min + diffY;
|
|
return result;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/rangeAlignment.ts
|
|
var import_ag_charts_core92 = require("ag-charts-core");
|
|
function rangeAlignment(start, end2) {
|
|
const startValue = start?.valueOf();
|
|
const endValue = end2?.valueOf();
|
|
if (typeof startValue !== "number" || typeof endValue !== "number")
|
|
return [void 0, void 0];
|
|
return startValue < endValue ? [import_ag_charts_core92.ScaleAlignment.Leading, import_ag_charts_core92.ScaleAlignment.Trailing] : [import_ag_charts_core92.ScaleAlignment.Trailing, import_ag_charts_core92.ScaleAlignment.Leading];
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/zoomManager.ts
|
|
var rangeValidator = (axis) => (0, import_ag_charts_core93.attachDescription)((value, { options }) => {
|
|
if (!ContinuousScale.is(axis?.scale) && !DiscreteTimeScale.is(axis?.scale))
|
|
return true;
|
|
if (value == null || options.end == null)
|
|
return true;
|
|
return value < options.end;
|
|
}, `to be less than end`);
|
|
function validateChanges(changes) {
|
|
for (const axisId of (0, import_ag_charts_core93.strictObjectKeys)(changes)) {
|
|
const zoom = changes[axisId];
|
|
if (!zoom)
|
|
continue;
|
|
const { min, max } = zoom;
|
|
if (min < 0 || max > 1) {
|
|
import_ag_charts_core93.Logger.warnOnce(
|
|
`Attempted to update axis (${axisId}) zoom to an invalid ratio of [{ min: ${min}, max: ${max} }], expecting a ratio of 0 to 1. Ignoring.`
|
|
);
|
|
delete changes[axisId];
|
|
}
|
|
}
|
|
}
|
|
function refreshCoreState(nextAxes, state) {
|
|
const result = {};
|
|
for (const { id, direction } of nextAxes) {
|
|
const { min, max } = state[id] ?? { min: 0, max: 1 };
|
|
result[id] = { min, max, direction };
|
|
}
|
|
return result;
|
|
}
|
|
function areEqualCoreZooms(p, q) {
|
|
const pKeys = (0, import_ag_charts_core93.strictObjectKeys)(p);
|
|
const qKeys = (0, import_ag_charts_core93.strictObjectKeys)(q);
|
|
if (pKeys.length !== qKeys.length)
|
|
return false;
|
|
for (const k of pKeys)
|
|
if (!qKeys.includes(k))
|
|
return false;
|
|
for (const k of pKeys) {
|
|
const pVal = p[k];
|
|
const qVal = q[k];
|
|
if (pVal === qVal) {
|
|
continue;
|
|
} else if (pVal == void 0 || qVal == void 0 || pVal.direction !== qVal.direction || pVal.min !== qVal.min || pVal.max !== qVal.max) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function userInteraction(sourceDetail) {
|
|
return { source: "user-interaction", sourceDetail };
|
|
}
|
|
var ZoomManager = class extends BaseManager {
|
|
constructor(eventsHub, updateService, fireChartEvent) {
|
|
super();
|
|
this.eventsHub = eventsHub;
|
|
this.fireChartEvent = fireChartEvent;
|
|
this.mementoOriginatorKey = "zoom";
|
|
this.state = {};
|
|
this.axes = [];
|
|
this.didLayoutAxes = false;
|
|
this.lastRestoredState = {};
|
|
this.independentAxes = false;
|
|
this.navigatorModule = false;
|
|
this.zoomModule = false;
|
|
// The initial state memento can not be restored until the chart has performed its first layout. Instead save it as
|
|
// pending and restore then delete it on the first layout.
|
|
this.pendingMemento = void 0;
|
|
this.cleanup.register(
|
|
eventsHub.on("zoom:change-request", (event) => {
|
|
this.constrainZoomToRequiredWidth(event);
|
|
}),
|
|
updateService.addListener("pre-series-update", ({ requiredRangeRatio, requiredRangeDirection }) => {
|
|
this.didLayoutAxes = true;
|
|
const { pendingMemento } = this;
|
|
if (pendingMemento) {
|
|
this.restoreMemento(pendingMemento.version, pendingMemento.mementoVersion, pendingMemento.memento);
|
|
} else {
|
|
this.restoreRequiredRange(requiredRangeRatio, requiredRangeDirection);
|
|
}
|
|
this.updateZoom({
|
|
source: "chart-update",
|
|
// FIXME(AG-16412): this is "probably" what caused, but we don't really know
|
|
sourceDetail: "unspecified"
|
|
});
|
|
}),
|
|
updateService.addListener("update-complete", ({ wasShortcut }) => {
|
|
if (wasShortcut)
|
|
return;
|
|
if (this.pendingZoomEventSource) {
|
|
const source = this.pendingZoomEventSource;
|
|
this.fireChartEvent({ type: "zoom", source, ...this.getMementoRanges() });
|
|
this.pendingZoomEventSource = void 0;
|
|
}
|
|
})
|
|
);
|
|
}
|
|
// FIXME: should be private
|
|
toCoreZoomState(axisZoom) {
|
|
const result = {};
|
|
let ids;
|
|
const { state } = this;
|
|
if (this.independentAxes) {
|
|
const xId = this.getPrimaryAxisId(import_ag_charts_core93.ChartAxisDirection.X);
|
|
const yId = this.getPrimaryAxisId(import_ag_charts_core93.ChartAxisDirection.Y);
|
|
ids = [];
|
|
if (xId)
|
|
ids.push(xId);
|
|
if (yId)
|
|
ids.push(yId);
|
|
} else {
|
|
ids = (0, import_ag_charts_core93.strictObjectKeys)(state);
|
|
}
|
|
for (const id of ids) {
|
|
const { direction } = state[id] ?? {};
|
|
if (direction != void 0) {
|
|
const zoom = axisZoom[direction];
|
|
if (zoom) {
|
|
const { min, max } = zoom;
|
|
result[id] = { min, max, direction };
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
// FIXME: should be private
|
|
toZoomState(coreZoom) {
|
|
let x;
|
|
let y;
|
|
for (const id of (0, import_ag_charts_core93.strictObjectKeys)(coreZoom)) {
|
|
const { min, max, direction } = coreZoom[id];
|
|
if (direction === import_ag_charts_core93.ChartAxisDirection.X) {
|
|
x ?? (x = { min, max });
|
|
} else if (direction === import_ag_charts_core93.ChartAxisDirection.Y) {
|
|
y ?? (y = { min, max });
|
|
}
|
|
}
|
|
if (x || y) {
|
|
return { x, y };
|
|
}
|
|
}
|
|
createMemento() {
|
|
return this.getMementoRanges();
|
|
}
|
|
guardMemento(blob, messages) {
|
|
if (blob == null)
|
|
return true;
|
|
if (!(0, import_ag_charts_core93.isObject)(blob))
|
|
return false;
|
|
const primaryX = this.getPrimaryAxis(import_ag_charts_core93.ChartAxisDirection.X);
|
|
const primaryY = this.getPrimaryAxis(import_ag_charts_core93.ChartAxisDirection.Y);
|
|
const zoomMementoDefs = {
|
|
rangeX: { start: rangeValidator(primaryX), end: import_ag_charts_core93.defined },
|
|
rangeY: { start: rangeValidator(primaryY), end: import_ag_charts_core93.defined },
|
|
ratioX: { start: import_ag_charts_core93.defined, end: import_ag_charts_core93.defined },
|
|
ratioY: { start: import_ag_charts_core93.defined, end: import_ag_charts_core93.defined },
|
|
autoScaledAxes: import_ag_charts_core93.defined
|
|
};
|
|
const { invalid } = (0, import_ag_charts_core93.validate)(blob, zoomMementoDefs);
|
|
if (invalid.length > 0) {
|
|
messages.push(...invalid.map(String));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
restoreMemento(version, mementoVersion, memento) {
|
|
if (!this.axes || !this.didLayoutAxes) {
|
|
this.pendingMemento = { version, mementoVersion, memento };
|
|
return;
|
|
}
|
|
this.pendingMemento = void 0;
|
|
const zoom = (0, import_ag_charts_core93.definedZoomState)(this.getZoom());
|
|
if (memento?.rangeX) {
|
|
zoom.x = this.rangeToRatioDirection(import_ag_charts_core93.ChartAxisDirection.X, memento.rangeX) ?? { min: 0, max: 1 };
|
|
} else if (memento?.ratioX) {
|
|
zoom.x = {
|
|
min: memento.ratioX.start ?? 0,
|
|
max: memento.ratioX.end ?? 1
|
|
};
|
|
} else {
|
|
zoom.x = { min: 0, max: 1 };
|
|
}
|
|
const { navigatorModule, zoomModule } = this;
|
|
this.eventsHub.emit("zoom:load-memento", { zoom, memento, navigatorModule, zoomModule });
|
|
const changes = this.toCoreZoomState(zoom);
|
|
this.lastRestoredState = (0, import_ag_charts_core93.deepFreeze)((0, import_ag_charts_core93.deepClone)(changes));
|
|
this.updateChanges({
|
|
source: "state-change",
|
|
sourceDetail: "internal-restoreMemento",
|
|
changes,
|
|
isReset: false
|
|
});
|
|
}
|
|
findAxis(axisId) {
|
|
for (const a of this.axes) {
|
|
if (a.id === axisId)
|
|
return a;
|
|
}
|
|
}
|
|
getAxes() {
|
|
return this.axes;
|
|
}
|
|
setAxes(nextAxes) {
|
|
const { axes } = this;
|
|
axes.length = 0;
|
|
for (const axis of nextAxes) {
|
|
if ("range" in axis) {
|
|
axes.push(axis);
|
|
}
|
|
}
|
|
const oldState = this.state;
|
|
const changes = refreshCoreState(nextAxes, oldState);
|
|
this.state = changes;
|
|
this.lastRestoredState = refreshCoreState(nextAxes, this.lastRestoredState);
|
|
this.updateChanges({ source: "chart-update", sourceDetail: "internal-setAxes", changes, isReset: false });
|
|
}
|
|
setIndependentAxes(independent = true) {
|
|
this.independentAxes = independent;
|
|
}
|
|
setNavigatorEnabled(enabled = true) {
|
|
this.navigatorModule = enabled;
|
|
}
|
|
setZoomModuleEnabled(enabled = true) {
|
|
this.zoomModule = enabled;
|
|
}
|
|
isNavigatorEnabled() {
|
|
return this.navigatorModule;
|
|
}
|
|
isZoomEnabled() {
|
|
return this.zoomModule;
|
|
}
|
|
updateZoom({ source, sourceDetail }, newZoom) {
|
|
const changes = this.toCoreZoomState(newZoom ?? {});
|
|
return this.updateChanges({ source, sourceDetail, changes, isReset: false });
|
|
}
|
|
computeChangedAxesIds(newState) {
|
|
const result = [];
|
|
const oldState = this.state;
|
|
for (const id of (0, import_ag_charts_core93.strictObjectKeys)(newState)) {
|
|
const newAxisState = newState[id] ?? { min: 0, max: 1 };
|
|
const oldAxisState = oldState[id];
|
|
if (oldAxisState == void 0 || oldAxisState.min !== newAxisState.min || oldAxisState.max !== newAxisState.max) {
|
|
result.push(id);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
updateChanges(params) {
|
|
const { source, sourceDetail, isReset, changes } = params;
|
|
validateChanges(changes);
|
|
const changedAxes = this.computeChangedAxesIds(changes);
|
|
const oldState = (0, import_ag_charts_core93.deepClone)(this.state);
|
|
const newState = (0, import_ag_charts_core93.deepClone)(this.state);
|
|
for (const id of changedAxes) {
|
|
const axis = newState[id];
|
|
if (axis != void 0) {
|
|
axis.min = changes[id]?.min ?? 0;
|
|
axis.max = changes[id]?.max ?? 1;
|
|
}
|
|
}
|
|
this.state = newState;
|
|
return this.dispatch(source, sourceDetail, changedAxes, isReset, oldState);
|
|
}
|
|
resetZoom({ source, sourceDetail }) {
|
|
this.updateChanges({ source, sourceDetail, changes: this.getRestoredZoom(), isReset: true });
|
|
}
|
|
resetAxisZoom({ source, sourceDetail }, axisId) {
|
|
this.updateChanges({
|
|
source,
|
|
sourceDetail,
|
|
changes: { [axisId]: this.getRestoredZoom()[axisId] },
|
|
isReset: true
|
|
});
|
|
}
|
|
panToBBox(seriesRect, target) {
|
|
if (!this.isZoomEnabled() && !this.isNavigatorEnabled())
|
|
return false;
|
|
const zoom = this.getZoom();
|
|
if (zoom === void 0 || !zoom.x && !zoom.y)
|
|
return false;
|
|
const panIsPossible = seriesRect.width > 0 && seriesRect.height > 0 && Math.abs(target.width) <= Math.abs(seriesRect.width) && Math.abs(target.height) <= Math.abs(seriesRect.height);
|
|
if (!panIsPossible) {
|
|
import_ag_charts_core93.Logger.warnOnce(`cannot pan to target BBox - chart too small?`);
|
|
return false;
|
|
}
|
|
const newZoom = calcPanToBBoxRatios(seriesRect, zoom, target);
|
|
const changes = this.toCoreZoomState(newZoom);
|
|
return this.updateChanges({
|
|
source: "user-interaction",
|
|
sourceDetail: "internal-panToBBox",
|
|
changes,
|
|
isReset: false
|
|
});
|
|
}
|
|
// Fire this event to signal to listeners that the view is changing through a zoom and/or pan change.
|
|
fireZoomPanStartEvent(callerId) {
|
|
this.eventsHub.emit("zoom:pan-start", { callerId });
|
|
}
|
|
extendToEnd(sourcing, direction, extent6) {
|
|
return this.extendWith(sourcing, direction, (end2) => Number(end2) - extent6);
|
|
}
|
|
extendWith({ source, sourceDetail }, direction, fn) {
|
|
const axis = this.getPrimaryAxis(direction);
|
|
if (!axis)
|
|
return;
|
|
const extents = this.getDomainExtents(axis);
|
|
if (!extents)
|
|
return;
|
|
const [, end2] = extents;
|
|
const start = fn(end2);
|
|
const ratio10 = this.rangeToRatioAxis(axis, { start });
|
|
if (!ratio10)
|
|
return;
|
|
this.updateChanges({ source, sourceDetail, changes: { [direction]: ratio10 }, isReset: false });
|
|
}
|
|
updateWith({ source, sourceDetail }, direction, fn) {
|
|
const axis = this.getPrimaryAxis(direction);
|
|
if (!axis)
|
|
return;
|
|
const extents = this.getDomainExtents(axis);
|
|
if (!extents)
|
|
return;
|
|
let [start, end2] = extents;
|
|
[start, end2] = fn(start, end2);
|
|
const ratio10 = this.rangeToRatioAxis(axis, { start, end: end2 });
|
|
if (!ratio10)
|
|
return;
|
|
this.updateChanges({ source, sourceDetail, changes: { [direction]: ratio10 }, isReset: false });
|
|
}
|
|
getZoom() {
|
|
return this.toZoomState(this.state);
|
|
}
|
|
getAxisZoom(axisId) {
|
|
return this.state[axisId] ?? { min: 0, max: 1 };
|
|
}
|
|
getAxisZooms() {
|
|
return this.state;
|
|
}
|
|
getCoreZoom() {
|
|
return this.state;
|
|
}
|
|
getRestoredZoom() {
|
|
return this.lastRestoredState;
|
|
}
|
|
getPrimaryAxisId(direction) {
|
|
return this.getPrimaryAxis(direction)?.id;
|
|
}
|
|
getBoundSeries() {
|
|
const xAxis = this.getPrimaryAxis(import_ag_charts_core93.ChartAxisDirection.X);
|
|
const yAxis = this.getPrimaryAxis(import_ag_charts_core93.ChartAxisDirection.Y);
|
|
let boundSeries;
|
|
if (this.independentAxes) {
|
|
const xBoundSeries = new Set(xAxis?.boundSeries ?? []);
|
|
const yBoundSeries = new Set(yAxis?.boundSeries ?? []);
|
|
boundSeries = /* @__PURE__ */ new Set();
|
|
for (const series of xBoundSeries) {
|
|
if (yBoundSeries.has(series)) {
|
|
boundSeries.add(series);
|
|
}
|
|
}
|
|
} else {
|
|
boundSeries = /* @__PURE__ */ new Set([...xAxis?.boundSeries ?? [], ...yAxis?.boundSeries ?? []]);
|
|
}
|
|
return boundSeries;
|
|
}
|
|
constrainZoomToItemCount(zoom, minVisibleItems, shouldAutoscale) {
|
|
let xVisibleRange = [zoom.x.min, zoom.x.max];
|
|
let yVisibleRange = shouldAutoscale ? void 0 : [zoom.y.min, zoom.y.max];
|
|
for (const series of this.getBoundSeries()) {
|
|
const nextZoom = series.getZoomRangeFittingItems(xVisibleRange, yVisibleRange, minVisibleItems);
|
|
if (nextZoom == null)
|
|
continue;
|
|
xVisibleRange = nextZoom.x;
|
|
yVisibleRange = nextZoom.y;
|
|
}
|
|
const x = { min: xVisibleRange[0], max: xVisibleRange[1] };
|
|
const y = yVisibleRange ? { min: yVisibleRange[0], max: yVisibleRange[1] } : void 0;
|
|
return (0, import_ag_charts_core93.definedZoomState)({ x, y });
|
|
}
|
|
isVisibleItemsCountAtLeast(zoom, minVisibleItems, opts) {
|
|
const boundSeries = this.getBoundSeries();
|
|
const xVisibleRange = [zoom.x.min, zoom.x.max];
|
|
const yVisibleRange = !opts.includeYVisibleRange && opts.autoScaleYAxis ? void 0 : [zoom.y.min, zoom.y.max];
|
|
let visibleItemsCount = 0;
|
|
for (const series of boundSeries) {
|
|
const remainingItems = minVisibleItems - (visibleItemsCount ?? 0);
|
|
const seriesVisibleItems = series.getVisibleItems(xVisibleRange, yVisibleRange, remainingItems);
|
|
visibleItemsCount += seriesVisibleItems;
|
|
if (visibleItemsCount >= minVisibleItems)
|
|
return true;
|
|
}
|
|
return boundSeries.size === 0;
|
|
}
|
|
getMementoRanges() {
|
|
const zoom = (0, import_ag_charts_core93.definedZoomState)(this.getZoom());
|
|
const memento = {
|
|
rangeX: this.getRangeDirection(import_ag_charts_core93.ChartAxisDirection.X, zoom.x),
|
|
rangeY: this.getRangeDirection(import_ag_charts_core93.ChartAxisDirection.Y, zoom.y),
|
|
ratioX: { start: zoom.x.min, end: zoom.x.max },
|
|
ratioY: { start: zoom.y.min, end: zoom.y.max },
|
|
autoScaledAxes: void 0
|
|
};
|
|
this.eventsHub.emit("zoom:save-memento", { memento });
|
|
return memento;
|
|
}
|
|
restoreRequiredRange(requiredRangeRatio, requiredRangeDirection) {
|
|
const { lastRestoredRequiredRange, lastRestoredRequiredRangeDirection } = this;
|
|
const directionInvalid = requiredRangeDirection !== import_ag_charts_core93.ChartAxisDirection.X && requiredRangeDirection !== import_ag_charts_core93.ChartAxisDirection.Y;
|
|
const requiredRangeUnchanged = lastRestoredRequiredRangeDirection === requiredRangeDirection && lastRestoredRequiredRange === requiredRangeRatio;
|
|
const requiredRangeUnset = requiredRangeRatio === 0 && (lastRestoredRequiredRange == null || lastRestoredRequiredRange === 0);
|
|
if (directionInvalid || requiredRangeUnchanged || requiredRangeUnset)
|
|
return;
|
|
const crossAxisId = this.getPrimaryAxisId(requiredRangeDirection);
|
|
if (!crossAxisId)
|
|
return;
|
|
const crossAxisZoom = this.getAxisZoom(crossAxisId);
|
|
const requiredZoom = Math.min(1, 1 / requiredRangeRatio);
|
|
let min = 0;
|
|
let max = 1;
|
|
if (requiredRangeDirection === import_ag_charts_core93.ChartAxisDirection.X) {
|
|
min = (0, import_ag_charts_core93.clamp)(0, 1 - requiredZoom, crossAxisZoom.min);
|
|
max = (0, import_ag_charts_core93.clamp)(0, min + requiredZoom, 1);
|
|
} else {
|
|
max = Math.min(1, crossAxisZoom.max);
|
|
min = max - requiredZoom;
|
|
if (min < 0) {
|
|
max -= min;
|
|
min = 0;
|
|
}
|
|
min = (0, import_ag_charts_core93.clamp)(0, min, 1);
|
|
max = (0, import_ag_charts_core93.clamp)(0, max, 1);
|
|
}
|
|
this.lastRestoredRequiredRange = requiredRangeRatio;
|
|
this.lastRestoredRequiredRangeDirection = requiredRangeDirection;
|
|
const zoom = { [requiredRangeDirection]: { min, max } };
|
|
const changes = this.toCoreZoomState(zoom);
|
|
this.lastRestoredState = (0, import_ag_charts_core93.deepFreeze)((0, import_ag_charts_core93.deepClone)(changes));
|
|
this.updateChanges({
|
|
source: "state-change",
|
|
sourceDetail: "internal-requiredWidth",
|
|
changes,
|
|
isReset: false
|
|
});
|
|
}
|
|
constrainZoomToRequiredWidth(event) {
|
|
if (this.lastRestoredRequiredRange == null || this.lastRestoredRequiredRangeDirection == null)
|
|
return;
|
|
const axis = this.lastRestoredRequiredRangeDirection;
|
|
const crossAxisId = this.getPrimaryAxisId(this.lastRestoredRequiredRangeDirection);
|
|
if (!crossAxisId)
|
|
return;
|
|
const zoom = event.stateAsDefinedZoom();
|
|
const oldState = event.oldState[crossAxisId];
|
|
const delta3 = zoom[axis].max - zoom[axis].min;
|
|
const minDelta = 1 / this.lastRestoredRequiredRange;
|
|
if (delta3 <= minDelta)
|
|
return;
|
|
event.constrainZoom({
|
|
...zoom,
|
|
[axis]: { min: oldState.min, max: oldState.min + minDelta }
|
|
});
|
|
}
|
|
dispatch(source, sourceDetail, changedAxes, isReset, oldState) {
|
|
const { x, y } = this.getZoom() ?? {};
|
|
const state = this.state;
|
|
let constrainedState;
|
|
const zoomManager = this;
|
|
const event = {
|
|
source,
|
|
sourceDetail,
|
|
isReset,
|
|
changedAxes,
|
|
state,
|
|
oldState,
|
|
x,
|
|
y,
|
|
stateAsDefinedZoom() {
|
|
return (0, import_ag_charts_core93.definedZoomState)(zoomManager.toZoomState(event.state));
|
|
},
|
|
constrainZoom(restrictions) {
|
|
this.constrainChanges(zoomManager.toCoreZoomState(restrictions));
|
|
},
|
|
constrainChanges(restrictions) {
|
|
constrainedState ?? (constrainedState = (0, import_ag_charts_core93.deepClone)(state));
|
|
for (const id of (0, import_ag_charts_core93.strictObjectKeys)(restrictions)) {
|
|
const src = restrictions[id];
|
|
const dst = constrainedState[id];
|
|
if (src && dst) {
|
|
dst.min = src.min;
|
|
dst.max = src.max;
|
|
}
|
|
}
|
|
event.state = constrainedState;
|
|
}
|
|
};
|
|
this.eventsHub.emit("zoom:change-request", event);
|
|
let wasChangeConstrained = false;
|
|
if (constrainedState && !areEqualCoreZooms(state, constrainedState)) {
|
|
wasChangeConstrained = true;
|
|
this.state = constrainedState;
|
|
}
|
|
const changeAccepted = changedAxes.length > 0 || wasChangeConstrained;
|
|
if (changeAccepted) {
|
|
const acceptedZoom = this.getZoom() ?? {};
|
|
this.eventsHub.emit("zoom:change-complete", { source, sourceDetail, x: acceptedZoom.x });
|
|
this.pendingZoomEventSource = source;
|
|
}
|
|
return changeAccepted;
|
|
}
|
|
getRange(axisId, ratio10) {
|
|
return this.getRangeAxis(this.findAxis(axisId), ratio10);
|
|
}
|
|
getRangeDirection(direction, ratio10) {
|
|
return this.getRangeAxis(this.getPrimaryAxis(direction), ratio10);
|
|
}
|
|
getRangeAxis(axis, ratio10) {
|
|
if (!axis || !ratio10 || !ContinuousScale.is(axis.scale) && !DiscreteTimeScale.is(axis.scale))
|
|
return;
|
|
const extents = this.getDomainPixelExtents(axis);
|
|
if (!extents)
|
|
return;
|
|
const [d0, d1] = extents;
|
|
let start;
|
|
let end2;
|
|
if (d0 <= d1) {
|
|
start = axis.scale.invert(0);
|
|
end2 = axis.scale.invert(d0 + (d1 - d0) * ratio10.max);
|
|
} else {
|
|
start = axis.scale.invert(d0 - (d0 - d1) * ratio10.min);
|
|
end2 = axis.scale.invert(0);
|
|
}
|
|
return { start, end: end2 };
|
|
}
|
|
rangeToRatio(axisId, range4) {
|
|
return this.rangeToRatioAxis(this.findAxis(axisId), range4);
|
|
}
|
|
rangeToRatioDirection(direction, range4) {
|
|
return this.rangeToRatioAxis(this.getPrimaryAxis(direction), range4);
|
|
}
|
|
rangeToRatioAxis(axis, range4) {
|
|
if (!axis)
|
|
return;
|
|
const extents = this.getDomainPixelExtents(axis);
|
|
if (!extents)
|
|
return;
|
|
const [d0, d1] = extents;
|
|
const { scale: scale2 } = axis;
|
|
const { start, end: end2 } = range4;
|
|
const [startAlignment = import_ag_charts_core93.ScaleAlignment.Leading, endAlignment = import_ag_charts_core93.ScaleAlignment.Trailing] = rangeAlignment(
|
|
start,
|
|
end2
|
|
);
|
|
const r0 = start == null ? d0 : scale2.convert(start, { alignment: startAlignment });
|
|
const r1 = end2 == null ? d1 : scale2.convert(end2, { alignment: endAlignment }) + (scale2.bandwidth ?? 0);
|
|
if (!(0, import_ag_charts_core93.isFiniteNumber)(r0) || !(0, import_ag_charts_core93.isFiniteNumber)(r1))
|
|
return;
|
|
const [dMin, dMax] = [Math.min(d0, d1), Math.max(d0, d1)];
|
|
if (r0 < dMin || r0 > dMax) {
|
|
import_ag_charts_core93.Logger.warnOnce(
|
|
`Invalid range start [${start}], expecting a value between [${scale2.invert(d0)}] and [${scale2.invert(d1)}], ignoring.`
|
|
);
|
|
return;
|
|
}
|
|
if (r1 < dMin || r1 > dMax) {
|
|
import_ag_charts_core93.Logger.warnOnce(
|
|
`Invalid range end [${end2}], expecting a value between [${scale2.invert(d0)}] and [${scale2.invert(d1)}], ignoring.`
|
|
);
|
|
return;
|
|
}
|
|
const diff2 = d1 - d0;
|
|
if (diff2 === 0)
|
|
return;
|
|
const min = Math.abs((r0 - d0) / diff2);
|
|
const max = Math.abs((r1 - d0) / diff2);
|
|
if (min >= max)
|
|
return;
|
|
return { min, max };
|
|
}
|
|
getPrimaryAxis(direction) {
|
|
return this.axes?.find((a) => a.direction === direction);
|
|
}
|
|
getDomainExtents(axis) {
|
|
const { domain } = axis.scale;
|
|
const d0 = domain.at(0);
|
|
const d1 = domain.at(-1);
|
|
if (d0 == null || d1 == null)
|
|
return;
|
|
return [d0, d1];
|
|
}
|
|
getDomainPixelExtents(axis) {
|
|
const [d0, d1] = axis.scale.range;
|
|
if (!(0, import_ag_charts_core93.isFiniteNumber)(d0) || !(0, import_ag_charts_core93.isFiniteNumber)(d1))
|
|
return;
|
|
return [d0, d1];
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/layout/layoutManager.ts
|
|
var LayoutElement = /* @__PURE__ */ ((LayoutElement2) => {
|
|
LayoutElement2[LayoutElement2["Caption"] = 0] = "Caption";
|
|
LayoutElement2[LayoutElement2["Legend"] = 1] = "Legend";
|
|
LayoutElement2[LayoutElement2["ToolbarLeft"] = 2] = "ToolbarLeft";
|
|
LayoutElement2[LayoutElement2["ToolbarBottom"] = 3] = "ToolbarBottom";
|
|
LayoutElement2[LayoutElement2["Scrollbar"] = 4] = "Scrollbar";
|
|
LayoutElement2[LayoutElement2["Navigator"] = 5] = "Navigator";
|
|
LayoutElement2[LayoutElement2["Overlay"] = 6] = "Overlay";
|
|
return LayoutElement2;
|
|
})(LayoutElement || {});
|
|
var LayoutManager = class {
|
|
constructor(eventsHub) {
|
|
this.eventsHub = eventsHub;
|
|
this.elements = /* @__PURE__ */ new Map();
|
|
}
|
|
registerElement(element2, listener) {
|
|
if (this.elements.has(element2)) {
|
|
this.elements.get(element2).add(listener);
|
|
} else {
|
|
this.elements.set(element2, /* @__PURE__ */ new Set([listener]));
|
|
}
|
|
return () => this.elements.get(element2)?.delete(listener);
|
|
}
|
|
createContext(width, height) {
|
|
const context = { width, height, layoutBox: new BBox(0, 0, width, height), scrollbars: {} };
|
|
for (const element2 of Object.values(LayoutElement)) {
|
|
if (typeof element2 !== "number")
|
|
continue;
|
|
const listeners = this.elements.get(element2);
|
|
if (listeners) {
|
|
for (const listener of listeners) {
|
|
listener(context);
|
|
}
|
|
}
|
|
}
|
|
return context;
|
|
}
|
|
emitLayoutComplete({ width, height }, options) {
|
|
this.eventsHub.emit("layout:complete", {
|
|
axes: options.axes ?? {},
|
|
chart: { width, height },
|
|
clipSeries: options.clipSeries ?? false,
|
|
series: options.series
|
|
});
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/layout/seriesLabelLayoutManager.ts
|
|
var import_ag_charts_core94 = require("ag-charts-core");
|
|
var SeriesLabelLayoutManager = class {
|
|
constructor() {
|
|
this.labelData = /* @__PURE__ */ new Map();
|
|
}
|
|
updateLabels(placedLabelSeries, padding2, seriesRect = BBox.zero) {
|
|
const bounds = {
|
|
x: -padding2.left,
|
|
y: -padding2.top,
|
|
width: seriesRect.width + padding2.left + padding2.right,
|
|
height: seriesRect.height + padding2.top + padding2.bottom
|
|
};
|
|
const expectedSeriesId = new Set(placedLabelSeries.map((s) => s.id));
|
|
for (const seriesId of this.labelData.keys()) {
|
|
if (!expectedSeriesId.has(seriesId)) {
|
|
this.labelData.delete(seriesId);
|
|
}
|
|
}
|
|
for (const series of placedLabelSeries) {
|
|
const labelData = series.getLabelData();
|
|
if (labelData.every(import_ag_charts_core94.isPointLabelDatum)) {
|
|
this.labelData.set(series.id, labelData);
|
|
}
|
|
}
|
|
const placedLabels = (0, import_ag_charts_core94.placeLabels)(this.labelData, bounds, 5);
|
|
for (const series of placedLabelSeries) {
|
|
series.updatePlacedLabelData?.(placedLabels.get(series.id) ?? []);
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/legend/legendManager.ts
|
|
var import_ag_charts_core95 = require("ag-charts-core");
|
|
var LegendManager = class {
|
|
constructor(eventsHub) {
|
|
this.eventsHub = eventsHub;
|
|
this.mementoOriginatorKey = "legend";
|
|
this.legendDataMap = /* @__PURE__ */ new Map();
|
|
}
|
|
createMemento() {
|
|
return this.getData().filter(({ hideInLegend, isFixed }) => !hideInLegend && !isFixed).map(({ enabled, seriesId, itemId, legendItemName }) => ({
|
|
visible: enabled,
|
|
seriesId,
|
|
itemId,
|
|
legendItemName
|
|
}));
|
|
}
|
|
guardMemento(blob) {
|
|
return blob == null || (0, import_ag_charts_core95.isArray)(blob);
|
|
}
|
|
restoreMemento(_version, _mementoVersion, memento) {
|
|
if (memento) {
|
|
for (const datum of memento) {
|
|
const { seriesId, data } = this.getRestoredData(datum) ?? {};
|
|
if (!seriesId || !data) {
|
|
continue;
|
|
}
|
|
this.updateData(seriesId, data);
|
|
}
|
|
}
|
|
this.update();
|
|
}
|
|
getRestoredData(datum) {
|
|
const { seriesId, itemId, legendItemName, visible } = datum;
|
|
if (seriesId) {
|
|
const legendData = this.legendDataMap.get(seriesId) ?? [];
|
|
const data = legendData.map((d) => {
|
|
const match = d.seriesId === seriesId && (!itemId || d.itemId === itemId);
|
|
if (match && d.isFixed) {
|
|
this.warnFixed(d.seriesId, d.itemId);
|
|
}
|
|
return !d.isFixed && match ? { ...d, enabled: visible } : d;
|
|
});
|
|
return { seriesId, data };
|
|
}
|
|
if (itemId == null && legendItemName == null) {
|
|
return;
|
|
}
|
|
for (const legendDatum of this.getData()) {
|
|
if (itemId != null && legendDatum.itemId !== itemId || legendItemName != null && legendDatum.legendItemName !== legendItemName) {
|
|
continue;
|
|
}
|
|
if (legendDatum.isFixed) {
|
|
this.warnFixed(legendDatum.seriesId, itemId);
|
|
return;
|
|
}
|
|
const seriesLegendData = (this.legendDataMap.get(legendDatum.seriesId) ?? []).map(
|
|
(d) => d.itemId === itemId || d.legendItemName === legendItemName ? { ...d, enabled: visible } : d
|
|
);
|
|
return {
|
|
seriesId: legendDatum.seriesId,
|
|
data: seriesLegendData
|
|
};
|
|
}
|
|
}
|
|
warnFixed(seriesId, itemId) {
|
|
import_ag_charts_core95.Logger.warnOnce(
|
|
`The legend item with seriesId [${seriesId}] and itemId [${itemId}] is not configurable, this series item cannot be toggled through the legend.`
|
|
);
|
|
}
|
|
update(data) {
|
|
this.eventsHub.emit("legend:change", {
|
|
legendData: data ?? this.getData()
|
|
});
|
|
}
|
|
updateData(seriesId, data = []) {
|
|
this.eventsHub.emit("legend:change-partial", { seriesId, legendData: data });
|
|
this.legendDataMap.set(seriesId, data);
|
|
}
|
|
clearData() {
|
|
this.legendDataMap.clear();
|
|
}
|
|
toggleItem(enabled, seriesId, itemId, legendItemName) {
|
|
if (legendItemName) {
|
|
for (const datum of this.getData()) {
|
|
const newData = (this.legendDataMap.get(datum.seriesId) ?? []).map(
|
|
(d) => d.legendItemName === legendItemName ? { ...d, enabled } : d
|
|
);
|
|
this.updateData(datum.seriesId, newData);
|
|
}
|
|
return;
|
|
}
|
|
const seriesLegendData = this.getData(seriesId);
|
|
const singleLegendItem = seriesLegendData.length === 1;
|
|
const data = seriesLegendData.map(
|
|
(datum) => itemId == null && singleLegendItem || datum.itemId === itemId ? { ...datum, enabled } : datum
|
|
);
|
|
this.updateData(seriesId, data);
|
|
}
|
|
getData(seriesId) {
|
|
if (seriesId) {
|
|
return this.legendDataMap.get(seriesId) ?? [];
|
|
}
|
|
return [...this.legendDataMap].reduce(
|
|
(data, [_, legendData]) => data.concat(legendData),
|
|
[]
|
|
);
|
|
}
|
|
getDatum({ seriesId, itemId } = {}) {
|
|
return this.getData(seriesId).find((datum) => datum.itemId === itemId);
|
|
}
|
|
getSeriesEnabled(seriesId) {
|
|
const data = this.getData(seriesId);
|
|
if (data.length > 0) {
|
|
return data.some((d) => d.enabled);
|
|
}
|
|
}
|
|
getItemEnabled({ seriesId, itemId } = {}) {
|
|
return this.getDatum({ seriesId, itemId })?.enabled ?? true;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/optionsGraphService.ts
|
|
var OptionsGraphService = class {
|
|
updateCallback(resolvePartialCallback) {
|
|
this.resolvePartialCallback = resolvePartialCallback;
|
|
}
|
|
resolvePartial(path, partialOptions, resolveOptions) {
|
|
return this.resolvePartialCallback?.(path, partialOptions, resolveOptions);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scale/irregularBandScale.ts
|
|
var import_ag_charts_core96 = require("ag-charts-core");
|
|
var IrregularBandScale = class extends BandScale {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "category";
|
|
// TODO: 'irregular-band'?
|
|
this.defaultTickCount = 0;
|
|
this._hasFixedWidth = false;
|
|
this._paddingInnerWidth = 0;
|
|
this._domain = [];
|
|
this._bandRanges = /* @__PURE__ */ new Map();
|
|
}
|
|
set domain(values) {
|
|
if (this._domain === values)
|
|
return;
|
|
if (values.length === 0) {
|
|
this._bandRanges.clear();
|
|
this._hasFixedWidth = false;
|
|
}
|
|
this.invalid = true;
|
|
this._domain = values;
|
|
}
|
|
get domain() {
|
|
return this._domain;
|
|
}
|
|
get bands() {
|
|
return this.domain;
|
|
}
|
|
addBand(groupIndex, stackIndex, value) {
|
|
this._domain.push(this.getDomainValue(groupIndex, stackIndex));
|
|
if (!this._bandRanges.has(groupIndex)) {
|
|
this._bandRanges.set(groupIndex, /* @__PURE__ */ new Map());
|
|
}
|
|
this._bandRanges.get(groupIndex).set(stackIndex, value);
|
|
this._hasFixedWidth || (this._hasFixedWidth = value != null);
|
|
this.invalid = true;
|
|
}
|
|
getDomainValue(groupIndex, stackIndex) {
|
|
return `${groupIndex}-${stackIndex}`;
|
|
}
|
|
findIndex(value) {
|
|
let index = 0;
|
|
for (const key of this._bandRanges.keys()) {
|
|
if (key === value)
|
|
return index;
|
|
index++;
|
|
}
|
|
}
|
|
convert(domainValue) {
|
|
const { _bandwidth, _bandRanges, _inset, _paddingInnerWidth } = this;
|
|
let value = _inset;
|
|
const valueDs = domainValue.split("-");
|
|
const valueGroupIndex = Number(valueDs[0]);
|
|
if (!this._hasFixedWidth) {
|
|
return super.convert(valueGroupIndex);
|
|
}
|
|
for (let i = 0; i < valueGroupIndex; i++) {
|
|
const stacks = _bandRanges.get(i);
|
|
if (!stacks) {
|
|
value += _paddingInnerWidth;
|
|
continue;
|
|
}
|
|
let maxStackWidth = 0;
|
|
for (const width of stacks.values()) {
|
|
maxStackWidth = Math.max(maxStackWidth, width == null ? _bandwidth : width);
|
|
}
|
|
value += maxStackWidth + _paddingInnerWidth;
|
|
}
|
|
return value;
|
|
}
|
|
invert(_value, _nearest) {
|
|
return;
|
|
}
|
|
getBandCountForUpdate() {
|
|
return this._bandRanges.size;
|
|
}
|
|
update() {
|
|
if (!this._hasFixedWidth) {
|
|
return super.update();
|
|
}
|
|
const [r0, r1] = this.range;
|
|
let { paddingInner } = this;
|
|
const bandCount = this.getBandCountForUpdate();
|
|
if (bandCount === 0)
|
|
return;
|
|
let totalBandRange = 0;
|
|
let bandCountWithUnfixedWidths = bandCount;
|
|
let bandCountWithOnlyFixedWidths = bandCount;
|
|
for (const stacks of this._bandRanges.values()) {
|
|
let maxStackWidth = 0;
|
|
let hasUnfixed = false;
|
|
for (const width of stacks.values()) {
|
|
if (width == null) {
|
|
hasUnfixed = true;
|
|
continue;
|
|
}
|
|
maxStackWidth = Math.max(maxStackWidth, width);
|
|
}
|
|
if (hasUnfixed) {
|
|
bandCountWithOnlyFixedWidths -= 1;
|
|
} else {
|
|
bandCountWithUnfixedWidths -= 1;
|
|
totalBandRange += maxStackWidth;
|
|
}
|
|
}
|
|
if (bandCount === 1) {
|
|
paddingInner = 0;
|
|
}
|
|
const targetRangeDistance = r1 - r0;
|
|
const paddingInnerWidth = targetRangeDistance / bandCount * paddingInner;
|
|
const actualRangeDistance = totalBandRange + paddingInnerWidth * (bandCount - 1);
|
|
const rangeDiff = targetRangeDistance - actualRangeDistance;
|
|
let inset = r0;
|
|
let rawBandwidth = bandCountWithUnfixedWidths > 0 && rangeDiff >= 0 ? rangeDiff / bandCountWithUnfixedWidths : targetRangeDistance / bandCount;
|
|
let bandwidth = rawBandwidth;
|
|
if (bandCountWithOnlyFixedWidths === bandCount && rangeDiff > 0) {
|
|
inset += rangeDiff / 2;
|
|
}
|
|
const round = this.round && Math.floor(bandwidth) > 0;
|
|
if (round) {
|
|
inset = Math.round(inset);
|
|
bandwidth = Math.round(bandwidth);
|
|
}
|
|
if (rangeDiff < 0) {
|
|
rawBandwidth = 0;
|
|
bandwidth = 0;
|
|
}
|
|
this._inset = inset;
|
|
this._bandwidth = bandwidth;
|
|
this._rawBandwidth = rawBandwidth;
|
|
this._paddingInnerWidth = paddingInnerWidth;
|
|
}
|
|
normalizeDomains(..._domains) {
|
|
return { domain: [], animatable: false };
|
|
}
|
|
toDomain(_value) {
|
|
return void 0;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/seriesStateManager.ts
|
|
var SeriesStateManager = class {
|
|
constructor() {
|
|
this.groups = /* @__PURE__ */ new Map();
|
|
this.groupScales = /* @__PURE__ */ new Map();
|
|
}
|
|
registerSeries({ internalId, seriesGrouping, visible, width, type }) {
|
|
if (!seriesGrouping)
|
|
return;
|
|
let group = this.groups.get(type);
|
|
if (group == null) {
|
|
group = /* @__PURE__ */ new Map();
|
|
this.groups.set(type, group);
|
|
}
|
|
group.set(internalId, { grouping: seriesGrouping, visible, width });
|
|
}
|
|
updateSeries({ internalId, seriesGrouping, visible, width, type }) {
|
|
if (!seriesGrouping)
|
|
return;
|
|
const entry = this.groups.get(type)?.get(internalId);
|
|
if (entry) {
|
|
entry.grouping = seriesGrouping;
|
|
entry.width = width;
|
|
entry.visible = visible;
|
|
}
|
|
}
|
|
deregisterSeries({ internalId, type }) {
|
|
const group = this.groups.get(type);
|
|
if (group == null)
|
|
return;
|
|
group.delete(internalId);
|
|
if (group.size === 0) {
|
|
this.groups.delete(type);
|
|
}
|
|
}
|
|
getVisiblePeerGroupIndex({ type, seriesGrouping, visible }) {
|
|
if (!seriesGrouping) {
|
|
return { visibleGroupCount: visible ? 1 : 0, visibleSameStackCount: visible ? 1 : 0, index: 0 };
|
|
}
|
|
const visibleGroupsSet = /* @__PURE__ */ new Set();
|
|
const visibleSameStackSet = /* @__PURE__ */ new Set();
|
|
const group = this.groups.get(type);
|
|
for (const entry of group?.values() ?? []) {
|
|
if (!entry.visible)
|
|
continue;
|
|
visibleGroupsSet.add(entry.grouping.groupIndex);
|
|
if (entry.grouping.groupIndex === seriesGrouping.groupIndex) {
|
|
visibleSameStackSet.add(entry.grouping.stackIndex);
|
|
}
|
|
}
|
|
const visibleGroups = Array.from(visibleGroupsSet);
|
|
visibleGroups.sort((a, b) => a - b);
|
|
return {
|
|
visibleGroupCount: visibleGroups.length,
|
|
visibleSameStackCount: visibleSameStackSet.size,
|
|
index: visibleGroups.indexOf(seriesGrouping.groupIndex)
|
|
};
|
|
}
|
|
updateGroupScale({ type }, bandwidth, axis) {
|
|
const groupScale = this.groupScales.get(type) ?? new IrregularBandScale();
|
|
this.groupScales.set(type, groupScale);
|
|
groupScale.domain = [];
|
|
const group = this.groups.get(type);
|
|
for (const entry of group?.values() ?? []) {
|
|
if (!entry.visible)
|
|
continue;
|
|
groupScale.addBand(entry.grouping.groupIndex, entry.grouping.stackIndex, entry.width);
|
|
}
|
|
if (groupScale.domain.length === 0) {
|
|
groupScale.addBand(0, 0, void 0);
|
|
}
|
|
groupScale.range = [0, bandwidth];
|
|
if (axis.type === "grouped-category") {
|
|
groupScale.paddingInner = axis.groupPaddingInner;
|
|
} else if (axis.type === "category" || axis.type === "unit-time") {
|
|
groupScale.paddingInner = axis.groupPaddingInner;
|
|
groupScale.round = groupScale.padding !== 0;
|
|
} else {
|
|
groupScale.padding = 0;
|
|
}
|
|
groupScale.update();
|
|
}
|
|
getGroupScale({ type }) {
|
|
return this.groupScales.get(type);
|
|
}
|
|
getGroupOffset(series) {
|
|
const { seriesGrouping } = series;
|
|
if (!seriesGrouping)
|
|
return 0;
|
|
const groupScale = this.getGroupScale(series);
|
|
if (!groupScale)
|
|
return 0;
|
|
const domainValue = groupScale.getDomainValue(seriesGrouping.groupIndex, seriesGrouping.stackIndex);
|
|
return groupScale.convert(domainValue);
|
|
}
|
|
getStackOffset(series, barWidth) {
|
|
const { seriesGrouping } = series;
|
|
if (!seriesGrouping)
|
|
return 0;
|
|
const group = this.groups.get(series.type);
|
|
if (!group)
|
|
return 0;
|
|
const scale2 = this.getGroupScale(series);
|
|
if (!scale2)
|
|
return 0;
|
|
const stackCount = seriesGrouping.stackCount ?? 0;
|
|
if (stackCount < 1)
|
|
return 0;
|
|
let maxStackWidth = 0;
|
|
for (const entry of group.values()) {
|
|
if (!entry.visible)
|
|
continue;
|
|
if (entry.grouping.groupIndex !== seriesGrouping.groupIndex)
|
|
continue;
|
|
maxStackWidth = Math.max(maxStackWidth, entry.width ?? scale2.bandwidth);
|
|
}
|
|
if (maxStackWidth === 0)
|
|
return 0;
|
|
return maxStackWidth / 2 - barWidth / 2;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/updateService.ts
|
|
var import_ag_charts_core97 = require("ag-charts-core");
|
|
var UpdateService = class {
|
|
constructor(updateCallback) {
|
|
this.updateCallback = updateCallback;
|
|
this.events = new import_ag_charts_core97.EventEmitter();
|
|
}
|
|
addListener(eventName, listener) {
|
|
return this.events.on(eventName, listener);
|
|
}
|
|
destroy() {
|
|
this.events.clear();
|
|
}
|
|
update(type = import_ag_charts_core97.ChartUpdateType.FULL, options) {
|
|
this.updateCallback(type, options);
|
|
}
|
|
dispatchUpdateComplete(apiUpdate, wasShortcut) {
|
|
this.events.emit("update-complete", { type: "update-complete", apiUpdate, wasShortcut });
|
|
}
|
|
dispatchPreDomUpdate() {
|
|
this.events.emit("pre-dom-update", { type: "pre-dom-update" });
|
|
}
|
|
dispatchPreSeriesUpdate(requiredRangeRatio, requiredRangeDirection) {
|
|
this.events.emit("pre-series-update", {
|
|
type: "pre-series-update",
|
|
requiredRangeRatio,
|
|
requiredRangeDirection
|
|
});
|
|
}
|
|
dispatchPreSceneRender() {
|
|
this.events.emit("pre-scene-render", { type: "pre-scene-render" });
|
|
}
|
|
dispatchProcessData({ series }) {
|
|
this.events.emit("process-data", { type: "process-data", series });
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/chartContext.ts
|
|
var ChartContext = class {
|
|
constructor(chart, vars) {
|
|
this.eventsHub = new import_ag_charts_core98.EventEmitter();
|
|
this.callbackCache = new import_ag_charts_core98.CallbackCache();
|
|
this.highlightManager = new HighlightManager(this.eventsHub);
|
|
this.formatManager = new FormatManager();
|
|
this.layoutManager = new LayoutManager(this.eventsHub);
|
|
this.localeManager = new LocaleManager(this.eventsHub);
|
|
this.seriesStateManager = new SeriesStateManager();
|
|
this.stateManager = new StateManager();
|
|
this.seriesLabelLayoutManager = new SeriesLabelLayoutManager();
|
|
this.cleanup = new import_ag_charts_core98.CleanupRegistry();
|
|
const {
|
|
scene,
|
|
root,
|
|
syncManager,
|
|
container,
|
|
fireEvent,
|
|
updateCallback,
|
|
updateMutex,
|
|
styleContainer,
|
|
skipCss,
|
|
chartType,
|
|
domMode,
|
|
withDragInterpretation
|
|
} = vars;
|
|
this.chartService = chart;
|
|
this.syncManager = syncManager;
|
|
this.domManager = new DOMManager(
|
|
this.eventsHub,
|
|
this.chartService,
|
|
container,
|
|
styleContainer,
|
|
skipCss,
|
|
domMode
|
|
);
|
|
this.widgets = new WidgetSet(this.domManager, { withDragInterpretation });
|
|
const canvasElement = this.domManager.addChild(
|
|
"canvas",
|
|
"scene-canvas",
|
|
scene?.canvas.element
|
|
);
|
|
this.scene = scene ?? new Scene({ canvasElement });
|
|
this.scene.setRoot(root);
|
|
this.cleanup.register(
|
|
this.scene.on("scene-changed", () => {
|
|
this.updateService.update(import_ag_charts_core98.ChartUpdateType.SCENE_RENDER);
|
|
})
|
|
);
|
|
this.axisManager = new AxisManager(this.eventsHub, root);
|
|
this.legendManager = new LegendManager(this.eventsHub);
|
|
this.annotationManager = new AnnotationManager(this.eventsHub, chart.annotationRoot, fireEvent);
|
|
this.chartTypeOriginator = new ChartTypeOriginator(chart);
|
|
this.interactionManager = new InteractionManager();
|
|
this.contextMenuRegistry = new ContextMenuRegistry(this.eventsHub);
|
|
this.optionsGraphService = new OptionsGraphService();
|
|
this.updateService = new UpdateService(updateCallback);
|
|
this.activeManager = new ActiveManager(
|
|
this.chartService,
|
|
this.eventsHub,
|
|
this.updateService,
|
|
this.interactionManager,
|
|
fireEvent
|
|
);
|
|
this.proxyInteractionService = new ProxyInteractionService(this.eventsHub, this.localeManager, this.domManager);
|
|
this.fontManager = new FontManager(this.domManager, this.updateService);
|
|
this.historyManager = new HistoryManager(this.eventsHub);
|
|
this.animationManager = new AnimationManager(this.interactionManager, updateMutex);
|
|
this.dataService = new DataService(this.eventsHub, chart, this.animationManager);
|
|
this.tooltipManager = new TooltipManager(this.eventsHub, this.localeManager, this.domManager, chart.tooltip);
|
|
this.zoomManager = new ZoomManager(this.eventsHub, this.updateService, fireEvent);
|
|
for (const module2 of import_ag_charts_core98.ModuleRegistry.listModulesByType(import_ag_charts_core98.ModuleType.Plugin)) {
|
|
if (!module2.chartType || module2.chartType === chartType) {
|
|
module2.patchContext?.(this);
|
|
}
|
|
}
|
|
}
|
|
destroy() {
|
|
this.animationManager.destroy();
|
|
this.axisManager.destroy();
|
|
this.callbackCache.invalidateCache();
|
|
this.domManager.destroy();
|
|
this.fontManager.destroy();
|
|
this.proxyInteractionService.destroy();
|
|
this.tooltipManager.destroy();
|
|
this.zoomManager.destroy();
|
|
this.widgets.destroy();
|
|
this.cleanup.flush();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/chartHighlight.ts
|
|
var import_ag_charts_core99 = require("ag-charts-core");
|
|
var ChartHighlight = class extends import_ag_charts_core99.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.range = "tooltip";
|
|
this.drawingMode = "cutout";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core99.Property
|
|
], ChartHighlight.prototype, "range", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core99.Property
|
|
], ChartHighlight.prototype, "drawingMode", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/data/caching.ts
|
|
var import_ag_charts_core100 = require("ag-charts-core");
|
|
function setsEqual(a, b) {
|
|
if (a.size !== b.size)
|
|
return false;
|
|
for (const value of a) {
|
|
if (!b.has(value))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function idsMapEqual(a, b) {
|
|
if (a == null || b == null)
|
|
return a === b;
|
|
if (a.size !== b.size)
|
|
return false;
|
|
for (const [key, aValue] of a) {
|
|
const bValue = b.get(key);
|
|
if (bValue == null)
|
|
return false;
|
|
if (!setsEqual(aValue, bValue))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function propsEqual(a, b) {
|
|
if (a.length !== b.length)
|
|
return false;
|
|
for (let i = 0; i < a.length; i += 1) {
|
|
const { type: typeA, idsMap: idsMapA, scopes: scopesA, data: dataA, ...propA } = a[i];
|
|
const { type: typeB, idsMap: idsMapB, scopes: scopesB, data: dataB, ...propB } = b[i];
|
|
if (typeA !== typeB)
|
|
return false;
|
|
if (scopesA && scopesB && !(0, import_ag_charts_core100.arraysEqual)(scopesA, scopesB))
|
|
return false;
|
|
if (dataA && dataB && dataA !== dataB)
|
|
return false;
|
|
if (!(0, import_ag_charts_core100.objectsEqual)(propA, propB) || !idsMapEqual(idsMapA, idsMapB))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function optsEqual(a, b) {
|
|
const { props: propsA, ...restA } = a;
|
|
const { props: propsB, ...restB } = b;
|
|
return (0, import_ag_charts_core100.objectsEqual)(restA, restB) && propsEqual(propsA, propsB);
|
|
}
|
|
function canReuseCachedData(cachedDataItem, dataSet, ids, opts) {
|
|
if (dataSet !== cachedDataItem.dataSet) {
|
|
return false;
|
|
}
|
|
return (0, import_ag_charts_core100.arraysEqual)(ids, cachedDataItem.ids) && optsEqual(opts, cachedDataItem.opts);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/data/dataController.ts
|
|
var import_ag_charts_core101 = require("ag-charts-core");
|
|
function getPropertyKeys(props) {
|
|
return props.filter((p) => p.type === "key").map((p) => p.property).join(";");
|
|
}
|
|
var _DataController = class _DataController {
|
|
constructor(mode, suppressFieldDotNotation, eventsHub) {
|
|
this.mode = mode;
|
|
this.suppressFieldDotNotation = suppressFieldDotNotation;
|
|
this.eventsHub = eventsHub;
|
|
this.debug = import_ag_charts_core101.Debug.create(true, "data-model");
|
|
this.requested = [];
|
|
this.status = "setup";
|
|
}
|
|
async request(id, dataSet, opts) {
|
|
if (this.status !== "setup") {
|
|
throw new Error(`AG Charts - data request after data setup phase.`);
|
|
}
|
|
return new Promise((resolve, reject) => {
|
|
this.requested.push({ id, opts, dataSet, resolve, reject });
|
|
});
|
|
}
|
|
execute(cachedData) {
|
|
if (this.status !== "setup") {
|
|
throw new Error(`AG Charts - data request after data setup phase.`);
|
|
}
|
|
this.status = "executed";
|
|
const dataSets = /* @__PURE__ */ new Map();
|
|
for (const request of this.requested) {
|
|
if (request.dataSet.hasPendingTransactions()) {
|
|
dataSets.set(request.dataSet, request.dataSet.getChangeDescription());
|
|
}
|
|
request.dataSet.commitPendingTransactions();
|
|
}
|
|
this.debug("DataController.execute() - requested", this.requested);
|
|
const valid = this.validateRequests(this.requested);
|
|
this.debug("DataController.execute() - validated", valid);
|
|
const merged = this.mergeRequested(valid);
|
|
this.debug("DataController.execute() - merged", merged);
|
|
if (this.debug.check()) {
|
|
(0, import_ag_charts_core101.getWindow)().processedData = [];
|
|
}
|
|
const nextCachedData = [];
|
|
for (const { dataSet, ids, opts, resolves, rejects } of merged) {
|
|
let cachePredicateFn2 = function(cacheItem) {
|
|
return canReuseCachedData(cacheItem, dataSet, ids, opts);
|
|
};
|
|
var cachePredicateFn = cachePredicateFn2;
|
|
const reusableCache = cachedData?.find(cachePredicateFn2);
|
|
const resolveResult = (dataModel2, processedData2) => {
|
|
if (this.debug.check()) {
|
|
(0, import_ag_charts_core101.getWindow)("processedData").push(processedData2);
|
|
}
|
|
if (processedData2 == null) {
|
|
for (const cb of rejects) {
|
|
cb(new Error(`AG Charts - no processed data generated`));
|
|
}
|
|
return;
|
|
}
|
|
nextCachedData.push({ opts, dataSet, dataLength: dataSet.data.length, ids, dataModel: dataModel2, processedData: processedData2 });
|
|
for (const resolve of resolves) {
|
|
resolve({ dataModel: dataModel2, processedData: processedData2 });
|
|
}
|
|
};
|
|
const fullReprocess = () => {
|
|
try {
|
|
const dataModel2 = new DataModel(
|
|
opts,
|
|
this.mode,
|
|
this.suppressFieldDotNotation,
|
|
this.eventsHub
|
|
);
|
|
const sources = new Map(valid.map((v) => [v.id, v.dataSet]));
|
|
const processedData2 = dataModel2.processData(sources);
|
|
resolveResult(dataModel2, processedData2);
|
|
return dataModel2;
|
|
} catch (error) {
|
|
for (const cb of rejects) {
|
|
cb(error);
|
|
}
|
|
}
|
|
};
|
|
if (reusableCache == null) {
|
|
fullReprocess();
|
|
continue;
|
|
}
|
|
const { dataModel, processedData } = reusableCache;
|
|
const changeDescription = dataSets.get(dataSet);
|
|
if (processedData && changeDescription && dataModel.isReprocessingSupported(processedData)) {
|
|
this.debug("DataController.execute() - reprocessing data", processedData, dataSet);
|
|
dataModel.reprocessData(processedData, dataSets);
|
|
if (import_ag_charts_core101.Debug.check("data-model:reprocess-diff")) {
|
|
const baselineModel = new DataModel(
|
|
opts,
|
|
this.mode,
|
|
this.suppressFieldDotNotation,
|
|
this.eventsHub
|
|
);
|
|
const sources = new Map(valid.map((v) => [v.id, v.dataSet]));
|
|
const baselineData = baselineModel.processData(sources);
|
|
const reprocessedJson = JSON.parse(JSON.stringify(processedData, _DataController.jsonReplacer));
|
|
const baselineJson = JSON.parse(JSON.stringify(baselineData, _DataController.jsonReplacer));
|
|
delete reprocessedJson.time;
|
|
delete reprocessedJson.optimizations;
|
|
delete baselineJson.time;
|
|
delete baselineJson.optimizations;
|
|
const diff2 = (0, import_ag_charts_core101.jsonDiff)(baselineJson, reprocessedJson);
|
|
if (diff2) {
|
|
import_ag_charts_core101.Logger.log("\u26A0\uFE0F DATA-MODEL REPROCESS DIFF DETECTED \u26A0\uFE0F");
|
|
import_ag_charts_core101.Logger.log("Difference between incremental update and full reprocess:");
|
|
import_ag_charts_core101.Logger.log("");
|
|
import_ag_charts_core101.Logger.log("BASELINE (full reprocess):");
|
|
import_ag_charts_core101.Logger.log(JSON.stringify(baselineJson, null, 2));
|
|
import_ag_charts_core101.Logger.log("");
|
|
import_ag_charts_core101.Logger.log("REPROCESSED (incremental update):");
|
|
import_ag_charts_core101.Logger.log(JSON.stringify(reprocessedJson, null, 2));
|
|
import_ag_charts_core101.Logger.log("");
|
|
import_ag_charts_core101.Logger.log("DIFF (what changed):");
|
|
import_ag_charts_core101.Logger.log(JSON.stringify(diff2, null, 2));
|
|
} else {
|
|
import_ag_charts_core101.Logger.log("\u2705 Data-model reprocess matches baseline (no diff)");
|
|
}
|
|
}
|
|
resolveResult(dataModel, processedData);
|
|
continue;
|
|
}
|
|
fullReprocess();
|
|
}
|
|
return nextCachedData;
|
|
}
|
|
validateRequests(requested) {
|
|
const valid = [];
|
|
for (const [index, request] of requested.entries()) {
|
|
if (index > 0 && request.dataSet.data.length !== requested[0].dataSet.data.length && request.opts.groupByData === false && request.opts.groupByKeys === false) {
|
|
request.reject(
|
|
new Error("all series[].data arrays must be of the same length and have matching keys.")
|
|
);
|
|
} else {
|
|
valid.push(request);
|
|
}
|
|
}
|
|
return valid;
|
|
}
|
|
mergeRequested(requested) {
|
|
const grouped = [];
|
|
for (const request of requested) {
|
|
const match = grouped.find(_DataController.groupMatch(request));
|
|
if (match) {
|
|
match.push(request);
|
|
} else {
|
|
grouped.push([request]);
|
|
}
|
|
}
|
|
return grouped.map(_DataController.mergeRequests);
|
|
}
|
|
static groupMatch({ dataSet, opts }) {
|
|
const { groupByData, groupByKeys = false, groupByFn, props } = opts;
|
|
const propsKeys = getPropertyKeys(props);
|
|
return ([group]) => (groupByData === false || group.dataSet === dataSet) && (group.opts.groupByKeys ?? false) === groupByKeys && group.opts.groupByFn === groupByFn && getPropertyKeys(group.opts.props) === propsKeys;
|
|
}
|
|
static mergeRequests(requests) {
|
|
const result = {
|
|
ids: [],
|
|
rejects: [],
|
|
resolves: [],
|
|
dataSet: requests[0].dataSet,
|
|
opts: { ...requests[0].opts, props: [] }
|
|
};
|
|
const optsByTypeAndDataId = /* @__PURE__ */ new Map();
|
|
const dataIds = /* @__PURE__ */ new Map();
|
|
let nextDataId = 0;
|
|
for (const request of requests) {
|
|
const {
|
|
id,
|
|
dataSet,
|
|
resolve,
|
|
reject,
|
|
opts: { props, ...opts }
|
|
} = request;
|
|
result.ids.push(id);
|
|
result.rejects.push(reject);
|
|
result.resolves.push(resolve);
|
|
result.dataSet ?? (result.dataSet = dataSet);
|
|
result.opts ?? (result.opts = { ...opts, props: [] });
|
|
for (const prop of props) {
|
|
const clone = { ...prop, scopes: [id], data: dataSet.data };
|
|
_DataController.createIdsMap(id, clone);
|
|
let dataId;
|
|
if (_DataController.crossScopeMergableTypes.has(clone.type)) {
|
|
dataId = -1;
|
|
} else if (dataIds.has(dataSet.data)) {
|
|
dataId = dataIds.get(dataSet.data);
|
|
} else {
|
|
dataId = nextDataId++;
|
|
dataIds.set(dataSet.data, dataId);
|
|
}
|
|
const matchKey = `${clone.type}-${dataId}-${clone.groupId}`;
|
|
const matches = optsByTypeAndDataId.get(matchKey);
|
|
const match = matches?.find((existing) => _DataController.deepEqual(existing, clone));
|
|
if (matches == null) {
|
|
result.opts.props.push(clone);
|
|
optsByTypeAndDataId.set(matchKey, [clone]);
|
|
continue;
|
|
} else if (match == null) {
|
|
result.opts.props.push(clone);
|
|
matches.push(clone);
|
|
continue;
|
|
}
|
|
if (clone.scopes != null) {
|
|
match.scopes ?? (match.scopes = []);
|
|
match.scopes.push(...clone.scopes);
|
|
}
|
|
if ((match.type === "key" || match.type === "value") && clone.idsMap?.size) {
|
|
match.idsMap ?? (match.idsMap = /* @__PURE__ */ new Map());
|
|
_DataController.mergeIdsMap(clone.idsMap, match.idsMap);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
static mergeIdsMap(fromMap, toMap) {
|
|
for (const [scope, ids] of fromMap) {
|
|
const toMapValue = toMap.get(scope);
|
|
if (toMapValue == null) {
|
|
toMap.set(scope, new Set(ids));
|
|
} else {
|
|
for (const id of ids) {
|
|
toMapValue.add(id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static createIdsMap(scope, prop) {
|
|
if (prop.id == null)
|
|
return;
|
|
prop.idsMap ?? (prop.idsMap = /* @__PURE__ */ new Map());
|
|
if (prop.idsMap.has(scope)) {
|
|
prop.idsMap.get(scope).add(prop.id);
|
|
} else {
|
|
prop.idsMap.set(scope, /* @__PURE__ */ new Set([prop.id]));
|
|
}
|
|
}
|
|
static deepEqual(a, b) {
|
|
if (a === b) {
|
|
return true;
|
|
}
|
|
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
if (a.constructor !== b.constructor) {
|
|
return false;
|
|
}
|
|
let i, length;
|
|
if (Array.isArray(a)) {
|
|
length = a.length;
|
|
if (length !== b.length) {
|
|
return false;
|
|
}
|
|
for (i = length - 1; i >= 0; i--) {
|
|
if (!_DataController.deepEqual(a[i], b[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
const keys = Object.keys(a);
|
|
length = keys.length;
|
|
if (length !== Object.keys(b).length) {
|
|
return false;
|
|
}
|
|
for (i = length - 1; i >= 0; i--) {
|
|
const key = keys[i];
|
|
if (!_DataController.skipKeys.has(key) && (!Object.hasOwn(b, key) || !_DataController.deepEqual(a[key], b[key]))) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
/** JSON replacer for serializing non-JSON-serializable objects like Map and Set */
|
|
static jsonReplacer(_key, value) {
|
|
if (value instanceof Map) {
|
|
return { __type: "Map", value: Array.from(value.entries()) };
|
|
}
|
|
if (value instanceof Set) {
|
|
return { __type: "Set", value: Array.from(value) };
|
|
}
|
|
return value;
|
|
}
|
|
};
|
|
_DataController.crossScopeMergableTypes = /* @__PURE__ */ new Set(["key", "group-value-processor"]);
|
|
// optimized version of deep equality for `mergeRequests` which can potentially loop over 1M times
|
|
_DataController.skipKeys = /* @__PURE__ */ new Set(["id", "idsMap", "type", "scopes", "data"]);
|
|
var DataController = _DataController;
|
|
|
|
// packages/ag-charts-community/src/chart/data/dataSet.ts
|
|
var import_ag_charts_core102 = require("ag-charts-core");
|
|
var DataSet = class _DataSet {
|
|
constructor(data) {
|
|
this.data = data;
|
|
this.pendingTransactions = [];
|
|
}
|
|
/**
|
|
* Creates an empty DataSet.
|
|
*/
|
|
static empty() {
|
|
return new _DataSet([]);
|
|
}
|
|
/**
|
|
* Wraps existing data in a DataSet.
|
|
*/
|
|
static wrap(data) {
|
|
return new _DataSet(data);
|
|
}
|
|
netSize() {
|
|
if (!this.hasPendingTransactions()) {
|
|
return this.data.length;
|
|
}
|
|
const changeDesc = this.getChangeDescription();
|
|
return changeDesc ? changeDesc.indexMap.finalLength : this.data.length;
|
|
}
|
|
/**
|
|
* Queues a transaction (applied on commit).
|
|
* Normalizes AG Grid-compatible format (add/addIndex) to internal format (prepend/append).
|
|
*/
|
|
addTransaction(transaction) {
|
|
const normalized = this.normalizeTransaction(transaction);
|
|
this.pendingTransactions.push(normalized);
|
|
this.cachedChangeDescription = void 0;
|
|
}
|
|
/**
|
|
* @returns A deep clone of the DataSet.
|
|
*/
|
|
deepClone() {
|
|
return new _DataSet([...this.data]);
|
|
}
|
|
/**
|
|
* Converts AG Grid-compatible transaction format to internal format.
|
|
* Maps `add` + `addIndex` to prepend, append, or arbitrary insertion based on the index.
|
|
*/
|
|
normalizeTransaction(transaction) {
|
|
const { add, addIndex, prepend, append, remove, update } = transaction;
|
|
if (add === void 0) {
|
|
return transaction;
|
|
}
|
|
const result = { remove, update };
|
|
if (prepend)
|
|
result.prepend = prepend;
|
|
if (append)
|
|
result.append = append;
|
|
if (add && add.length > 0) {
|
|
const currentSize = this.netSize();
|
|
if (addIndex === void 0 || addIndex >= currentSize) {
|
|
result.append = append ? [...append, ...add] : add;
|
|
} else if (addIndex === 0) {
|
|
result.prepend = prepend ? [...add, ...prepend] : add;
|
|
} else {
|
|
result.insertions = [{ index: addIndex, items: add }];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
hasPendingTransactions() {
|
|
return this.pendingTransactions.length > 0;
|
|
}
|
|
getPendingTransactionCount() {
|
|
return this.pendingTransactions.length;
|
|
}
|
|
/** Applies all pending transactions to the data array. */
|
|
commitPendingTransactions() {
|
|
if (!this.hasPendingTransactions()) {
|
|
return false;
|
|
}
|
|
const changeDescription = this.getChangeDescription();
|
|
if (!changeDescription) {
|
|
return false;
|
|
}
|
|
const prependedValues = changeDescription.getPrependedValues();
|
|
const insertionValues = changeDescription.getInsertionValues();
|
|
const appendedValues = changeDescription.getAppendedValues();
|
|
const allInsertionValues = [...prependedValues, ...insertionValues, ...appendedValues];
|
|
let insertionValueIndex = 0;
|
|
changeDescription.applyToArray(this.data, function applyToArrayResultFn(destIndex) {
|
|
if (insertionValueIndex >= allInsertionValues.length) {
|
|
throw new Error(`AG Charts - Internal error: No insertion value found for index ${destIndex}`);
|
|
}
|
|
return allInsertionValues[insertionValueIndex++];
|
|
});
|
|
this.pendingTransactions = [];
|
|
this.cachedChangeDescription = void 0;
|
|
this.updateItemToIndexCache(changeDescription, appendedValues, prependedValues, insertionValues);
|
|
return true;
|
|
}
|
|
/** Updates item→index cache incrementally, or invalidates for complex changes. */
|
|
updateItemToIndexCache(changeDescription, appendedValues, prependedValues, insertionValues) {
|
|
if (!this.itemToIndexCache)
|
|
return;
|
|
const { indexMap } = changeDescription;
|
|
const { totalPrependCount, totalAppendCount, removedIndices } = indexMap;
|
|
const hasRemovals = removedIndices.size > 0;
|
|
const hasArbitraryInsertions = insertionValues.length > 0;
|
|
if (!hasRemovals && totalPrependCount === 0 && totalAppendCount === 0 && !hasArbitraryInsertions) {
|
|
return;
|
|
}
|
|
if (hasArbitraryInsertions) {
|
|
this.itemToIndexCache = void 0;
|
|
return;
|
|
}
|
|
let removalsAreContiguousAtStart = false;
|
|
let contiguousRemovalCount = 0;
|
|
if (hasRemovals) {
|
|
const sortedRemovals = Array.from(removedIndices).sort((a, b) => a - b);
|
|
removalsAreContiguousAtStart = sortedRemovals[0] === 0;
|
|
if (removalsAreContiguousAtStart) {
|
|
for (let i = 0; i < sortedRemovals.length; i++) {
|
|
if (sortedRemovals[i] !== i) {
|
|
removalsAreContiguousAtStart = false;
|
|
break;
|
|
}
|
|
}
|
|
if (removalsAreContiguousAtStart) {
|
|
contiguousRemovalCount = sortedRemovals.length;
|
|
}
|
|
}
|
|
}
|
|
if (hasRemovals && !removalsAreContiguousAtStart) {
|
|
this.itemToIndexCache = void 0;
|
|
return;
|
|
}
|
|
const cache = this.itemToIndexCache;
|
|
const indexShift = totalPrependCount - contiguousRemovalCount;
|
|
if (indexShift !== 0) {
|
|
for (const [item, oldIndex] of cache) {
|
|
if (removedIndices.has(oldIndex)) {
|
|
cache.delete(item);
|
|
} else {
|
|
cache.set(item, oldIndex + indexShift);
|
|
}
|
|
}
|
|
} else if (hasRemovals) {
|
|
for (const [item, oldIndex] of cache) {
|
|
if (removedIndices.has(oldIndex)) {
|
|
cache.delete(item);
|
|
}
|
|
}
|
|
}
|
|
for (let i = 0; i < prependedValues.length; i++) {
|
|
const item = prependedValues[i];
|
|
if (!cache.has(item)) {
|
|
cache.set(item, i);
|
|
}
|
|
}
|
|
const appendStartIndex = indexMap.finalLength - totalAppendCount;
|
|
for (let i = 0; i < appendedValues.length; i++) {
|
|
const item = appendedValues[i];
|
|
if (!cache.has(item)) {
|
|
cache.set(item, appendStartIndex + i);
|
|
}
|
|
}
|
|
}
|
|
clearPendingTransactions() {
|
|
const count = this.pendingTransactions.length;
|
|
this.pendingTransactions = [];
|
|
this.cachedChangeDescription = void 0;
|
|
return count;
|
|
}
|
|
getPendingTransactions() {
|
|
return [...this.pendingTransactions];
|
|
}
|
|
/** Custom JSON serialization (avoids snapshot bloat). */
|
|
toJSON() {
|
|
return this.data;
|
|
}
|
|
/** Builds a DataChangeDescription from pending transactions (does not modify data). */
|
|
getChangeDescription() {
|
|
if (!this.hasPendingTransactions()) {
|
|
return void 0;
|
|
}
|
|
if (this.cachedChangeDescription) {
|
|
return this.cachedChangeDescription;
|
|
}
|
|
const { indexMap, prependValues, appendValues, insertionValues } = this.buildIndexMap();
|
|
const changeDescription = new DataChangeDescription(indexMap, {
|
|
prependValues,
|
|
appendValues,
|
|
insertionValues
|
|
});
|
|
this.cachedChangeDescription = changeDescription;
|
|
return changeDescription;
|
|
}
|
|
/**
|
|
* Helper method to remove items from a list of groups.
|
|
* Mutates the groups in-place and removes found items from toRemove set.
|
|
* @param groups List of groups to search and remove from
|
|
* @param toRemove Set of items to remove (modified in-place)
|
|
*/
|
|
removeFromGroups(groups, toRemove) {
|
|
for (const group of groups) {
|
|
let i = 0;
|
|
while (i < group.length && toRemove.size > 0) {
|
|
if (toRemove.has(group[i])) {
|
|
toRemove.delete(group[i]);
|
|
group.splice(i, 1);
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
if (toRemove.size === 0)
|
|
break;
|
|
}
|
|
}
|
|
/**
|
|
* Builds the index transformation map by sequentially applying all pending transactions.
|
|
* Optimized to:
|
|
* - Track operation boundaries instead of individual items
|
|
* - Only scan for values that are actually being removed
|
|
* - Stop scanning early when all removed values are found
|
|
* - Support arbitrary insertions at any index
|
|
* - Track updated items by referential equality
|
|
*/
|
|
buildIndexMap() {
|
|
const originalLength = this.data.length;
|
|
const effects = this.collectTransactionEffects();
|
|
const survivingPrepends = effects.prependsList.flat();
|
|
const survivingAppends = effects.appendsList.flat();
|
|
const survivingInsertions = effects.insertionsList.flat();
|
|
const totalPrependCount = survivingPrepends.length;
|
|
const totalAppendCount = survivingAppends.length;
|
|
const totalInsertionCount = survivingInsertions.length;
|
|
const survivingOriginalCount = originalLength - effects.removedOriginalIndices.size;
|
|
const finalLength = totalPrependCount + survivingOriginalCount + totalInsertionCount + totalAppendCount;
|
|
const sortedRemoved = effects.removedOriginalIndices.size > 0 ? this.getSortedRemovedIndices(effects.removedOriginalIndices) : void 0;
|
|
const spliceOps = this.buildSpliceOperations(
|
|
totalPrependCount,
|
|
totalInsertionCount,
|
|
totalAppendCount,
|
|
survivingOriginalCount,
|
|
effects.trackedInsertions,
|
|
sortedRemoved?.desc,
|
|
sortedRemoved?.asc
|
|
);
|
|
const updatedFinalIndices = this.resolveUpdatedIndices(
|
|
totalPrependCount,
|
|
totalInsertionCount,
|
|
survivingOriginalCount,
|
|
effects.updateTracking,
|
|
sortedRemoved?.asc,
|
|
effects.updatedOriginalIndices,
|
|
effects.trackedInsertions
|
|
);
|
|
const indexMap = {
|
|
originalLength,
|
|
finalLength,
|
|
spliceOps,
|
|
removedIndices: effects.removedOriginalIndices,
|
|
updatedIndices: updatedFinalIndices,
|
|
totalPrependCount,
|
|
totalAppendCount
|
|
};
|
|
return {
|
|
indexMap,
|
|
prependValues: survivingPrepends,
|
|
appendValues: survivingAppends,
|
|
insertionValues: survivingInsertions
|
|
};
|
|
}
|
|
getSortedRemovedIndices(removedOriginalIndices) {
|
|
const asc = Array.from(removedOriginalIndices).sort((a, b) => a - b);
|
|
return { asc, desc: [...asc].reverse() };
|
|
}
|
|
collectTransactionEffects() {
|
|
const state = {
|
|
prependsList: [],
|
|
appendsList: [],
|
|
insertionsList: [],
|
|
trackedInsertions: [],
|
|
removedOriginalIndices: /* @__PURE__ */ new Set(),
|
|
updatedOriginalIndices: /* @__PURE__ */ new Set(),
|
|
virtualLength: this.data.length
|
|
};
|
|
for (const transaction of this.pendingTransactions) {
|
|
const { prepend, append, insertions, remove, update } = transaction;
|
|
this.applyPrepends(prepend, state);
|
|
this.applyInsertions(insertions, state);
|
|
this.applyAppends(append, state);
|
|
this.applyRemovals(remove, state);
|
|
this.applyUpdates(update, state);
|
|
}
|
|
return {
|
|
prependsList: state.prependsList,
|
|
appendsList: state.appendsList,
|
|
insertionsList: state.insertionsList,
|
|
trackedInsertions: state.trackedInsertions,
|
|
removedOriginalIndices: state.removedOriginalIndices,
|
|
updatedOriginalIndices: state.updatedOriginalIndices,
|
|
updateTracking: state.updateTracking
|
|
};
|
|
}
|
|
applyPrepends(prepend, state) {
|
|
if (!Array.isArray(prepend) || prepend.length === 0) {
|
|
return;
|
|
}
|
|
state.prependsList.unshift([...prepend]);
|
|
state.virtualLength += prepend.length;
|
|
}
|
|
applyInsertions(insertions, state) {
|
|
if (!Array.isArray(insertions)) {
|
|
return;
|
|
}
|
|
for (const { index, items } of insertions) {
|
|
if (index >= 0 && index <= state.virtualLength && items.length > 0) {
|
|
state.trackedInsertions.push({
|
|
virtualIndex: index,
|
|
items: [...items]
|
|
});
|
|
state.insertionsList.push([...items]);
|
|
state.virtualLength += items.length;
|
|
}
|
|
}
|
|
}
|
|
applyAppends(append, state) {
|
|
if (!Array.isArray(append) || append.length === 0) {
|
|
return;
|
|
}
|
|
state.appendsList.push([...append]);
|
|
state.virtualLength += append.length;
|
|
}
|
|
applyRemovals(remove, state) {
|
|
if (!Array.isArray(remove) || remove.length === 0) {
|
|
return;
|
|
}
|
|
const toRemove = new Set(remove);
|
|
this.removeFromGroups(state.prependsList, toRemove);
|
|
if (toRemove.size > 0) {
|
|
this.removeFromGroups(state.insertionsList, toRemove);
|
|
}
|
|
if (state.trackedInsertions.length > 0) {
|
|
this.removeFromTrackedInsertions(remove, state);
|
|
}
|
|
if (toRemove.size > 0) {
|
|
this.removeFromGroups(state.appendsList, toRemove);
|
|
}
|
|
if (toRemove.size > 0) {
|
|
for (let i = 0; i < this.data.length && toRemove.size > 0; i++) {
|
|
const value = this.data[i];
|
|
if (toRemove.has(value)) {
|
|
state.removedOriginalIndices.add(i);
|
|
toRemove.delete(value);
|
|
state.virtualLength--;
|
|
}
|
|
}
|
|
}
|
|
if (toRemove.size > 0) {
|
|
import_ag_charts_core102.Logger.warnOnce(
|
|
"applyTransaction() remove includes items not present in current data; ignoring missing items."
|
|
);
|
|
}
|
|
}
|
|
applyUpdates(update, state) {
|
|
if (!Array.isArray(update) || update.length === 0) {
|
|
return;
|
|
}
|
|
const toUpdate = new Set(update);
|
|
const updatedPrependsIndices = this.collectUpdatedIndicesFromGroups(state.prependsList, toUpdate);
|
|
const updatedInsertionsIndices = toUpdate.size > 0 ? this.collectUpdatedIndicesFromGroups(state.insertionsList, toUpdate) : [];
|
|
const updatedAppendsIndices = toUpdate.size > 0 ? this.collectUpdatedIndicesFromGroups(state.appendsList, toUpdate) : [];
|
|
if (toUpdate.size > 0) {
|
|
this.collectUpdatedOriginalIndices(toUpdate, state);
|
|
}
|
|
state.updateTracking = {
|
|
updatedPrependsIndices,
|
|
updatedAppendsIndices,
|
|
updatedInsertionsIndices
|
|
};
|
|
if (toUpdate.size > 0) {
|
|
import_ag_charts_core102.Logger.warnOnce(
|
|
"applyTransaction() update includes items not present in current data; ignoring missing items."
|
|
);
|
|
}
|
|
}
|
|
// Flattens grouped inserts to find updated item offsets while consuming the lookup set.
|
|
collectUpdatedIndicesFromGroups(groups, toUpdate) {
|
|
if (toUpdate.size === 0 || groups.length === 0) {
|
|
return [];
|
|
}
|
|
const updatedIndices = [];
|
|
let flatIndex = 0;
|
|
for (const group of groups) {
|
|
for (const item of group) {
|
|
if (toUpdate.has(item)) {
|
|
updatedIndices.push(flatIndex);
|
|
toUpdate.delete(item);
|
|
}
|
|
flatIndex++;
|
|
}
|
|
if (toUpdate.size === 0) {
|
|
break;
|
|
}
|
|
}
|
|
return updatedIndices;
|
|
}
|
|
/** Lazy item→index map for O(1) lookups. */
|
|
getItemToIndexMap() {
|
|
if (this.itemToIndexCache === void 0) {
|
|
this.itemToIndexCache = /* @__PURE__ */ new Map();
|
|
for (let i = 0; i < this.data.length; i++) {
|
|
if (!this.itemToIndexCache.has(this.data[i])) {
|
|
this.itemToIndexCache.set(this.data[i], i);
|
|
}
|
|
}
|
|
}
|
|
return this.itemToIndexCache;
|
|
}
|
|
collectUpdatedOriginalIndices(toUpdate, state) {
|
|
const indexMap = this.getItemToIndexMap();
|
|
for (const item of [...toUpdate]) {
|
|
const idx = indexMap.get(item);
|
|
if (idx !== void 0 && !state.removedOriginalIndices.has(idx)) {
|
|
state.updatedOriginalIndices.add(idx);
|
|
toUpdate.delete(item);
|
|
}
|
|
}
|
|
}
|
|
removeFromTrackedInsertions(removeValues, state) {
|
|
for (let trackedIdx = 0; trackedIdx < state.trackedInsertions.length; trackedIdx++) {
|
|
const tracked = state.trackedInsertions[trackedIdx];
|
|
const previousLength = tracked.items.length;
|
|
const removedOffsets = [];
|
|
let itemIndex = 0;
|
|
while (itemIndex < tracked.items.length) {
|
|
if (removeValues.includes(tracked.items[itemIndex])) {
|
|
removedOffsets.push(itemIndex + removedOffsets.length);
|
|
tracked.items.splice(itemIndex, 1);
|
|
state.virtualLength--;
|
|
} else {
|
|
itemIndex++;
|
|
}
|
|
}
|
|
if (removedOffsets.length > 0) {
|
|
this.adjustLaterInsertionsAfterRemoval(
|
|
state.trackedInsertions,
|
|
trackedIdx,
|
|
tracked,
|
|
previousLength,
|
|
removedOffsets
|
|
);
|
|
}
|
|
}
|
|
}
|
|
adjustLaterInsertionsAfterRemoval(trackedInsertions, trackedIdx, tracked, previousLength, removedOffsets) {
|
|
const removedCount = removedOffsets.length;
|
|
for (let j = trackedIdx + 1; j < trackedInsertions.length; j++) {
|
|
const later = trackedInsertions[j];
|
|
if (later.virtualIndex <= tracked.virtualIndex) {
|
|
continue;
|
|
}
|
|
const relativeInsertionPosition = Math.min(
|
|
Math.max(later.virtualIndex - tracked.virtualIndex, 0),
|
|
previousLength
|
|
);
|
|
let removedBeforeInsertion = 0;
|
|
for (const offset of removedOffsets) {
|
|
if (offset < relativeInsertionPosition) {
|
|
removedBeforeInsertion++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (relativeInsertionPosition === previousLength) {
|
|
removedBeforeInsertion = removedCount;
|
|
}
|
|
if (removedBeforeInsertion > 0) {
|
|
later.virtualIndex -= removedBeforeInsertion;
|
|
}
|
|
}
|
|
}
|
|
buildSpliceOperations(totalPrependCount, totalInsertionCount, totalAppendCount, survivingOriginalCount, trackedInsertions, sortedRemovedDesc, sortedRemovedAsc) {
|
|
const spliceOps = [];
|
|
if (totalPrependCount > 0) {
|
|
spliceOps.push({
|
|
index: 0,
|
|
deleteCount: 0,
|
|
insertCount: totalPrependCount
|
|
});
|
|
}
|
|
if (sortedRemovedDesc && sortedRemovedDesc.length > 0) {
|
|
let currentGroupStart = sortedRemovedDesc[0];
|
|
let currentGroupCount = 1;
|
|
for (let i = 1; i < sortedRemovedDesc.length; i++) {
|
|
const currentIndex = sortedRemovedDesc[i];
|
|
const prevIndex = sortedRemovedDesc[i - 1];
|
|
if (prevIndex - currentIndex === 1) {
|
|
currentGroupCount++;
|
|
} else {
|
|
spliceOps.push({
|
|
index: currentGroupStart - currentGroupCount + 1 + totalPrependCount,
|
|
deleteCount: currentGroupCount,
|
|
insertCount: 0
|
|
});
|
|
currentGroupStart = currentIndex;
|
|
currentGroupCount = 1;
|
|
}
|
|
}
|
|
spliceOps.push({
|
|
index: currentGroupStart - currentGroupCount + 1 + totalPrependCount,
|
|
deleteCount: currentGroupCount,
|
|
insertCount: 0
|
|
});
|
|
}
|
|
if (trackedInsertions.length > 0) {
|
|
for (const insertion of trackedInsertions) {
|
|
const removalsBeforeInsertion = this.countRemovalsBeforeIndex(
|
|
sortedRemovedAsc,
|
|
totalPrependCount,
|
|
insertion.virtualIndex
|
|
);
|
|
const adjustedIndex = insertion.virtualIndex - removalsBeforeInsertion;
|
|
spliceOps.push({
|
|
index: adjustedIndex,
|
|
deleteCount: 0,
|
|
insertCount: insertion.items.length
|
|
});
|
|
}
|
|
}
|
|
if (totalAppendCount > 0) {
|
|
spliceOps.push({
|
|
index: totalPrependCount + survivingOriginalCount + totalInsertionCount,
|
|
deleteCount: 0,
|
|
insertCount: totalAppendCount
|
|
});
|
|
}
|
|
return spliceOps;
|
|
}
|
|
countRemovalsBeforeIndex(sortedRemovedAsc, totalPrependCount, insertionVirtualIndex) {
|
|
if (!sortedRemovedAsc || sortedRemovedAsc.length === 0) {
|
|
return 0;
|
|
}
|
|
let removalsBeforeInsertion = 0;
|
|
for (const removedIndex of sortedRemovedAsc) {
|
|
const virtualIndexOfRemoval = removedIndex + totalPrependCount;
|
|
if (virtualIndexOfRemoval < insertionVirtualIndex) {
|
|
removalsBeforeInsertion++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return removalsBeforeInsertion;
|
|
}
|
|
resolveUpdatedIndices(totalPrependCount, totalInsertionCount, survivingOriginalCount, updateTracking, sortedRemovedAsc, updatedOriginalIndices, trackedInsertions) {
|
|
const updatedFinalIndices = /* @__PURE__ */ new Set();
|
|
if (updateTracking) {
|
|
for (const prependIdx of updateTracking.updatedPrependsIndices) {
|
|
updatedFinalIndices.add(prependIdx);
|
|
}
|
|
}
|
|
if (updatedOriginalIndices.size > 0) {
|
|
const sortedUpdatedOriginals = Array.from(updatedOriginalIndices).sort((a, b) => a - b);
|
|
let removalPtr = 0;
|
|
for (const originalIdx of sortedUpdatedOriginals) {
|
|
if (sortedRemovedAsc) {
|
|
while (removalPtr < sortedRemovedAsc.length && sortedRemovedAsc[removalPtr] < originalIdx) {
|
|
removalPtr++;
|
|
}
|
|
}
|
|
const removalsBeforeCount = sortedRemovedAsc ? removalPtr : 0;
|
|
const virtualPosOfOriginal = originalIdx + totalPrependCount;
|
|
let insertionsBeforeCount = 0;
|
|
for (const insertion of trackedInsertions) {
|
|
if (insertion.virtualIndex <= virtualPosOfOriginal) {
|
|
insertionsBeforeCount += insertion.items.length;
|
|
}
|
|
}
|
|
const finalIdx = originalIdx + totalPrependCount - removalsBeforeCount + insertionsBeforeCount;
|
|
updatedFinalIndices.add(finalIdx);
|
|
}
|
|
}
|
|
if (updateTracking) {
|
|
const appendStartIdx = totalPrependCount + survivingOriginalCount + totalInsertionCount;
|
|
for (const appendIdx of updateTracking.updatedAppendsIndices) {
|
|
updatedFinalIndices.add(appendStartIdx + appendIdx);
|
|
}
|
|
if (updateTracking.updatedInsertionsIndices.length > 0 && trackedInsertions.length > 0) {
|
|
let flatIdx = 0;
|
|
for (const insertion of trackedInsertions) {
|
|
const removalsBeforeInsertion = this.countRemovalsBeforeIndex(
|
|
sortedRemovedAsc,
|
|
totalPrependCount,
|
|
insertion.virtualIndex
|
|
);
|
|
const insertionFinalIdx = insertion.virtualIndex - removalsBeforeInsertion;
|
|
for (let itemOffset = 0; itemOffset < insertion.items.length; itemOffset++) {
|
|
if (updateTracking.updatedInsertionsIndices.includes(flatIdx)) {
|
|
updatedFinalIndices.add(insertionFinalIdx + itemOffset);
|
|
}
|
|
flatIdx++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return updatedFinalIndices;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/syncManager.ts
|
|
var _SyncManager = class _SyncManager {
|
|
constructor(chart) {
|
|
this.chart = chart;
|
|
}
|
|
subscribe(groupId = _SyncManager.DEFAULT_GROUP) {
|
|
let syncGroup = this.get(groupId);
|
|
if (!syncGroup) {
|
|
syncGroup = { members: /* @__PURE__ */ new Set() };
|
|
_SyncManager.chartsGroups.set(groupId, syncGroup);
|
|
}
|
|
syncGroup.members.add(this.chart);
|
|
return this;
|
|
}
|
|
unsubscribe(groupId = _SyncManager.DEFAULT_GROUP) {
|
|
const groupState = this.get(groupId);
|
|
groupState?.members.delete(this.chart);
|
|
delete groupState?.domains?.x?.sources?.[this.chart.id];
|
|
delete groupState?.domains?.y?.sources?.[this.chart.id];
|
|
return this;
|
|
}
|
|
getChart() {
|
|
return this.chart;
|
|
}
|
|
getGroupState(groupId = _SyncManager.DEFAULT_GROUP) {
|
|
return this.get(groupId);
|
|
}
|
|
getGroupMembers(groupId = _SyncManager.DEFAULT_GROUP) {
|
|
const syncGroup = this.get(groupId);
|
|
return syncGroup ? Array.from(syncGroup.members) : [];
|
|
}
|
|
getGroupSiblings(groupId = _SyncManager.DEFAULT_GROUP) {
|
|
return this.getGroupMembers(groupId).filter((chart) => chart !== this.chart);
|
|
}
|
|
getGroupSyncMode(groupId = _SyncManager.DEFAULT_GROUP) {
|
|
if (this.getGroupMembers(groupId).some((c) => c.series.length > 1)) {
|
|
return "multi-series";
|
|
}
|
|
return "single-series";
|
|
}
|
|
get(groupId) {
|
|
return _SyncManager.chartsGroups.get(groupId);
|
|
}
|
|
};
|
|
_SyncManager.chartsGroups = /* @__PURE__ */ new Map();
|
|
_SyncManager.DEFAULT_GROUP = Symbol("sync-group-default");
|
|
var SyncManager = _SyncManager;
|
|
|
|
// packages/ag-charts-community/src/chart/keyboard.ts
|
|
var import_ag_charts_core103 = require("ag-charts-core");
|
|
var Keyboard = class extends import_ag_charts_core103.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core103.Property
|
|
], Keyboard.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core103.Property
|
|
], Keyboard.prototype, "tabIndex", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/cartesianAxis.ts
|
|
var import_ag_charts_core126 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/motion/fromToMotion.ts
|
|
var fromToMotion_exports = {};
|
|
__export(fromToMotion_exports, {
|
|
NODE_UPDATE_STATE_TO_PHASE_MAPPING: () => NODE_UPDATE_STATE_TO_PHASE_MAPPING,
|
|
fromToMotion: () => fromToMotion,
|
|
staticFromToMotion: () => staticFromToMotion
|
|
});
|
|
var import_ag_charts_core104 = require("ag-charts-core");
|
|
var NODE_UPDATE_STATE_TO_PHASE_MAPPING = {
|
|
added: "add",
|
|
updated: "update",
|
|
removed: "remove",
|
|
unknown: "initial",
|
|
"no-op": "none"
|
|
};
|
|
function fromToMotion(groupId, subId, animationManager, selectionsOrNodes, fns, getDatumId, diff2) {
|
|
const { fromFn, toFn, applyFn = (node, props) => node.setProperties(props) } = fns;
|
|
const { nodes, selections } = deconstructSelectionsOrNodes(selectionsOrNodes);
|
|
const processNodes = (liveNodes, subNodes) => {
|
|
let prevFromProps;
|
|
let liveNodeIndex = 0;
|
|
let nodeIndex = 0;
|
|
for (const node of subNodes) {
|
|
const isLive = liveNodes[liveNodeIndex] === node;
|
|
const ctx = {
|
|
last: nodeIndex >= subNodes.length - 1,
|
|
lastLive: liveNodeIndex >= liveNodes.length - 1,
|
|
prev: subNodes[nodeIndex - 1],
|
|
prevFromProps,
|
|
prevLive: liveNodes[liveNodeIndex - 1],
|
|
next: subNodes[nodeIndex + 1],
|
|
nextLive: liveNodes[liveNodeIndex + (isLive ? 1 : 0)]
|
|
};
|
|
const animationId = `${groupId}_${subId}_${node.id}`;
|
|
animationManager.stopByAnimationId(animationId);
|
|
let status = "unknown";
|
|
if (!isLive) {
|
|
status = "removed";
|
|
} else if (getDatumId && diff2) {
|
|
status = calculateStatus(node, node.datum, getDatumId, diff2);
|
|
}
|
|
node.transitionOut = status === "removed";
|
|
const { phase, start, finish, delay, duration, ...from } = fromFn(node, node.datum, status, ctx);
|
|
const {
|
|
phase: toPhase,
|
|
start: toStart,
|
|
finish: toFinish,
|
|
delay: toDelay,
|
|
duration: toDuration,
|
|
...to
|
|
} = toFn(node, node.datum, status, ctx);
|
|
const collapsable = finish == null;
|
|
animationManager.animate({
|
|
id: animationId,
|
|
groupId,
|
|
phase: phase ?? toPhase ?? "update",
|
|
duration: duration ?? toDuration,
|
|
delay: delay ?? toDelay,
|
|
from,
|
|
to,
|
|
ease: import_ag_charts_core104.easeOut,
|
|
collapsable,
|
|
onPlay: () => {
|
|
const startProps = { ...start, ...toStart, ...from };
|
|
applyFn(node, startProps, "start");
|
|
},
|
|
onUpdate(props) {
|
|
applyFn(node, props, "update");
|
|
},
|
|
onStop: () => {
|
|
const endProps = {
|
|
...start,
|
|
...toStart,
|
|
...from,
|
|
...to,
|
|
...finish,
|
|
...toFinish
|
|
};
|
|
applyFn(node, endProps, "end");
|
|
}
|
|
});
|
|
if (isLive) {
|
|
liveNodeIndex++;
|
|
}
|
|
nodeIndex++;
|
|
prevFromProps = from;
|
|
}
|
|
};
|
|
let selectionIndex = 0;
|
|
for (const selection of selections) {
|
|
const selectionNodes = selection.nodes();
|
|
const liveNodes = selectionNodes.filter((n) => !selection.isGarbage(n));
|
|
processNodes(liveNodes, selectionNodes);
|
|
animationManager.animate({
|
|
id: `${groupId}_${subId}_selection_${selectionIndex}`,
|
|
groupId,
|
|
phase: "end",
|
|
from: 0,
|
|
to: 1,
|
|
ease: import_ag_charts_core104.easeOut,
|
|
onStop() {
|
|
selection.cleanup();
|
|
}
|
|
});
|
|
selectionIndex++;
|
|
}
|
|
processNodes(nodes, nodes);
|
|
}
|
|
function staticFromToMotion(groupId, subId, animationManager, selectionsOrNodes, from, to, extraOpts) {
|
|
const { nodes, selections } = deconstructSelectionsOrNodes(selectionsOrNodes);
|
|
const { start, finish, phase } = extraOpts;
|
|
animationManager.animate({
|
|
id: `${groupId}_${subId}`,
|
|
groupId,
|
|
phase: phase ?? "update",
|
|
from,
|
|
to,
|
|
ease: import_ag_charts_core104.easeOut,
|
|
onPlay: () => {
|
|
if (!start)
|
|
return;
|
|
for (const node of nodes) {
|
|
node.setProperties(start);
|
|
}
|
|
for (const selection of selections) {
|
|
const selectionNodes = selection.nodes();
|
|
selection.batchedUpdate(function staticMotionPlay() {
|
|
for (const node of selectionNodes) {
|
|
node.setProperties(start);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
onUpdate(props) {
|
|
for (const node of nodes) {
|
|
node.setProperties(props);
|
|
}
|
|
for (const selection of selections) {
|
|
const selectionNodes = selection.nodes();
|
|
selection.batchedUpdate(function staticMotionUpdate() {
|
|
for (const node of selectionNodes) {
|
|
node.setProperties(props);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
onStop: () => {
|
|
for (const node of nodes) {
|
|
node.setProperties({ ...to, ...finish });
|
|
}
|
|
for (const selection of selections) {
|
|
const selectionNodes = selection.nodes();
|
|
selection.batchedUpdate(function staticMotionStop() {
|
|
for (const node of selectionNodes) {
|
|
node.setProperties({ ...to, ...finish });
|
|
}
|
|
selection.cleanup();
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function calculateStatus(node, datum, getDatumId, diff2) {
|
|
const id = getDatumId(node, datum);
|
|
if (diff2.added.has(id)) {
|
|
return "added";
|
|
}
|
|
if (diff2.removed.has(id)) {
|
|
return "removed";
|
|
}
|
|
if (node.previousDatum == null && node.datum != null) {
|
|
return "added";
|
|
}
|
|
if (node.previousDatum != null && node.datum == null) {
|
|
return "removed";
|
|
}
|
|
return "updated";
|
|
}
|
|
|
|
// packages/ag-charts-community/src/motion/resetMotion.ts
|
|
var resetMotion_exports = {};
|
|
__export(resetMotion_exports, {
|
|
resetMotion: () => resetMotion
|
|
});
|
|
function resetMotion(selectionsOrNodes, propsFn) {
|
|
const { nodes, selections } = deconstructSelectionsOrNodes(selectionsOrNodes);
|
|
for (const selection of selections) {
|
|
const selectionNodes = selection.nodes();
|
|
selection.batchedUpdate(function resetMotionNodes() {
|
|
for (const node of selectionNodes) {
|
|
const from = propsFn(node, node.datum);
|
|
node.setProperties(from);
|
|
}
|
|
selection.cleanup();
|
|
});
|
|
}
|
|
for (const node of nodes) {
|
|
const from = propsFn(node, node.datum);
|
|
node.setProperties(from);
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/selection.ts
|
|
var import_ag_charts_core105 = require("ag-charts-core");
|
|
var Selection = class _Selection {
|
|
constructor(parentNode, classOrFactory, autoCleanup = true) {
|
|
this.parentNode = parentNode;
|
|
this.autoCleanup = autoCleanup;
|
|
this.garbageBin = /* @__PURE__ */ new Set();
|
|
this._nodesMap = /* @__PURE__ */ new Map();
|
|
this._nodes = [];
|
|
this.data = [];
|
|
this.debug = import_ag_charts_core105.Debug.create(true, "scene", "scene:selections");
|
|
this.nodeFactory = Object.prototype.isPrototypeOf.call(Node, classOrFactory) ? () => new classOrFactory() : classOrFactory;
|
|
}
|
|
static select(parent, classOrFactory, garbageCollection = true) {
|
|
return new _Selection(parent, classOrFactory, garbageCollection);
|
|
}
|
|
static selectAll(parent, predicate) {
|
|
const results = [];
|
|
const traverse = (node) => {
|
|
if (predicate(node)) {
|
|
results.push(node);
|
|
}
|
|
if (node instanceof Group) {
|
|
for (const child of node.children()) {
|
|
traverse(child);
|
|
}
|
|
}
|
|
};
|
|
traverse(parent);
|
|
return results;
|
|
}
|
|
static selectByClass(node, ...Classes) {
|
|
return _Selection.selectAll(node, (n) => Classes.some((C2) => n instanceof C2));
|
|
}
|
|
static selectByTag(node, tag) {
|
|
return _Selection.selectAll(node, (n) => n.tag === tag);
|
|
}
|
|
createNode(datum, initializer, idx) {
|
|
const node = this.nodeFactory(datum);
|
|
node.datum = datum;
|
|
initializer?.(node);
|
|
if (idx == null) {
|
|
this._nodes.push(node);
|
|
} else {
|
|
this._nodes.splice(idx, 0, node);
|
|
}
|
|
this.parentNode.appendChild(node);
|
|
return node;
|
|
}
|
|
/**
|
|
* Update the data in a selection. If an `getDatumId()` function is provided, maintain a list of ids related to
|
|
* the nodes. Otherwise, take the more efficient route of simply creating and destroying nodes at the end
|
|
* of the array.
|
|
*/
|
|
update(data, initializer, getDatumId) {
|
|
if (this.garbageBin.size > 0) {
|
|
this.debug(`Selection - update() called with pending garbage`, data);
|
|
}
|
|
if (getDatumId && this._nodesMap.size === 0 && this._nodes.length > 0) {
|
|
for (const node of this._nodes) {
|
|
this.garbageBin.add(node);
|
|
}
|
|
}
|
|
if (!getDatumId && this._nodesMap.size > 0) {
|
|
this._nodesMap.clear();
|
|
}
|
|
if (getDatumId) {
|
|
const dataMap = /* @__PURE__ */ new Map();
|
|
const duplicateMap = /* @__PURE__ */ new Map();
|
|
for (let idx = 0; idx < data.length; idx++) {
|
|
const datum = data[idx];
|
|
let id = getDatumId(datum);
|
|
if (dataMap.has(id)) {
|
|
const index = (duplicateMap.get(id) ?? 0) + 1;
|
|
duplicateMap.set(id, index);
|
|
id = `${id}:${index}`;
|
|
}
|
|
dataMap.set(id, idx);
|
|
}
|
|
for (const [node, datumId] of this._nodesMap.entries()) {
|
|
const idx = dataMap.get(datumId);
|
|
if (idx == null) {
|
|
this.garbageBin.add(node);
|
|
} else {
|
|
node.datum = data[idx];
|
|
this.garbageBin.delete(node);
|
|
dataMap.delete(datumId);
|
|
}
|
|
}
|
|
for (const [datumId, idx] of dataMap.entries()) {
|
|
const datum = data[idx];
|
|
this._nodesMap.set(this.createNode(datum, initializer, idx), datumId);
|
|
}
|
|
} else {
|
|
const maxLength = Math.max(data.length, this.data.length);
|
|
for (let i = 0; i < maxLength; i++) {
|
|
if (i >= data.length) {
|
|
this.garbageBin.add(this._nodes[i]);
|
|
} else if (i >= this._nodes.length) {
|
|
this.createNode(data[i], initializer);
|
|
} else {
|
|
this._nodes[i].datum = data[i];
|
|
this.garbageBin.delete(this._nodes[i]);
|
|
}
|
|
}
|
|
}
|
|
this.data = data.slice();
|
|
if (this.autoCleanup) {
|
|
this.cleanup();
|
|
}
|
|
return this;
|
|
}
|
|
cleanup() {
|
|
if (this.garbageBin.size === 0) {
|
|
return this;
|
|
}
|
|
const selection = this;
|
|
function removeGarbage(node) {
|
|
if (selection.garbageBin.has(node)) {
|
|
selection._nodesMap.delete(node);
|
|
selection.garbageBin.delete(node);
|
|
node.destroy();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
this._nodes = this._nodes.filter(removeGarbage);
|
|
return this;
|
|
}
|
|
clear() {
|
|
this.update([]);
|
|
for (const node of this._nodesMap.keys()) {
|
|
this.garbageBin.add(node);
|
|
}
|
|
this._nodesMap.clear();
|
|
return this;
|
|
}
|
|
isGarbage(node) {
|
|
return this.garbageBin.has(node);
|
|
}
|
|
each(iterate5) {
|
|
const nodes = this._nodes;
|
|
this.parentNode.batchedUpdate(function selectionEach() {
|
|
for (const entry of nodes.entries()) {
|
|
iterate5(entry[1], entry[1].datum, entry[0]);
|
|
}
|
|
});
|
|
return this;
|
|
}
|
|
*[Symbol.iterator]() {
|
|
for (let index = 0; index < this._nodes.length; index++) {
|
|
const node = this._nodes[index];
|
|
yield { node, datum: node.datum, index };
|
|
}
|
|
}
|
|
select(predicate) {
|
|
return _Selection.selectAll(this.parentNode, predicate);
|
|
}
|
|
selectByClass(Class) {
|
|
return _Selection.selectByClass(this.parentNode, Class);
|
|
}
|
|
selectByTag(tag) {
|
|
return _Selection.selectByTag(this.parentNode, tag);
|
|
}
|
|
nodes() {
|
|
return this._nodes;
|
|
}
|
|
at(index) {
|
|
return this._nodes.at(index);
|
|
}
|
|
get length() {
|
|
return this._nodes.length;
|
|
}
|
|
batchedUpdate(fn) {
|
|
this.parentNode.batchedUpdate(fn);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/shape/line.ts
|
|
var import_ag_charts_core106 = require("ag-charts-core");
|
|
var Line = class extends Shape {
|
|
constructor(opts = {}) {
|
|
super(opts);
|
|
this.x1 = 0;
|
|
this.y1 = 0;
|
|
this.x2 = 0;
|
|
this.y2 = 0;
|
|
this.fill = void 0;
|
|
this.strokeWidth = 1;
|
|
}
|
|
set x(value) {
|
|
this.x1 = value;
|
|
this.x2 = value;
|
|
}
|
|
set y(value) {
|
|
this.y1 = value;
|
|
this.y2 = value;
|
|
}
|
|
get midPoint() {
|
|
return { x: (this.x1 + this.x2) / 2, y: (this.y1 + this.y2) / 2 };
|
|
}
|
|
computeBBox() {
|
|
return new BBox(
|
|
Math.min(this.x1, this.x2),
|
|
Math.min(this.y1, this.y2),
|
|
Math.abs(this.x2 - this.x1),
|
|
Math.abs(this.y2 - this.y1)
|
|
);
|
|
}
|
|
isPointInPath(x, y) {
|
|
if (this.x1 === this.x2 || this.y1 === this.y2) {
|
|
return this.getBBox().clone().grow(this.strokeWidth / 2).containsPoint(x, y);
|
|
}
|
|
return false;
|
|
}
|
|
distanceSquared(px, py) {
|
|
const { x1, y1, x2, y2 } = this;
|
|
return (0, import_ag_charts_core106.lineDistanceSquared)(px, py, x1, y1, x2, y2, Infinity);
|
|
}
|
|
render(renderCtx) {
|
|
const { ctx, devicePixelRatio } = renderCtx;
|
|
let { x1, y1, x2, y2 } = this;
|
|
if (x1 === x2) {
|
|
const { strokeWidth } = this;
|
|
const x = Math.round(x1 * devicePixelRatio) / devicePixelRatio + Math.trunc(strokeWidth * devicePixelRatio) % 2 / (devicePixelRatio * 2);
|
|
x1 = x;
|
|
x2 = x;
|
|
} else if (y1 === y2) {
|
|
const { strokeWidth } = this;
|
|
const y = Math.round(y1 * devicePixelRatio) / devicePixelRatio + Math.trunc(strokeWidth * devicePixelRatio) % 2 / (devicePixelRatio * 2);
|
|
y1 = y;
|
|
y2 = y;
|
|
}
|
|
ctx.beginPath();
|
|
ctx.moveTo(x1, y1);
|
|
ctx.lineTo(x2, y2);
|
|
this.fillStroke(ctx);
|
|
this.fillShadow?.markClean();
|
|
super.render(renderCtx);
|
|
}
|
|
toSVG() {
|
|
if (!this.visible)
|
|
return;
|
|
const element2 = (0, import_ag_charts_core106.createSvgElement)("line");
|
|
element2.setAttribute("x1", String(this.x1));
|
|
element2.setAttribute("y1", String(this.y1));
|
|
element2.setAttribute("x2", String(this.x2));
|
|
element2.setAttribute("y2", String(this.y2));
|
|
this.applySvgStrokeAttributes(element2);
|
|
return {
|
|
elements: [element2]
|
|
};
|
|
}
|
|
};
|
|
Line.className = "Line";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Line.prototype, "x1", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Line.prototype, "y1", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Line.prototype, "x2", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Line.prototype, "y2", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/label.ts
|
|
var import_ag_charts_core107 = require("ag-charts-core");
|
|
var LabelBorder = class {
|
|
constructor() {
|
|
this.enabled = true;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelBorder.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelBorder.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelBorder.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelBorder.prototype, "strokeOpacity", 2);
|
|
var LabelStyle = class extends import_ag_charts_core107.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.border = new LabelBorder();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "border", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "color", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "fontFamily", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], LabelStyle.prototype, "padding", 2);
|
|
var Label = class extends LabelStyle {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = false;
|
|
this._cachedFormatter = void 0;
|
|
}
|
|
formatValue(formatWithContext, type, value, params) {
|
|
const { formatter, format } = this;
|
|
let result;
|
|
if (formatter != null) {
|
|
result ?? (result = formatWithContext(formatter, params));
|
|
}
|
|
if (format != null) {
|
|
let cachedFormatter = this._cachedFormatter;
|
|
if (cachedFormatter?.type !== type || cachedFormatter?.format !== format) {
|
|
cachedFormatter = {
|
|
type,
|
|
format,
|
|
formatter: FormatManager.getFormatter(type, format)
|
|
};
|
|
this._cachedFormatter = cachedFormatter;
|
|
}
|
|
result ?? (result = cachedFormatter.formatter?.(value));
|
|
}
|
|
return result == null || (0, import_ag_charts_core107.isArray)(result) ? result : String(result);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], Label.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], Label.prototype, "formatter", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], Label.prototype, "format", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core107.Property
|
|
], Label.prototype, "itemStyler", 2);
|
|
function expandLabelPadding(label) {
|
|
const { enabled: borderEnabled = false, stroke: borderStroke } = label?.border ?? {};
|
|
const hasBoxing = label?.fill != null || borderEnabled && borderStroke != null;
|
|
const padding2 = hasBoxing ? label?.padding : null;
|
|
if (padding2 == null) {
|
|
return { bottom: 0, left: 0, right: 0, top: 0 };
|
|
} else if (typeof padding2 === "number") {
|
|
return { bottom: padding2, left: padding2, right: padding2, top: padding2 };
|
|
} else {
|
|
const { bottom = 0, left = 0, right = 0, top = 0 } = padding2;
|
|
return { bottom, left, right, top };
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axis.ts
|
|
var import_ag_charts_core117 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/module/moduleMap.ts
|
|
var ModuleMap = class {
|
|
constructor() {
|
|
this.moduleMap = /* @__PURE__ */ new Map();
|
|
}
|
|
modules() {
|
|
return this.moduleMap.values();
|
|
}
|
|
addModule(moduleName, moduleInstance) {
|
|
if (this.moduleMap.has(moduleName)) {
|
|
throw new Error(`AG Charts - module already initialised: ${moduleName}`);
|
|
}
|
|
this.moduleMap.set(moduleName, moduleInstance);
|
|
}
|
|
removeModule(moduleName) {
|
|
this.moduleMap.get(moduleName)?.destroy?.();
|
|
this.moduleMap.delete(moduleName);
|
|
}
|
|
getModule(moduleName) {
|
|
return this.moduleMap.get(moduleName);
|
|
}
|
|
isEnabled(moduleName) {
|
|
return this.moduleMap.has(moduleName);
|
|
}
|
|
mapModules(callback4) {
|
|
return Array.from(this.moduleMap.values(), callback4);
|
|
}
|
|
destroy() {
|
|
for (const moduleInstance of this.moduleMap.values()) {
|
|
moduleInstance?.destroy?.();
|
|
}
|
|
this.moduleMap.clear();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/crossline/cartesianCrossLine.ts
|
|
var import_ag_charts_core109 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/shape/range.ts
|
|
var Range = class extends Shape {
|
|
constructor(opts = {}) {
|
|
super(opts);
|
|
this.x1 = 0;
|
|
this.y1 = 0;
|
|
this.x2 = 0;
|
|
this.y2 = 0;
|
|
this.startLine = false;
|
|
this.endLine = false;
|
|
this.horizontal = false;
|
|
this.strokeWidth = 1;
|
|
}
|
|
computeBBox() {
|
|
return new BBox(this.x1, this.y1, this.x2 - this.x1, this.y2 - this.y1);
|
|
}
|
|
isPointInPath(_x, _y) {
|
|
return false;
|
|
}
|
|
render(renderCtx) {
|
|
const { ctx } = renderCtx;
|
|
let { x1, y1, x2, y2 } = this;
|
|
x1 = this.align(x1);
|
|
y1 = this.align(y1);
|
|
x2 = this.align(x2);
|
|
y2 = this.align(y2);
|
|
const { fill, horizontal } = this;
|
|
const { globalAlpha } = ctx;
|
|
if (fill != null) {
|
|
this.applyFillAndAlpha(ctx);
|
|
ctx.beginPath();
|
|
ctx.moveTo(x1, y1);
|
|
ctx.lineTo(x2, y1);
|
|
ctx.lineTo(x2, y2);
|
|
ctx.lineTo(x1, y2);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
ctx.globalAlpha = globalAlpha;
|
|
}
|
|
const { stroke, strokeWidth, startLine, endLine } = this;
|
|
const strokeActive = !!((startLine || endLine) && stroke && strokeWidth);
|
|
if (strokeActive) {
|
|
const { lineDash, lineDashOffset, lineCap, lineJoin } = this;
|
|
this.applyStrokeAndAlpha(ctx);
|
|
ctx.lineWidth = strokeWidth;
|
|
if (lineDash) {
|
|
ctx.setLineDash([...lineDash]);
|
|
}
|
|
if (lineDashOffset) {
|
|
ctx.lineDashOffset = lineDashOffset;
|
|
}
|
|
if (lineCap) {
|
|
ctx.lineCap = lineCap;
|
|
}
|
|
if (lineJoin) {
|
|
ctx.lineJoin = lineJoin;
|
|
}
|
|
ctx.beginPath();
|
|
if (startLine) {
|
|
ctx.moveTo(x1, y1);
|
|
if (horizontal) {
|
|
ctx.lineTo(x1, y2);
|
|
} else {
|
|
ctx.lineTo(x2, y1);
|
|
}
|
|
}
|
|
if (endLine) {
|
|
ctx.moveTo(x2, y2);
|
|
if (horizontal) {
|
|
ctx.lineTo(x2, y1);
|
|
} else {
|
|
ctx.lineTo(x1, y2);
|
|
}
|
|
}
|
|
ctx.stroke();
|
|
ctx.globalAlpha = globalAlpha;
|
|
}
|
|
this.fillShadow?.markClean();
|
|
super.render(renderCtx);
|
|
}
|
|
};
|
|
Range.className = "Range";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Range.prototype, "x1", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Range.prototype, "y1", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Range.prototype, "x2", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Range.prototype, "y2", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Range.prototype, "startLine", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Range.prototype, "endLine", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Range.prototype, "horizontal", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/crossline/crossLine.ts
|
|
var import_ag_charts_core108 = require("ag-charts-core");
|
|
function getCrossLineValue(crossLine) {
|
|
switch (crossLine.type) {
|
|
case "line":
|
|
return crossLine.value;
|
|
case "range":
|
|
return crossLine.range;
|
|
}
|
|
}
|
|
function validateCrossLineValue(crossLine, scale2) {
|
|
const value = getCrossLineValue(crossLine);
|
|
if (value == null) {
|
|
return false;
|
|
}
|
|
const isContinuous3 = ContinuousScale.is(scale2) || DiscreteTimeScale.is(scale2);
|
|
const validValue = (val) => (0, import_ag_charts_core108.checkDatum)(val, isContinuous3) && !Number.isNaN(scale2.convert(val, { clamp: true }));
|
|
if (crossLine.type === "range") {
|
|
const [start, end2] = value;
|
|
return validValue(start) && validValue(end2);
|
|
} else {
|
|
return validValue(value);
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/crossline/cartesianCrossLine.ts
|
|
var horizontalLineAnchors = {
|
|
top: { rangeH: 0, rangeV: -1, labelH: 0, labelV: 1 },
|
|
"inside-top": { rangeH: 0, rangeV: -1, labelH: 0, labelV: 1 },
|
|
"top-left": { rangeH: -1, rangeV: -1, labelH: -1, labelV: 1 },
|
|
"inside-top-left": { rangeH: -1, rangeV: -1, labelH: -1, labelV: 1 },
|
|
left: { rangeH: -1, rangeV: 0, labelH: 1, labelV: 0 },
|
|
"inside-left": { rangeH: -1, rangeV: 0, labelH: -1, labelV: 0 },
|
|
"bottom-left": { rangeH: -1, rangeV: 1, labelH: -1, labelV: -1 },
|
|
"inside-bottom-left": { rangeH: -1, rangeV: 1, labelH: -1, labelV: -1 },
|
|
bottom: { rangeH: 0, rangeV: 1, labelH: 0, labelV: -1 },
|
|
"inside-bottom": { rangeH: 0, rangeV: 1, labelH: 0, labelV: -1 },
|
|
"bottom-right": { rangeH: 1, rangeV: 1, labelH: 1, labelV: -1 },
|
|
"inside-bottom-right": { rangeH: 1, rangeV: 1, labelH: 1, labelV: -1 },
|
|
right: { rangeH: 1, rangeV: 0, labelH: -1, labelV: 0 },
|
|
"inside-right": { rangeH: 1, rangeV: 0, labelH: 1, labelV: 0 },
|
|
"top-right": { rangeH: 1, rangeV: -1, labelH: 1, labelV: 1 },
|
|
"inside-top-right": { rangeH: 1, rangeV: -1, labelH: 1, labelV: 1 },
|
|
inside: { rangeH: 0, rangeV: 0, labelH: 0, labelV: 0 }
|
|
};
|
|
var verticalLineAnchors = {
|
|
top: { rangeH: 0, rangeV: -1, labelH: 0, labelV: 1 },
|
|
"inside-top": { rangeH: 0, rangeV: -1, labelH: 0, labelV: -1 },
|
|
"top-left": { rangeH: -1, rangeV: -1, labelH: 1, labelV: -1 },
|
|
"inside-top-left": { rangeH: -1, rangeV: -1, labelH: 1, labelV: -1 },
|
|
left: { rangeH: -1, rangeV: 0, labelH: 1, labelV: 0 },
|
|
"inside-left": { rangeH: -1, rangeV: 0, labelH: 1, labelV: 0 },
|
|
"bottom-left": { rangeH: -1, rangeV: 1, labelH: 1, labelV: 1 },
|
|
"inside-bottom-left": { rangeH: -1, rangeV: 1, labelH: 1, labelV: 1 },
|
|
bottom: { rangeH: 0, rangeV: 1, labelH: 0, labelV: -1 },
|
|
"inside-bottom": { rangeH: 0, rangeV: 1, labelH: 0, labelV: 1 },
|
|
"bottom-right": { rangeH: 1, rangeV: 1, labelH: -1, labelV: 1 },
|
|
"inside-bottom-right": { rangeH: 1, rangeV: 1, labelH: -1, labelV: 1 },
|
|
right: { rangeH: 1, rangeV: 0, labelH: -1, labelV: 0 },
|
|
"inside-right": { rangeH: 1, rangeV: 0, labelH: -1, labelV: 0 },
|
|
"top-right": { rangeH: 1, rangeV: -1, labelH: -1, labelV: -1 },
|
|
"inside-top-right": { rangeH: -1, rangeV: -1, labelH: -1, labelV: -1 },
|
|
inside: { rangeH: 0, rangeV: 0, labelH: 0, labelV: 0 }
|
|
};
|
|
var horizontalRangeAnchors = {
|
|
top: { rangeH: 0, rangeV: -1, labelH: 0, labelV: 1 },
|
|
"inside-top": { rangeH: 0, rangeV: -1, labelH: 0, labelV: -1 },
|
|
"top-left": { rangeH: -1, rangeV: -1, labelH: -1, labelV: 1 },
|
|
"inside-top-left": { rangeH: -1, rangeV: -1, labelH: -1, labelV: -1 },
|
|
left: { rangeH: -1, rangeV: 0, labelH: 1, labelV: 0 },
|
|
"inside-left": { rangeH: -1, rangeV: 0, labelH: -1, labelV: 0 },
|
|
"bottom-left": { rangeH: -1, rangeV: 1, labelH: -1, labelV: -1 },
|
|
"inside-bottom-left": { rangeH: -1, rangeV: 1, labelH: -1, labelV: 1 },
|
|
bottom: { rangeH: 0, rangeV: 1, labelH: 0, labelV: -1 },
|
|
"inside-bottom": { rangeH: 0, rangeV: 1, labelH: 0, labelV: 1 },
|
|
"bottom-right": { rangeH: 1, rangeV: 1, labelH: 1, labelV: -1 },
|
|
"inside-bottom-right": { rangeH: 1, rangeV: 1, labelH: 1, labelV: 1 },
|
|
right: { rangeH: 1, rangeV: 0, labelH: -1, labelV: 0 },
|
|
"inside-right": { rangeH: 1, rangeV: 0, labelH: 1, labelV: 0 },
|
|
"top-right": { rangeH: 1, rangeV: -1, labelH: 1, labelV: 1 },
|
|
"inside-top-right": { rangeH: 1, rangeV: -1, labelH: 1, labelV: -1 },
|
|
inside: { rangeH: 0, rangeV: 0, labelH: 0, labelV: 0 }
|
|
};
|
|
var verticalRangeAnchors = {
|
|
top: { rangeH: 0, rangeV: -1, labelH: 0, labelV: 1 },
|
|
"inside-top": { rangeH: 0, rangeV: -1, labelH: 0, labelV: -1 },
|
|
"top-left": { rangeH: -1, rangeV: -1, labelH: 1, labelV: -1 },
|
|
"inside-top-left": { rangeH: -1, rangeV: -1, labelH: -1, labelV: -1 },
|
|
left: { rangeH: -1, rangeV: 0, labelH: 1, labelV: 0 },
|
|
"inside-left": { rangeH: -1, rangeV: 0, labelH: -1, labelV: 0 },
|
|
"bottom-left": { rangeH: -1, rangeV: 1, labelH: 1, labelV: 1 },
|
|
"inside-bottom-left": { rangeH: -1, rangeV: 1, labelH: -1, labelV: 1 },
|
|
bottom: { rangeH: 0, rangeV: 1, labelH: 0, labelV: -1 },
|
|
"inside-bottom": { rangeH: 0, rangeV: 1, labelH: 0, labelV: 1 },
|
|
"bottom-right": { rangeH: 1, rangeV: 1, labelH: -1, labelV: 1 },
|
|
"inside-bottom-right": { rangeH: 1, rangeV: 1, labelH: 1, labelV: 1 },
|
|
right: { rangeH: 1, rangeV: 0, labelH: -1, labelV: 0 },
|
|
"inside-right": { rangeH: 1, rangeV: 0, labelH: 1, labelV: 0 },
|
|
"top-right": { rangeH: 1, rangeV: -1, labelH: -1, labelV: -1 },
|
|
"inside-top-right": { rangeH: 1, rangeV: -1, labelH: 1, labelV: -1 },
|
|
inside: { rangeH: 0, rangeV: 0, labelH: 0, labelV: 0 }
|
|
};
|
|
var CartesianCrossLineLabel = class extends LabelStyle {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = void 0;
|
|
this.padding = 5;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLineLabel.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLineLabel.prototype, "padding", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLineLabel.prototype, "text", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLineLabel.prototype, "position", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLineLabel.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLineLabel.prototype, "parallel", 2);
|
|
var CartesianCrossLine = class extends import_ag_charts_core109.BaseProperties {
|
|
constructor() {
|
|
super();
|
|
this.id = (0, import_ag_charts_core109.createId)(this);
|
|
this.defaultColorRange = [];
|
|
this.fill = "#c16068";
|
|
this.label = new CartesianCrossLineLabel();
|
|
this.scale = void 0;
|
|
this.clippedRange = [-Infinity, Infinity];
|
|
this.gridLength = 0;
|
|
this.position = "top";
|
|
this.rangeGroup = new Group({ name: this.id });
|
|
this.lineGroup = new Group({ name: this.id });
|
|
this.labelGroup = new Group({ name: this.id });
|
|
this.crossLineRange = this.lineGroup.appendChild(new Range());
|
|
this.crossLineLabel = this.labelGroup.appendChild(new TransformableText());
|
|
this.data = void 0;
|
|
this.startLine = false;
|
|
this.endLine = false;
|
|
this._isRange = void 0;
|
|
this.crossLineRange.pointerEvents = 1 /* None */;
|
|
}
|
|
get defaultLabelPosition() {
|
|
return "top";
|
|
}
|
|
update(visible) {
|
|
const { enabled, type, data, scale: scale2 } = this;
|
|
if (!scale2 || !enabled || !visible || !validateCrossLineValue(this, scale2) || data == null) {
|
|
this.rangeGroup.visible = false;
|
|
this.lineGroup.visible = false;
|
|
this.labelGroup.visible = false;
|
|
return;
|
|
}
|
|
this.rangeGroup.visible = visible;
|
|
this.lineGroup.visible = visible;
|
|
this.labelGroup.visible = visible;
|
|
this.updateNodes();
|
|
const isRange = type === "range";
|
|
if (isRange !== this._isRange) {
|
|
if (isRange) {
|
|
this.rangeGroup.appendChild(this.crossLineRange);
|
|
} else {
|
|
this.lineGroup.appendChild(this.crossLineRange);
|
|
}
|
|
}
|
|
this._isRange = isRange;
|
|
}
|
|
calculateLayout(visible) {
|
|
this.data = void 0;
|
|
if (!visible)
|
|
return;
|
|
const { type, range: range4, value, scale: scale2, clippedRange, strokeWidth = 0 } = this;
|
|
if (!scale2)
|
|
return;
|
|
const bandwidth = scale2.bandwidth ?? 0;
|
|
const step = scale2.step ?? 0;
|
|
const rangePadding = scale2 instanceof BandScale ? (step - bandwidth) / 2 : 0;
|
|
let [clippedRange0, clippedRange1] = (0, import_ag_charts_core109.findMinMax)(clippedRange);
|
|
clippedRange0 -= bandwidth;
|
|
clippedRange1 += bandwidth;
|
|
let yStart;
|
|
let yEnd;
|
|
let clampedYStart;
|
|
let clampedYEnd;
|
|
if (type === "line") {
|
|
const offset = bandwidth / 2;
|
|
yStart = scale2.convert(value) + offset;
|
|
yEnd = Number.NaN;
|
|
clampedYStart = scale2.convert(value, { clamp: true }) + offset;
|
|
clampedYEnd = Number.NaN;
|
|
if (clampedYStart >= clippedRange1 || clampedYStart <= clippedRange0) {
|
|
return;
|
|
}
|
|
} else if (range4) {
|
|
const [r0, r1] = range4;
|
|
const [startAlignment, endAlignment] = rangeAlignment(r0, r1);
|
|
yStart = scale2.convert(r0, { alignment: startAlignment });
|
|
yEnd = scale2.convert(r1, { alignment: endAlignment });
|
|
clampedYStart = scale2.convert(r0, { clamp: true, alignment: startAlignment });
|
|
clampedYEnd = scale2.convert(r1, { clamp: true, alignment: endAlignment });
|
|
if (clampedYStart > clampedYEnd) {
|
|
[clampedYStart, clampedYEnd] = [clampedYEnd, clampedYStart];
|
|
[yStart, yEnd] = [yEnd, yStart];
|
|
}
|
|
if (clampedYStart >= clippedRange1 || clampedYEnd <= clippedRange0) {
|
|
return;
|
|
}
|
|
if (Number.isFinite(yStart)) {
|
|
clampedYStart -= rangePadding;
|
|
}
|
|
if (Number.isFinite(yEnd)) {
|
|
yEnd += bandwidth;
|
|
clampedYEnd += bandwidth + rangePadding;
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
clampedYStart = (0, import_ag_charts_core109.clampArray)(clampedYStart, clippedRange);
|
|
clampedYEnd = (0, import_ag_charts_core109.clampArray)(clampedYEnd, clippedRange);
|
|
if (yStart - rangePadding >= clampedYStart)
|
|
yStart -= rangePadding;
|
|
if (yEnd + rangePadding <= clampedYEnd)
|
|
yEnd += rangePadding;
|
|
this.startLine = strokeWidth > 0 && yStart >= clampedYStart && yStart <= clampedYStart + rangePadding;
|
|
this.endLine = strokeWidth > 0 && yEnd >= clampedYEnd - bandwidth - rangePadding && yEnd <= clampedYEnd;
|
|
this.data = [clampedYStart, clampedYEnd];
|
|
if (this.label.enabled === false || !this.label.text)
|
|
return;
|
|
}
|
|
updateNodes() {
|
|
const { position, data: [r0, r1] = [0, 0], gridLength } = this;
|
|
const dr = Number.isFinite(r1) ? r1 - r0 : 0;
|
|
let bounds;
|
|
switch (position) {
|
|
case "top":
|
|
case "bottom":
|
|
bounds = new BBox(r0, position === "top" ? 0 : -gridLength, dr, gridLength);
|
|
break;
|
|
case "left":
|
|
case "right":
|
|
bounds = new BBox(position === "left" ? 0 : -gridLength, r0, gridLength, dr);
|
|
}
|
|
this.updateRangeNode(bounds);
|
|
const { label } = this;
|
|
if (label.enabled !== false && label.text) {
|
|
this.updateLabel();
|
|
this.positionLabel(bounds);
|
|
}
|
|
}
|
|
updateRangeNode(bounds) {
|
|
const {
|
|
type,
|
|
position,
|
|
crossLineRange,
|
|
startLine,
|
|
endLine,
|
|
fill,
|
|
fillOpacity,
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash
|
|
} = this;
|
|
crossLineRange.x1 = bounds.x;
|
|
crossLineRange.x2 = bounds.x + bounds.width;
|
|
crossLineRange.y1 = bounds.y;
|
|
crossLineRange.y2 = bounds.y + bounds.height;
|
|
crossLineRange.horizontal = position === "top" || position === "bottom";
|
|
crossLineRange.startLine = startLine;
|
|
crossLineRange.endLine = endLine;
|
|
crossLineRange.fill = type === "range" ? fill : void 0;
|
|
crossLineRange.fillOpacity = fillOpacity ?? 1;
|
|
crossLineRange.stroke = stroke;
|
|
crossLineRange.strokeWidth = strokeWidth ?? 1;
|
|
crossLineRange.strokeOpacity = strokeOpacity ?? 1;
|
|
crossLineRange.lineDash = lineDash;
|
|
}
|
|
updateLabel() {
|
|
const { crossLineLabel, label } = this;
|
|
if (!label.text)
|
|
return;
|
|
crossLineLabel.fill = label.color;
|
|
crossLineLabel.text = label.text;
|
|
crossLineLabel.textAlign = "center";
|
|
crossLineLabel.textBaseline = "middle";
|
|
crossLineLabel.setFont(label);
|
|
crossLineLabel.setBoxing(label);
|
|
}
|
|
get anchor() {
|
|
const horizontal = this.position === "left" || this.position === "right";
|
|
const range4 = this.type === "range";
|
|
const { position = this.defaultLabelPosition } = this.label;
|
|
if (range4) {
|
|
const anchors = horizontal ? horizontalRangeAnchors : verticalRangeAnchors;
|
|
return anchors[position];
|
|
} else {
|
|
const anchors = horizontal ? horizontalLineAnchors : verticalLineAnchors;
|
|
return anchors[position];
|
|
}
|
|
}
|
|
positionLabel(bounds) {
|
|
const { crossLineLabel, label, anchor } = this;
|
|
crossLineLabel.rotation = (0, import_ag_charts_core109.toRadians)(label.rotation ?? 0);
|
|
const bbox = crossLineLabel.getBBox();
|
|
if (!bbox)
|
|
return;
|
|
const { width, height } = bbox;
|
|
const xOffset = label.padding + width / 2;
|
|
const yOffset = label.padding + height / 2;
|
|
const x = bounds.x + bounds.width * (anchor.rangeH + 1) / 2 - xOffset * anchor.labelH;
|
|
const y = bounds.y + bounds.height * (anchor.rangeV + 1) / 2 - yOffset * anchor.labelV;
|
|
crossLineLabel.x = x;
|
|
crossLineLabel.y = y;
|
|
crossLineLabel.rotationCenterX = x;
|
|
crossLineLabel.rotationCenterY = y;
|
|
}
|
|
computeLabelSize() {
|
|
const { label } = this;
|
|
if (label.enabled === false || !label.text)
|
|
return;
|
|
const tempText = new TransformableText();
|
|
tempText.fontFamily = label.fontFamily;
|
|
tempText.fontSize = label.fontSize;
|
|
tempText.fontStyle = label.fontStyle;
|
|
tempText.fontWeight = label.fontWeight;
|
|
tempText.text = label.text;
|
|
tempText.rotation = (0, import_ag_charts_core109.toRadians)(label.rotation ?? 0);
|
|
tempText.textBaseline = "middle";
|
|
tempText.textAlign = "center";
|
|
const bbox = tempText.getBBox();
|
|
if (!bbox)
|
|
return;
|
|
const { width, height } = bbox;
|
|
return { width, height };
|
|
}
|
|
calculatePadding(into) {
|
|
const { label, anchor } = this;
|
|
const size = this.computeLabelSize();
|
|
if (!size)
|
|
return;
|
|
const { width, height } = size;
|
|
const xOffset = label.padding + width;
|
|
const yOffset = label.padding + height;
|
|
const horizontal = this.position === "left" || this.position === "right";
|
|
if (horizontal) {
|
|
if (anchor.rangeH === -1 && anchor.labelH === 1) {
|
|
into.left = Math.max(into.left ?? 0, xOffset);
|
|
} else if (anchor.rangeH === 1 && anchor.labelH === -1) {
|
|
into.right = Math.max(into.right ?? 0, xOffset);
|
|
}
|
|
}
|
|
if (!horizontal) {
|
|
if (anchor.rangeV === -1 && anchor.labelV === 1) {
|
|
into.top = Math.max(into.top ?? 0, yOffset);
|
|
} else if (anchor.rangeV === 1 && anchor.labelV === -1) {
|
|
into.bottom = Math.max(into.bottom ?? 0, yOffset);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
CartesianCrossLine.className = "CrossLine";
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "type", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "range", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "value", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "defaultColorRange", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core109.Property
|
|
], CartesianCrossLine.prototype, "label", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axisGridLine.ts
|
|
var import_ag_charts_core110 = require("ag-charts-core");
|
|
var AxisGridLine = class {
|
|
constructor() {
|
|
this.enabled = true;
|
|
this.width = 1;
|
|
this.style = [
|
|
{
|
|
fill: void 0,
|
|
fillOpacity: 1,
|
|
stroke: void 0,
|
|
strokeWidth: void 0,
|
|
lineDash: []
|
|
}
|
|
];
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core110.Property
|
|
], AxisGridLine.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core110.Property
|
|
], AxisGridLine.prototype, "width", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core110.Property
|
|
], AxisGridLine.prototype, "style", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axisInterval.ts
|
|
var import_ag_charts_core111 = require("ag-charts-core");
|
|
var AxisInterval = class extends import_ag_charts_core111.BaseProperties {
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core111.Property
|
|
], AxisInterval.prototype, "placement", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core111.Property
|
|
], AxisInterval.prototype, "step", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core111.Property
|
|
], AxisInterval.prototype, "values", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core111.Property
|
|
], AxisInterval.prototype, "minSpacing", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core111.Property
|
|
], AxisInterval.prototype, "maxSpacing", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axisLabel.ts
|
|
var import_ag_charts_core112 = require("ag-charts-core");
|
|
var AxisLabel = class extends import_ag_charts_core112.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.border = new LabelBorder();
|
|
this.wrapping = "never";
|
|
this.truncate = false;
|
|
this.spacing = 5;
|
|
this.color = "#575757";
|
|
this.avoidCollisions = true;
|
|
this.mirrored = false;
|
|
this.parallel = false;
|
|
this._formatters = {
|
|
"component:year": void 0,
|
|
"component:month": void 0,
|
|
"component:day": void 0,
|
|
"component:none": void 0,
|
|
"long:year": void 0,
|
|
"long:month": void 0,
|
|
"long:day": void 0,
|
|
"long:none": void 0
|
|
};
|
|
}
|
|
/**
|
|
* The side of the axis line to position the labels on.
|
|
* -1 = left (default)
|
|
* 1 = right
|
|
*/
|
|
getSideFlag() {
|
|
return this.mirrored ? 1 : -1;
|
|
}
|
|
formatValue(callWithContext7, params, index, options) {
|
|
const { formatter, format } = this;
|
|
const { type, value, domain, boundSeries } = params;
|
|
const fractionDigits = params.type === "number" ? params.fractionDigits : void 0;
|
|
const unit = params.type === "date" ? params.unit : void 0;
|
|
let result;
|
|
if (formatter != null) {
|
|
const step = params.type === "date" ? params.step : void 0;
|
|
const visibleDomain = params.type === "number" ? params.visibleDomain : void 0;
|
|
result = callWithContext7(formatter, {
|
|
value,
|
|
index,
|
|
domain,
|
|
fractionDigits,
|
|
unit,
|
|
step,
|
|
boundSeries,
|
|
visibleDomain
|
|
});
|
|
}
|
|
if (format != null && result == null) {
|
|
const { specifier, dateStyle = "long", truncateDate } = options ?? {};
|
|
const cacheKey = `${dateStyle}:${truncateDate ?? "none"}`;
|
|
let valueFormatter = this._formatters[cacheKey];
|
|
const mergedFormat = FormatManager.mergeSpecifiers(specifier, format);
|
|
if (valueFormatter?.type !== type || valueFormatter?.unit !== unit || !(0, import_ag_charts_core112.objectsEqual)(valueFormatter?.mergedFormat, mergedFormat)) {
|
|
valueFormatter = {
|
|
type,
|
|
mergedFormat,
|
|
unit,
|
|
formatter: FormatManager.getFormatter(type, mergedFormat, unit, dateStyle, { truncateDate })
|
|
};
|
|
this._formatters[cacheKey] = valueFormatter;
|
|
}
|
|
result = valueFormatter.formatter?.(value, fractionDigits);
|
|
}
|
|
return result == null || (0, import_ag_charts_core112.isArray)(result) ? result : String(result);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "border", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "fontFamily", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "wrapping", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "truncate", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "minSpacing", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "color", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "avoidCollisions", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "mirrored", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "padding", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "parallel", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "formatter", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core112.Property
|
|
], AxisLabel.prototype, "format", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axisLine.ts
|
|
var import_ag_charts_core113 = require("ag-charts-core");
|
|
var AxisLine = class {
|
|
constructor() {
|
|
this.enabled = true;
|
|
this.width = 1;
|
|
this.stroke = void 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core113.Property
|
|
], AxisLine.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core113.Property
|
|
], AxisLine.prototype, "width", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core113.Property
|
|
], AxisLine.prototype, "stroke", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axisTick.ts
|
|
var import_ag_charts_core114 = require("ag-charts-core");
|
|
var AxisTick = class extends import_ag_charts_core114.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.width = 1;
|
|
this.size = 6;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core114.Property
|
|
], AxisTick.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core114.Property
|
|
], AxisTick.prototype, "width", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core114.Property
|
|
], AxisTick.prototype, "size", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core114.Property
|
|
], AxisTick.prototype, "stroke", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axisTitle.ts
|
|
var import_ag_charts_core115 = require("ag-charts-core");
|
|
var AxisTitle = class extends import_ag_charts_core115.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.caption = new Caption();
|
|
this.enabled = false;
|
|
this.spacing = Caption.SMALL_PADDING;
|
|
this.fontSize = import_ag_charts_core115.FONT_SIZE.SMALLER;
|
|
this.fontFamily = "sans-serif";
|
|
this.wrapping = "always";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "text", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "fontFamily", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "color", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "wrapping", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core115.Property
|
|
], AxisTitle.prototype, "formatter", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axisUtil.ts
|
|
var import_ag_charts_core116 = require("ag-charts-core");
|
|
var NiceMode = /* @__PURE__ */ ((NiceMode2) => {
|
|
NiceMode2[NiceMode2["TickAndDomain"] = 0] = "TickAndDomain";
|
|
NiceMode2[NiceMode2["TicksOnly"] = 1] = "TicksOnly";
|
|
NiceMode2[NiceMode2["Off"] = 2] = "Off";
|
|
return NiceMode2;
|
|
})(NiceMode || {});
|
|
function prepareAxisAnimationContext(axis) {
|
|
const [requestedRangeMin, requestedRangeMax] = (0, import_ag_charts_core116.findMinMax)(axis.range);
|
|
const min = Math.floor(requestedRangeMin);
|
|
const max = Math.ceil(requestedRangeMax);
|
|
return { min, max, visible: min !== max };
|
|
}
|
|
var fullCircle = Math.PI * 2;
|
|
var halfCircle = fullCircle / 2;
|
|
function normaliseEndRotation(start, end2) {
|
|
const directDistance = Math.abs(end2 - start);
|
|
if (directDistance < halfCircle) {
|
|
return end2;
|
|
} else if (start > end2) {
|
|
return end2 + fullCircle;
|
|
}
|
|
return end2 - fullCircle;
|
|
}
|
|
function prepareAxisAnimationFunctions(ctx) {
|
|
const { min, max } = ctx;
|
|
const outOfBounds = (y) => {
|
|
return y < min || y > max;
|
|
};
|
|
const tick = {
|
|
fromFn(node, datum, status) {
|
|
let { x1, x2, y1, y2 } = node;
|
|
let opacity = node.opacity;
|
|
if (status === "added" || outOfBounds(datum.offset)) {
|
|
({ x1, x2, y1, y2 } = datum);
|
|
opacity = 0;
|
|
}
|
|
return {
|
|
x1,
|
|
x2,
|
|
y1,
|
|
y2,
|
|
opacity,
|
|
phase: NODE_UPDATE_STATE_TO_PHASE_MAPPING[status]
|
|
};
|
|
},
|
|
toFn(_node, datum, status) {
|
|
const { x1, x2, y1, y2 } = datum;
|
|
let opacity = 1;
|
|
if (status === "removed") {
|
|
opacity = 0;
|
|
}
|
|
return { x1, x2, y1, y2, opacity };
|
|
},
|
|
applyFn(node, props) {
|
|
node.setProperties(props);
|
|
node.visible = !outOfBounds(node.y);
|
|
}
|
|
};
|
|
const label = {
|
|
fromFn(node, newDatum, status) {
|
|
const datum = node.previousDatum ?? newDatum;
|
|
let { x, y, rotationCenterX, rotationCenterY, rotation } = datum;
|
|
let opacity = node.opacity;
|
|
if (status === "removed" || outOfBounds(datum.y)) {
|
|
rotation = newDatum.rotation;
|
|
} else if (status === "added" || outOfBounds(node.datum.y)) {
|
|
({ x, y, rotationCenterX, rotationCenterY, rotation } = newDatum);
|
|
opacity = 0;
|
|
}
|
|
return {
|
|
x,
|
|
y,
|
|
rotationCenterX,
|
|
rotationCenterY,
|
|
rotation,
|
|
opacity,
|
|
phase: NODE_UPDATE_STATE_TO_PHASE_MAPPING[status]
|
|
};
|
|
},
|
|
toFn(node, datum, status) {
|
|
const { x, y, rotationCenterX, rotationCenterY } = datum;
|
|
let rotation = 0;
|
|
let opacity = 1;
|
|
if (status === "added") {
|
|
rotation = datum.rotation;
|
|
} else if (status === "removed") {
|
|
opacity = 0;
|
|
rotation = datum.rotation;
|
|
} else {
|
|
rotation = normaliseEndRotation(node.previousDatum?.rotation ?? datum.rotation, datum.rotation);
|
|
}
|
|
return {
|
|
x,
|
|
y,
|
|
rotationCenterX,
|
|
rotationCenterY,
|
|
rotation,
|
|
opacity,
|
|
finish: { rotation: datum.rotation }
|
|
};
|
|
}
|
|
};
|
|
const line = {
|
|
fromFn(node, datum) {
|
|
const { x1, x2, y1, y2 } = node.previousDatum ?? datum;
|
|
return {
|
|
x1,
|
|
x2,
|
|
y1,
|
|
y2,
|
|
phase: NODE_UPDATE_STATE_TO_PHASE_MAPPING["updated"]
|
|
};
|
|
},
|
|
toFn(_node, datum) {
|
|
const { x1, x2, y1, y2 } = datum;
|
|
return { x1, x2, y1, y2 };
|
|
}
|
|
};
|
|
const group = {
|
|
fromFn(node, _datum) {
|
|
const { translationX, translationY } = node;
|
|
return {
|
|
translationX,
|
|
translationY,
|
|
phase: NODE_UPDATE_STATE_TO_PHASE_MAPPING["updated"]
|
|
};
|
|
},
|
|
toFn(_node, datum) {
|
|
const { translationX, translationY } = datum;
|
|
return { translationX, translationY };
|
|
}
|
|
};
|
|
return { tick, line, label, group };
|
|
}
|
|
function resetAxisGroupFn() {
|
|
return (_node, datum) => {
|
|
return {
|
|
translationX: datum.translationX,
|
|
translationY: datum.translationY
|
|
};
|
|
};
|
|
}
|
|
function resetAxisLabelSelectionFn() {
|
|
return (_node, datum) => {
|
|
return {
|
|
x: datum.x,
|
|
y: datum.y,
|
|
rotationCenterX: datum.rotationCenterX,
|
|
rotationCenterY: datum.rotationCenterY,
|
|
rotation: datum.rotation
|
|
};
|
|
};
|
|
}
|
|
function resetAxisLineSelectionFn() {
|
|
return (_node, datum) => {
|
|
const { x1, x2, y1, y2 } = datum;
|
|
return { x1, x2, y1, y2 };
|
|
};
|
|
}
|
|
function resetAxisFillSelectionFn() {
|
|
return (_node, datum) => {
|
|
const { x1, x2, y1, y2 } = datum;
|
|
return { x: x1, y: y1, width: x2 - x1, height: y2 - y1 };
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/axis/axis.ts
|
|
var AxisGroupZIndexMap = /* @__PURE__ */ ((AxisGroupZIndexMap2) => {
|
|
AxisGroupZIndexMap2[AxisGroupZIndexMap2["TickLines"] = 0] = "TickLines";
|
|
AxisGroupZIndexMap2[AxisGroupZIndexMap2["AxisLine"] = 1] = "AxisLine";
|
|
AxisGroupZIndexMap2[AxisGroupZIndexMap2["TickLabels"] = 2] = "TickLabels";
|
|
return AxisGroupZIndexMap2;
|
|
})(AxisGroupZIndexMap || {});
|
|
function tickLayoutCacheValid(a, b) {
|
|
return a.domain === b.domain && a.rangeExtent === b.rangeExtent && a.nice[0] === b.nice[0] && a.nice[1] === b.nice[1] && a.gridLength === b.gridLength && a.visibleRange[0] === b.visibleRange[0] && a.visibleRange[1] === b.visibleRange[1] && a.scrollbarKey === b.scrollbarKey && a.initialPrimaryTickCount?.unzoomed === b.initialPrimaryTickCount?.unzoomed && a.initialPrimaryTickCount?.zoomed === b.initialPrimaryTickCount?.zoomed;
|
|
}
|
|
function computeBand(scale2, range4, value) {
|
|
const bandwidth = scale2.bandwidth ?? 0;
|
|
const step = scale2.step ?? 0;
|
|
const offset = (step - bandwidth) / 2;
|
|
const position = scale2.convert(value);
|
|
const start = position - offset;
|
|
const end2 = position + bandwidth + offset;
|
|
return [position, (0, import_ag_charts_core117.clampArray)(start, range4), (0, import_ag_charts_core117.clampArray)(end2, range4)];
|
|
}
|
|
var _Axis = class _Axis {
|
|
constructor(moduleCtx, scale2) {
|
|
this.moduleCtx = moduleCtx;
|
|
this.scale = scale2;
|
|
this.id = "unknown";
|
|
this._crossLines = [];
|
|
this.nice = true;
|
|
this.reverse = false;
|
|
this.interval = new AxisInterval();
|
|
this.dataDomain = { domain: [], clipped: false };
|
|
this.allowNull = false;
|
|
this.title = new AxisTitle();
|
|
this.gridLength = 0;
|
|
/**
|
|
* The distance between the grid ticks and the axis ticks.
|
|
*/
|
|
this.gridPadding = 0;
|
|
/**
|
|
* Is used to avoid collisions between axis labels and series.
|
|
*/
|
|
this.seriesAreaPadding = 0;
|
|
this.layoutConstraints = {
|
|
stacked: true,
|
|
align: "justify",
|
|
width: 100,
|
|
unit: "percent"
|
|
};
|
|
this.boundSeries = [];
|
|
this.includeInvisibleDomains = false;
|
|
this.interactionEnabled = true;
|
|
this.axisGroup = new Group({ name: `${this.id}-axis` });
|
|
// Order is important to apply the correct z-index.
|
|
this.tickLineGroup = this.axisGroup.appendChild(
|
|
new TransformableGroup({ name: `${this.id}-Axis-tick-lines`, zIndex: 0 /* TickLines */ })
|
|
);
|
|
this.tickLabelGroup = this.axisGroup.appendChild(
|
|
new TransformableGroup({ name: `${this.id}-Axis-tick-labels`, zIndex: 2 /* TickLabels */ })
|
|
);
|
|
this.labelGroup = new Group({
|
|
name: `${this.id}-Labels`,
|
|
zIndex: import_ag_charts_core117.ZIndexMap.SERIES_ANNOTATION
|
|
});
|
|
this.gridGroup = new TranslatableGroup({ name: `${this.id}-Axis-grid`, zIndex: import_ag_charts_core117.ZIndexMap.AXIS_GRID });
|
|
this.gridFillGroup = this.gridGroup.appendChild(new Group({ name: `${this.id}-gridFills` }));
|
|
this.gridLineGroup = this.gridGroup.appendChild(new Group({ name: `${this.id}-gridLines` }));
|
|
this.crossLineRangeGroup = new TransformableGroup({
|
|
name: `${this.id}-CrossLines-Range`,
|
|
zIndex: import_ag_charts_core117.ZIndexMap.SERIES_CROSSLINE_RANGE
|
|
});
|
|
this.crossLineLineGroup = new TransformableGroup({
|
|
name: `${this.id}-CrossLines-Line`,
|
|
zIndex: import_ag_charts_core117.ZIndexMap.SERIES_CROSSLINE_LINE
|
|
});
|
|
this.crossLineLabelGroup = new TransformableGroup({
|
|
name: `${this.id}-CrossLines-Label`,
|
|
zIndex: import_ag_charts_core117.ZIndexMap.SERIES_LABEL
|
|
});
|
|
this.tickLabelGroupSelection = Selection.select(
|
|
this.tickLabelGroup,
|
|
TransformableText,
|
|
false
|
|
);
|
|
this.line = new AxisLine();
|
|
this.tick = new AxisTick();
|
|
this.gridLine = new AxisGridLine();
|
|
this.label = this.createLabel();
|
|
this.defaultTickMinSpacing = _Axis.defaultTickMinSpacing;
|
|
this.translation = { x: 0, y: 0 };
|
|
this.layout = {
|
|
label: {
|
|
fractionDigits: 0,
|
|
spacing: this.label.spacing,
|
|
format: this.label.format
|
|
},
|
|
labelThickness: 0
|
|
};
|
|
this.axisContext = void 0;
|
|
this.cleanup = new import_ag_charts_core117.CleanupRegistry();
|
|
// AG-15360 Avoid calling removeTooltip() if no tooltip is shown. This avoid a laggy tooltips caused by interference
|
|
// with SeriesAreaManager's tooltip updates.
|
|
this.isHovering = false;
|
|
this.range = [0, 1];
|
|
this.visibleRange = [0, 1];
|
|
this.animatable = true;
|
|
this.tickLayout = void 0;
|
|
this.formatterBoundSeries = new import_ag_charts_core117.WeakCache(() => {
|
|
const { direction, boundSeries } = this;
|
|
return (0, import_ag_charts_core117.deepFreeze)(boundSeries.flatMap((series) => series.getFormatterContext(direction)));
|
|
});
|
|
this.moduleMap = new ModuleMap();
|
|
this.range = this.scale.range.slice();
|
|
for (const crossLine of this.crossLines) {
|
|
this.initCrossLine(crossLine);
|
|
}
|
|
this.cleanup.register(
|
|
this.moduleCtx.widgets.containerWidget.addListener("mousemove", (e) => this.onMouseMove(e)),
|
|
this.moduleCtx.widgets.containerWidget.addListener("mouseleave", () => this.endHovering())
|
|
);
|
|
}
|
|
set crossLines(value) {
|
|
const { CrossLineConstructor } = this.constructor;
|
|
for (const crossLine of this._crossLines) {
|
|
this.detachCrossLine(crossLine);
|
|
}
|
|
this._crossLines = value.map((crossLine) => {
|
|
const instance = new CrossLineConstructor();
|
|
instance.set(crossLine);
|
|
return instance;
|
|
});
|
|
for (const crossLine of this._crossLines) {
|
|
this.attachCrossLine(crossLine);
|
|
this.initCrossLine(crossLine);
|
|
}
|
|
}
|
|
get crossLines() {
|
|
return this._crossLines;
|
|
}
|
|
get type() {
|
|
return this.constructor.type ?? "";
|
|
}
|
|
get primaryLabel() {
|
|
return void 0;
|
|
}
|
|
get primaryTick() {
|
|
return void 0;
|
|
}
|
|
isCategoryLike() {
|
|
return false;
|
|
}
|
|
resetAnimation(_phase) {
|
|
}
|
|
onMouseMove(event) {
|
|
const node = this.tickLabelGroup.pickNode(event.currentX, event.currentY);
|
|
const datum = node?.datum;
|
|
const { textUntruncated: title = void 0 } = datum ?? {};
|
|
if (title) {
|
|
this.moduleCtx.tooltipManager.updateTooltip(
|
|
this.id,
|
|
{ canvasX: event.currentX, canvasY: event.currentY, showArrow: false },
|
|
[{ type: "structured", title }]
|
|
);
|
|
this.isHovering = true;
|
|
} else {
|
|
this.endHovering();
|
|
}
|
|
}
|
|
endHovering() {
|
|
if (this.isHovering) {
|
|
this.moduleCtx.tooltipManager.removeTooltip(this.id, void 0, true);
|
|
this.isHovering = false;
|
|
}
|
|
}
|
|
attachCrossLine(crossLine) {
|
|
this.crossLineRangeGroup.appendChild(crossLine.rangeGroup);
|
|
this.crossLineLineGroup.appendChild(crossLine.lineGroup);
|
|
this.crossLineLabelGroup.appendChild(crossLine.labelGroup);
|
|
}
|
|
detachCrossLine(crossLine) {
|
|
crossLine.rangeGroup.remove();
|
|
crossLine.lineGroup.remove();
|
|
crossLine.labelGroup.remove();
|
|
}
|
|
destroy() {
|
|
this.moduleMap.destroy();
|
|
this.cleanup.flush();
|
|
}
|
|
setScaleRange(visibleRange) {
|
|
const { range: rr, scale: scale2 } = this;
|
|
const span = (rr[1] - rr[0]) / (visibleRange[1] - visibleRange[0]);
|
|
const shift = span * visibleRange[0];
|
|
const start = rr[0] - shift;
|
|
scale2.range = [start, start + span];
|
|
}
|
|
updateScale() {
|
|
const {
|
|
range: [r0, r1]
|
|
} = this;
|
|
this.setScaleRange(this.visibleRange);
|
|
for (const crossLine of this.crossLines) {
|
|
crossLine.clippedRange = [r0, r1];
|
|
}
|
|
}
|
|
setCrossLinesVisible(visible) {
|
|
this.crossLineRangeGroup.visible = visible;
|
|
this.crossLineLineGroup.visible = visible;
|
|
this.crossLineLabelGroup.visible = visible;
|
|
}
|
|
attachAxis(groups) {
|
|
groups.gridNode.appendChild(this.gridGroup);
|
|
groups.axisNode.appendChild(this.axisGroup);
|
|
groups.labelNode.appendChild(this.labelGroup);
|
|
groups.crossLineRangeNode.appendChild(this.crossLineRangeGroup);
|
|
groups.crossLineLineNode.appendChild(this.crossLineLineGroup);
|
|
groups.crossLineLabelNode.appendChild(this.crossLineLabelGroup);
|
|
}
|
|
detachAxis() {
|
|
this.gridGroup.remove();
|
|
this.axisGroup.remove();
|
|
this.labelGroup.remove();
|
|
this.crossLineRangeGroup.remove();
|
|
this.crossLineLineGroup.remove();
|
|
this.crossLineLabelGroup.remove();
|
|
}
|
|
attachLabel(axisLabelNode) {
|
|
this.labelGroup.append(axisLabelNode);
|
|
}
|
|
/**
|
|
* Checks if a point or an object is in range.
|
|
* @param value A point (or object's starting point).
|
|
* @param tolerance Expands the range on both ends by this amount.
|
|
*/
|
|
inRange(value, tolerance = 0) {
|
|
const [min, max] = (0, import_ag_charts_core117.findMinMax)(this.range);
|
|
return value >= min - tolerance && value <= max + tolerance;
|
|
}
|
|
/**
|
|
* Get a point's overflow on the range, expanded to include the non-visible range.
|
|
* @param value Point
|
|
* @returns Overflow
|
|
*/
|
|
getRangeOverflow(value) {
|
|
const { range: rr, visibleRange: vr } = this;
|
|
const size = (rr[1] - rr[0]) / (vr[1] - vr[0]);
|
|
const [min, max] = (0, import_ag_charts_core117.findMinMax)([rr[0] - size * vr[0], rr[0] - size * vr[0] + size]);
|
|
if (value < min)
|
|
return value - min;
|
|
if (value > max)
|
|
return value - max;
|
|
return 0;
|
|
}
|
|
onGridLengthChange(value, prevValue) {
|
|
if (prevValue ^ value) {
|
|
this.onGridVisibilityChange();
|
|
}
|
|
for (const crossLine of this.crossLines) {
|
|
this.initCrossLine(crossLine);
|
|
}
|
|
}
|
|
onGridVisibilityChange() {
|
|
}
|
|
createLabel() {
|
|
return new AxisLabel();
|
|
}
|
|
/**
|
|
* Creates/removes/updates the scene graph nodes that constitute the axis.
|
|
*/
|
|
update() {
|
|
this.formatterBoundSeries.clear();
|
|
this.updatePosition();
|
|
this.updateSelections();
|
|
this.gridLineGroup.visible = this.gridLine.enabled;
|
|
this.updateLabels();
|
|
this.updateCrossLines();
|
|
}
|
|
getLabelStyles(params, additionalStyles, label = this.label) {
|
|
const defaultStyle = {
|
|
border: label.border,
|
|
color: label.color,
|
|
cornerRadius: label.cornerRadius,
|
|
fill: label.fill,
|
|
fillOpacity: label.fillOpacity,
|
|
fontFamily: label.fontFamily,
|
|
fontSize: label.fontSize,
|
|
fontStyle: label.fontStyle,
|
|
fontWeight: label.fontWeight,
|
|
padding: label.padding,
|
|
spacing: label.spacing
|
|
};
|
|
let stylerOutput;
|
|
if (label.itemStyler) {
|
|
stylerOutput = this.cachedCallWithContext(label.itemStyler, {
|
|
...params,
|
|
...defaultStyle
|
|
});
|
|
}
|
|
const merged = (0, import_ag_charts_core117.mergeDefaults)(stylerOutput, additionalStyles, defaultStyle);
|
|
return {
|
|
border: merged.border,
|
|
color: merged.color,
|
|
cornerRadius: merged.cornerRadius,
|
|
fill: merged.fill,
|
|
fillOpacity: merged.fillOpacity,
|
|
fontFamily: merged.fontFamily,
|
|
fontSize: merged.fontSize,
|
|
fontStyle: merged.fontStyle,
|
|
fontWeight: merged.fontWeight,
|
|
padding: merged.padding,
|
|
spacing: merged.spacing
|
|
};
|
|
}
|
|
getTickSize(tick = this.tick) {
|
|
return tick.enabled ? tick.size : 0;
|
|
}
|
|
getTickSpacing(tick = this.tick) {
|
|
if (!tick.enabled)
|
|
return 0;
|
|
const scrollbar = this.chartLayout?.scrollbars?.[this.id];
|
|
if (!scrollbar?.enabled || scrollbar.placement !== "inner")
|
|
return 0;
|
|
return scrollbar.tickSpacing ?? 0;
|
|
}
|
|
processData() {
|
|
this.invalidateLayoutCache();
|
|
const { includeInvisibleDomains, boundSeries, direction } = this;
|
|
const visibleSeries = includeInvisibleDomains ? boundSeries : boundSeries.filter((s) => s.isEnabled());
|
|
const domains = visibleSeries.map((series) => series.getDomain(direction));
|
|
this.setDomains(...domains);
|
|
}
|
|
getDomainExtentsNice() {
|
|
return [this.nice, this.nice];
|
|
}
|
|
setDomains(...domains) {
|
|
let normalizedDomain;
|
|
let animatable;
|
|
if (domains.length > 0) {
|
|
const result = this.scale.normalizeDomains(...domains);
|
|
normalizedDomain = { domain: result.domain, sortMetadata: { sortOrder: 1 } };
|
|
animatable = result.animatable;
|
|
} else {
|
|
normalizedDomain = { domain: [] };
|
|
animatable = true;
|
|
}
|
|
this.dataDomain = this.normaliseDataDomain(normalizedDomain);
|
|
this.allowNull = this.dataDomain.domain.some(function(v) {
|
|
return v == null;
|
|
});
|
|
if (this.reverse) {
|
|
this.dataDomain.domain.reverse();
|
|
}
|
|
this.animatable = animatable;
|
|
}
|
|
calculateDomain(initialPrimaryTickCount, scrollbarKey = "none") {
|
|
const {
|
|
dataDomain: { domain },
|
|
range: range4,
|
|
scale: scale2,
|
|
gridLength
|
|
} = this;
|
|
const rangeExtent = (0, import_ag_charts_core117.findRangeExtent)(range4);
|
|
const visibleRange = [0, 1];
|
|
const nice = this.getDomainExtentsNice();
|
|
this.updateScale();
|
|
const { unzoomedTickLayoutCache } = this;
|
|
let unzoomedTickLayout;
|
|
if (unzoomedTickLayoutCache == null || !tickLayoutCacheValid(unzoomedTickLayoutCache, {
|
|
domain,
|
|
rangeExtent,
|
|
nice,
|
|
gridLength,
|
|
visibleRange,
|
|
initialPrimaryTickCount,
|
|
scrollbarKey
|
|
})) {
|
|
const scaleRange = scale2.range;
|
|
this.setScaleRange([0, 1]);
|
|
const niceMode = nice.map((n) => n ? 0 /* TickAndDomain */ : 2 /* Off */);
|
|
unzoomedTickLayout = this.calculateTickLayout(domain, niceMode, [0, 1], initialPrimaryTickCount);
|
|
scale2.range = scaleRange;
|
|
this.unzoomedTickLayoutCache = {
|
|
domain,
|
|
rangeExtent,
|
|
nice,
|
|
gridLength,
|
|
visibleRange,
|
|
initialPrimaryTickCount,
|
|
scrollbarKey,
|
|
tickLayout: unzoomedTickLayout
|
|
};
|
|
} else {
|
|
unzoomedTickLayout = unzoomedTickLayoutCache.tickLayout;
|
|
}
|
|
this.updateScale();
|
|
scale2.domain = unzoomedTickLayout.niceDomain;
|
|
return { unzoomedTickLayout, domain: scale2.domain };
|
|
}
|
|
calculateLayout(initialPrimaryTickCount, chartLayout) {
|
|
this.chartLayout = chartLayout;
|
|
const scrollbarKey = this.getScrollbarLayoutCacheKey(chartLayout);
|
|
const { visibleRange } = this;
|
|
const unzoomed = visibleRange[0] === 0 && visibleRange[1] === 1;
|
|
const { unzoomedTickLayout, domain } = this.calculateDomain(initialPrimaryTickCount, scrollbarKey);
|
|
const nice = this.getDomainExtentsNice();
|
|
let tickLayout;
|
|
if (unzoomed) {
|
|
tickLayout = unzoomedTickLayout;
|
|
} else {
|
|
const { range: range4, gridLength } = this;
|
|
const rangeExtent = (0, import_ag_charts_core117.findRangeExtent)(range4);
|
|
const niceMode = nice.map((n) => n ? 1 /* TicksOnly */ : 2 /* Off */);
|
|
const { tickLayoutCache } = this;
|
|
if (tickLayoutCache == null || !tickLayoutCacheValid(tickLayoutCache, {
|
|
domain,
|
|
rangeExtent,
|
|
nice,
|
|
gridLength,
|
|
visibleRange,
|
|
initialPrimaryTickCount,
|
|
scrollbarKey
|
|
})) {
|
|
tickLayout = this.calculateTickLayout(domain, niceMode, visibleRange, initialPrimaryTickCount);
|
|
this.tickLayoutCache = {
|
|
domain,
|
|
rangeExtent,
|
|
nice,
|
|
gridLength,
|
|
visibleRange,
|
|
initialPrimaryTickCount,
|
|
scrollbarKey,
|
|
tickLayout
|
|
};
|
|
} else {
|
|
tickLayout = tickLayoutCache.tickLayout;
|
|
}
|
|
}
|
|
const { rawTickCount: zoomedTickCount = 0, fractionDigits, bbox } = tickLayout;
|
|
const unzoomedTickCount = unzoomedTickLayout.rawTickCount ?? 0;
|
|
const primaryTickCount = zoomedTickCount !== 0 && unzoomedTickCount !== 0 ? { zoomed: zoomedTickCount, unzoomed: unzoomedTickCount } : void 0;
|
|
this.tickLayout = tickLayout.layout;
|
|
this.layout.label = {
|
|
fractionDigits,
|
|
spacing: this.label.spacing,
|
|
format: this.label.format
|
|
};
|
|
this.layoutCrossLines();
|
|
return { primaryTickCount, bbox };
|
|
}
|
|
invalidateLayoutCache() {
|
|
this.unzoomedTickLayoutCache = void 0;
|
|
this.tickLayoutCache = void 0;
|
|
this.tickLayout = void 0;
|
|
}
|
|
getScrollbarLayoutCacheKey(chartLayout) {
|
|
const scrollbar = chartLayout?.scrollbars?.[this.id];
|
|
if (!scrollbar?.enabled)
|
|
return "none";
|
|
return `${scrollbar.placement}:${scrollbar.spacing}:${scrollbar.thickness}:${scrollbar.tickSpacing}`;
|
|
}
|
|
updateCrossLines() {
|
|
const crosslinesVisible = this.hasDefinedDomain() || this.hasVisibleSeries();
|
|
for (const crossLine of this.crossLines) {
|
|
crossLine.update(crosslinesVisible);
|
|
}
|
|
}
|
|
updatePosition() {
|
|
const { crossLineRangeGroup, crossLineLineGroup, crossLineLabelGroup, gridGroup, translation } = this;
|
|
const translationX = Math.floor(translation.x);
|
|
const translationY = Math.floor(translation.y);
|
|
gridGroup.setProperties({ translationX, translationY });
|
|
crossLineRangeGroup.setProperties({ translationX, translationY });
|
|
crossLineLineGroup.setProperties({ translationX, translationY });
|
|
crossLineLabelGroup.setProperties({ translationX, translationY });
|
|
}
|
|
// For formatting (nice rounded) tick values.
|
|
tickFormatter(domain, ticks, primary, inputFractionDigits, inputTimeInterval, dateStyle = "long") {
|
|
const { moduleCtx, label } = this;
|
|
const { formatManager } = moduleCtx;
|
|
const primaryLabel = primary ? this.primaryLabel : void 0;
|
|
const tickFormatParams = this.tickFormatParams(domain, ticks, inputFractionDigits, inputTimeInterval);
|
|
const boundSeries = this.formatterBoundSeries.get();
|
|
let fractionDigits;
|
|
let timeInterval2;
|
|
let truncateDate;
|
|
if (tickFormatParams.type === "number") {
|
|
fractionDigits = tickFormatParams.fractionDigits;
|
|
} else if (tickFormatParams.type === "date") {
|
|
const { unit, step, epoch } = tickFormatParams;
|
|
timeInterval2 = { unit, step, epoch };
|
|
truncateDate = tickFormatParams.truncateDate;
|
|
}
|
|
const f = this.uncachedCallWithContext.bind(this);
|
|
const params = {
|
|
datum: void 0,
|
|
seriesId: void 0,
|
|
legendItemName: void 0,
|
|
key: void 0,
|
|
source: "axis-label",
|
|
property: this.getFormatterProperty(),
|
|
domain,
|
|
boundSeries
|
|
};
|
|
const currentLabel = primaryLabel ?? label;
|
|
const specifier = primary ? label.format : void 0;
|
|
const { allowNull } = this;
|
|
const options = {
|
|
specifier: FormatManager.mergeSpecifiers(primaryLabel?.format, label.format),
|
|
truncateDate,
|
|
allowNull
|
|
};
|
|
return (value, index) => {
|
|
const formatParams = this.datumFormatParams(value, params, fractionDigits, timeInterval2, dateStyle);
|
|
formatParams.value = value;
|
|
return currentLabel.formatValue(f, formatParams, index, { specifier, dateStyle, truncateDate }) ?? formatManager.format(f, formatParams, options) ?? formatManager.defaultFormat(formatParams, options);
|
|
};
|
|
}
|
|
formatDatum(contextProvider, input, source, seriesId, legendItemName, datum, key, domain, label, params, allowNull) {
|
|
if (input == null && !allowNull)
|
|
return "";
|
|
const { moduleCtx, dataDomain } = this;
|
|
domain ?? (domain = dataDomain.domain);
|
|
const { formatManager } = moduleCtx;
|
|
const boundSeries = this.formatterBoundSeries.get();
|
|
let inputFractionDigits;
|
|
switch (source) {
|
|
case "crosshair":
|
|
case "annotation-label":
|
|
inputFractionDigits = this.layout.label.fractionDigits + 1;
|
|
break;
|
|
case "series-label":
|
|
inputFractionDigits = 2;
|
|
break;
|
|
case "tooltip":
|
|
inputFractionDigits = 3;
|
|
break;
|
|
case "legend-label":
|
|
inputFractionDigits = void 0;
|
|
break;
|
|
}
|
|
const formatParams = this.datumFormatParams(
|
|
input,
|
|
{
|
|
source,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key,
|
|
property: this.getFormatterProperty(),
|
|
domain,
|
|
boundSeries
|
|
},
|
|
inputFractionDigits,
|
|
void 0,
|
|
"long"
|
|
);
|
|
const { type, value } = formatParams;
|
|
const f = this.createCallWithContext(contextProvider);
|
|
const result = label?.formatValue(f, type, value, params ?? formatParams) ?? formatManager.format(f, formatParams, { allowNull }) ?? this.label.formatValue(f, formatParams, Number.NaN) ?? formatManager.defaultFormat(formatParams);
|
|
return (0, import_ag_charts_core117.isArray)(result) ? result : String(result);
|
|
}
|
|
getBBox() {
|
|
return this.axisGroup.getBBox();
|
|
}
|
|
initCrossLine(crossLine) {
|
|
crossLine.scale = this.scale;
|
|
crossLine.gridLength = this.gridLength;
|
|
}
|
|
hasVisibleSeries() {
|
|
return this.boundSeries.some((s) => s.isEnabled());
|
|
}
|
|
clipTickLines(x, y, width, height) {
|
|
this.tickLineGroup.setClipRect(new BBox(x, y, width, height));
|
|
}
|
|
clipGrid(x, y, width, height) {
|
|
this.gridGroup.setClipRect(new BBox(x, y, width, height));
|
|
}
|
|
getFormatterProperty() {
|
|
const { direction, boundSeries } = this;
|
|
let resolvedDirection = direction;
|
|
for (const series of boundSeries) {
|
|
const seriesResolvedDirection = series.resolveKeyDirection(direction);
|
|
if (seriesResolvedDirection !== direction) {
|
|
resolvedDirection = seriesResolvedDirection;
|
|
break;
|
|
}
|
|
}
|
|
return resolvedDirection;
|
|
}
|
|
getTitleFormatterParams(domain) {
|
|
const { direction } = this;
|
|
const boundSeries = this.formatterBoundSeries.get();
|
|
return { domain, direction, boundSeries, defaultValue: this.title?.text };
|
|
}
|
|
normaliseDataDomain(d) {
|
|
return { domain: [...d.domain], clipped: false };
|
|
}
|
|
getLayoutTranslation() {
|
|
return this.translation;
|
|
}
|
|
getLayoutState() {
|
|
return {
|
|
id: this.id,
|
|
rect: this.getBBox(),
|
|
translation: this.getLayoutTranslation(),
|
|
gridPadding: this.gridPadding,
|
|
seriesAreaPadding: this.seriesAreaPadding,
|
|
tickSize: this.getTickSize(),
|
|
direction: this.direction,
|
|
domain: this.dataDomain.domain,
|
|
scale: this.scale,
|
|
...this.layout
|
|
};
|
|
}
|
|
getModuleMap() {
|
|
return this.moduleMap;
|
|
}
|
|
getUpdateTypeOnResize() {
|
|
return import_ag_charts_core117.ChartUpdateType.PERFORM_LAYOUT;
|
|
}
|
|
createModuleContext() {
|
|
this.axisContext ?? (this.axisContext = this.createAxisContext());
|
|
return { ...this.moduleCtx, parent: this.axisContext };
|
|
}
|
|
createAxisContext() {
|
|
const { scale: scale2 } = this;
|
|
return {
|
|
axisId: this.id,
|
|
scale: this.scale,
|
|
direction: this.direction,
|
|
continuous: ContinuousScale.is(scale2) || DiscreteTimeScale.is(scale2),
|
|
getCanvasBounds: () => {
|
|
return Transformable.toCanvas(this.axisGroup);
|
|
},
|
|
seriesKeyProperties: () => this.boundSeries.reduce((keys, series) => {
|
|
const seriesKeys = series.getKeyProperties(this.direction);
|
|
for (const key of seriesKeys) {
|
|
keys.add(key);
|
|
}
|
|
return keys;
|
|
}, /* @__PURE__ */ new Set()),
|
|
seriesIds: () => this.boundSeries.map((series) => series.id),
|
|
scaleInvert: (val) => scale2.invert(val, true),
|
|
scaleInvertNearest: (val) => scale2.invert(val, true),
|
|
formatScaleValue: (value, source, label) => {
|
|
const { allowNull } = this;
|
|
return this.formatDatum(
|
|
void 0,
|
|
value,
|
|
source,
|
|
void 0,
|
|
void 0,
|
|
void 0,
|
|
void 0,
|
|
void 0,
|
|
label,
|
|
void 0,
|
|
allowNull
|
|
);
|
|
},
|
|
attachLabel: (node) => this.attachLabel(node),
|
|
inRange: (value, tolerance) => this.inRange(value, tolerance),
|
|
getRangeOverflow: (value) => this.getRangeOverflow(value),
|
|
pickBand: (point) => this.pickBand(point),
|
|
measureBand: (value) => this.measureBand(value)
|
|
};
|
|
}
|
|
pickBand(point) {
|
|
if (!BandScale.is(this.scale)) {
|
|
return;
|
|
}
|
|
const { scale: scale2, range: range4, id } = this;
|
|
const value = scale2.invert(this.isVertical() ? point.y : point.x, true);
|
|
const [position, start, end2] = computeBand(scale2, range4, value);
|
|
return { id, value, band: [start, end2], position };
|
|
}
|
|
measureBand(value) {
|
|
if (!BandScale.is(this.scale)) {
|
|
return;
|
|
}
|
|
const [, start, end2] = computeBand(this.scale, this.range, value);
|
|
return { band: [start, end2] };
|
|
}
|
|
isVertical() {
|
|
return this.direction === import_ag_charts_core117.ChartAxisDirection.Y;
|
|
}
|
|
isReversed() {
|
|
return this.reverse;
|
|
}
|
|
cachedCallWithContext(fn, params) {
|
|
const { callbackCache, chartService } = this.moduleCtx;
|
|
return callbackCache.call([this, chartService], fn, params);
|
|
}
|
|
uncachedCallWithContext(fn, params) {
|
|
const { chartService } = this.moduleCtx;
|
|
return (0, import_ag_charts_core117.callWithContext)([this, chartService], fn, params);
|
|
}
|
|
createCallWithContext(contextProvider) {
|
|
const { chartService } = this.moduleCtx;
|
|
return (fn, params) => (0, import_ag_charts_core117.callWithContext)([contextProvider, this, chartService], fn, params);
|
|
}
|
|
};
|
|
_Axis.defaultTickMinSpacing = 50;
|
|
_Axis.CrossLineConstructor = CartesianCrossLine;
|
|
__decorateClass([
|
|
import_ag_charts_core117.Property
|
|
], _Axis.prototype, "nice", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core117.Property
|
|
], _Axis.prototype, "reverse", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core117.Property
|
|
], _Axis.prototype, "interval", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core117.Property
|
|
], _Axis.prototype, "title", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core117.ObserveChanges)((target, value, oldValue) => target.onGridLengthChange(value, oldValue))
|
|
], _Axis.prototype, "gridLength", 2);
|
|
var Axis = _Axis;
|
|
|
|
// packages/ag-charts-community/src/chart/axis/cartesianAxisLabel.ts
|
|
var import_ag_charts_core118 = require("ag-charts-core");
|
|
var CartesianAxisLabel = class extends AxisLabel {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.autoRotateAngle = 335;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core118.Property
|
|
], CartesianAxisLabel.prototype, "autoRotate", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core118.Property
|
|
], CartesianAxisLabel.prototype, "autoRotateAngle", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/generateTicks.ts
|
|
var import_ag_charts_core125 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scale/categoryScale.ts
|
|
var import_ag_charts_core119 = require("ag-charts-core");
|
|
var CategoryScale = class _CategoryScale extends BandScale {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "category";
|
|
this.defaultTickCount = 0;
|
|
/**
|
|
* Maps datum to its index in the {@link domain} array.
|
|
* Used to check for duplicate data (not allowed).
|
|
*/
|
|
this.index = /* @__PURE__ */ new Map();
|
|
this.indexInitialized = false;
|
|
/**
|
|
* Contains unique data only.
|
|
*/
|
|
this._domain = [];
|
|
}
|
|
static is(value) {
|
|
return value instanceof _CategoryScale;
|
|
}
|
|
set domain(values) {
|
|
if (this._domain === values)
|
|
return;
|
|
this.invalid = true;
|
|
this._domain = values;
|
|
this.index.clear();
|
|
this.indexInitialized = false;
|
|
}
|
|
get domain() {
|
|
return this._domain;
|
|
}
|
|
get bands() {
|
|
return this._domain;
|
|
}
|
|
normalizeDomains(...domains) {
|
|
let normalizedDomain = void 0;
|
|
const seenDomains = /* @__PURE__ */ new Set();
|
|
let animatable = true;
|
|
for (const input of domains) {
|
|
const domain = input.domain;
|
|
if (seenDomains.has(domain))
|
|
continue;
|
|
seenDomains.add(domain);
|
|
if (normalizedDomain == null) {
|
|
normalizedDomain = deduplicateCategories(domain);
|
|
} else {
|
|
animatable && (animatable = domainOrderedToNormalizedDomain(domain, normalizedDomain));
|
|
normalizedDomain = deduplicateCategories([...normalizedDomain, ...domain]);
|
|
}
|
|
}
|
|
normalizedDomain ?? (normalizedDomain = []);
|
|
return { domain: normalizedDomain, animatable };
|
|
}
|
|
toDomain(_value) {
|
|
return void 0;
|
|
}
|
|
invert(position, nearest = false) {
|
|
this.refresh();
|
|
const offset = nearest ? this.bandwidth / 2 : 0;
|
|
const index = this.invertNearestIndex(Math.max(0, position - offset));
|
|
const matches = nearest || position === this.ordinalRange(index);
|
|
return matches ? this.domain[index] : void 0;
|
|
}
|
|
ticks(params, domain = this.domain, visibleRange) {
|
|
const { bands } = this;
|
|
let { tickCount } = params;
|
|
if (tickCount === 0) {
|
|
const firstTickIndex2 = bands.length > 1 ? 1 : 0;
|
|
const ticks2 = bands[firstTickIndex2] ? [bands[firstTickIndex2]] : [];
|
|
return { ticks: ticks2, count: void 0, firstTickIndex: firstTickIndex2 };
|
|
}
|
|
let step = tickCount != null && tickCount !== 0 ? Math.trunc(bands.length / tickCount) : 1;
|
|
step = (0, import_ag_charts_core119.previousPowerOf2)(step);
|
|
if (step <= 1) {
|
|
return filterVisibleTicks(domain, false, visibleRange);
|
|
}
|
|
tickCount = Math.trunc(bands.length / step);
|
|
const span = step * tickCount;
|
|
const inset = (0, import_ag_charts_core119.previousPowerOf2)(Math.trunc((bands.length - span) / 2));
|
|
const vt0 = (0, import_ag_charts_core119.clamp)(0, Math.floor((visibleRange?.[0] ?? 0) * bands.length), bands.length);
|
|
const vt1 = (0, import_ag_charts_core119.clamp)(0, Math.ceil((visibleRange?.[1] ?? 1) * bands.length), bands.length);
|
|
const i0 = Math.floor((vt0 - inset) / step) * step + inset;
|
|
const i1 = Math.ceil((vt1 - inset) / step) * step + inset;
|
|
const ticks = [];
|
|
for (let i = i0; i < i1; i += step) {
|
|
if (i >= 0 && i < bands.length) {
|
|
ticks.push(bands[i]);
|
|
}
|
|
}
|
|
let firstTickIndex = ticks.length > 0 ? this.findIndex(ticks[0]) : void 0;
|
|
if (firstTickIndex != null) {
|
|
firstTickIndex = Math.floor((firstTickIndex - inset) / step);
|
|
}
|
|
return { ticks, count: void 0, firstTickIndex };
|
|
}
|
|
findIndex(value) {
|
|
const { index, indexInitialized } = this;
|
|
if (!indexInitialized) {
|
|
const { domain } = this;
|
|
for (let i = 0; i < domain.length; i++) {
|
|
index.set((0, import_ag_charts_core119.dateToNumber)(domain[i]), i);
|
|
}
|
|
this.indexInitialized = true;
|
|
}
|
|
return index.get((0, import_ag_charts_core119.dateToNumber)(value));
|
|
}
|
|
};
|
|
function deduplicateCategories(d) {
|
|
let domain;
|
|
const uniqueValues = /* @__PURE__ */ new Set();
|
|
for (const value of d) {
|
|
const key = (0, import_ag_charts_core119.dateToNumber)(value);
|
|
const lastSize = uniqueValues.size;
|
|
uniqueValues.add(key);
|
|
const isUniqueValue = uniqueValues.size !== lastSize;
|
|
if (isUniqueValue) {
|
|
domain?.push(value);
|
|
} else {
|
|
domain ?? (domain = d.slice(0, uniqueValues.size));
|
|
}
|
|
}
|
|
return domain ?? d;
|
|
}
|
|
function domainOrderedToNormalizedDomain(domain, normalizedDomain) {
|
|
let normalizedIndex = -1;
|
|
for (const value of domain) {
|
|
const normalizedNextIndex = normalizedDomain.indexOf(value);
|
|
if (normalizedNextIndex === -1) {
|
|
normalizedIndex = Infinity;
|
|
} else if (normalizedNextIndex <= normalizedIndex) {
|
|
return false;
|
|
} else {
|
|
normalizedIndex = normalizedNextIndex;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scale/ordinalTimeScale.ts
|
|
var import_ag_charts_core121 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scale/timeScale.ts
|
|
var import_ag_charts_core120 = require("ag-charts-core");
|
|
var sunday = new Date(1970, 0, 4);
|
|
var TimeScale = class _TimeScale extends ContinuousScale {
|
|
constructor() {
|
|
super([], [0, 1]);
|
|
this.type = "time";
|
|
}
|
|
static is(value) {
|
|
return value instanceof _TimeScale;
|
|
}
|
|
toDomain(d) {
|
|
return new Date(d);
|
|
}
|
|
convert(value, options) {
|
|
return super.convert(typeof value === "number" ? value : value?.valueOf() ?? Number.NaN, options);
|
|
}
|
|
invert(value) {
|
|
return new Date(super.invert(value));
|
|
}
|
|
niceDomain(ticks, domain = this.domain) {
|
|
if (domain.length < 2)
|
|
return [];
|
|
let [d0, d1] = domain;
|
|
const maxAttempts = 4;
|
|
const availableRange = this.getPixelRange();
|
|
for (let i = 0; i < maxAttempts; i++) {
|
|
const [n0, n1] = updateNiceDomainIteration(d0, d1, ticks, availableRange);
|
|
if ((0, import_ag_charts_core120.dateToNumber)(d0) === (0, import_ag_charts_core120.dateToNumber)(n0) && (0, import_ag_charts_core120.dateToNumber)(d1) === (0, import_ag_charts_core120.dateToNumber)(n1)) {
|
|
break;
|
|
}
|
|
d0 = n0;
|
|
d1 = n1;
|
|
}
|
|
return [d0, d1];
|
|
}
|
|
/**
|
|
* Returns uniformly-spaced dates that represent the scale's domain.
|
|
*/
|
|
ticks(params, domain = this.domain, visibleRange = [0, 1], { extend = false } = {}) {
|
|
const { nice, interval, tickCount = ContinuousScale.defaultTickCount, minTickCount, maxTickCount } = params;
|
|
if (domain.length < 2)
|
|
return;
|
|
const timestamps = domain.map(import_ag_charts_core120.dateToNumber);
|
|
const start = timestamps[0];
|
|
const stop = timestamps.at(-1);
|
|
if (interval != null) {
|
|
const availableRange = this.getPixelRange();
|
|
return {
|
|
ticks: getDateTicksForInterval({ start, stop, interval, availableRange, visibleRange, extend }) ?? getDefaultDateTicks({ start, stop, tickCount, minTickCount, maxTickCount, visibleRange, extend }),
|
|
count: void 0
|
|
};
|
|
} else if (nice.every(Boolean) && tickCount === 2) {
|
|
return { ticks: domain, count: void 0 };
|
|
} else if (nice.every(Boolean) && tickCount === 1) {
|
|
return { ticks: domain.slice(0, 1), count: void 0 };
|
|
}
|
|
const timeInterval2 = (0, import_ag_charts_core120.getTickTimeInterval)(start, stop, tickCount, minTickCount, maxTickCount, {
|
|
weekStart: sunday
|
|
});
|
|
if (timeInterval2 == null)
|
|
return;
|
|
const ticks = (0, import_ag_charts_core120.intervalRange)(timeInterval2, new Date(start), new Date(stop), { visibleRange, extend });
|
|
const firstTickIndex = (0, import_ag_charts_core120.intervalRangeStartIndex)(timeInterval2, new Date(start), new Date(stop), {
|
|
visibleRange,
|
|
extend
|
|
});
|
|
return {
|
|
ticks,
|
|
count: void 0,
|
|
firstTickIndex,
|
|
timeInterval: timeInterval2
|
|
};
|
|
}
|
|
};
|
|
function getDefaultDateTicks({
|
|
start,
|
|
stop,
|
|
tickCount,
|
|
minTickCount,
|
|
maxTickCount,
|
|
visibleRange,
|
|
extend
|
|
}) {
|
|
const t = (0, import_ag_charts_core120.getTickTimeInterval)(start, stop, tickCount, minTickCount, maxTickCount, { weekStart: sunday });
|
|
return t ? (0, import_ag_charts_core120.intervalRange)(t, new Date(start), new Date(stop), { visibleRange, extend }) : [];
|
|
}
|
|
function getDateTicksForInterval({
|
|
start,
|
|
stop,
|
|
interval,
|
|
availableRange,
|
|
visibleRange,
|
|
extend
|
|
}) {
|
|
if (!interval) {
|
|
return [];
|
|
}
|
|
if ((0, import_ag_charts_core120.isPlainObject)(interval) || typeof interval === "string") {
|
|
const ticks2 = (0, import_ag_charts_core120.intervalRange)(interval, new Date(start), new Date(stop), { visibleRange, extend });
|
|
if ((0, import_ag_charts_core120.isDenseInterval)(ticks2.length, availableRange)) {
|
|
return;
|
|
}
|
|
return ticks2;
|
|
}
|
|
const absInterval = Math.abs(interval);
|
|
if ((0, import_ag_charts_core120.isDenseInterval)(Math.abs(stop - start) / absInterval, availableRange))
|
|
return;
|
|
const tickInterval = import_ag_charts_core120.TickIntervals.findLast((t) => absInterval % t.duration === 0);
|
|
if (tickInterval) {
|
|
const { timeInterval: timeInterval2, step, duration } = tickInterval;
|
|
const alignedInterval = {
|
|
...timeInterval2,
|
|
step: step * (0, import_ag_charts_core120.intervalStep)(timeInterval2) * Math.round(absInterval / duration),
|
|
epoch: (0, import_ag_charts_core120.defaultEpoch)(timeInterval2, { weekStart: sunday })
|
|
};
|
|
return (0, import_ag_charts_core120.intervalRange)(alignedInterval, new Date(start), new Date(stop), { visibleRange, extend });
|
|
}
|
|
let date3 = new Date(Math.min(start, stop));
|
|
const stopDate = new Date(Math.max(start, stop));
|
|
const ticks = [];
|
|
while (date3 <= stopDate) {
|
|
ticks.push(date3);
|
|
date3 = new Date(date3);
|
|
date3.setMilliseconds(date3.getMilliseconds() + absInterval);
|
|
}
|
|
return ticks;
|
|
}
|
|
function updateNiceDomainIteration(d0, d1, ticks, availableRange) {
|
|
const { interval } = ticks;
|
|
const start = Math.min((0, import_ag_charts_core120.dateToNumber)(d0), (0, import_ag_charts_core120.dateToNumber)(d1));
|
|
const stop = Math.max((0, import_ag_charts_core120.dateToNumber)(d0), (0, import_ag_charts_core120.dateToNumber)(d1));
|
|
let i;
|
|
if ((0, import_ag_charts_core120.isPlainObject)(interval) || typeof interval === "string") {
|
|
i = interval;
|
|
} else {
|
|
let tickCount;
|
|
if (typeof interval === "number") {
|
|
tickCount = (stop - start) / Math.max(interval, 1);
|
|
if ((0, import_ag_charts_core120.isDenseInterval)(tickCount, availableRange)) {
|
|
tickCount = void 0;
|
|
}
|
|
}
|
|
tickCount ?? (tickCount = ticks.tickCount ?? ContinuousScale.defaultTickCount);
|
|
i = (0, import_ag_charts_core120.getTickTimeInterval)(start, stop, tickCount, ticks.minTickCount, ticks.maxTickCount, { weekStart: sunday });
|
|
}
|
|
if (i == null)
|
|
return [d0, d1];
|
|
const domain = (0, import_ag_charts_core120.intervalRange)(i, new Date(start), new Date(stop), { extend: true });
|
|
if (domain == null || domain.length < 2)
|
|
return [d0, d1];
|
|
const r0 = domain[0];
|
|
const r1 = domain.at(-1);
|
|
return d0 <= d1 ? [r0, r1] : [r1, r0];
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scale/ordinalTimeScale.ts
|
|
var APPROXIMATE_THRESHOLD2 = 1e3;
|
|
var OrdinalTimeScale = class _OrdinalTimeScale extends DiscreteTimeScale {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "ordinal-time";
|
|
this.defaultTickCount = ContinuousScale.defaultTickCount;
|
|
this._domain = [];
|
|
this.isReversed = false;
|
|
}
|
|
static is(value) {
|
|
return value instanceof _OrdinalTimeScale;
|
|
}
|
|
set domain(domain) {
|
|
if (domain === this._domain)
|
|
return;
|
|
this.invalid = true;
|
|
this._domain = domain;
|
|
this._bands = void 0;
|
|
this._numericBands = void 0;
|
|
this._uniformityCache = void 0;
|
|
this.isReversed = domainReversed(domain);
|
|
}
|
|
get domain() {
|
|
return this._domain;
|
|
}
|
|
get bands() {
|
|
this._bands ?? (this._bands = this.isReversed ? this.domain.slice().reverse() : this.domain);
|
|
return this._bands;
|
|
}
|
|
get numericBands() {
|
|
this._numericBands ?? (this._numericBands = this.bands.map((d) => d.valueOf()));
|
|
return this._numericBands;
|
|
}
|
|
getUniformityCache(visibleRange) {
|
|
const { bands } = this;
|
|
const n = bands.length;
|
|
if (!visibleRange || visibleRange[0] === 0 && visibleRange[1] === 1) {
|
|
if (n > APPROXIMATE_THRESHOLD2 && this._uniformityCache === void 0) {
|
|
this._uniformityCache = checkUniformityBySampling(bands);
|
|
}
|
|
return this._uniformityCache;
|
|
}
|
|
const startIdx = Math.floor(visibleRange[0] * n);
|
|
const endIdx = Math.min(Math.ceil(visibleRange[1] * n), n - 1);
|
|
return checkUniformityBySampling(bands, startIdx, endIdx);
|
|
}
|
|
normalizeDomains(...domains) {
|
|
const nonEmptyDomains = domains.filter((d) => d.domain.length > 0);
|
|
if (nonEmptyDomains.length === 0) {
|
|
return { domain: [], animatable: false };
|
|
}
|
|
const firstDomain = nonEmptyDomains[0].domain;
|
|
const allSame = nonEmptyDomains.every((d) => d.domain === firstDomain);
|
|
if (nonEmptyDomains.length === 1 || allSame) {
|
|
const input = nonEmptyDomains[0];
|
|
let domain = input.domain;
|
|
let sortOrder;
|
|
let isUnique = false;
|
|
if (input.sortMetadata?.sortOrder === void 0) {
|
|
sortOrder = (0, import_ag_charts_core121.datesSortOrder)(domain);
|
|
} else {
|
|
sortOrder = input.sortMetadata.sortOrder;
|
|
isUnique = input.sortMetadata.isUnique ?? false;
|
|
}
|
|
if (sortOrder === -1) {
|
|
domain = domain.slice().reverse();
|
|
} else if (sortOrder == null) {
|
|
domain = isUnique ? domain.slice().sort((a, b) => a.valueOf() - b.valueOf()) : (0, import_ag_charts_core121.sortAndUniqueDates)(domain.slice());
|
|
}
|
|
return { domain, animatable: true };
|
|
}
|
|
return {
|
|
domain: (0, import_ag_charts_core121.sortAndUniqueDates)(nonEmptyDomains.map((d) => d.domain).flat()),
|
|
animatable: true
|
|
};
|
|
}
|
|
ticks(params, domain, visibleRange = [0, 1], { extend = false, dropInitial = false } = {}) {
|
|
const { interval, maxTickCount, tickCount = maxTickCount } = params;
|
|
const { bands, reversed } = this;
|
|
if (!bands.length)
|
|
return;
|
|
if (reversed) {
|
|
visibleRange = [1 - visibleRange[1], 1 - visibleRange[0]];
|
|
}
|
|
this.refresh();
|
|
if (interval == null) {
|
|
const { ticks: ticks2, tickOffset, tickEvery } = this.getDefaultTicks(domain, tickCount, visibleRange, extend);
|
|
let firstTickIndex = ticks2.length > 0 ? this.findIndex(ticks2[0]) : void 0;
|
|
firstTickIndex = firstTickIndex == null ? void 0 : Math.floor((firstTickIndex - tickOffset) / tickEvery);
|
|
return { ticks: ticks2, count: void 0, firstTickIndex };
|
|
}
|
|
let start;
|
|
let stop;
|
|
if (domain && domain.length >= 2) {
|
|
start = domain[0].valueOf();
|
|
stop = domain.at(-1).valueOf();
|
|
} else {
|
|
start = bands[0].valueOf();
|
|
stop = bands.at(-1).valueOf();
|
|
}
|
|
const [r0, r1] = this.range;
|
|
const availableRange = Math.abs(r1 - r0);
|
|
const dateTicks = getDateTicksForInterval({ start, stop, interval, availableRange, visibleRange, extend }) ?? this.getDefaultTicks(domain, tickCount, visibleRange, extend).ticks;
|
|
const ticks = [];
|
|
let lastIndex = -1;
|
|
for (const dateTick of dateTicks) {
|
|
const index = this.findIndex(dateTick, import_ag_charts_core121.ScaleAlignment.Trailing) ?? -1;
|
|
const duplicated = index === lastIndex;
|
|
lastIndex = index;
|
|
if (!(dropInitial && index === 0) && index !== -1 && !duplicated) {
|
|
ticks.push(bands[index]);
|
|
}
|
|
}
|
|
return { ticks, count: void 0, firstTickIndex: void 0 };
|
|
}
|
|
stepTicks(bandStep, domain, visibleRange = [0, 1], dropLast = true) {
|
|
const bandIndices = domain ? this.bandDomainIndices(domain) : void 0;
|
|
const ticks = this.ticksEvery(bandIndices, visibleRange, bandStep, 0, false);
|
|
const lastTick = ticks.at(-1);
|
|
const lastBandIndex = dropLast && bandStep > 1 ? bandIndices?.[1] : void 0;
|
|
const lastTickIndex = lastBandIndex != null && lastTick != null ? this.findIndex(lastTick) : void 0;
|
|
if (lastTickIndex != null && lastBandIndex != null && lastBandIndex - lastTickIndex < bandStep) {
|
|
ticks.pop();
|
|
}
|
|
return ticks;
|
|
}
|
|
bandCount(visibleRange = [0, 1]) {
|
|
const { domain } = this;
|
|
const startIndex = Math.floor(visibleRange[0] * domain.length);
|
|
const endIndex = Math.ceil(visibleRange[1] * domain.length);
|
|
return endIndex - startIndex;
|
|
}
|
|
getDefaultTicks(domain, maxTickCount, visibleRange, extend) {
|
|
const { bands } = this;
|
|
const tickEvery = Math.ceil(bands.length / maxTickCount);
|
|
const tickOffset = Math.floor(tickEvery / 2);
|
|
const bandIndices = domain ? this.bandDomainIndices(domain) : void 0;
|
|
return {
|
|
ticks: this.ticksEvery(bandIndices, visibleRange, tickEvery, tickOffset, extend),
|
|
tickOffset,
|
|
tickEvery
|
|
};
|
|
}
|
|
bandDomainIndices(domain) {
|
|
const isReversed = domainReversed(domain);
|
|
const i0 = this.findIndex(domain[isReversed ? domain.length - 1 : 0], import_ag_charts_core121.ScaleAlignment.Trailing) ?? 0;
|
|
const i1 = this.findIndex(domain[isReversed ? 0 : domain.length - 1], import_ag_charts_core121.ScaleAlignment.Trailing) ?? this.bands.length - 1;
|
|
return [i0, i1];
|
|
}
|
|
ticksEvery([i0, i1] = [0, this.bands.length], visibleRange, tickEvery, tickOffset, extend) {
|
|
const { bands } = this;
|
|
const offset = i0;
|
|
const span = i1 - i0 + 1;
|
|
let startIndex = offset + Math.floor(visibleRange[0] * span);
|
|
let endIndex = offset + Math.ceil(visibleRange[1] * span);
|
|
if (extend) {
|
|
startIndex -= tickEvery;
|
|
endIndex += tickEvery;
|
|
}
|
|
startIndex = Math.max(startIndex, 0);
|
|
endIndex = Math.min(endIndex, bands.length);
|
|
let ticks;
|
|
if (tickEvery <= 1) {
|
|
ticks = bands.slice(startIndex, endIndex);
|
|
} else {
|
|
ticks = [];
|
|
for (let index = startIndex; index < endIndex; index += 1) {
|
|
if ((index - offset + tickOffset) % tickEvery === 0) {
|
|
ticks.push(bands[index]);
|
|
}
|
|
}
|
|
}
|
|
return ticks;
|
|
}
|
|
};
|
|
function domainReversed(domain) {
|
|
return domain.length > 0 && domain[0] > domain.at(-1);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scale/unitTimeScale.ts
|
|
var import_ag_charts_core122 = require("ag-charts-core");
|
|
var APPROXIMATE_THRESHOLD3 = 1e3;
|
|
var MAX_BANDS = 5e7;
|
|
var UnitTimeScale = class _UnitTimeScale extends DiscreteTimeScale {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.type = "unit-time";
|
|
this.defaultTickCount = 12;
|
|
this._domain = [];
|
|
this._bands = void 0;
|
|
}
|
|
static is(value) {
|
|
return value instanceof _UnitTimeScale;
|
|
}
|
|
static supportsInterval(domain, interval) {
|
|
return supportsInterval(domain, interval);
|
|
}
|
|
set domain(domain) {
|
|
if (domain === this._domain)
|
|
return;
|
|
this._domain = domain;
|
|
this._bands = void 0;
|
|
this._numericBands = void 0;
|
|
this._uniformityCache = void 0;
|
|
this._domainBoundaries = void 0;
|
|
this._bandRangeCache = void 0;
|
|
this._encodedBands = void 0;
|
|
this._encodingParams = void 0;
|
|
this._linearParams = void 0;
|
|
}
|
|
get domain() {
|
|
return this._domain;
|
|
}
|
|
get interval() {
|
|
return this._interval;
|
|
}
|
|
set interval(interval) {
|
|
if (this._interval === interval)
|
|
return;
|
|
this._interval = interval;
|
|
this._bands = void 0;
|
|
this._numericBands = void 0;
|
|
this._uniformityCache = void 0;
|
|
this._domainBoundaries = void 0;
|
|
this._bandRangeCache = void 0;
|
|
this._encodedBands = void 0;
|
|
this._encodingParams = void 0;
|
|
this._linearParams = void 0;
|
|
}
|
|
get bands() {
|
|
if (this._bands === void 0) {
|
|
this.ensureEncodedBands();
|
|
if (this._encodedBands != null && this._encodingParams != null) {
|
|
const params = this._encodingParams;
|
|
this._bands = this._encodedBands.map((e) => (0, import_ag_charts_core122.decodeIntervalValue)(e, params));
|
|
} else {
|
|
this._bands = [];
|
|
}
|
|
}
|
|
return this._bands;
|
|
}
|
|
get numericBands() {
|
|
if (this._numericBands === void 0) {
|
|
this.ensureEncodedBands();
|
|
if (this._encodedBands != null && this._encodingParams != null) {
|
|
const params = this._encodingParams;
|
|
this._numericBands = this._encodedBands.map((e) => (0, import_ag_charts_core122.encodedToTimestamp)(e, params));
|
|
} else {
|
|
this._numericBands = [];
|
|
}
|
|
}
|
|
return this._numericBands;
|
|
}
|
|
/**
|
|
* Ensure encoded bands are computed. This is the numeric-first optimization:
|
|
* we compute just the encoded values (cheap numbers) and defer Date creation.
|
|
*/
|
|
ensureEncodedBands() {
|
|
if (this._encodedBands !== void 0)
|
|
return;
|
|
const { domain, interval } = this;
|
|
if (domain.length < 2 || interval == null) {
|
|
this._encodedBands = [];
|
|
return;
|
|
}
|
|
const bandRange = this.getCachedBandRange();
|
|
if (bandRange == null) {
|
|
this._encodedBands = [];
|
|
return;
|
|
}
|
|
const [start, stop] = bandRange;
|
|
const rangeParams = { visibleRange: [0, 1], extend: false };
|
|
if ((0, import_ag_charts_core122.intervalRangeCount)(interval, start, stop, rangeParams) > MAX_BANDS) {
|
|
import_ag_charts_core122.Logger.warnOnce(`the configured unit results in too many bands, ignoring. Supply a larger unit.`);
|
|
this._encodedBands = [];
|
|
return;
|
|
}
|
|
const { encodedValues, encodingParams } = (0, import_ag_charts_core122.intervalRangeNumeric)(interval, start, stop, rangeParams);
|
|
this._encodedBands = encodedValues;
|
|
this._encodingParams = encodingParams;
|
|
}
|
|
/** Override to return band count without triggering Date materialization */
|
|
getBandCountForUpdate() {
|
|
this.ensureEncodedBands();
|
|
return this._encodedBands?.length ?? 0;
|
|
}
|
|
getUniformityCache(visibleRange) {
|
|
const n = this.getBandCountForUpdate();
|
|
if (!visibleRange || visibleRange[0] === 0 && visibleRange[1] === 1) {
|
|
if (n > APPROXIMATE_THRESHOLD3 && this._uniformityCache === void 0) {
|
|
this.ensureEncodedBands();
|
|
if (this._encodingParams != null && this._encodedBands != null && this._encodedBands.length >= 2) {
|
|
const t0 = (0, import_ag_charts_core122.encodedToTimestamp)(this._encodedBands[0], this._encodingParams);
|
|
const t1 = (0, import_ag_charts_core122.encodedToTimestamp)(this._encodedBands[1], this._encodingParams);
|
|
this._uniformityCache = { isUniform: true, interval: t1 - t0 };
|
|
} else {
|
|
this._uniformityCache = { isUniform: false };
|
|
}
|
|
}
|
|
return this._uniformityCache;
|
|
}
|
|
this.ensureEncodedBands();
|
|
if (this._encodingParams != null && this._encodedBands != null && this._encodedBands.length >= 2) {
|
|
const t0 = (0, import_ag_charts_core122.encodedToTimestamp)(this._encodedBands[0], this._encodingParams);
|
|
const t1 = (0, import_ag_charts_core122.encodedToTimestamp)(this._encodedBands[1], this._encodingParams);
|
|
return { isUniform: true, interval: t1 - t0 };
|
|
}
|
|
return { isUniform: false };
|
|
}
|
|
normalizeDomains(...domains) {
|
|
return normalizeContinuousDomains(...domains);
|
|
}
|
|
getCachedBandRange() {
|
|
const { domain, interval } = this;
|
|
if (domain.length < 2 || interval == null)
|
|
return void 0;
|
|
this._bandRangeCache ?? (this._bandRangeCache = {
|
|
start: (0, import_ag_charts_core122.intervalFloor)(interval, domain[0]),
|
|
stop: (0, import_ag_charts_core122.intervalFloor)(interval, domain[1])
|
|
});
|
|
return [this._bandRangeCache.start, this._bandRangeCache.stop];
|
|
}
|
|
getDomainBoundaries() {
|
|
const { interval } = this;
|
|
if (interval == null)
|
|
return void 0;
|
|
if (this._domainBoundaries === void 0) {
|
|
const bandRange = this.getCachedBandRange();
|
|
if (bandRange == null)
|
|
return void 0;
|
|
const [start, stop] = bandRange;
|
|
const d0 = Math.min(start.valueOf(), stop.valueOf());
|
|
const d1 = Math.max(start.valueOf(), stop.valueOf());
|
|
const dNext = (0, import_ag_charts_core122.intervalNext)(interval, new Date(d1)).valueOf();
|
|
this._domainBoundaries = { d0, dNext };
|
|
}
|
|
return this._domainBoundaries;
|
|
}
|
|
/** Get linear params for O(1) index calculation and scaling metadata */
|
|
getLinearParams() {
|
|
if (this._linearParams === void 0) {
|
|
this.ensureEncodedBands();
|
|
if (this._encodedBands != null && this._encodingParams != null && this._encodedBands.length >= 2) {
|
|
const firstBandTime = (0, import_ag_charts_core122.encodedToTimestamp)(this._encodedBands[0], this._encodingParams);
|
|
const secondBandTime = (0, import_ag_charts_core122.encodedToTimestamp)(this._encodedBands[1], this._encodingParams);
|
|
this._linearParams = {
|
|
firstBandTime,
|
|
intervalMs: secondBandTime - firstBandTime
|
|
};
|
|
}
|
|
}
|
|
return this._linearParams;
|
|
}
|
|
/** Check if current encoding uses a linear unit (exact arithmetic, no DST issues) */
|
|
isLinearUnit() {
|
|
const unit = this._encodingParams?.unit;
|
|
return unit === "millisecond" || unit === "second" || unit === "minute" || unit === "hour";
|
|
}
|
|
/**
|
|
* O(1) findIndex for uniform bands.
|
|
* For linear units (ms/sec/min/hour), uses pure arithmetic without verification.
|
|
* For non-linear units (day/month/year), verifies against actual band values.
|
|
*/
|
|
findIndex(value, alignment = import_ag_charts_core122.ScaleAlignment.Leading) {
|
|
if (value == null)
|
|
return void 0;
|
|
const n = this.getBandCountForUpdate();
|
|
if (n === 0)
|
|
return void 0;
|
|
if (n === 1)
|
|
return 0;
|
|
const linearParams = this.getLinearParams();
|
|
if (linearParams == null || linearParams.intervalMs === 0) {
|
|
return super.findIndex(value, alignment);
|
|
}
|
|
const { firstBandTime, intervalMs } = linearParams;
|
|
const target = value.valueOf();
|
|
const rawIndex = (target - firstBandTime) / intervalMs;
|
|
let index = alignment === import_ag_charts_core122.ScaleAlignment.Trailing ? Math.ceil(rawIndex) : Math.floor(rawIndex);
|
|
index = Math.max(0, Math.min(index, n - 1));
|
|
if (this.isLinearUnit()) {
|
|
if (alignment === import_ag_charts_core122.ScaleAlignment.Trailing) {
|
|
const bandTime = firstBandTime + index * intervalMs;
|
|
if (bandTime < target && index === n - 1)
|
|
return void 0;
|
|
} else {
|
|
const bandTime = firstBandTime + index * intervalMs;
|
|
if (bandTime > target && index === 0)
|
|
return void 0;
|
|
}
|
|
return index;
|
|
}
|
|
const numericBands = this.numericBands;
|
|
if (alignment === import_ag_charts_core122.ScaleAlignment.Trailing) {
|
|
while (index > 0 && numericBands[index - 1] >= target)
|
|
index--;
|
|
while (index < n - 1 && numericBands[index] < target)
|
|
index++;
|
|
if (numericBands[index] < target)
|
|
return void 0;
|
|
} else {
|
|
while (index < n - 1 && numericBands[index + 1] <= target)
|
|
index++;
|
|
while (index > 0 && numericBands[index] > target)
|
|
index--;
|
|
if (numericBands[index] > target)
|
|
return void 0;
|
|
}
|
|
return index;
|
|
}
|
|
/**
|
|
* Optimized convert for UnitTimeScale with O(1) boundary checks.
|
|
* Uses linear params for fast bounds checking while delegating actual
|
|
* conversion to parent for accuracy in edge cases.
|
|
*/
|
|
convert(value, options) {
|
|
this.refresh();
|
|
if (!(value instanceof Date))
|
|
value = new Date(value);
|
|
const { domain, interval } = this;
|
|
if (domain.length < 2)
|
|
return Number.NaN;
|
|
if (options?.clamp !== true && interval != null) {
|
|
const boundaries = this.getDomainBoundaries();
|
|
if (boundaries != null) {
|
|
const t = value.valueOf();
|
|
if (t < boundaries.d0 || t >= boundaries.dNext)
|
|
return Number.NaN;
|
|
}
|
|
}
|
|
return super.convert(value, options);
|
|
}
|
|
calculateBands(domain, visibleRange, extend = false) {
|
|
if (domain === this.domain && visibleRange[0] === 0 && visibleRange[1] === 1 && !extend && this._bands != null) {
|
|
return { bands: this._bands, firstBandIndex: 0 };
|
|
}
|
|
if (domain.length < 2)
|
|
return { bands: [], firstBandIndex: void 0 };
|
|
const { interval } = this;
|
|
if (interval == null)
|
|
return { bands: [], firstBandIndex: void 0 };
|
|
const rangeParams = { visibleRange, extend };
|
|
if (!supportsInterval(domain, interval, rangeParams))
|
|
return { bands: [], firstBandIndex: void 0 };
|
|
const bandRange = domain === this.domain ? this.getCachedBandRange() : calculateBandRange(domain, interval);
|
|
if (bandRange == null)
|
|
return { bands: [], firstBandIndex: void 0 };
|
|
const [start, stop] = bandRange;
|
|
if ((0, import_ag_charts_core122.intervalRangeCount)(interval, start, stop, rangeParams) > MAX_BANDS) {
|
|
import_ag_charts_core122.Logger.warnOnce(`the configured unit results in too many bands, ignoring. Supply a larger unit.`);
|
|
return { bands: [], firstBandIndex: void 0 };
|
|
}
|
|
const bands = (0, import_ag_charts_core122.intervalRange)(interval, start, stop, rangeParams);
|
|
const firstBandIndex = (0, import_ag_charts_core122.intervalRangeStartIndex)(interval, start, stop, rangeParams);
|
|
return { bands, firstBandIndex };
|
|
}
|
|
ticks({ interval }, domain = this.domain, visibleRange = [0, 1], { extend = false } = {}) {
|
|
if (domain.length < 2)
|
|
return;
|
|
let bands;
|
|
let firstBandIndex;
|
|
let bandsSliceIndices;
|
|
if (domain === this.domain && !extend) {
|
|
({ bands } = this.calculateBands(domain, [0, 1], false));
|
|
bandsSliceIndices = visibleTickSliceIndices(bands, false, visibleRange);
|
|
firstBandIndex = bandsSliceIndices[0];
|
|
} else {
|
|
({ bands, firstBandIndex } = this.calculateBands(domain, visibleRange, extend));
|
|
}
|
|
if (interval == null) {
|
|
return { ticks: bands, count: void 0, firstTickIndex: firstBandIndex };
|
|
}
|
|
const milliseconds = this.interval ? (0, import_ag_charts_core122.intervalMilliseconds)(this.interval) : Infinity;
|
|
const d0 = Math.min(domain[0].valueOf(), domain[1].valueOf());
|
|
const d1 = Math.max(domain[0].valueOf(), domain[1].valueOf());
|
|
let intervalTicks;
|
|
let intervalStartIndex;
|
|
let intervalEndIndex;
|
|
if ((0, import_ag_charts_core122.isPlainObject)(interval) || typeof interval === "string") {
|
|
intervalTicks = (0, import_ag_charts_core122.intervalRange)(interval, domain[0], domain[1], { extend: true, visibleRange });
|
|
intervalStartIndex = 0;
|
|
intervalEndIndex = intervalTicks.length - 1;
|
|
} else {
|
|
const i0 = bandsSliceIndices ? bandsSliceIndices[0] : 0;
|
|
const i1 = bandsSliceIndices ? bandsSliceIndices[1] : bands.length - 1;
|
|
intervalTicks = bands;
|
|
intervalStartIndex = (0, import_ag_charts_core122.findMaxIndex)(i0, i1, (index) => bands[index].valueOf() <= d0) ?? i0;
|
|
intervalEndIndex = (0, import_ag_charts_core122.findMaxIndex)(i0, i1, (index) => bands[index].valueOf() <= d1) ?? i1;
|
|
}
|
|
const ticks = [];
|
|
let lastIndex;
|
|
for (let i = intervalStartIndex; i <= intervalEndIndex; i++) {
|
|
const intervalTickValue = intervalTicks[i].valueOf();
|
|
const bandIndex = (0, import_ag_charts_core122.findMaxIndex)(0, bands.length - 1, (index) => bands[index].valueOf() <= intervalTickValue);
|
|
const tick = bandIndex != null && bandIndex != lastIndex ? bands[bandIndex] : void 0;
|
|
lastIndex = bandIndex;
|
|
if (tick != null && intervalTickValue - tick.getTime() <= milliseconds)
|
|
ticks.push(tick);
|
|
}
|
|
let bandStart;
|
|
let bandEnd;
|
|
if (this.interval) {
|
|
const bandRange = calculateBandRange([new Date(d0), new Date(d1)], this.interval);
|
|
bandStart = bandRange[0].valueOf();
|
|
bandEnd = bandRange[1].valueOf();
|
|
} else {
|
|
bandStart = d0;
|
|
bandEnd = d1;
|
|
}
|
|
let firstTickIndex = (0, import_ag_charts_core122.findMinIndex)(0, ticks.length - 1, (i) => ticks[i].valueOf() >= bandStart) ?? 0;
|
|
let lastTickIndex = (0, import_ag_charts_core122.findMaxIndex)(0, ticks.length - 1, (i) => ticks[i].valueOf() <= bandEnd) ?? ticks.length - 1;
|
|
if (extend) {
|
|
firstTickIndex = Math.max(firstTickIndex - 1, 0);
|
|
lastTickIndex = Math.min(lastTickIndex + 1, ticks.length - 1);
|
|
}
|
|
return {
|
|
ticks: ticks.slice(firstTickIndex, lastTickIndex + 1),
|
|
count: ticks.length,
|
|
firstTickIndex: firstBandIndex
|
|
};
|
|
}
|
|
};
|
|
function supportsInterval(domain, interval, rangeParams) {
|
|
const [start, stop] = calculateBandRange(domain, interval);
|
|
return (0, import_ag_charts_core122.intervalRangeCount)(interval, start, stop, rangeParams) <= MAX_BANDS;
|
|
}
|
|
function calculateBandRange(domain, interval) {
|
|
const start = (0, import_ag_charts_core122.intervalFloor)(interval, domain[0]);
|
|
const stop = (0, import_ag_charts_core122.intervalFloor)(interval, domain[1]);
|
|
return [start, stop];
|
|
}
|
|
|
|
// packages/ag-charts-community/src/util/secondaryAxisTicks.ts
|
|
var import_ag_charts_core123 = require("ag-charts-core");
|
|
function calculateNiceSecondaryAxis(scale2, domain, primaryTickCount, reverse, visibleRange) {
|
|
let [d0, d1] = (0, import_ag_charts_core123.findMinMax)(domain.map(Number));
|
|
const unzoomedTickCount = Math.floor(primaryTickCount.unzoomed);
|
|
if (unzoomedTickCount <= 1) {
|
|
const [start2, stop2] = domainWithOddTickCount(d0, d1);
|
|
const tickCount = 5 * Math.pow(2, -Math.ceil(Math.log2(visibleRange[1] - visibleRange[0])));
|
|
const { ticks: ticks2 } = (0, import_ag_charts_core123.createTicks)(start2, stop2, tickCount, void 0, void 0, visibleRange);
|
|
const d2 = [scale2.toDomain(start2), scale2.toDomain(stop2)];
|
|
if (reverse)
|
|
d2.reverse();
|
|
return { domain: d2, ticks: ticks2 };
|
|
}
|
|
if (d0 === d1) {
|
|
const order = Math.floor(Math.log10(d0));
|
|
const magnitude = Math.pow(10, order);
|
|
const rangeOffsetStep = Math.min(magnitude, 1);
|
|
const rangeOffset = unzoomedTickCount - 1;
|
|
d0 -= rangeOffsetStep * Math.floor(rangeOffset / 2);
|
|
d1 = d0 + rangeOffsetStep * rangeOffset;
|
|
}
|
|
let start = d0;
|
|
let stop = d1;
|
|
start = calculateNiceStart(start, stop, unzoomedTickCount);
|
|
const baseStep = getTickStep(start, stop, unzoomedTickCount);
|
|
const segments = unzoomedTickCount - 1;
|
|
stop = start + segments * baseStep;
|
|
const stepAlignedStart = Math.floor(start / baseStep) * baseStep;
|
|
const stepAlignedStop = Math.floor(stop / baseStep) * baseStep;
|
|
if (stepAlignedStart <= d0 && stepAlignedStop >= d1) {
|
|
start = stepAlignedStart;
|
|
stop = stepAlignedStop;
|
|
}
|
|
const d = [scale2.toDomain(start), scale2.toDomain(stop)];
|
|
if (reverse)
|
|
d.reverse();
|
|
const step = baseStep * ((primaryTickCount.unzoomed - 1) / (primaryTickCount.zoomed - 1));
|
|
const ticks = getTicks(start, step, Math.floor(primaryTickCount.zoomed));
|
|
return { domain: d, ticks };
|
|
}
|
|
function domainWithOddTickCount(d0, d1) {
|
|
let start = d0;
|
|
let stop = d1;
|
|
let iterations = 0;
|
|
do {
|
|
[start, stop] = (0, import_ag_charts_core123.niceTicksDomain)(start, stop);
|
|
const { ticks } = (0, import_ag_charts_core123.createTicks)(start, stop, 5);
|
|
if (ticks.length % 2 === 1)
|
|
return [start, stop];
|
|
start -= 1;
|
|
stop += 1;
|
|
} while (iterations++ < 10);
|
|
return [d0, d1];
|
|
}
|
|
function calculateNiceStart(a, b, count) {
|
|
a = Math.floor(a);
|
|
const rawStep = Math.abs(b - a) / (count - 1);
|
|
const order = Math.floor(Math.log10(rawStep));
|
|
const magnitude = Math.pow(10, order);
|
|
return Math.floor(a / magnitude) * magnitude;
|
|
}
|
|
function getTicks(start, step, count) {
|
|
const fractionDigits = (0, import_ag_charts_core123.countFractionDigits)(step);
|
|
const f = Math.pow(10, fractionDigits);
|
|
const ticks = [];
|
|
for (let i = 0; i < count; i++) {
|
|
const tick = start + step * i;
|
|
ticks.push(Math.round(tick * f) / f);
|
|
}
|
|
return ticks;
|
|
}
|
|
function getTickStep(start, stop, count) {
|
|
const segments = count - 1;
|
|
const rawStep = (stop - start) / segments;
|
|
return calculateNextNiceStep(rawStep);
|
|
}
|
|
function calculateNextNiceStep(rawStep) {
|
|
const order = Math.floor(Math.log10(rawStep));
|
|
const magnitude = Math.pow(10, order);
|
|
const step = rawStep / magnitude;
|
|
if (step > 0 && step <= 1)
|
|
return magnitude;
|
|
if (step > 1 && step <= 2)
|
|
return 2 * magnitude;
|
|
if (step > 2 && step <= 5)
|
|
return 5 * magnitude;
|
|
if (step > 5 && step <= 10)
|
|
return 10 * magnitude;
|
|
return rawStep;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/axis/generateTicksUtils.ts
|
|
var import_ag_charts_core124 = require("ag-charts-core");
|
|
var DENSE_TICK_COUNT = 18;
|
|
var TICK_STEP_VALUES = [1, 2, 3, 4, 6, 8, 9, 10, 12];
|
|
function axisLabelsOverlap(data, padding2 = 0) {
|
|
const result = [];
|
|
for (const datum of data) {
|
|
const { x, y, width, height } = datum;
|
|
if (result.some((l) => (0, import_ag_charts_core124.boxCollides)(l, x, y, width + padding2, height + padding2))) {
|
|
return true;
|
|
}
|
|
result.push(datum);
|
|
}
|
|
return false;
|
|
}
|
|
function createTimeScaleTicks(interval, domain, visibleRange, extend) {
|
|
if (interval == null) {
|
|
return domain;
|
|
}
|
|
if (typeof interval !== "number") {
|
|
const epoch = domain[0];
|
|
const alignedInterval = typeof interval === "string" ? { unit: interval, epoch } : { ...interval, epoch };
|
|
return (0, import_ag_charts_core124.intervalRange)(alignedInterval, domain[0], domain[1], { visibleRange, extend });
|
|
}
|
|
const ticks = [];
|
|
const d0 = domain[0].valueOf();
|
|
const d1 = domain[1].valueOf();
|
|
for (let intervalTickTime = d0; intervalTickTime <= d1; intervalTickTime += interval) {
|
|
ticks.push(new Date(intervalTickTime));
|
|
}
|
|
return ticks;
|
|
}
|
|
function ticksEqual(a, b) {
|
|
if (a.length !== b.length) {
|
|
return false;
|
|
}
|
|
for (let i = 0; i < a.length; i += 1) {
|
|
if (a[i]?.valueOf() !== b[i]?.valueOf()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function ticksSpacing(ticks) {
|
|
if (ticks.length < 2)
|
|
return Infinity;
|
|
let spacing = 0;
|
|
let y0 = ticks[0].translation;
|
|
for (let i = 1; i < ticks.length; i++) {
|
|
const y1 = ticks[i].translation;
|
|
const delta3 = Math.abs(y1 - y0);
|
|
spacing = Math.max(spacing, delta3);
|
|
y0 = y1;
|
|
}
|
|
return spacing;
|
|
}
|
|
function formatTicks(options, {
|
|
niceDomain,
|
|
rawTicks,
|
|
rawFirstTickIndex = 0,
|
|
generatePrimaryTicks,
|
|
primaryTicksIndices,
|
|
alignment,
|
|
fractionDigits,
|
|
timeInterval: timeInterval2
|
|
}) {
|
|
const { scale: scale2, label, tickFormatter, inRange: inRange2, isVertical, sizeLimit = Infinity } = options;
|
|
const isContinuous3 = TimeScale.is(scale2) || DiscreteTimeScale.is(scale2);
|
|
const measurer = (0, import_ag_charts_core124.cachedTextMeasurer)(label);
|
|
const idGenerator = (0, import_ag_charts_core124.createIdsGenerator)();
|
|
const ticks = [];
|
|
withTemporaryDomain(scale2, niceDomain, () => {
|
|
const maxBandwidth = BandScale.is(scale2) ? scale2.bandwidth ?? Infinity : Infinity;
|
|
const halfBandwidth = (scale2.bandwidth ?? 0) / 2;
|
|
const axisFormatter = axisTickFormatter(
|
|
label.enabled,
|
|
generatePrimaryTicks,
|
|
niceDomain,
|
|
rawTicks,
|
|
fractionDigits,
|
|
timeInterval2,
|
|
tickFormatter
|
|
);
|
|
let maxWidth = isVertical ? sizeLimit : maxBandwidth;
|
|
let maxHeight = isVertical ? maxBandwidth : sizeLimit;
|
|
if (label.rotation) {
|
|
const innerRect = (0, import_ag_charts_core124.getMaxInnerRectSize)(label.rotation, maxWidth, maxHeight);
|
|
maxWidth = innerRect.width;
|
|
maxHeight = innerRect.height;
|
|
}
|
|
const wrapOptions = {
|
|
font: label,
|
|
maxWidth,
|
|
maxHeight,
|
|
overflow: label.truncate ? "ellipsis" : "hide",
|
|
textWrap: label.wrapping
|
|
};
|
|
for (let i = 0; i < rawTicks.length; i++) {
|
|
const tick = rawTicks[i];
|
|
const translation = scale2.convert(tick, { alignment }) + halfBandwidth;
|
|
if (inRange2 && !inRange2(translation))
|
|
continue;
|
|
const isPrimary = primaryTicksIndices?.has(i) ?? false;
|
|
const inputText = axisFormatter(isPrimary, tick, i);
|
|
let wrappedLabel = null;
|
|
if (label.avoidCollisions) {
|
|
wrappedLabel = (0, import_ag_charts_core124.wrapTextOrSegments)(inputText, wrapOptions) || null;
|
|
}
|
|
const tickLabel = wrappedLabel ?? inputText;
|
|
const isSegmented = (0, import_ag_charts_core124.isArray)(tickLabel);
|
|
const isTruncated2 = tickLabel !== inputText && (isSegmented ? (0, import_ag_charts_core124.isSegmentTruncated)(tickLabel.at(-1)) : (0, import_ag_charts_core124.isTextTruncated)((0, import_ag_charts_core124.toTextString)(tickLabel)));
|
|
let tickId;
|
|
if (isContinuous3) {
|
|
const tickValue = tick?.valueOf();
|
|
if (Number.isFinite(tickValue)) {
|
|
tickId = idGenerator(`v:${tickValue}`);
|
|
}
|
|
}
|
|
tickId ?? (tickId = idGenerator(`l:${isSegmented ? (0, import_ag_charts_core124.toPlainText)(tickLabel.flat()) : tickLabel}`));
|
|
ticks.push({
|
|
tick,
|
|
tickId,
|
|
tickLabel,
|
|
isPrimary,
|
|
index: i + rawFirstTickIndex,
|
|
textUntruncated: isTruncated2 ? (0, import_ag_charts_core124.toPlainText)(inputText) : void 0,
|
|
textMetrics: isSegmented ? (0, import_ag_charts_core124.measureTextSegments)(tickLabel, label) : measurer.measureLines((0, import_ag_charts_core124.toTextString)(tickLabel)),
|
|
translation: Math.floor(translation)
|
|
});
|
|
}
|
|
});
|
|
return ticks;
|
|
}
|
|
function withTemporaryDomain(scale2, temporaryDomain, callback4) {
|
|
const originalDomain = scale2.domain;
|
|
try {
|
|
scale2.domain = temporaryDomain;
|
|
callback4();
|
|
} finally {
|
|
scale2.domain = originalDomain;
|
|
}
|
|
}
|
|
function axisTickFormatter(labelEnabled, generatePrimaryTicks, niceDomain, rawTicks, fractionDigits, timeInterval2, tickFormatter) {
|
|
const dateStyle = generatePrimaryTicks ? "component" : "long";
|
|
const parentInterval = generatePrimaryTicks && timeInterval2 ? (0, import_ag_charts_core124.intervalHierarchy)(timeInterval2) : void 0;
|
|
const primaryFormatter = generatePrimaryTicks ? tickFormatter(niceDomain, rawTicks, true, fractionDigits, parentInterval, dateStyle) : null;
|
|
const defaultFormatter = labelEnabled ? tickFormatter(niceDomain, rawTicks, false, fractionDigits, timeInterval2, dateStyle) : null;
|
|
return (isPrimary, tick, index) => {
|
|
const formatter = isPrimary ? primaryFormatter : defaultFormatter;
|
|
return formatter?.(tick, index) ?? String(tick);
|
|
};
|
|
}
|
|
function getTimeIntervalTicks(scale2, visibleRange, tickCount, maxTickCount, tickParams, timeInterval2, reverse, minimumTimeGranularity) {
|
|
if (!TimeScale.is(scale2) && !DiscreteTimeScale.is(scale2))
|
|
return;
|
|
const parentInterval = (0, import_ag_charts_core124.intervalHierarchy)(timeInterval2);
|
|
if (parentInterval == null)
|
|
return;
|
|
if (reverse) {
|
|
visibleRange = [1 - visibleRange[1], 1 - visibleRange[0]];
|
|
}
|
|
const dv0 = Math.min(scale2.domain[0].valueOf(), scale2.domain.at(-1).valueOf());
|
|
const dv1 = Math.max(scale2.domain[0].valueOf(), scale2.domain.at(-1).valueOf());
|
|
let [dp0, dp1] = (0, import_ag_charts_core124.intervalExtent)(new Date(dv0), new Date(dv1), visibleRange);
|
|
dp0 = (0, import_ag_charts_core124.intervalFloor)(parentInterval, dp0);
|
|
if (dp0.valueOf() >= dv0) {
|
|
dp0 = (0, import_ag_charts_core124.intervalPrevious)(parentInterval, dp0);
|
|
}
|
|
dp1 = (0, import_ag_charts_core124.intervalCeil)(parentInterval, dp1);
|
|
if (dp1.valueOf() <= dv1) {
|
|
dp1 = (0, import_ag_charts_core124.intervalNext)(parentInterval, dp1);
|
|
}
|
|
const primaryTicks = (0, import_ag_charts_core124.intervalRange)(parentInterval, dp0, dp1);
|
|
const milliseconds = (0, import_ag_charts_core124.intervalMilliseconds)(timeInterval2);
|
|
const skipFirstPrimaryTick = OrdinalTimeScale.is(scale2);
|
|
const intervalTickParams = { ...tickParams, interval: timeInterval2 };
|
|
const ticks = [];
|
|
let primaryTicksIndices;
|
|
let parentLevelMode;
|
|
let alignment;
|
|
let ordinalTickStep = 0;
|
|
if (OrdinalTimeScale.is(scale2)) {
|
|
const timeIntervalGranularity = (0, import_ag_charts_core124.intervalUnit)(timeInterval2);
|
|
parentLevelMode = minimumTimeGranularity != null && (0, import_ag_charts_core124.intervalMilliseconds)(minimumTimeGranularity) >= (0, import_ag_charts_core124.intervalMilliseconds)(timeIntervalGranularity) ? 2 /* OrdinalTimeStepTicks */ : 3 /* OrdinalTimeScaleTicks */;
|
|
alignment = import_ag_charts_core124.ScaleAlignment.Trailing;
|
|
const tickDensity = tickCount / maxTickCount;
|
|
const baseTickStep = scale2.bandCount(visibleRange) / (tickDensity * DENSE_TICK_COUNT);
|
|
ordinalTickStep = TICK_STEP_VALUES.findLast((t) => baseTickStep >= t) ?? 1;
|
|
} else if (UnitTimeScale.is(scale2) && (scale2.interval == null || (0, import_ag_charts_core124.intervalMilliseconds)(scale2.interval) >= milliseconds)) {
|
|
parentLevelMode = 1 /* UnitTimeScaleTicks */;
|
|
} else {
|
|
parentLevelMode = 0 /* ContinuousTimeScaleTicks */;
|
|
alignment = import_ag_charts_core124.ScaleAlignment.Interpolate;
|
|
}
|
|
for (let i = 0; i < primaryTicks.length - 1; i++) {
|
|
const p0 = primaryTicks[i];
|
|
const p1 = primaryTicks[i + 1];
|
|
const first8 = i === 0;
|
|
const last = i === primaryTicks.length - 2;
|
|
const dp = p1.valueOf() - p0.valueOf();
|
|
const pVisibleRange = [
|
|
Math.max((dv0 - p0.valueOf()) / dp, 0),
|
|
Math.min((dv1 - p0.valueOf()) / dp, 1)
|
|
];
|
|
let intervalTicks;
|
|
switch (parentLevelMode) {
|
|
case 0 /* ContinuousTimeScaleTicks */:
|
|
intervalTicks = createTimeScaleTicks(intervalTickParams.interval, [p0, p1], pVisibleRange, true);
|
|
break;
|
|
case 1 /* UnitTimeScaleTicks */:
|
|
case 3 /* OrdinalTimeScaleTicks */: {
|
|
const scaleTicks = scale2.ticks(intervalTickParams, [p0, p1], pVisibleRange, {
|
|
extend: true,
|
|
dropInitial: true
|
|
});
|
|
intervalTicks = scaleTicks?.ticks ?? [];
|
|
break;
|
|
}
|
|
case 2 /* OrdinalTimeStepTicks */:
|
|
intervalTicks = scale2.stepTicks(
|
|
ordinalTickStep,
|
|
[p0, p1],
|
|
void 0,
|
|
!last
|
|
);
|
|
break;
|
|
}
|
|
(0, import_ag_charts_core124.dropFirstWhile)(intervalTicks, (firstTick2) => firstTick2.valueOf() < p0.valueOf());
|
|
if (!last) {
|
|
(0, import_ag_charts_core124.dropLastWhile)(intervalTicks, (lastTick) => {
|
|
switch (parentLevelMode) {
|
|
case 0 /* ContinuousTimeScaleTicks */:
|
|
case 3 /* OrdinalTimeScaleTicks */:
|
|
return lastTick.valueOf() + milliseconds > p1.valueOf();
|
|
case 1 /* UnitTimeScaleTicks */:
|
|
case 2 /* OrdinalTimeStepTicks */:
|
|
return lastTick.valueOf() >= p1.valueOf();
|
|
}
|
|
});
|
|
}
|
|
if (intervalTicks.length === 0)
|
|
continue;
|
|
const firstTick = intervalTicks[0];
|
|
const firstTickDiff = (0, import_ag_charts_core124.compareDates)(firstTick, p0);
|
|
const firstPrimary = parentLevelMode === 0 /* ContinuousTimeScaleTicks */ ? firstTickDiff === 0 : firstTickDiff <= milliseconds;
|
|
if (firstPrimary && (!skipFirstPrimaryTick || !first8)) {
|
|
primaryTicksIndices ?? (primaryTicksIndices = /* @__PURE__ */ new Set());
|
|
primaryTicksIndices.add(ticks.length);
|
|
}
|
|
ticks.push(...intervalTicks);
|
|
}
|
|
if (primaryTicksIndices?.size === 1 && primaryTicksIndices.has(0)) {
|
|
primaryTicksIndices = void 0;
|
|
}
|
|
return { ticks, primaryTicksIndices, alignment };
|
|
}
|
|
function timeIntervalMaxLabelSize(label, primaryLabel, domain, timeInterval2, textMeasurer) {
|
|
const specifier = labelSpecifier(label.format, timeInterval2);
|
|
if (specifier == null) {
|
|
return { width: 0, height: 0 };
|
|
}
|
|
const labelFormatter = (0, import_ag_charts_core124.buildDateFormatter)(specifier);
|
|
const hierarchy = timeInterval2 ? (0, import_ag_charts_core124.intervalHierarchy)(timeInterval2) : void 0;
|
|
const primarySpecifier = labelSpecifier(primaryLabel?.format, hierarchy);
|
|
const primaryLabelFormatter = primarySpecifier ? (0, import_ag_charts_core124.buildDateFormatter)(primarySpecifier) : labelFormatter;
|
|
const d0 = new Date(domain[0]);
|
|
const d1 = new Date(domain.at(-1));
|
|
const hierarchyRange = hierarchy ? (0, import_ag_charts_core124.intervalRange)(hierarchy, new Date(domain[0]), new Date(domain.at(-1)), { extend: true }) : void 0;
|
|
let maxWidth = 0;
|
|
let maxHeight = 0;
|
|
if (labelFormatter != null) {
|
|
const padding2 = expandLabelPadding(label);
|
|
const xPadding = padding2.left + padding2.right;
|
|
const yPadding = padding2.top + padding2.bottom;
|
|
let l0;
|
|
let l1;
|
|
if (hierarchyRange != null && hierarchyRange.length > 1) {
|
|
l0 = hierarchyRange[0];
|
|
l1 = hierarchyRange[1];
|
|
} else {
|
|
l0 = d0;
|
|
l1 = d1;
|
|
}
|
|
const labelRange = (0, import_ag_charts_core124.intervalRange)(timeInterval2, l0, l1, { limit: 50 });
|
|
for (const date3 of labelRange) {
|
|
const text = labelFormatter(date3);
|
|
const { width, height } = textMeasurer.measureLines(text);
|
|
maxWidth = Math.max(maxWidth, width + xPadding);
|
|
maxHeight = Math.max(maxHeight, height + yPadding);
|
|
}
|
|
}
|
|
if (primaryLabelFormatter != null && hierarchyRange != null) {
|
|
const padding2 = expandLabelPadding(primaryLabel);
|
|
const xPadding = padding2.left + padding2.right;
|
|
const yPadding = padding2.top + padding2.bottom;
|
|
for (const date3 of hierarchyRange) {
|
|
const text = primaryLabelFormatter(date3);
|
|
const { width, height } = textMeasurer.measureLines(text);
|
|
maxWidth = Math.max(maxWidth, width + xPadding);
|
|
maxHeight = Math.max(maxHeight, height + yPadding);
|
|
}
|
|
}
|
|
return {
|
|
width: Math.ceil(maxWidth),
|
|
height: Math.ceil(maxHeight)
|
|
};
|
|
}
|
|
function getTextBaseline(parallel, labelRotation, sideFlag, parallelFlipFlag) {
|
|
if (parallel && !labelRotation) {
|
|
return sideFlag * parallelFlipFlag === -1 ? "top" : "bottom";
|
|
}
|
|
return "middle";
|
|
}
|
|
function getTextAlign(parallel, labelRotation, labelAutoRotation, sideFlag, regularFlipFlag) {
|
|
const labelRotated = labelRotation > 0 && labelRotation <= Math.PI;
|
|
const labelAutoRotated = labelAutoRotation > 0 && labelAutoRotation <= Math.PI;
|
|
const alignFlag = labelRotated || labelAutoRotated ? -1 : 1;
|
|
if (parallel) {
|
|
if (labelRotation || labelAutoRotation) {
|
|
if (sideFlag * alignFlag === -1) {
|
|
return "end";
|
|
}
|
|
} else {
|
|
return "center";
|
|
}
|
|
} else if (sideFlag * regularFlipFlag === -1) {
|
|
return "end";
|
|
}
|
|
return "start";
|
|
}
|
|
function labelSpecifier(format, timeInterval2) {
|
|
if (format == null)
|
|
return;
|
|
if (typeof format === "string") {
|
|
return format;
|
|
} else if ((0, import_ag_charts_core124.isPlainObject)(format) && timeInterval2 != null) {
|
|
return format[(0, import_ag_charts_core124.intervalUnit)(timeInterval2)];
|
|
}
|
|
}
|
|
function calculateLabelRotation(rotation, parallel, axisRotation = 0) {
|
|
const configuredRotation = (0, import_ag_charts_core124.normalizeAngle360FromDegrees)(rotation);
|
|
const parallelFlipFlag = !configuredRotation && axisRotation >= 0 && axisRotation <= Math.PI ? -1 : 1;
|
|
const regularFlipFlag = !configuredRotation && axisRotation - Math.PI / 2 >= 0 && axisRotation - Math.PI / 2 <= Math.PI ? -1 : 1;
|
|
const defaultRotation = parallel ? parallelFlipFlag * (Math.PI / 2) : 0;
|
|
return { configuredRotation, defaultRotation, parallelFlipFlag, regularFlipFlag };
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/axis/generateTicks.ts
|
|
var sunday2 = new Date(1970, 0, 4);
|
|
function generateTicks(options) {
|
|
const { label, domain, axisRotation, labelOffset, sideFlag } = options;
|
|
const { defaultRotation, configuredRotation, parallelFlipFlag, regularFlipFlag } = calculateLabelRotation(
|
|
label.rotation,
|
|
label.parallel,
|
|
axisRotation
|
|
);
|
|
const initialRotation = configuredRotation + defaultRotation;
|
|
const checkLabelOverlap = (tickData2, rotation2 = 0) => {
|
|
const labelSpacing = label.minSpacing ?? (configuredRotation === 0 && rotation2 === 0 ? 10 : 0);
|
|
const labelRotation = initialRotation + rotation2;
|
|
const labelPadding = expandLabelPadding(label);
|
|
return axisLabelsOverlap(createTimeLabelData(options, tickData2, labelRotation), labelSpacing) || axisLabelsOverlap(createLabelData(tickData2.ticks, labelOffset, labelRotation, labelPadding), labelSpacing);
|
|
};
|
|
const { maxTickCount } = estimateScaleTickCount(options);
|
|
const tickGenerationType = getTickGenerationType(options);
|
|
const avoidCollisions = label.enabled && label.avoidCollisions;
|
|
const maxIterations = Number.isFinite(maxTickCount) ? maxTickCount : 10;
|
|
const tryAutoRotate = avoidCollisions && label.autoRotate && label.rotation == null;
|
|
let index = 0;
|
|
let autoRotation = 0;
|
|
let labelOverlap = true;
|
|
let tickData = {
|
|
tickDomain: [],
|
|
niceDomain: domain,
|
|
ticks: [],
|
|
rawTicks: [],
|
|
rawTickCount: void 0,
|
|
timeInterval: void 0,
|
|
fractionDigits: 0
|
|
};
|
|
while (labelOverlap && index <= maxIterations) {
|
|
({ tickData, index } = buildTickData(options, tickGenerationType, tickData, index));
|
|
autoRotation = tryAutoRotate && checkLabelOverlap(tickData, 0) ? (0, import_ag_charts_core125.normalizeAngle360FromDegrees)(label.autoRotateAngle) : 0;
|
|
labelOverlap = avoidCollisions && checkLabelOverlap(tickData, autoRotation);
|
|
}
|
|
const textAlign = getTextAlign(label.parallel, configuredRotation, autoRotation, sideFlag, regularFlipFlag);
|
|
const textBaseline = getTextBaseline(label.parallel, configuredRotation, sideFlag, parallelFlipFlag);
|
|
const rotation = configuredRotation + autoRotation;
|
|
return { tickData, textAlign, textBaseline, rotation };
|
|
}
|
|
function getTickGenerationType(options) {
|
|
if (options.interval?.values) {
|
|
return 2 /* VALUES */;
|
|
} else if (options.primaryTickCount != null) {
|
|
return 1 /* CREATE_SECONDARY */;
|
|
}
|
|
return 0 /* CREATE */;
|
|
}
|
|
function estimateScaleTickCount({
|
|
scale: scale2,
|
|
domain,
|
|
range: range4,
|
|
visibleRange,
|
|
label,
|
|
defaultTickMinSpacing,
|
|
interval: { minSpacing, maxSpacing }
|
|
}) {
|
|
const { defaultTickCount } = scale2;
|
|
const rangeExtent = (0, import_ag_charts_core125.findRangeExtent)(range4);
|
|
const zoomExtent = (0, import_ag_charts_core125.findRangeExtent)(visibleRange);
|
|
if (CategoryScale.is(scale2) || OrdinalTimeScale.is(scale2) && domain.length < 1e3) {
|
|
const maxTickCount = CategoryScale.is(scale2) ? domain.length : Math.min(domain.length, Math.max(1, Math.floor(rangeExtent / (zoomExtent * defaultTickMinSpacing))));
|
|
const estimatedTickCount = Math.ceil(rangeExtent / (zoomExtent * label.fontSize));
|
|
return {
|
|
tickCount: Math.min(estimatedTickCount, maxTickCount),
|
|
minTickCount: 0,
|
|
maxTickCount
|
|
};
|
|
}
|
|
return (0, import_ag_charts_core125.estimateTickCount)(rangeExtent, zoomExtent, minSpacing, maxSpacing, defaultTickCount, defaultTickMinSpacing);
|
|
}
|
|
function buildTickData(options, tickGenerationType, previousTickData, index) {
|
|
const { step, values } = options.interval;
|
|
const { maxTickCount, minTickCount, tickCount } = estimateScaleTickCount(options);
|
|
const countTicks = (i) => Math.max(tickCount - i, minTickCount);
|
|
const regenerateTicks = step == null && values == null && countTicks(index) > minTickCount;
|
|
const previousTicks = previousTickData.rawTicks;
|
|
const maxIterations = tickCount - minTickCount;
|
|
const countParams = { minTickCount, maxTickCount, tickCount: countTicks(index) };
|
|
let nextTicks = calculateRawTicks(options, tickGenerationType, countParams);
|
|
if (regenerateTicks && ticksEqual(nextTicks.rawTicks, previousTicks)) {
|
|
let lowerBound = index;
|
|
let upperBound = maxIterations;
|
|
while (lowerBound <= upperBound) {
|
|
index = Math.trunc((lowerBound + upperBound) / 2);
|
|
countParams.tickCount = countTicks(index);
|
|
const nextTicksCandidate = calculateRawTicks(options, tickGenerationType, countParams);
|
|
if (ticksEqual(nextTicksCandidate.rawTicks, previousTicks)) {
|
|
lowerBound = index + 1;
|
|
} else {
|
|
nextTicks = nextTicksCandidate;
|
|
upperBound = index - 1;
|
|
}
|
|
}
|
|
}
|
|
const {
|
|
tickDomain,
|
|
niceDomain,
|
|
rawTicks,
|
|
rawTickCount,
|
|
rawFirstTickIndex,
|
|
generatePrimaryTicks,
|
|
primaryTicksIndices,
|
|
alignment,
|
|
fractionDigits,
|
|
timeInterval: timeInterval2
|
|
} = nextTicks;
|
|
return {
|
|
tickData: {
|
|
tickDomain,
|
|
niceDomain,
|
|
rawTicks,
|
|
rawTickCount,
|
|
fractionDigits,
|
|
timeInterval: timeInterval2,
|
|
ticks: formatTicks(options, {
|
|
niceDomain,
|
|
rawTicks,
|
|
rawFirstTickIndex,
|
|
generatePrimaryTicks,
|
|
primaryTicksIndices,
|
|
alignment,
|
|
fractionDigits,
|
|
timeInterval: timeInterval2
|
|
})
|
|
},
|
|
index: index + 1
|
|
};
|
|
}
|
|
function calculateRawTicks(options, tickGenerationType, countParams) {
|
|
const {
|
|
domain,
|
|
reverse,
|
|
visibleRange,
|
|
scale: scale2,
|
|
interval,
|
|
primaryLabel,
|
|
niceMode,
|
|
primaryTickCount,
|
|
minimumTimeGranularity
|
|
} = options;
|
|
const domainParams = {
|
|
nice: niceMode.map((n) => n === 0 /* TickAndDomain */),
|
|
interval: interval.step,
|
|
...countParams
|
|
};
|
|
const tickParams = {
|
|
...domainParams,
|
|
nice: niceMode.map((n) => n === 0 /* TickAndDomain */ || n === 1 /* TicksOnly */)
|
|
};
|
|
let secondaryAxisTicks;
|
|
if (tickGenerationType === 1 /* CREATE_SECONDARY */ && primaryTickCount != null && ContinuousScale.is(scale2)) {
|
|
secondaryAxisTicks = calculateNiceSecondaryAxis(scale2, domain, primaryTickCount, reverse, visibleRange);
|
|
}
|
|
const niceDomain = niceMode.includes(0 /* TickAndDomain */) ? secondaryAxisTicks?.domain ?? scale2.niceDomain(domainParams, domain) : domain;
|
|
let tickDomain = niceDomain;
|
|
let rawTicks;
|
|
let rawTickCount;
|
|
let rawFirstTickIndex;
|
|
let timeInterval2;
|
|
let primaryTicksIndices;
|
|
let alignment;
|
|
const generatePrimaryTicks = primaryLabel?.enabled === true && tickParams.interval == null;
|
|
withTemporaryDomain(scale2, niceDomain, () => {
|
|
switch (tickGenerationType) {
|
|
case 2 /* VALUES */:
|
|
tickDomain = interval.values;
|
|
rawTicks = interval.values;
|
|
rawTickCount = rawTicks.length;
|
|
if (OrdinalTimeScale.is(scale2)) {
|
|
alignment = import_ag_charts_core125.ScaleAlignment.Trailing;
|
|
} else if (UnitTimeScale.is(scale2)) {
|
|
alignment = import_ag_charts_core125.ScaleAlignment.Interpolate;
|
|
}
|
|
if (ContinuousScale.is(scale2)) {
|
|
const [d0, d1] = (0, import_ag_charts_core125.findMinMax)(niceDomain.map(Number));
|
|
rawTicks = rawTicks.filter((value) => Number(value) >= d0 && Number(value) <= d1).sort((a, b) => Number(a) - Number(b));
|
|
}
|
|
break;
|
|
case 1 /* CREATE_SECONDARY */:
|
|
if (secondaryAxisTicks) {
|
|
rawTicks = secondaryAxisTicks.ticks;
|
|
rawTickCount = secondaryAxisTicks.ticks.length;
|
|
} else {
|
|
const tickGeneration = scale2.ticks(tickParams, niceDomain, visibleRange);
|
|
rawTicks = tickGeneration?.ticks;
|
|
rawTickCount = tickGeneration?.count;
|
|
}
|
|
break;
|
|
default: {
|
|
const { tickCount, minTickCount, maxTickCount } = countParams;
|
|
if (niceDomain.length > 0 && tickParams.interval == null && (UnitTimeScale.is(scale2) || generatePrimaryTicks && (TimeScale.is(scale2) || OrdinalTimeScale.is(scale2)))) {
|
|
const dates = niceDomain;
|
|
const start = Math.min(dates[0].valueOf(), dates.at(-1).valueOf());
|
|
const end2 = Math.max(dates[0].valueOf(), dates.at(-1).valueOf());
|
|
timeInterval2 = (0, import_ag_charts_core125.getTickTimeInterval)(start, end2, tickCount, minTickCount, maxTickCount, {
|
|
weekStart: primaryLabel == null ? sunday2 : void 0,
|
|
primaryOnly: true
|
|
});
|
|
}
|
|
let minTimeInterval;
|
|
if (OrdinalTimeScale.is(scale2)) {
|
|
minTimeInterval = minimumTimeGranularity;
|
|
} else if (UnitTimeScale.is(scale2)) {
|
|
minTimeInterval = scale2.interval;
|
|
}
|
|
if (minTimeInterval != null && timeInterval2 != null && // Prefer UnitTimeAxis.unit over this interval, because the user may have defined an epoch
|
|
(0, import_ag_charts_core125.intervalMilliseconds)(minTimeInterval) >= (0, import_ag_charts_core125.intervalMilliseconds)(timeInterval2)) {
|
|
timeInterval2 = minTimeInterval;
|
|
}
|
|
const intervalTicks = timeInterval2 ? getTimeIntervalTicks(
|
|
scale2,
|
|
visibleRange,
|
|
tickCount,
|
|
maxTickCount,
|
|
tickParams,
|
|
timeInterval2,
|
|
reverse,
|
|
minimumTimeGranularity
|
|
) : void 0;
|
|
if (intervalTicks) {
|
|
({ ticks: rawTicks, primaryTicksIndices, alignment } = intervalTicks);
|
|
} else {
|
|
const intervalTickParams = UnitTimeScale.is(scale2) && tickParams.interval == null && timeInterval2 != null ? { ...tickParams, interval: timeInterval2 } : tickParams;
|
|
const tickGeneration = scale2.ticks(intervalTickParams, niceDomain, visibleRange);
|
|
rawTicks = tickGeneration?.ticks;
|
|
rawTickCount = tickGeneration?.count;
|
|
rawFirstTickIndex = tickGeneration?.firstTickIndex;
|
|
if (TimeScale.is(scale2) || DiscreteTimeScale.is(scale2)) {
|
|
const paramsInterval = typeof tickParams.interval === "number" ? (0, import_ag_charts_core125.lowestGranularityForInterval)(tickParams.interval) : tickParams.interval;
|
|
timeInterval2 ?? (timeInterval2 = paramsInterval ?? tickGeneration?.timeInterval);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
rawTicks ?? (rawTicks = []);
|
|
let fractionDigits = 0;
|
|
for (const tick of rawTicks) {
|
|
if (typeof tick !== "number")
|
|
continue;
|
|
const value = (0, import_ag_charts_core125.countFractionDigits)(tick);
|
|
if (value > fractionDigits) {
|
|
fractionDigits = value;
|
|
}
|
|
}
|
|
if (!generatePrimaryTicks) {
|
|
primaryTicksIndices = void 0;
|
|
}
|
|
return {
|
|
tickDomain,
|
|
niceDomain,
|
|
rawTicks,
|
|
rawTickCount,
|
|
rawFirstTickIndex,
|
|
generatePrimaryTicks,
|
|
primaryTicksIndices,
|
|
alignment,
|
|
fractionDigits,
|
|
timeInterval: timeInterval2
|
|
};
|
|
}
|
|
function createTimeLabelData(options, tickData, labelRotation) {
|
|
const { niceDomain, ticks, timeInterval: timeInterval2 } = tickData;
|
|
if (timeInterval2 == null)
|
|
return [];
|
|
const spacing = ticksSpacing(ticks);
|
|
const { label, labelOffset, primaryLabel, domain } = options;
|
|
const { width, height } = timeIntervalMaxLabelSize(
|
|
label,
|
|
primaryLabel,
|
|
niceDomain ?? domain,
|
|
timeInterval2,
|
|
(0, import_ag_charts_core125.cachedTextMeasurer)(label)
|
|
);
|
|
const labelData = [];
|
|
for (const translation of [0, spacing]) {
|
|
const { x, y } = (0, import_ag_charts_core125.rotatePoint)(labelOffset, translation, labelRotation);
|
|
labelData.push({ x, y, width, height });
|
|
}
|
|
return labelData;
|
|
}
|
|
function createLabelData(tickData, labelOffset, labelRotation, labelPadding) {
|
|
const labelData = [];
|
|
const xPadding = labelPadding.left + labelPadding.right;
|
|
const yPadding = labelPadding.top + labelPadding.bottom;
|
|
for (const { tickLabel, textMetrics, translation } of tickData) {
|
|
if (!tickLabel)
|
|
continue;
|
|
const { x, y } = (0, import_ag_charts_core125.rotatePoint)(labelOffset, translation, labelRotation);
|
|
const width = textMetrics.width + xPadding;
|
|
const height = textMetrics.height + yPadding;
|
|
labelData.push({ x, y, width, height });
|
|
}
|
|
return labelData;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/axis/cartesianAxis.ts
|
|
var _CartesianAxis = class _CartesianAxis extends Axis {
|
|
constructor(moduleCtx, scale2) {
|
|
super(moduleCtx, scale2);
|
|
this.maxThicknessRatio = 0.3;
|
|
this.crossAxisTranslation = { x: 0, y: 0 };
|
|
this.minimumTimeGranularity = void 0;
|
|
this.headingLabelGroup = this.axisGroup.appendChild(
|
|
new TranslatableGroup({ name: `${this.id}-Axis-heading` })
|
|
);
|
|
this.lineNodeGroup = this.axisGroup.appendChild(
|
|
new TranslatableGroup({ name: `${this.id}-Axis-line` })
|
|
);
|
|
this.lineNode = this.lineNodeGroup.appendChild(new Line({ zIndex: 1 /* AxisLine */ }));
|
|
this.tickLineGroupSelection = Selection.select(this.tickLineGroup, Line, false);
|
|
this.gridLineGroupSelection = Selection.select(this.gridLineGroup, Line, false);
|
|
this.gridFillGroupSelection = Selection.select(this.gridFillGroup, Rect, false);
|
|
this.tempText = new TransformableText({ debugDirty: false });
|
|
this.tempCaption = new Caption();
|
|
this.animationManager = moduleCtx.animationManager;
|
|
this.animationState = new import_ag_charts_core126.StateMachine("empty", {
|
|
empty: {
|
|
update: {
|
|
target: "ready",
|
|
action: () => this.resetSelectionNodes()
|
|
},
|
|
reset: "empty"
|
|
},
|
|
ready: {
|
|
update: (data) => this.animateReadyUpdate(data),
|
|
resize: () => this.resetSelectionNodes(),
|
|
reset: "empty"
|
|
}
|
|
});
|
|
this.headingLabelGroup.appendChild(this.title.caption.node);
|
|
let previousSize = void 0;
|
|
this.cleanup.register(
|
|
moduleCtx.eventsHub.on("layout:complete", (e) => {
|
|
const size = [e.chart.width, e.chart.height];
|
|
if (previousSize != null && !(0, import_ag_charts_core126.arraysEqual)(size, previousSize)) {
|
|
this.animationState.transition("resize");
|
|
}
|
|
previousSize = size;
|
|
}),
|
|
this.title.caption.registerInteraction(this.moduleCtx, "afterend")
|
|
);
|
|
}
|
|
static is(value) {
|
|
return value instanceof _CartesianAxis;
|
|
}
|
|
get horizontal() {
|
|
return this.position === "top" || this.position === "bottom";
|
|
}
|
|
onGridVisibilityChange() {
|
|
}
|
|
resetAnimation(phase) {
|
|
if (phase === "initial") {
|
|
this.animationState.transition("reset");
|
|
}
|
|
}
|
|
get direction() {
|
|
return this.position === "top" || this.position === "bottom" ? import_ag_charts_core126.ChartAxisDirection.X : import_ag_charts_core126.ChartAxisDirection.Y;
|
|
}
|
|
createAxisContext() {
|
|
return { ...super.createAxisContext(), position: this.position };
|
|
}
|
|
createLabel() {
|
|
return new CartesianAxisLabel();
|
|
}
|
|
updateDirection() {
|
|
switch (this.position) {
|
|
case "top":
|
|
this.label.mirrored = true;
|
|
this.label.parallel = true;
|
|
break;
|
|
case "right":
|
|
this.label.mirrored = true;
|
|
this.label.parallel = false;
|
|
break;
|
|
case "bottom":
|
|
this.label.mirrored = false;
|
|
this.label.parallel = true;
|
|
break;
|
|
case "left":
|
|
this.label.mirrored = false;
|
|
this.label.parallel = false;
|
|
break;
|
|
}
|
|
if (this.axisContext) {
|
|
this.axisContext.position = this.position;
|
|
this.axisContext.direction = this.direction;
|
|
}
|
|
}
|
|
calculateLayout(primaryTickCount, chartLayout) {
|
|
this.updateDirection();
|
|
return super.calculateLayout(primaryTickCount, chartLayout);
|
|
}
|
|
layoutCrossLines() {
|
|
const crosslinesVisible = this.hasDefinedDomain() || this.hasVisibleSeries();
|
|
for (const crossLine of this.crossLines) {
|
|
crossLine.calculateLayout?.(crosslinesVisible);
|
|
}
|
|
}
|
|
calculateTickLayout(domain, niceMode, visibleRange, initialPrimaryTickCount) {
|
|
const sideFlag = this.label.getSideFlag();
|
|
const labelX = sideFlag * (this.getTickSize() + this.getTickSpacing() + this.label.spacing + this.seriesAreaPadding);
|
|
const scrollbar = this.chartLayout?.scrollbars?.[this.id];
|
|
const scrollbarThickness = this.getScrollbarThickness(scrollbar);
|
|
if (niceMode[0] === 2 /* Off */ && niceMode[1] === 2 /* Off */ && this.label.enabled === false && this.tick.enabled === false && this.gridLine.enabled === false) {
|
|
const { bbox: bbox2, spacing: spacing2 } = this.measureAxisLayout(domain, [], [], scrollbar, scrollbarThickness);
|
|
const layout2 = {
|
|
ticks: [],
|
|
tickLines: [],
|
|
gridLines: [],
|
|
gridFills: [],
|
|
labels: [],
|
|
spacing: spacing2
|
|
};
|
|
return {
|
|
ticks: [],
|
|
rawTickCount: 0,
|
|
tickDomain: domain,
|
|
niceDomain: domain,
|
|
fractionDigits: 0,
|
|
timeInterval: void 0,
|
|
bbox: bbox2,
|
|
layout: layout2
|
|
};
|
|
}
|
|
const { label, primaryLabel, scale: scale2, range: range4, interval, reverse, defaultTickMinSpacing, minimumTimeGranularity } = this;
|
|
const tickGenerationResult = generateTicks({
|
|
label,
|
|
scale: scale2,
|
|
interval,
|
|
primaryLabel,
|
|
domain,
|
|
range: range4,
|
|
reverse,
|
|
niceMode,
|
|
visibleRange,
|
|
defaultTickMinSpacing,
|
|
minimumTimeGranularity,
|
|
sideFlag,
|
|
labelOffset: labelX,
|
|
primaryTickCount: initialPrimaryTickCount,
|
|
axisRotation: this.horizontal ? Math.PI / -2 : 0,
|
|
isVertical: this.direction === import_ag_charts_core126.ChartAxisDirection.Y,
|
|
sizeLimit: this.chartLayout?.sizeLimit,
|
|
inRange: (translation) => this.inRange(translation, 1e-3),
|
|
tickFormatter: (...args) => this.tickFormatter(...args)
|
|
});
|
|
const { tickData } = tickGenerationResult;
|
|
const removeOverflowLabels = this.label.avoidCollisions && this.horizontal && tickData.ticks.length > 2 && (ContinuousScale.is(this.scale) || DiscreteTimeScale.is(this.scale));
|
|
if (removeOverflowLabels) {
|
|
const removeOverflowThreshold = this.chartLayout?.padding.right ?? 0;
|
|
const lastTick = tickData.ticks.at(-1);
|
|
if (lastTick?.tickLabel != null && lastTick.translation + lastTick.textMetrics.width / 2 > range4[1] + removeOverflowThreshold) {
|
|
lastTick.tickLabel = void 0;
|
|
if (visibleRange[0] === 0 && visibleRange[1] === 1) {
|
|
tickData.ticks[0].tickLabel = void 0;
|
|
}
|
|
}
|
|
}
|
|
const { ticks, tickDomain, rawTicks, rawTickCount, fractionDigits, timeInterval: timeInterval2, niceDomain } = tickData;
|
|
const labels = ticks.map((d) => this.getTickLabelProps(d, tickGenerationResult, scrollbarThickness));
|
|
const { position, gridPadding, gridLength } = this;
|
|
const direction = position === "bottom" || position === "right" ? -1 : 1;
|
|
const p1 = direction * gridPadding;
|
|
const p2 = direction * (gridLength + gridPadding);
|
|
const gridLines = this.calculateGridLines(ticks, p1, p2);
|
|
const gridFills = this.calculateGridFills(ticks, p1, p2);
|
|
const tickLines = this.calculateTickLines(ticks, direction, scrollbarThickness);
|
|
const { bbox, spacing } = this.measureAxisLayout(tickDomain, ticks, labels, scrollbar, scrollbarThickness);
|
|
const layout = { ticks, gridLines, gridFills, tickLines, labels, spacing };
|
|
return { ticks: rawTicks, rawTickCount, tickDomain, niceDomain, fractionDigits, timeInterval: timeInterval2, bbox, layout };
|
|
}
|
|
calculateGridLines(ticks, p1, p2) {
|
|
return ticks.map((tick, index) => this.calculateGridLine(tick, index, p1, p2, ticks));
|
|
}
|
|
calculateGridLine({ index: tickIndex, tickId, translation: offset }, _index, p1, p2, _ticks) {
|
|
const { gridLine, horizontal } = this;
|
|
const [x1, y1, x2, y2] = horizontal ? [offset, p1, offset, p2] : [p1, offset, p2, offset];
|
|
const { style } = gridLine;
|
|
const { stroke, strokeWidth = 0, lineDash } = style[tickIndex % style.length] ?? {};
|
|
return { tickId, offset, x1, y1, x2, y2, stroke, strokeWidth, lineDash };
|
|
}
|
|
calculateGridFills(ticks, p1, p2) {
|
|
const { horizontal, range: range4, type } = this;
|
|
const gridFills = [];
|
|
if (ticks.length == 0)
|
|
return gridFills;
|
|
let gridFillIndexOffset = 0;
|
|
const isVerticalUnitTime = !horizontal && type === "unit-time";
|
|
const firstFillOffCanvas = isVerticalUnitTime && ticks[0].translation < range4[0] || !isVerticalUnitTime && ticks[0].translation > range4[0];
|
|
if (firstFillOffCanvas) {
|
|
const injectedTick = { tickId: `before:${ticks[0].tickId}`, translation: range4[0] };
|
|
gridFills.push(this.calculateGridFill(injectedTick, -1, ticks[0].index, p1, p2, ticks));
|
|
gridFillIndexOffset = 1;
|
|
}
|
|
gridFills.push(
|
|
...ticks.map(
|
|
(tick, index) => this.calculateGridFill(tick, index, tick.index + gridFillIndexOffset, p1, p2, ticks)
|
|
)
|
|
);
|
|
return gridFills;
|
|
}
|
|
calculateGridFill({ tickId, translation }, index, gridFillIndex, p1, p2, ticks) {
|
|
const { gridLine, horizontal, range: range4 } = this;
|
|
const nextTick = ticks[index + 1];
|
|
const startOffset = translation;
|
|
const endOffset = nextTick ? nextTick.translation : range4[1];
|
|
const [x1, y1, x2, y2] = horizontal ? [startOffset, Math.max(p1, p2), endOffset, Math.min(p1, p2)] : [Math.min(p1, p2), Math.min(startOffset, endOffset), Math.max(p1, p2), Math.max(startOffset, endOffset)];
|
|
const { fill, fillOpacity } = gridLine.style[gridFillIndex % gridLine.style.length] ?? {};
|
|
return { tickId, x1, y1, x2, y2, fill, fillOpacity };
|
|
}
|
|
calculateTickLines(ticks, direction, scrollbarThickness = 0) {
|
|
return ticks.map((tick) => this.calculateTickLine(tick, tick.index, direction, ticks, scrollbarThickness));
|
|
}
|
|
calculateTickLine({ isPrimary, tickId, translation: offset }, _index, direction, _ticks, scrollbarThickness = 0) {
|
|
const { horizontal, tick, primaryTick } = this;
|
|
const datumTick = isPrimary && primaryTick ? primaryTick : tick;
|
|
const tickSize = this.getTickSize(datumTick);
|
|
const tickSpacing = this.getTickSpacing(datumTick);
|
|
const tickOffset = -direction * (scrollbarThickness + tickSpacing);
|
|
const h = -direction * tickSize;
|
|
const [x1, y1, x2, y2] = horizontal ? [offset, tickOffset, offset, tickOffset + h] : [tickOffset, offset, tickOffset + h, offset];
|
|
const { stroke, width: strokeWidth } = datumTick;
|
|
const lineDash = void 0;
|
|
return { tickId, offset, x1, y1, x2, y2, stroke, strokeWidth, lineDash };
|
|
}
|
|
update() {
|
|
this.updateDirection();
|
|
const previousTicksIds = Array.from(this.tickLabelGroupSelection.nodes(), (node) => node.datum.tickId);
|
|
super.update();
|
|
const { tickLayout } = this;
|
|
this.updateTitle(this.scale.domain, tickLayout?.spacing ?? 0);
|
|
if (!this.animatable) {
|
|
this.moduleCtx.animationManager.skipCurrentBatch();
|
|
}
|
|
if (tickLayout) {
|
|
const { ticks } = tickLayout;
|
|
if (this.animationManager.isSkipped()) {
|
|
this.resetSelectionNodes();
|
|
} else {
|
|
const tickIds = ticks.map((datum) => datum.tickId);
|
|
const diff2 = (0, import_ag_charts_core126.diffArrays)(previousTicksIds, tickIds);
|
|
this.animationState.transition("update", diff2);
|
|
}
|
|
}
|
|
const { enabled, stroke, width } = this.line;
|
|
this.lineNode.setProperties({ stroke, strokeWidth: enabled ? width : 0 });
|
|
this.updateTickLines();
|
|
this.updateGridLines();
|
|
this.updateGridFills();
|
|
}
|
|
getAxisTransform() {
|
|
return {
|
|
translationX: Math.floor(this.translation.x + this.crossAxisTranslation.x),
|
|
translationY: Math.floor(this.translation.y + this.crossAxisTranslation.y)
|
|
};
|
|
}
|
|
getLayoutTranslation() {
|
|
const { translationX, translationY } = this.getAxisTransform();
|
|
return { x: translationX, y: translationY };
|
|
}
|
|
getLayoutState() {
|
|
const layout = super.getLayoutState();
|
|
return { ...layout, position: this.position };
|
|
}
|
|
updatePosition() {
|
|
super.updatePosition();
|
|
const axisTransform = this.getAxisTransform();
|
|
this.tickLineGroup.datum = axisTransform;
|
|
this.tickLabelGroup.datum = axisTransform;
|
|
this.lineNodeGroup.datum = axisTransform;
|
|
this.headingLabelGroup.datum = axisTransform;
|
|
}
|
|
setAxisVisible(visible) {
|
|
this.tickLineGroup.visible = visible && (this.tick.enabled || (this.primaryTick?.enabled ?? false));
|
|
this.tickLabelGroup.visible = visible && (this.label.enabled || (this.primaryTick?.enabled ?? false));
|
|
this.lineNodeGroup.visible = visible;
|
|
this.headingLabelGroup.visible = visible;
|
|
}
|
|
getAxisLineCoordinates() {
|
|
const { horizontal } = this;
|
|
const [c1, c2] = (0, import_ag_charts_core126.findMinMax)(this.lineRange ?? this.range);
|
|
return horizontal ? { x1: c1, x2: c2, y1: 0, y2: 0 } : { x1: 0, x2: 0, y1: c1, y2: c2 };
|
|
}
|
|
getTickLineBBox(datum, scrollbarThickness) {
|
|
const { translation } = datum;
|
|
const { position, primaryTick } = this;
|
|
let tickSize = this.getTickSize();
|
|
if (primaryTick?.enabled) {
|
|
tickSize = Math.max(tickSize, this.getTickSize(primaryTick));
|
|
}
|
|
const direction = position === "bottom" || position === "right" ? -1 : 1;
|
|
const tickSpacing = this.getTickSpacing(this.tick);
|
|
const tickOffset = -direction * (scrollbarThickness + tickSpacing);
|
|
const start = tickOffset;
|
|
const end2 = tickOffset - direction * (tickSize + tickSpacing);
|
|
const min = Math.min(start, end2);
|
|
const max = Math.max(start, end2);
|
|
switch (position) {
|
|
case "top":
|
|
return new BBox(translation, min, 0, max - min);
|
|
case "bottom":
|
|
return new BBox(translation, min, 0, max - min);
|
|
case "left":
|
|
return new BBox(min, translation, max - min, 0);
|
|
case "right":
|
|
return new BBox(min, translation, max - min, 0);
|
|
}
|
|
}
|
|
lineNodeBBox() {
|
|
const { position, seriesAreaPadding } = this;
|
|
const { y1, y2 } = this.getAxisLineCoordinates();
|
|
const dy = y2 - y1;
|
|
switch (position) {
|
|
case "top":
|
|
return new BBox(y1, -seriesAreaPadding, dy, seriesAreaPadding);
|
|
case "bottom":
|
|
return new BBox(y1, 0, dy, seriesAreaPadding);
|
|
case "left":
|
|
return new BBox(-seriesAreaPadding, y1, seriesAreaPadding, dy);
|
|
case "right":
|
|
return new BBox(0, y1, seriesAreaPadding, dy);
|
|
}
|
|
}
|
|
titleBBox(domain, spacing) {
|
|
const { tempCaption } = this;
|
|
tempCaption.node.setProperties(this.titleProps(tempCaption, domain, spacing));
|
|
return tempCaption.node.getBBox();
|
|
}
|
|
getScrollbarThickness(scrollbar) {
|
|
if (!scrollbar?.enabled)
|
|
return 0;
|
|
return scrollbar.placement === "inner" ? scrollbar.spacing + scrollbar.thickness : 0;
|
|
}
|
|
resolveScrollbarLayout(scrollbar, labelThickness) {
|
|
if (!scrollbar)
|
|
return void 0;
|
|
const { position } = this;
|
|
const direction = position === "top" || position === "left" ? -1 : 1;
|
|
if (scrollbar.placement === "inner") {
|
|
const offset2 = direction === 1 ? scrollbar.spacing : -scrollbar.spacing - scrollbar.thickness;
|
|
return { ...scrollbar, offset: offset2 };
|
|
}
|
|
const offset = direction === 1 ? labelThickness + scrollbar.spacing : -labelThickness - scrollbar.spacing - scrollbar.thickness;
|
|
return { ...scrollbar, offset };
|
|
}
|
|
applyScrollbarLayout(boxes, labelThickness, scrollbar) {
|
|
const scrollbarLayout = this.resolveScrollbarLayout(scrollbar, labelThickness);
|
|
let spacing = labelThickness;
|
|
if (scrollbarLayout) {
|
|
const { offset, thickness, placement } = scrollbarLayout;
|
|
if (placement === "outer") {
|
|
spacing += scrollbarLayout.spacing + thickness;
|
|
}
|
|
if (this.horizontal) {
|
|
boxes.push(new BBox(0, offset, 0, thickness));
|
|
} else {
|
|
boxes.push(new BBox(offset, 0, thickness, 0));
|
|
}
|
|
}
|
|
return { spacing, scrollbarLayout };
|
|
}
|
|
measureAxisLayout(domain, ticks, labels, scrollbar, scrollbarThickness) {
|
|
const { tick, primaryTick, label, primaryLabel, title, position, horizontal, seriesAreaPadding } = this;
|
|
const boxes = [];
|
|
boxes.push(this.lineNodeBBox());
|
|
if (tick.enabled || primaryTick?.enabled) {
|
|
for (const datum of ticks) {
|
|
boxes.push(this.getTickLineBBox(datum, scrollbarThickness));
|
|
}
|
|
}
|
|
const { tempText } = this;
|
|
if (label.enabled) {
|
|
for (const datum of labels) {
|
|
if (!datum.visible)
|
|
continue;
|
|
tempText.setProperties(datum);
|
|
const box = tempText.getBBox();
|
|
if (box) {
|
|
boxes.push(box);
|
|
}
|
|
}
|
|
}
|
|
if (primaryLabel?.enabled && position === "bottom") {
|
|
const inexactMeasurementPadding = 2;
|
|
boxes.push(
|
|
new BBox(
|
|
0,
|
|
(0, import_ag_charts_core126.calcLineHeight)(label.fontSize) + inexactMeasurementPadding,
|
|
1,
|
|
this.getTickSize(tick) + this.getTickSpacing(tick) + label.spacing + seriesAreaPadding
|
|
)
|
|
);
|
|
if (primaryLabel.format != null) {
|
|
const { format } = primaryLabel;
|
|
const formats = (0, import_ag_charts_core126.isPlainObject)(format) ? Object.values(format) : [format];
|
|
const maxLines = formats.reduce((m, f) => Math.max(m, (0, import_ag_charts_core126.countLines)(f)), 0);
|
|
boxes.push(
|
|
new BBox(
|
|
0,
|
|
this.getTickSize(primaryTick ?? tick) + this.getTickSpacing(primaryTick ?? tick) + primaryLabel.spacing + seriesAreaPadding,
|
|
1,
|
|
maxLines * (0, import_ag_charts_core126.calcLineHeight)(primaryLabel.fontSize) + inexactMeasurementPadding
|
|
)
|
|
);
|
|
}
|
|
}
|
|
const combined = BBox.merge(boxes);
|
|
const labelThickness = horizontal ? combined.height : combined.width;
|
|
const { spacing, scrollbarLayout } = this.applyScrollbarLayout(boxes, labelThickness, scrollbar);
|
|
this.layout.labelThickness = labelThickness;
|
|
this.layout.scrollbar = scrollbarLayout;
|
|
if (title.enabled) {
|
|
boxes.push(this.titleBBox(domain, spacing));
|
|
}
|
|
const bbox = BBox.merge(boxes);
|
|
return { bbox, spacing };
|
|
}
|
|
titleProps(caption, domain, spacing) {
|
|
const { title } = this;
|
|
if (!title.enabled) {
|
|
caption.enabled = false;
|
|
return {
|
|
visible: false,
|
|
text: "",
|
|
textBaseline: "bottom",
|
|
x: 0,
|
|
y: 0,
|
|
rotationCenterX: 0,
|
|
rotationCenterY: 0,
|
|
rotation: 0
|
|
};
|
|
}
|
|
caption.enabled = true;
|
|
caption.color = title.color;
|
|
caption.fontFamily = title.fontFamily;
|
|
caption.fontSize = title.fontSize;
|
|
caption.fontStyle = title.fontStyle;
|
|
caption.fontWeight = title.fontWeight;
|
|
caption.wrapping = title.wrapping;
|
|
const padding2 = (title.spacing ?? 0) + spacing;
|
|
const { range: range4 } = this;
|
|
const midOffset = (range4[0] + range4[1]) / 2;
|
|
let x;
|
|
let y;
|
|
let rotation;
|
|
let textBaseline;
|
|
switch (this.position) {
|
|
case "top":
|
|
x = midOffset;
|
|
y = -padding2;
|
|
rotation = 0;
|
|
textBaseline = "bottom";
|
|
break;
|
|
case "bottom":
|
|
x = midOffset;
|
|
y = padding2;
|
|
rotation = 0;
|
|
textBaseline = "top";
|
|
break;
|
|
case "left":
|
|
x = -padding2;
|
|
y = midOffset;
|
|
rotation = Math.PI / -2;
|
|
textBaseline = "bottom";
|
|
break;
|
|
case "right":
|
|
x = padding2;
|
|
y = midOffset;
|
|
rotation = Math.PI / 2;
|
|
textBaseline = "bottom";
|
|
break;
|
|
}
|
|
const { formatter = (p) => p.defaultValue } = title;
|
|
const text = this.cachedCallWithContext(formatter, this.getTitleFormatterParams(domain));
|
|
caption.text = text;
|
|
return {
|
|
visible: true,
|
|
text,
|
|
textBaseline,
|
|
x,
|
|
y,
|
|
rotationCenterX: x,
|
|
rotationCenterY: y,
|
|
rotation
|
|
};
|
|
}
|
|
getTickLabelProps(datum, tickGenerationResult, scrollbarThickness) {
|
|
const { horizontal, primaryLabel, primaryTick, seriesAreaPadding, scale: scale2 } = this;
|
|
const { tickId, tickLabel: text = "", translation, isPrimary, textUntruncated } = datum;
|
|
const label = isPrimary && primaryLabel?.enabled ? primaryLabel : this.label;
|
|
const tick = isPrimary && primaryTick?.enabled ? primaryTick : this.tick;
|
|
const { rotation, textBaseline, textAlign } = tickGenerationResult;
|
|
const { range: range4 } = scale2;
|
|
const sideFlag = this.label.getSideFlag();
|
|
const borderOffset = expandLabelPadding(label)[this.position];
|
|
let labelOffset = sideFlag * (this.getTickSize(tick) + this.getTickSpacing(tick) + label.spacing + seriesAreaPadding) - borderOffset;
|
|
if (scrollbarThickness) {
|
|
labelOffset += sideFlag * scrollbarThickness;
|
|
}
|
|
const visible = text !== "";
|
|
const x = horizontal ? translation : labelOffset;
|
|
const y = horizontal ? -labelOffset : translation;
|
|
return {
|
|
...this.getLabelStyles({ value: datum.tick, formattedValue: text }, void 0, label),
|
|
tickId,
|
|
rotation,
|
|
text,
|
|
textAlign,
|
|
textBaseline,
|
|
textUntruncated,
|
|
visible,
|
|
x,
|
|
y,
|
|
rotationCenterX: x,
|
|
rotationCenterY: y,
|
|
range: range4
|
|
};
|
|
}
|
|
updateSelections() {
|
|
if (!this.tickLayout)
|
|
return;
|
|
const lineData = this.getAxisLineCoordinates();
|
|
const { tickLines, gridLines, gridFills, labels } = this.tickLayout;
|
|
const getDatumId = (datum) => datum.tickId;
|
|
this.lineNode.datum = lineData;
|
|
this.gridLineGroupSelection.update(this.gridLine.enabled ? gridLines : [], void 0, getDatumId);
|
|
this.gridFillGroupSelection.update(this.gridLine.enabled ? gridFills : [], void 0, getDatumId);
|
|
this.tickLineGroupSelection.update(tickLines, void 0, getDatumId);
|
|
this.tickLabelGroupSelection.update(labels, void 0, getDatumId);
|
|
}
|
|
updateGridLines() {
|
|
this.gridLineGroupSelection.each((line, datum) => {
|
|
line.stroke = datum.stroke;
|
|
line.strokeWidth = datum.strokeWidth;
|
|
line.lineDash = datum.lineDash;
|
|
});
|
|
}
|
|
updateGridFills() {
|
|
this.gridFillGroupSelection.each((rect2, datum) => {
|
|
rect2.fill = datum.fill;
|
|
rect2.fillOpacity = datum.fillOpacity ?? 1;
|
|
});
|
|
}
|
|
updateTickLines() {
|
|
this.tickLineGroupSelection.each((line, datum) => {
|
|
line.stroke = datum.stroke;
|
|
line.strokeWidth = datum.strokeWidth;
|
|
line.lineDash = datum.lineDash;
|
|
});
|
|
}
|
|
updateTitle(domain, spacing) {
|
|
const { caption } = this.title;
|
|
const titleProps = this.titleProps(caption, domain, spacing);
|
|
caption.node.visible = titleProps.visible;
|
|
caption.node.text = titleProps.text;
|
|
caption.node.textBaseline = titleProps.textBaseline;
|
|
caption.node.datum = titleProps;
|
|
}
|
|
updateLabels() {
|
|
if (!this.label.enabled)
|
|
return;
|
|
this.tickLabelGroupSelection.each((node, datum) => {
|
|
node.fill = datum.color;
|
|
node.text = datum.text;
|
|
node.textBaseline = datum.textBaseline;
|
|
node.textAlign = datum.textAlign ?? "center";
|
|
node.pointerEvents = datum.textUntruncated == null ? 1 /* None */ : 0 /* All */;
|
|
node.setFont(datum);
|
|
node.setBoxing(datum);
|
|
});
|
|
}
|
|
animateReadyUpdate(diff2) {
|
|
const { animationManager } = this.moduleCtx;
|
|
const selectionCtx = prepareAxisAnimationContext(this);
|
|
const fns = prepareAxisAnimationFunctions(selectionCtx);
|
|
fromToMotion(
|
|
this.id,
|
|
"axis-group",
|
|
animationManager,
|
|
[this.lineNodeGroup, this.tickLabelGroup, this.tickLineGroup, this.headingLabelGroup],
|
|
fns.group
|
|
);
|
|
fromToMotion(this.id, "line", animationManager, [this.lineNode], fns.line);
|
|
fromToMotion(
|
|
this.id,
|
|
"line-paths",
|
|
animationManager,
|
|
[this.gridLineGroupSelection, this.tickLineGroupSelection],
|
|
fns.tick,
|
|
(_, d) => d.tickId,
|
|
diff2
|
|
);
|
|
fromToMotion(
|
|
this.id,
|
|
"tick-labels",
|
|
animationManager,
|
|
[this.tickLabelGroupSelection],
|
|
fns.label,
|
|
(_, d) => d.tickId,
|
|
diff2
|
|
);
|
|
fromToMotion(
|
|
this.id,
|
|
"title",
|
|
animationManager,
|
|
[this.title.caption.node],
|
|
fns.label,
|
|
(_, d) => d.tickId,
|
|
diff2
|
|
);
|
|
}
|
|
resetSelectionNodes() {
|
|
resetMotion(
|
|
[this.lineNodeGroup, this.tickLabelGroup, this.tickLineGroup, this.headingLabelGroup],
|
|
resetAxisGroupFn()
|
|
);
|
|
resetMotion([this.gridLineGroupSelection, this.tickLineGroupSelection], resetAxisLineSelectionFn());
|
|
resetMotion([this.gridFillGroupSelection], resetAxisFillSelectionFn());
|
|
resetMotion([this.tickLabelGroupSelection], resetAxisLabelSelectionFn());
|
|
resetMotion([this.title.caption.node], resetAxisLabelSelectionFn());
|
|
resetMotion([this.lineNode], resetAxisLineSelectionFn());
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core126.Property
|
|
], _CartesianAxis.prototype, "thickness", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core126.Property
|
|
], _CartesianAxis.prototype, "maxThicknessRatio", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core126.Property
|
|
], _CartesianAxis.prototype, "position", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core126.Property
|
|
], _CartesianAxis.prototype, "crossAt", 2);
|
|
var CartesianAxis = _CartesianAxis;
|
|
|
|
// packages/ag-charts-community/src/chart/mapping/prepareAxis.ts
|
|
var CartesianAxisPositions = ["right", "top", "left", "bottom"];
|
|
function isAxisPosition(position) {
|
|
return typeof position === "string" && CartesianAxisPositions.includes(position);
|
|
}
|
|
function guessInvalidPositions(axes) {
|
|
const invalidAxes = [];
|
|
const usedPositions = [];
|
|
const guesses = [...CartesianAxisPositions];
|
|
for (const axis of axes) {
|
|
if (axis instanceof CartesianAxis) {
|
|
if (isAxisPosition(axis.position)) {
|
|
usedPositions.push(axis.position);
|
|
} else {
|
|
invalidAxes.push(axis);
|
|
}
|
|
}
|
|
}
|
|
for (const axis of invalidAxes) {
|
|
let nextGuess;
|
|
do {
|
|
nextGuess = guesses.pop();
|
|
} while (nextGuess && usedPositions.includes(nextGuess));
|
|
if (nextGuess == null)
|
|
break;
|
|
axis.position = nextGuess;
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/mapping/prepareSeries.ts
|
|
var import_ag_charts_core127 = require("ag-charts-core");
|
|
var DEFAULT_MATCHING_KEYS = ["direction", "xKey", "yKey", "sizeKey", "angleKey", "radiusKey", "normalizedTo"];
|
|
function matchSeriesOptions(series, optSeries, oldOptsSeries) {
|
|
const matchingKeysCache = /* @__PURE__ */ new Map();
|
|
const getMatchingKeys = (type) => {
|
|
if (type === void 0) {
|
|
return DEFAULT_MATCHING_KEYS;
|
|
}
|
|
if (matchingKeysCache.has(type))
|
|
return matchingKeysCache.get(type);
|
|
const matchingKeys = import_ag_charts_core127.ModuleRegistry.getSeriesModule(type)?.matchingKeys ?? DEFAULT_MATCHING_KEYS;
|
|
matchingKeysCache.set(type, matchingKeys);
|
|
return matchingKeys;
|
|
};
|
|
const generateKey = (type, i, opts) => {
|
|
const matchingKeys = getMatchingKeys(type);
|
|
const result = [type];
|
|
for (const key of matchingKeys) {
|
|
if (key in i && i[key] != null)
|
|
result.push(`${key}=${i[key]}`);
|
|
}
|
|
if (opts?.seriesGrouping) {
|
|
result.push(`seriesGrouping.groupId=${opts?.seriesGrouping.groupId}`);
|
|
}
|
|
return result.join(";");
|
|
};
|
|
const seriesMap = /* @__PURE__ */ new Map();
|
|
let idx = 0;
|
|
for (const s of series) {
|
|
const key = generateKey(s.type, s.properties, oldOptsSeries?.[idx]);
|
|
if (!seriesMap.has(key)) {
|
|
seriesMap.set(key, []);
|
|
}
|
|
seriesMap.get(key)?.push([s, idx++]);
|
|
}
|
|
const optsMap = /* @__PURE__ */ new Map();
|
|
idx = 0;
|
|
for (const o of optSeries) {
|
|
const key = generateKey(o.type, o, o);
|
|
if (!optsMap.has(key)) {
|
|
optsMap.set(key, []);
|
|
}
|
|
optsMap.get(key)?.push([o, idx++]);
|
|
}
|
|
const overlap = [...seriesMap.keys()].some((k) => optsMap.has(k));
|
|
if (!overlap) {
|
|
return { status: "no-overlap", oldKeys: seriesMap.keys(), newKeys: optsMap.keys() };
|
|
}
|
|
const changes = [];
|
|
for (const [key, optsTuples] of optsMap.entries()) {
|
|
for (const [opts, targetIdx] of optsTuples) {
|
|
const seriesArray = seriesMap.get(key);
|
|
if (seriesArray == null || seriesArray.length < 1) {
|
|
changes.push({ opts, targetIdx, idx: targetIdx, status: "add" });
|
|
seriesMap.delete(key);
|
|
continue;
|
|
}
|
|
const [outputSeries, currentIdx] = seriesArray.shift();
|
|
const previousOpts = oldOptsSeries?.[currentIdx] ?? {};
|
|
const diff2 = (0, import_ag_charts_core127.jsonDiff)(previousOpts, opts ?? {});
|
|
const { groupIndex, stackIndex } = diff2?.seriesGrouping ?? {};
|
|
if (groupIndex != null || stackIndex != null) {
|
|
changes.push({
|
|
opts,
|
|
series: outputSeries,
|
|
diff: diff2,
|
|
targetIdx,
|
|
idx: currentIdx,
|
|
status: "series-grouping"
|
|
});
|
|
} else if (diff2) {
|
|
changes.push({
|
|
opts,
|
|
series: outputSeries,
|
|
diff: diff2,
|
|
targetIdx,
|
|
idx: currentIdx,
|
|
status: "update"
|
|
});
|
|
} else {
|
|
changes.push({ opts, series: outputSeries, targetIdx, idx: currentIdx, status: "no-op" });
|
|
}
|
|
if (seriesArray.length === 0) {
|
|
seriesMap.delete(key);
|
|
}
|
|
}
|
|
}
|
|
for (const seriesArray of seriesMap.values()) {
|
|
for (const [outputSeries, currentIdx] of seriesArray) {
|
|
changes.push({ series: outputSeries, idx: currentIdx, targetIdx: -1, status: "remove" });
|
|
}
|
|
}
|
|
return { status: "overlap", changes };
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/mapping/types.ts
|
|
var import_ag_charts_core129 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/factory/expectedModules.ts
|
|
var import_ag_charts_core128 = require("ag-charts-core");
|
|
var ExpectedModules = new Map(
|
|
[
|
|
// Chart types
|
|
{
|
|
type: "chart",
|
|
name: "cartesian",
|
|
moduleId: "CartesianChartModule"
|
|
},
|
|
{
|
|
type: "chart",
|
|
name: "standalone",
|
|
moduleId: "StandaloneChartModule",
|
|
enterprise: true
|
|
},
|
|
{
|
|
type: "chart",
|
|
name: "polar",
|
|
moduleId: "PolarChartModule"
|
|
},
|
|
{
|
|
type: "chart",
|
|
name: "topology",
|
|
moduleId: "TopologyChartModule",
|
|
enterprise: true
|
|
},
|
|
// Axis types
|
|
{
|
|
type: "axis",
|
|
name: "number",
|
|
chartType: "cartesian",
|
|
moduleId: "NumberAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "log",
|
|
chartType: "cartesian",
|
|
moduleId: "LogAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "time",
|
|
chartType: "cartesian",
|
|
moduleId: "TimeAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "unit-time",
|
|
chartType: "cartesian",
|
|
moduleId: "UnitTimeAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "category",
|
|
chartType: "cartesian",
|
|
moduleId: "CategoryAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "grouped-category",
|
|
chartType: "cartesian",
|
|
moduleId: "GroupedCategoryAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "ordinal-time",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "OrdinalTimeAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "angle-category",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
moduleId: "AngleCategoryAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "angle-number",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
moduleId: "AngleNumberAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "radius-category",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
moduleId: "RadiusCategoryAxisModule"
|
|
},
|
|
{
|
|
type: "axis",
|
|
name: "radius-number",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
moduleId: "RadiusNumberAxisModule"
|
|
},
|
|
// Series types
|
|
{
|
|
type: "series",
|
|
name: "bar",
|
|
chartType: "cartesian",
|
|
moduleId: "BarSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "scatter",
|
|
chartType: "cartesian",
|
|
moduleId: "ScatterSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "bubble",
|
|
chartType: "cartesian",
|
|
moduleId: "BubbleSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "line",
|
|
chartType: "cartesian",
|
|
moduleId: "LineSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "area",
|
|
chartType: "cartesian",
|
|
moduleId: "AreaSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "pie",
|
|
chartType: "polar",
|
|
moduleId: "PieSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "donut",
|
|
chartType: "polar",
|
|
moduleId: "DonutSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "box-plot",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "BoxPlotSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "candlestick",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "CandlestickSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "cone-funnel",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "ConeFunnelSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "funnel",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "FunnelSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "ohlc",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "OhlcSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "heatmap",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "HeatmapSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "histogram",
|
|
chartType: "cartesian",
|
|
// enterprise: true,
|
|
moduleId: "HistogramSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "range-area",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "RangeAreaSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "range-bar",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "RangeBarSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "waterfall",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "WaterfallSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "nightingale",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
moduleId: "NightingaleSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "radar-area",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
moduleId: "RadarAreaSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "radar-line",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
moduleId: "RadarLineSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "radial-bar",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
moduleId: "RadialBarSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "radial-column",
|
|
chartType: "polar",
|
|
enterprise: true,
|
|
moduleId: "RadialColumnSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "map-shape",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
moduleId: "MapShapeSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "map-line",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
moduleId: "MapLineSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "map-marker",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
moduleId: "MapMarkerSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "map-shape-background",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
moduleId: "MapShapeBackgroundSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "map-line-background",
|
|
chartType: "topology",
|
|
enterprise: true,
|
|
moduleId: "MapLineBackgroundSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "pyramid",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
moduleId: "PyramidSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "linear-gauge",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
moduleId: "LinearGaugeModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "radial-gauge",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
moduleId: "RadialGaugeModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "sunburst",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
moduleId: "SunburstSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "treemap",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
moduleId: "TreemapSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "chord",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
moduleId: "ChordSeriesModule"
|
|
},
|
|
{
|
|
type: "series",
|
|
name: "sankey",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
moduleId: "SankeySeriesModule"
|
|
},
|
|
// Plugins
|
|
{
|
|
type: "plugin",
|
|
name: "animation",
|
|
enterprise: true,
|
|
moduleId: "AnimationModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "annotations",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "AnnotationsModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "legend",
|
|
moduleId: "LegendModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "locale",
|
|
moduleId: "LocaleModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "chartToolbar",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "ChartToolbarModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "contextMenu",
|
|
enterprise: true,
|
|
moduleId: "ContextMenuModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "statusBar",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "StatusBarModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "dataSource",
|
|
enterprise: true,
|
|
moduleId: "DataSourceModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "sync",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "SyncModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "ranges",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "RangesModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "zoom",
|
|
enterprise: true,
|
|
moduleId: "ZoomModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "flashOnUpdate",
|
|
enterprise: true,
|
|
moduleId: "FlashOnUpdateModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "gradientLegend",
|
|
enterprise: true,
|
|
moduleId: "GradientLegendModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "navigator",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "NavigatorModule"
|
|
},
|
|
{
|
|
type: "plugin",
|
|
name: "scrollbar",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "ScrollbarModule"
|
|
},
|
|
{
|
|
type: "axis:plugin",
|
|
name: "crosshair",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "CrosshairModule"
|
|
},
|
|
{
|
|
type: "axis:plugin",
|
|
name: "bandHighlight",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "BandHighlightModule"
|
|
},
|
|
{
|
|
type: "series:plugin",
|
|
name: "errorBar",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "ErrorBarsModule"
|
|
},
|
|
{
|
|
type: "preset",
|
|
name: "gauge-preset",
|
|
chartType: "standalone",
|
|
enterprise: true,
|
|
moduleId: "GaugePresetModule"
|
|
},
|
|
{
|
|
type: "preset",
|
|
name: "price-volume",
|
|
chartType: "cartesian",
|
|
enterprise: true,
|
|
moduleId: "PriceVolumePresetModule"
|
|
},
|
|
{
|
|
type: "preset",
|
|
name: "sparkline",
|
|
moduleId: "SparklinePresetModule"
|
|
}
|
|
].map((m) => [m.name, m])
|
|
);
|
|
function getSeriesExpectedChartType(seriesName) {
|
|
const expectedModule = ExpectedModules.get(seriesName);
|
|
return expectedModule?.type === import_ag_charts_core128.ModuleType.Series ? expectedModule.chartType : void 0;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/mapping/types.ts
|
|
function detectChartType(input) {
|
|
const mainSeriesType = input.series?.[0]?.type ?? "line";
|
|
return import_ag_charts_core129.ModuleRegistry.getSeriesModule(mainSeriesType)?.chartType ?? getSeriesExpectedChartType(mainSeriesType) ?? "unknown";
|
|
}
|
|
function isAgCartesianChartOptions(input) {
|
|
return detectChartType(input) === "cartesian";
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/modulesManager.ts
|
|
var import_ag_charts_core130 = require("ag-charts-core");
|
|
var ModulesManager = class extends ModuleMap {
|
|
*legends() {
|
|
for (const module2 of import_ag_charts_core130.ModuleRegistry.listModulesByType(import_ag_charts_core130.ModuleType.Plugin)) {
|
|
if (module2.name === "legend" || module2.name === "gradientLegend") {
|
|
yield {
|
|
legendType: module2.name === "legend" ? "category" : "gradient",
|
|
legend: this.getModule(module2.name)
|
|
};
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/overlay/chartOverlays.ts
|
|
var import_ag_charts_core132 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/overlay/overlay.ts
|
|
var import_ag_charts_core131 = require("ag-charts-core");
|
|
var DEFAULT_OVERLAY_CLASS = "ag-charts-overlay";
|
|
var DEFAULT_OVERLAY_DARK_CLASS = "ag-charts-dark-overlay";
|
|
var Overlay = class extends import_ag_charts_core131.BaseProperties {
|
|
constructor(className, defaultMessageId) {
|
|
super();
|
|
this.className = className;
|
|
this.defaultMessageId = defaultMessageId;
|
|
this.enabled = true;
|
|
}
|
|
getText(localeManager) {
|
|
if ((0, import_ag_charts_core131.isArray)(this.text)) {
|
|
return (0, import_ag_charts_core131.toPlainText)(this.text);
|
|
}
|
|
if (this.rendererAsText) {
|
|
return this.rendererAsText;
|
|
}
|
|
return localeManager.t((0, import_ag_charts_core131.toTextString)(this.text) || this.defaultMessageId);
|
|
}
|
|
getElement(callers, animationManager, localeManager, rect2) {
|
|
this.content?.remove();
|
|
this.rendererAsText = void 0;
|
|
this.focusBox = rect2;
|
|
if (this.renderer) {
|
|
const params = {};
|
|
const htmlContent = (0, import_ag_charts_core131.callWithContext)(callers, this.renderer, params);
|
|
if ((0, import_ag_charts_core131.isHTMLElement)(htmlContent)) {
|
|
this.content = htmlContent;
|
|
} else {
|
|
const tempDiv = (0, import_ag_charts_core131.createElement)("div");
|
|
tempDiv.innerHTML = htmlContent;
|
|
const { firstElementChild } = tempDiv;
|
|
if ((0, import_ag_charts_core131.isHTMLElement)(firstElementChild) && tempDiv.childElementCount === 1) {
|
|
this.content = firstElementChild;
|
|
} else {
|
|
this.content = tempDiv;
|
|
}
|
|
}
|
|
this.rendererAsText = this.content?.textContent?.trim() ?? void 0;
|
|
} else {
|
|
const content = (0, import_ag_charts_core131.createElement)("div", {
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
boxSizing: "border-box",
|
|
height: "100%",
|
|
margin: "8px",
|
|
fontFamily: "var(--ag-charts-font-family)",
|
|
fontSize: "var(--ag-charts-font-size)",
|
|
fontWeight: "var(--ag-charts-font-weight)"
|
|
});
|
|
if ((0, import_ag_charts_core131.isArray)(this.text)) {
|
|
const container = (0, import_ag_charts_core131.createElement)("div");
|
|
for (const segment of this.text) {
|
|
const el = (0, import_ag_charts_core131.createElement)("span", {
|
|
color: segment.color,
|
|
fontSize: `${segment.fontSize}px`,
|
|
fontFamily: segment.fontFamily ?? "inherit",
|
|
fontWeight: String(segment.fontWeight),
|
|
fontStyle: segment.fontStyle
|
|
});
|
|
el.innerText = (0, import_ag_charts_core131.toTextString)(segment.text);
|
|
container.appendChild(el);
|
|
}
|
|
content.appendChild(container);
|
|
} else {
|
|
content.innerText = this.getText(localeManager);
|
|
}
|
|
this.content = content;
|
|
this.content.classList.add(this.className);
|
|
animationManager?.animate({
|
|
from: 0,
|
|
to: 1,
|
|
id: "overlay",
|
|
phase: "add",
|
|
groupId: "opacity",
|
|
onUpdate(value) {
|
|
content.style.opacity = String(value);
|
|
},
|
|
onStop() {
|
|
content.style.opacity = "1";
|
|
}
|
|
});
|
|
}
|
|
return this.content;
|
|
}
|
|
removeElement(cleanup = () => this.content?.remove(), animationManager) {
|
|
if (!this.content)
|
|
return;
|
|
if (animationManager) {
|
|
const { content } = this;
|
|
animationManager.animate({
|
|
from: 1,
|
|
to: 0,
|
|
phase: "remove",
|
|
id: "overlay",
|
|
groupId: "opacity",
|
|
onUpdate(value) {
|
|
content.style.opacity = String(value);
|
|
},
|
|
onStop() {
|
|
cleanup?.();
|
|
}
|
|
});
|
|
} else {
|
|
cleanup?.();
|
|
}
|
|
this.content = void 0;
|
|
this.focusBox = void 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core131.Property
|
|
], Overlay.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core131.Property
|
|
], Overlay.prototype, "text", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core131.Property
|
|
], Overlay.prototype, "renderer", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/overlay/chartOverlays.ts
|
|
var ChartOverlays = class extends import_ag_charts_core132.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.darkTheme = false;
|
|
this.loading = new Overlay("ag-charts-loading-overlay", "overlayLoadingData");
|
|
this.noData = new Overlay("ag-charts-no-data-overlay", "overlayNoData");
|
|
this.noVisibleSeries = new Overlay("ag-charts-no-visible-series", "overlayNoVisibleSeries");
|
|
this.unsupportedBrowser = new Overlay("ag-charts-unsupported-browser", "overlayUnsupportedBrowser");
|
|
}
|
|
getFocusInfo(localeManager) {
|
|
for (const overlay of [this.loading, this.noData, this.noVisibleSeries, this.unsupportedBrowser]) {
|
|
if (overlay.focusBox !== void 0) {
|
|
return { text: overlay.getText(localeManager), rect: overlay.focusBox };
|
|
}
|
|
}
|
|
return void 0;
|
|
}
|
|
destroy() {
|
|
this.loading.removeElement();
|
|
this.noData.removeElement();
|
|
this.noVisibleSeries.removeElement();
|
|
this.unsupportedBrowser.removeElement();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core132.Property
|
|
], ChartOverlays.prototype, "darkTheme", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core132.Property
|
|
], ChartOverlays.prototype, "loading", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core132.Property
|
|
], ChartOverlays.prototype, "noData", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core132.Property
|
|
], ChartOverlays.prototype, "noVisibleSeries", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core132.Property
|
|
], ChartOverlays.prototype, "unsupportedBrowser", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/overlay/loadingSpinner.ts
|
|
var import_ag_charts_core133 = require("ag-charts-core");
|
|
function getLoadingSpinner(text, defaultDuration) {
|
|
const { animationDuration } = PHASE_METADATA["add"];
|
|
const duration = animationDuration * defaultDuration;
|
|
const container = (0, import_ag_charts_core133.createElement)("div", `${DEFAULT_OVERLAY_CLASS}--loading`, {
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
flexDirection: "column",
|
|
height: "100%",
|
|
boxSizing: "border-box",
|
|
font: "13px Verdana, sans-serif",
|
|
// FONT_SIZE.MEDIUM
|
|
userSelect: "none",
|
|
animation: `ag-charts-loading ${duration}ms linear 50ms both`
|
|
});
|
|
const matrix = (0, import_ag_charts_core133.createElement)("span", {
|
|
width: "45px",
|
|
height: "40px",
|
|
backgroundImage: [
|
|
"linear-gradient(#0000 calc(1 * 100% / 6), #ccc 0 calc(3 * 100% / 6), #0000 0), ",
|
|
"linear-gradient(#0000 calc(2 * 100% / 6), #ccc 0 calc(4 * 100% / 6), #0000 0), ",
|
|
"linear-gradient(#0000 calc(3 * 100% / 6), #ccc 0 calc(5 * 100% / 6), #0000 0)"
|
|
].join(""),
|
|
backgroundSize: "10px 400%",
|
|
backgroundRepeat: "no-repeat",
|
|
animation: "ag-charts-loading-matrix 1s infinite linear"
|
|
});
|
|
const label = (0, import_ag_charts_core133.createElement)("p", { marginTop: "1em" });
|
|
label.innerText = text;
|
|
const background = (0, import_ag_charts_core133.createElement)("div", `${DEFAULT_OVERLAY_CLASS}__loading-background`, {
|
|
position: "absolute",
|
|
inset: "0",
|
|
opacity: "0.5",
|
|
zIndex: "-1"
|
|
});
|
|
const animationStyles = (0, import_ag_charts_core133.createElement)("style");
|
|
animationStyles.innerText = [
|
|
"@keyframes ag-charts-loading { from { opacity: 0 } to { opacity: 1 } }",
|
|
"@keyframes ag-charts-loading-matrix {",
|
|
"0% { background-position: 0% 0%, 50% 0%, 100% 0%; }",
|
|
"100% { background-position: 0% 100%, 50% 100%, 100% 100%; }",
|
|
"}"
|
|
].join(" ");
|
|
container.replaceChildren(animationStyles, matrix, label, background);
|
|
return container;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series-area/seriesArea.ts
|
|
var import_ag_charts_core134 = require("ag-charts-core");
|
|
var SeriesArea = class extends import_ag_charts_core134.BaseProperties {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.rectNode = new Rect();
|
|
this.border = new import_ag_charts_core134.Border(this.rectNode);
|
|
this.cornerRadius = 0;
|
|
this.padding = 0;
|
|
this.cleanup = new import_ag_charts_core134.CleanupRegistry();
|
|
this.node = this.createNode();
|
|
this.node.append([this.rectNode]);
|
|
this.rectNode.fill = void 0;
|
|
this.cleanup.register(
|
|
ctx.scene.attachNode(this.node),
|
|
ctx.eventsHub.on("layout:complete", (e) => this.onLayoutComplete(e))
|
|
);
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
getPadding() {
|
|
const { border, padding: padding2 } = this;
|
|
const strokeWidth = border.enabled ? border.strokeWidth : 0;
|
|
if (typeof padding2 === "number") {
|
|
const total = padding2 + strokeWidth;
|
|
return { top: total, right: total, bottom: total, left: total };
|
|
}
|
|
return {
|
|
top: (padding2.top ?? 0) + strokeWidth,
|
|
right: (padding2.right ?? 0) + strokeWidth,
|
|
bottom: (padding2.bottom ?? 0) + strokeWidth,
|
|
left: (padding2.left ?? 0) + strokeWidth
|
|
};
|
|
}
|
|
createNode() {
|
|
return new Group({ name: "series-area-container", zIndex: import_ag_charts_core134.ZIndexMap.SERIES_AREA_CONTAINER });
|
|
}
|
|
onLayoutComplete(event) {
|
|
const { x, y, width, height } = event.series.paddedRect;
|
|
this.rectNode.x = x;
|
|
this.rectNode.y = y;
|
|
this.rectNode.width = width;
|
|
this.rectNode.height = height;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core134.Property
|
|
], SeriesArea.prototype, "border", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core134.Property
|
|
], SeriesArea.prototype, "clip", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core134.ProxyPropertyOnWrite)("rectNode", "cornerRadius"),
|
|
import_ag_charts_core134.Property
|
|
], SeriesArea.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core134.Property
|
|
], SeriesArea.prototype, "padding", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/series.ts
|
|
var import_ag_charts_core136 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/shapeUtil.ts
|
|
var import_ag_charts_core135 = require("ag-charts-core");
|
|
function getShapeFill(fill, defaultGradient, defaultPattern, defaultImage) {
|
|
if ((0, import_ag_charts_core135.isGradientFill)(fill)) {
|
|
return {
|
|
type: "gradient",
|
|
gradient: fill.gradient ?? defaultGradient.gradient,
|
|
colorStops: fill.colorStops ?? defaultGradient.colorStops,
|
|
bounds: fill.bounds ?? defaultGradient.bounds,
|
|
rotation: fill.rotation ?? defaultGradient.rotation,
|
|
reverse: fill.reverse ?? defaultGradient.reverse,
|
|
colorSpace: fill.colorSpace ?? defaultGradient.colorSpace
|
|
};
|
|
}
|
|
if ((0, import_ag_charts_core135.isPatternFill)(fill)) {
|
|
const pattern = fill.pattern ?? defaultPattern.pattern;
|
|
let strokeWidth = fill.strokeWidth;
|
|
if (pattern === "backward-slanted-lines" || pattern === "forward-slanted-lines" || pattern === "horizontal-lines" || pattern === "vertical-lines") {
|
|
strokeWidth ?? (strokeWidth = defaultPattern.strokeWidth);
|
|
} else {
|
|
strokeWidth ?? (strokeWidth = 0);
|
|
}
|
|
const width = fill.width ?? fill.height ?? defaultPattern.width;
|
|
const height = fill.height ?? fill.width ?? defaultPattern.height;
|
|
return {
|
|
type: "pattern",
|
|
pattern,
|
|
width,
|
|
height,
|
|
path: fill.path,
|
|
padding: fill.padding ?? defaultPattern.padding,
|
|
fill: fill.fill ?? defaultPattern.fill,
|
|
fillOpacity: fill.fillOpacity ?? defaultPattern.fillOpacity,
|
|
backgroundFill: fill.backgroundFill ?? defaultPattern.backgroundFill,
|
|
backgroundFillOpacity: fill.backgroundFillOpacity ?? defaultPattern.backgroundFillOpacity,
|
|
stroke: fill.stroke ?? defaultPattern.stroke,
|
|
strokeOpacity: fill.strokeOpacity ?? defaultPattern.strokeOpacity,
|
|
strokeWidth,
|
|
rotation: fill.rotation ?? defaultPattern.rotation,
|
|
scale: fill.scale ?? defaultPattern.scale
|
|
};
|
|
}
|
|
if ((0, import_ag_charts_core135.isImageFill)(fill)) {
|
|
return {
|
|
type: "image",
|
|
url: fill.url,
|
|
width: fill.width,
|
|
height: fill.height,
|
|
backgroundFill: fill.backgroundFill ?? defaultImage.backgroundFill,
|
|
backgroundFillOpacity: fill.backgroundFillOpacity ?? defaultImage.backgroundFillOpacity,
|
|
rotation: fill.rotation ?? defaultImage.rotation,
|
|
repeat: fill.repeat ?? defaultImage.repeat,
|
|
fit: fill.fit ?? defaultImage.fit
|
|
};
|
|
}
|
|
return fill;
|
|
}
|
|
function getShapeStyle(style, defaultGradient, defaultPattern, defaultImage) {
|
|
if (!(0, import_ag_charts_core135.isGradientFill)(style?.fill) && !(0, import_ag_charts_core135.isPatternFill)(style?.fill) && !(0, import_ag_charts_core135.isImageFill)(style?.fill))
|
|
return style;
|
|
return {
|
|
...style,
|
|
fill: getShapeFill(style.fill, defaultGradient, defaultPattern, defaultImage)
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/series.ts
|
|
var SeriesNodePickMode = /* @__PURE__ */ ((SeriesNodePickMode2) => {
|
|
SeriesNodePickMode2[SeriesNodePickMode2["EXACT_SHAPE_MATCH"] = 0] = "EXACT_SHAPE_MATCH";
|
|
SeriesNodePickMode2[SeriesNodePickMode2["NEAREST_NODE"] = 1] = "NEAREST_NODE";
|
|
SeriesNodePickMode2[SeriesNodePickMode2["AXIS_ALIGNED"] = 2] = "AXIS_ALIGNED";
|
|
return SeriesNodePickMode2;
|
|
})(SeriesNodePickMode || {});
|
|
var CROSS_FILTER_MARKER_FILL_OPACITY_FACTOR = 0.25;
|
|
var CROSS_FILTER_MARKER_STROKE_OPACITY_FACTOR = 0.125;
|
|
var SeriesNodeEvent = class {
|
|
constructor(type, event, nodeDatum, series) {
|
|
this.type = type;
|
|
this.event = event;
|
|
this.defaultPrevented = false;
|
|
this.datum = nodeDatum.datum;
|
|
this.seriesId = series.id;
|
|
}
|
|
preventDefault() {
|
|
this.defaultPrevented = true;
|
|
}
|
|
};
|
|
var SeriesGroupingChangedEvent = class {
|
|
constructor(series, seriesGrouping) {
|
|
this.series = series;
|
|
this.seriesGrouping = seriesGrouping;
|
|
this.type = "groupingChanged";
|
|
}
|
|
};
|
|
function propertyAxisDirection(property) {
|
|
switch (property) {
|
|
case "x":
|
|
return import_ag_charts_core136.ChartAxisDirection.X;
|
|
case "y":
|
|
return import_ag_charts_core136.ChartAxisDirection.Y;
|
|
case "angle":
|
|
return import_ag_charts_core136.ChartAxisDirection.Angle;
|
|
case "radius":
|
|
return import_ag_charts_core136.ChartAxisDirection.Radius;
|
|
}
|
|
}
|
|
function axisDirectionProperty(direction) {
|
|
switch (direction) {
|
|
case import_ag_charts_core136.ChartAxisDirection.X:
|
|
return "x";
|
|
case import_ag_charts_core136.ChartAxisDirection.Y:
|
|
return "y";
|
|
case import_ag_charts_core136.ChartAxisDirection.Angle:
|
|
return "angle";
|
|
case import_ag_charts_core136.ChartAxisDirection.Radius:
|
|
return "radius";
|
|
default:
|
|
return "x";
|
|
}
|
|
}
|
|
var Series = class extends Observable {
|
|
constructor(seriesOpts) {
|
|
super();
|
|
this.cleanup = new import_ag_charts_core136.CleanupRegistry();
|
|
this.usesPlacedLabels = false;
|
|
this.alwaysClip = false;
|
|
this.hasChangesOnHighlight = false;
|
|
this.seriesGrouping = void 0;
|
|
this.NodeEvent = SeriesNodeEvent;
|
|
this.internalId = (0, import_ag_charts_core136.createId)(this);
|
|
// The group node that contains the series rendering in its default (non-highlighted) state.
|
|
this.contentGroup = new TranslatableGroup({
|
|
name: `${this.internalId}-content`,
|
|
zIndex: import_ag_charts_core136.SeriesZIndexMap.ANY_CONTENT
|
|
});
|
|
// The group node that contains all highlighted series items. This is a performance optimisation
|
|
// for large-scale data-sets, where the only thing that routinely varies is the currently
|
|
// highlighted node.
|
|
this.highlightGroup = new TranslatableGroup({
|
|
name: `${this.internalId}-highlight`,
|
|
zIndex: import_ag_charts_core136.SeriesZIndexMap.ANY_CONTENT
|
|
});
|
|
this.highlightNodeGroup = this.highlightGroup.appendChild(
|
|
new Group({ name: `${this.internalId}-highlight-node` })
|
|
);
|
|
this.highlightLabelGroup = this.highlightGroup.appendChild(
|
|
new Group({
|
|
name: `${this.internalId}-highlight-label`,
|
|
zIndex: import_ag_charts_core136.SeriesContentZIndexMap.LABEL
|
|
})
|
|
);
|
|
// Error bars etc.
|
|
this.annotationGroup = new TranslatableGroup({
|
|
name: `${this.internalId}-annotation`
|
|
});
|
|
// Lazily initialised labelGroup for label presentation.
|
|
this.labelGroup = new TranslatableGroup({
|
|
name: `${this.internalId}-series-labels`
|
|
});
|
|
this.axes = {};
|
|
this.directions = [import_ag_charts_core136.ChartAxisDirection.X, import_ag_charts_core136.ChartAxisDirection.Y];
|
|
// Flag to determine if we should recalculate node data.
|
|
this.nodeDataRefresh = true;
|
|
this.processedDataUpdated = true;
|
|
this.moduleMap = new ModuleMap();
|
|
this.datumCallbackCache = /* @__PURE__ */ new Map();
|
|
this.connectsToYAxis = false;
|
|
this.declarationOrder = -1;
|
|
this._broughtToFront = false;
|
|
this.events = new import_ag_charts_core136.EventEmitter();
|
|
this._pickNodeCache = new import_ag_charts_core136.LRUCache(5);
|
|
// Use a wrapper to comply with the @typescript-eslint/unbound-method rule.
|
|
this.fireEventWrapper = (event) => super.fireEvent(event);
|
|
const {
|
|
moduleCtx,
|
|
pickModes,
|
|
propertyKeys = {},
|
|
propertyNames = {},
|
|
canHaveAxes = false,
|
|
usesPlacedLabels = false,
|
|
alwaysClip = false
|
|
} = seriesOpts;
|
|
this.ctx = moduleCtx;
|
|
this.propertyKeys = propertyKeys;
|
|
this.propertyNames = propertyNames;
|
|
this.canHaveAxes = canHaveAxes;
|
|
this.usesPlacedLabels = usesPlacedLabels;
|
|
this.pickModes = pickModes;
|
|
this.alwaysClip = alwaysClip;
|
|
this.highlightLabelGroup.pointerEvents = 1 /* None */;
|
|
this.cleanup.register(
|
|
this.ctx.eventsHub.on("data:update", (data) => this.setChartData(data)),
|
|
this.ctx.eventsHub.on("highlight:change", (event) => this.onChangeHighlight(event))
|
|
);
|
|
}
|
|
get pickModeAxis() {
|
|
return "main";
|
|
}
|
|
get id() {
|
|
return this.properties?.id ?? this.internalId;
|
|
}
|
|
get type() {
|
|
return this.constructor.type ?? "";
|
|
}
|
|
get focusable() {
|
|
return true;
|
|
}
|
|
get data() {
|
|
return this._data ?? this._chartData;
|
|
}
|
|
set visible(newVisibility) {
|
|
this.properties.visible = newVisibility;
|
|
this.ctx.legendManager.toggleItem(newVisibility, this.id);
|
|
this.ctx.legendManager.update();
|
|
this.visibleMaybeChanged();
|
|
}
|
|
get visible() {
|
|
return this.ctx.legendManager.getSeriesEnabled(this.id) ?? this.properties.visible;
|
|
}
|
|
get hasData() {
|
|
const dataSet = this.data;
|
|
if (dataSet == null)
|
|
return false;
|
|
return dataSet.netSize() > 0;
|
|
}
|
|
get tooltipEnabled() {
|
|
return this.properties.tooltip?.enabled;
|
|
}
|
|
onDataChange() {
|
|
this.nodeDataRefresh = true;
|
|
this.processedDataUpdated = true;
|
|
this._pickNodeCache.clear();
|
|
}
|
|
setOptionsData(input) {
|
|
this._data = input;
|
|
this.onDataChange();
|
|
}
|
|
isHighlightEnabled() {
|
|
return this.properties.highlight.enabled;
|
|
}
|
|
setChartData(input) {
|
|
this._chartData = input;
|
|
if (this.data === input) {
|
|
this.onDataChange();
|
|
}
|
|
}
|
|
onSeriesGroupingChange(prev, next) {
|
|
const { internalId, type, visible } = this;
|
|
if (prev) {
|
|
this.ctx.seriesStateManager.deregisterSeries(this);
|
|
}
|
|
if (next) {
|
|
this.ctx.seriesStateManager.registerSeries({
|
|
internalId,
|
|
type,
|
|
visible,
|
|
seriesGrouping: next,
|
|
// TODO: is there a better way to pass width through here?
|
|
width: "width" in this.properties ? this.properties.width : 0
|
|
});
|
|
}
|
|
this.fireEvent(new SeriesGroupingChangedEvent(this, next));
|
|
}
|
|
getBandScalePadding() {
|
|
return { inner: 1, outer: 0 };
|
|
}
|
|
attachSeries(seriesContentNode, seriesNode, annotationNode) {
|
|
seriesContentNode.appendChild(this.contentGroup);
|
|
seriesNode.appendChild(this.highlightGroup);
|
|
seriesNode.appendChild(this.labelGroup);
|
|
annotationNode?.appendChild(this.annotationGroup);
|
|
}
|
|
detachSeries(_seriesContentNode, _seriesNode, _annotationNode) {
|
|
this.contentGroup.remove();
|
|
this.highlightGroup.remove();
|
|
this.labelGroup.remove();
|
|
this.annotationGroup.remove();
|
|
}
|
|
setSeriesIndex(index, forceUpdate = false) {
|
|
const bringToFront = this.bringToFront();
|
|
if (!forceUpdate && index === this.declarationOrder && bringToFront === this._broughtToFront)
|
|
return false;
|
|
this.declarationOrder = index;
|
|
this._broughtToFront = bringToFront;
|
|
this.setZIndex(bringToFront ? Number.MAX_VALUE : index);
|
|
this.fireEvent(new SeriesGroupingChangedEvent(this, this.seriesGrouping));
|
|
return true;
|
|
}
|
|
setZIndex(zIndex) {
|
|
this.contentGroup.zIndex = [import_ag_charts_core136.SeriesZIndexMap.ANY_CONTENT, zIndex, import_ag_charts_core136.SeriesContentZIndexMap.FOREGROUND];
|
|
this.highlightGroup.zIndex = [import_ag_charts_core136.SeriesZIndexMap.ANY_CONTENT, zIndex, import_ag_charts_core136.SeriesContentZIndexMap.HIGHLIGHT];
|
|
this.labelGroup.zIndex = [import_ag_charts_core136.SeriesZIndexMap.ANY_CONTENT, zIndex, import_ag_charts_core136.SeriesContentZIndexMap.LABEL];
|
|
this.annotationGroup.zIndex = zIndex;
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
return false;
|
|
}
|
|
hasHighlightOpacity() {
|
|
if (!this.properties.highlight.enabled)
|
|
return false;
|
|
if (this.ctx.highlightManager.getActiveHighlight() == null)
|
|
return false;
|
|
const { unhighlightedItem, unhighlightedSeries } = this.properties.highlight;
|
|
return hasDimmedOpacity(unhighlightedItem) || hasDimmedOpacity(unhighlightedSeries);
|
|
}
|
|
getDrawingMode(isHighlight, highlightDrawingMode = "cutout") {
|
|
if (isHighlight) {
|
|
return highlightDrawingMode;
|
|
}
|
|
return this.hasHighlightOpacity() ? this.ctx.chartService.highlight?.drawingMode ?? "overlay" : "overlay";
|
|
}
|
|
getAnimationDrawingModes() {
|
|
const drawingMode = this.getDrawingMode(false);
|
|
return {
|
|
start: { drawingMode: "overlay" },
|
|
finish: { drawingMode }
|
|
};
|
|
}
|
|
addEventListener(type, listener) {
|
|
return super.addEventListener(type, listener);
|
|
}
|
|
removeEventListener(type, listener) {
|
|
return super.removeEventListener(type, listener);
|
|
}
|
|
hasEventListener(type) {
|
|
return super.hasEventListener(type);
|
|
}
|
|
updatedDomains() {
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
this.resetDatumCallbackCache();
|
|
this.ctx.seriesStateManager.deregisterSeries(this);
|
|
}
|
|
getPropertyValues(property, properties) {
|
|
const direction = propertyAxisDirection(property);
|
|
const resolvedProperty = direction == null ? property : axisDirectionProperty(this.resolveKeyDirection(direction));
|
|
const keys = properties?.[resolvedProperty];
|
|
const values = [];
|
|
if (!keys) {
|
|
return values;
|
|
}
|
|
const addValues = (...items) => {
|
|
for (const value of items) {
|
|
if (Array.isArray(value)) {
|
|
addValues(...value);
|
|
} else if (typeof value === "object") {
|
|
addValues(...Object.values(value));
|
|
} else {
|
|
values.push(value);
|
|
}
|
|
}
|
|
};
|
|
addValues(...keys.map((key) => this.properties[key]));
|
|
return values;
|
|
}
|
|
getKeyAxis(_direction) {
|
|
return void 0;
|
|
}
|
|
getKeys(direction) {
|
|
return this.getPropertyValues(axisDirectionProperty(direction), this.propertyKeys);
|
|
}
|
|
getKeyProperties(direction) {
|
|
return this.propertyKeys[this.resolveKeyDirection(direction)] ?? [];
|
|
}
|
|
getNames(direction) {
|
|
return this.getPropertyValues(axisDirectionProperty(direction), this.propertyNames);
|
|
}
|
|
getFormatterContext(property) {
|
|
const { id: seriesId } = this;
|
|
const keys = this.getPropertyValues(property, this.propertyKeys);
|
|
const names = this.getPropertyValues(property, this.propertyNames);
|
|
const out = [];
|
|
for (let idx = 0; idx < keys.length; idx++) {
|
|
out.push({ seriesId, key: keys[idx], name: names[idx] });
|
|
}
|
|
return out;
|
|
}
|
|
resolveKeyDirection(direction) {
|
|
return direction;
|
|
}
|
|
// The union of the series domain ('community') and series-option domains ('enterprise').
|
|
getDomain(direction) {
|
|
const seriesDomain = this.getSeriesDomain(direction);
|
|
const moduleDomains = this.moduleMap.mapModules((module2) => module2.getDomain(direction)).flat();
|
|
if (moduleDomains.length === 0) {
|
|
return seriesDomain;
|
|
}
|
|
return { domain: seriesDomain.domain.concat(moduleDomains) };
|
|
}
|
|
getRange(direction, visibleRange) {
|
|
return this.getSeriesRange(direction, visibleRange);
|
|
}
|
|
getMinimumRangeSeries(_range) {
|
|
}
|
|
getMinimumRangeChart(_ranges) {
|
|
return 0;
|
|
}
|
|
getZoomRangeFittingItems(_xVisibleRange, _yVisibleRange, _minVisibleItems) {
|
|
return void 0;
|
|
}
|
|
getVisibleItems(_xVisibleRange, _yVisibleRange, _minVisibleItems) {
|
|
return Infinity;
|
|
}
|
|
toCanvasFromMidPoint(nodeDatum) {
|
|
const { x = 0, y = 0 } = nodeDatum.midPoint ?? {};
|
|
return Transformable.toCanvasPoint(this.contentGroup, x, y);
|
|
}
|
|
// Indicate that something external changed and we should recalculate nodeData.
|
|
markNodeDataDirty() {
|
|
this.nodeDataRefresh = true;
|
|
this._pickNodeCache.clear();
|
|
this.visibleMaybeChanged();
|
|
}
|
|
visibleMaybeChanged() {
|
|
const { internalId, seriesGrouping, type, visible } = this;
|
|
this.ctx.seriesStateManager.updateSeries({
|
|
internalId,
|
|
type,
|
|
visible,
|
|
seriesGrouping,
|
|
// TODO: is there a better way to pass width through here?
|
|
width: "width" in this.properties ? this.properties.width : 0
|
|
});
|
|
}
|
|
getOpacity() {
|
|
const defaultOpacity = 1;
|
|
if (!this.properties.highlight) {
|
|
return defaultOpacity;
|
|
}
|
|
const { opacity = defaultOpacity } = this.getHighlightStyle();
|
|
return opacity;
|
|
}
|
|
getHighlightState(highlightedDatum, isHighlight, datumIndex, legendItemValues) {
|
|
if (!this.properties.highlight.enabled) {
|
|
return 0 /* None */;
|
|
}
|
|
if (isHighlight) {
|
|
return 1 /* Item */;
|
|
}
|
|
if (highlightedDatum?.series == null) {
|
|
return 0 /* None */;
|
|
}
|
|
if (this.isSeriesHighlighted(highlightedDatum, legendItemValues)) {
|
|
const itemHighlighted = this.isItemHighlighted(highlightedDatum, datumIndex);
|
|
if (itemHighlighted == null) {
|
|
return 2 /* Series */;
|
|
}
|
|
return 4 /* OtherItem */;
|
|
}
|
|
return 3 /* OtherSeries */;
|
|
}
|
|
getHighlightStateString(datum, isHighlight, datumIndex, legendItemValues) {
|
|
return toHighlightString(this.getHighlightState(datum, isHighlight, datumIndex, legendItemValues));
|
|
}
|
|
onChangeHighlight(event) {
|
|
const previousHighlightedDatum = event.previousHighlight;
|
|
const currentHighlightedDatum = event.currentHighlight;
|
|
const currentHighlightState = this.getHighlightState(currentHighlightedDatum);
|
|
const previousHighlightState = this.getHighlightState(previousHighlightedDatum);
|
|
this.setSeriesIndex(this.declarationOrder);
|
|
const hasItemStylers = this.hasItemStylers();
|
|
if (!hasItemStylers && currentHighlightState === previousHighlightState) {
|
|
this.hasChangesOnHighlight = false;
|
|
return;
|
|
}
|
|
const { highlightedSeries, unhighlightedItem, unhighlightedSeries } = this.properties.highlight;
|
|
this.hasChangesOnHighlight = hasItemStylers || !(0, import_ag_charts_core136.isEmptyObject)(highlightedSeries) || !(0, import_ag_charts_core136.isEmptyObject)(unhighlightedItem) || !(0, import_ag_charts_core136.isEmptyObject)(unhighlightedSeries);
|
|
}
|
|
bringToFront() {
|
|
return this.properties.highlight.enabled && this.properties.highlight.bringToFront && this.isSeriesHighlighted(this.ctx.highlightManager.getActiveHighlight());
|
|
}
|
|
isSeriesHighlighted(highlightedDatum, _legendItemValues) {
|
|
if (!this.properties.highlight.enabled) {
|
|
return false;
|
|
}
|
|
return highlightedDatum?.series === this;
|
|
}
|
|
isItemHighlighted(highlightedDatum, datumIndex) {
|
|
if (highlightedDatum?.datumIndex == null || datumIndex == null)
|
|
return;
|
|
return highlightedDatum.datumIndex === datumIndex;
|
|
}
|
|
getHighlightStyle(isHighlight, datumIndex, highlightState, legendItemValues) {
|
|
const highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
highlightState ?? (highlightState = this.getHighlightState(highlightedDatum, isHighlight, datumIndex, legendItemValues));
|
|
return this.properties.highlight.getStyle(highlightState);
|
|
}
|
|
resolveMarkerDrawingModeForState(drawingMode, style) {
|
|
return resolveMarkerDrawingMode(drawingMode, style);
|
|
}
|
|
filterItemStylerFillParams(fill) {
|
|
if ((0, import_ag_charts_core136.isGradientFill)(fill)) {
|
|
return (0, import_ag_charts_core136.without)(fill, ["bounds", "colorSpace", "gradient", "reverse"]);
|
|
} else if ((0, import_ag_charts_core136.isPatternFill)(fill)) {
|
|
return (0, import_ag_charts_core136.without)(fill, ["padding"]);
|
|
}
|
|
return fill;
|
|
}
|
|
getModuleTooltipParams() {
|
|
return this.moduleMap.mapModules((module2) => module2.getTooltipParams()).reduce((total, current) => Object.assign(total, current), {});
|
|
}
|
|
pickNodes(point, intent, exactMatchOnly = false) {
|
|
const { pickModes, pickModeAxis, visible, contentGroup } = this;
|
|
if (!visible || !contentGroup.visible)
|
|
return;
|
|
if (intent === "highlight" && !this.properties.highlight.enabled)
|
|
return;
|
|
if (intent === "highlight-tooltip" && !this.properties.highlight.enabled)
|
|
return;
|
|
let maxDistance = Infinity;
|
|
if (intent === "tooltip" || intent === "highlight-tooltip") {
|
|
const { tooltip } = this.properties;
|
|
maxDistance = typeof tooltip.range === "number" ? tooltip.range : Infinity;
|
|
exactMatchOnly || (exactMatchOnly = tooltip.range === "exact");
|
|
} else if (intent === "event" || intent === "context-menu") {
|
|
const { nodeClickRange } = this.properties;
|
|
maxDistance = typeof nodeClickRange === "number" ? nodeClickRange : Infinity;
|
|
exactMatchOnly || (exactMatchOnly = nodeClickRange === "exact");
|
|
}
|
|
const selectedPickModes = pickModes.filter(
|
|
(m) => !exactMatchOnly || m === 0 /* EXACT_SHAPE_MATCH */
|
|
);
|
|
const { x, y } = point;
|
|
const key = JSON.stringify({ x, y, maxDistance, selectedPickModes });
|
|
if (this._pickNodeCache.has(key)) {
|
|
return this._pickNodeCache.get(key);
|
|
}
|
|
for (const pickMode of selectedPickModes) {
|
|
let result;
|
|
switch (pickMode) {
|
|
case 0 /* EXACT_SHAPE_MATCH */: {
|
|
const exact = this.pickNodesExactShape(point);
|
|
result = exact.length === 0 ? void 0 : { datums: exact, distance: 0 };
|
|
break;
|
|
}
|
|
case 1 /* NEAREST_NODE */: {
|
|
const closest = this.pickNodeClosestDatum(point);
|
|
const exact = closest?.distance === 0 ? this.pickNodesExactShape(point) : void 0;
|
|
if (exact != null && exact.length !== 0) {
|
|
result = { datums: exact, distance: 0 };
|
|
} else if (closest) {
|
|
result = { datums: [closest.datum], distance: closest.distance };
|
|
} else {
|
|
result = void 0;
|
|
}
|
|
break;
|
|
}
|
|
case 2 /* AXIS_ALIGNED */: {
|
|
const closest = pickModeAxis == null ? void 0 : this.pickNodeMainAxisFirst(point, pickModeAxis === "main-category");
|
|
result = closest == null ? void 0 : { datums: [closest.datum], distance: closest.distance };
|
|
break;
|
|
}
|
|
}
|
|
if (result && result.distance <= maxDistance) {
|
|
return this._pickNodeCache.set(key, { pickMode, datums: result.datums, distance: result.distance });
|
|
}
|
|
}
|
|
return this._pickNodeCache.set(key, void 0);
|
|
}
|
|
pickNodesExactShape(point) {
|
|
const datums = [];
|
|
for (const node of this.contentGroup.pickNodes(point.x, point.y)) {
|
|
const datum = node.closestDatum();
|
|
if (datum != null && datum.missing !== true) {
|
|
datums.push(datum);
|
|
}
|
|
}
|
|
return datums;
|
|
}
|
|
pickNodeClosestDatum(_point) {
|
|
throw new Error("AG Charts - Series.pickNodeClosestDatum() not implemented");
|
|
}
|
|
pickNodeNearestDistantObject(point, items) {
|
|
const match = (0, import_ag_charts_core136.nearestSquared)(point.x, point.y, items);
|
|
const datum = match.nearest?.closestDatum();
|
|
if (datum != null && datum.missing !== true) {
|
|
return { datum, distance: Math.sqrt(match.distanceSquared) };
|
|
}
|
|
}
|
|
pickNodeMainAxisFirst(_point, _requireCategoryAxis) {
|
|
throw new Error("AG Charts - Series.pickNodeMainAxisFirst() not implemented");
|
|
}
|
|
getLabelData() {
|
|
return [];
|
|
}
|
|
updatePlacedLabelData(_labels) {
|
|
return;
|
|
}
|
|
fireEvent(event) {
|
|
(0, import_ag_charts_core136.callWithContext)([this.properties, this.ctx.chartService], this.fireEventWrapper, event);
|
|
}
|
|
fireNodeClickEvent(event, datum) {
|
|
const clickEvent = new this.NodeEvent("seriesNodeClick", event, datum, this);
|
|
this.fireEvent(clickEvent);
|
|
return !clickEvent.defaultPrevented;
|
|
}
|
|
fireNodeDoubleClickEvent(event, datum) {
|
|
const clickEvent = new this.NodeEvent("seriesNodeDoubleClick", event, datum, this);
|
|
this.fireEvent(clickEvent);
|
|
return !clickEvent.defaultPrevented;
|
|
}
|
|
createNodeContextMenuActionEvent(event, datum) {
|
|
return new this.NodeEvent("nodeContextMenuAction", event, datum, this);
|
|
}
|
|
onLegendInitialState(legendType, initialState) {
|
|
const { visible = true, itemId, legendItemName } = initialState ?? {};
|
|
this.toggleSeriesItem(visible, legendType, itemId, legendItemName);
|
|
}
|
|
onLegendItemClick(event) {
|
|
const { enabled, itemId, series, legendType } = event;
|
|
const legendItemName = "legendItemName" in this.properties ? this.properties.legendItemName : void 0;
|
|
const legendItemKey = "legendItemKey" in this.properties ? this.properties.legendItemKey : void 0;
|
|
const matchedLegendItemName = legendItemName != void 0 && legendItemName === event.legendItemName;
|
|
if (series.id === this.id || matchedLegendItemName || legendItemKey != void 0) {
|
|
this.toggleSeriesItem(enabled, legendType, itemId, legendItemName, event);
|
|
}
|
|
}
|
|
onLegendItemDoubleClick(event) {
|
|
const { enabled, itemId, series, numVisibleItems, legendType } = event;
|
|
const legendItemName = "legendItemName" in this.properties ? this.properties.legendItemName : void 0;
|
|
const legendItemKey = "legendItemKey" in this.properties ? this.properties.legendItemKey : void 0;
|
|
const matchedLegendItemName = legendItemName != void 0 && legendItemName === event.legendItemName;
|
|
if (series.id === this.id || matchedLegendItemName || legendItemKey != void 0) {
|
|
this.toggleSeriesItem(true, legendType, itemId, legendItemName, event);
|
|
} else if (enabled && numVisibleItems === 1) {
|
|
this.toggleSeriesItem(true, legendType, void 0, legendItemName);
|
|
} else {
|
|
this.toggleSeriesItem(false, legendType, void 0, legendItemName);
|
|
}
|
|
}
|
|
toggleSeriesItem(enabled, legendType, itemId, legendItemName, legendEvent) {
|
|
const seriesId = this.id;
|
|
if (enabled || legendType !== "category") {
|
|
this.visible = enabled;
|
|
}
|
|
this.nodeDataRefresh = true;
|
|
this._pickNodeCache.clear();
|
|
const event = {
|
|
type: "seriesVisibilityChange",
|
|
seriesId,
|
|
itemId,
|
|
legendItemName: legendEvent?.legendItemName ?? legendItemName,
|
|
visible: enabled
|
|
};
|
|
this.fireEvent(event);
|
|
this.ctx.legendManager.toggleItem(enabled, seriesId, itemId, legendItemName);
|
|
}
|
|
isEnabled() {
|
|
return this.visible;
|
|
}
|
|
getModuleMap() {
|
|
return this.moduleMap;
|
|
}
|
|
createModuleContext() {
|
|
return { ...this.ctx, series: this };
|
|
}
|
|
getAxisValueText(axis, source, value, datum, key, legendItemName, allowNull) {
|
|
const { id: seriesId, properties } = this;
|
|
return axis.formatDatum(
|
|
properties,
|
|
value,
|
|
source,
|
|
seriesId,
|
|
legendItemName,
|
|
datum,
|
|
key,
|
|
void 0,
|
|
void 0,
|
|
void 0,
|
|
allowNull
|
|
);
|
|
}
|
|
getLabelText(value, datum, key, property, domain, label, baseParams, allowNullValue = false) {
|
|
if (value == null && !allowNullValue)
|
|
return "";
|
|
const { axes, canHaveAxes, ctx, id: seriesId, properties } = this;
|
|
const source = "series-label";
|
|
const legendItemName = "legendItemName" in properties ? properties.legendItemName : void 0;
|
|
const params = {
|
|
seriesId: this.id,
|
|
...baseParams
|
|
};
|
|
const direction = canHaveAxes ? propertyAxisDirection(property) : void 0;
|
|
const axis = direction == null ? void 0 : axes[this.resolveKeyDirection(direction)];
|
|
if (axis != null) {
|
|
return axis.formatDatum(
|
|
properties,
|
|
value,
|
|
source,
|
|
seriesId,
|
|
legendItemName,
|
|
datum,
|
|
key,
|
|
domain,
|
|
label,
|
|
params,
|
|
allowNullValue
|
|
);
|
|
}
|
|
const { formatManager } = ctx;
|
|
const formatInContext = this.callWithContext.bind(this);
|
|
const format = (formatParams) => label.formatValue(formatInContext, formatParams.type, formatParams.value, params) ?? formatManager.format(formatInContext, formatParams) ?? (value == null ? "" : String(value));
|
|
const boundSeries = this.getFormatterContext(property);
|
|
switch (property) {
|
|
case "y":
|
|
case "color":
|
|
case "size": {
|
|
const fractionDigits = void 0;
|
|
return format({
|
|
type: "number",
|
|
value,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key,
|
|
source,
|
|
property,
|
|
domain,
|
|
boundSeries,
|
|
fractionDigits,
|
|
visibleDomain: void 0
|
|
});
|
|
}
|
|
case "x":
|
|
case "radius":
|
|
case "angle":
|
|
case "label":
|
|
case "secondaryLabel":
|
|
case "calloutLabel":
|
|
case "sectorLabel":
|
|
case "legendItem":
|
|
return format({
|
|
type: "category",
|
|
value,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key,
|
|
source,
|
|
property,
|
|
domain,
|
|
boundSeries
|
|
});
|
|
}
|
|
}
|
|
getMarkerStyle(marker, { datumIndex, datum, point }, params, opts, defaultOverrideStyle = { size: point?.size ?? marker.size ?? 0 }, inheritedStyle) {
|
|
const { itemStyler } = marker;
|
|
const {
|
|
highlightState,
|
|
isHighlight = false,
|
|
checkForHighlight = true,
|
|
resolveMarkerSubPath = ["marker"],
|
|
resolveStyler = false
|
|
} = opts ?? {};
|
|
const resolvePath2 = ["series", `${this.declarationOrder}`, ...resolveMarkerSubPath];
|
|
if (resolveStyler) {
|
|
const resolveOpt = { permissivePath: true };
|
|
const resolved = this.ctx.optionsGraphService.resolvePartial(resolvePath2, defaultOverrideStyle, resolveOpt);
|
|
if (resolved) {
|
|
defaultOverrideStyle = { ...resolved, size: resolved.size ?? defaultOverrideStyle.size };
|
|
}
|
|
}
|
|
const highlightStyle = checkForHighlight ? this.getHighlightStyle(isHighlight, datumIndex, highlightState) : void 0;
|
|
const baseStyle = (0, import_ag_charts_core136.mergeDefaults)(highlightStyle, defaultOverrideStyle, marker.getStyle(), inheritedStyle);
|
|
let markerStyle = baseStyle;
|
|
if (itemStyler && params) {
|
|
const highlight5 = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightStateString = this.getHighlightStateString(highlight5, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(markerStyle.fill);
|
|
const style = this.cachedCallWithContext(itemStyler, {
|
|
seriesId: this.id,
|
|
...markerStyle,
|
|
fill,
|
|
...params,
|
|
highlightState: highlightStateString,
|
|
datum
|
|
});
|
|
const resolved = this.ctx.optionsGraphService.resolvePartial(resolvePath2, style);
|
|
markerStyle = (0, import_ag_charts_core136.mergeDefaults)(resolved, markerStyle);
|
|
}
|
|
return markerStyle;
|
|
}
|
|
applyMarkerStyle(style, markerNode, point, fillBBox, { applyTranslation = true, selected = true } = {}) {
|
|
const { shape, size = 0 } = style;
|
|
const visible = this.visible && size > 0 && point && !Number.isNaN(point.x) && !Number.isNaN(point.y);
|
|
markerNode.setStyleProperties(style, fillBBox);
|
|
if (applyTranslation) {
|
|
markerNode.setProperties({
|
|
visible,
|
|
shape,
|
|
size,
|
|
x: point?.x,
|
|
y: point?.y,
|
|
scalingCenterX: point?.x,
|
|
scalingCenterY: point?.y
|
|
});
|
|
} else {
|
|
markerNode.setProperties({ visible, shape, size });
|
|
}
|
|
if (!selected) {
|
|
markerNode.fillOpacity *= CROSS_FILTER_MARKER_FILL_OPACITY_FACTOR;
|
|
markerNode.strokeOpacity *= CROSS_FILTER_MARKER_STROKE_OPACITY_FACTOR;
|
|
}
|
|
if (typeof shape === "function" && !markerNode.dirtyPath) {
|
|
markerNode.path.clear(true);
|
|
markerNode.updatePath();
|
|
markerNode.checkPathDirty();
|
|
const bb = markerNode.getBBox();
|
|
if (point != null && bb.isFinite()) {
|
|
const center = bb.computeCenter();
|
|
const [dx, dy] = ["x", "y"].map(
|
|
(key) => (style.strokeWidth ?? 0) + Math.abs(center[key] - point[key])
|
|
);
|
|
point.focusSize = Math.max(bb.width + dx, bb.height + dy);
|
|
}
|
|
}
|
|
}
|
|
get nodeDataDependencies() {
|
|
return this._nodeDataDependencies ?? { seriesRectWidth: Number.NaN, seriesRectHeight: Number.NaN };
|
|
}
|
|
checkResize(newSeriesRect) {
|
|
const { width: seriesRectWidth, height: seriesRectHeight } = newSeriesRect ?? {
|
|
width: Number.NaN,
|
|
height: Number.NaN
|
|
};
|
|
const newNodeDataDependencies = newSeriesRect ? { seriesRectWidth, seriesRectHeight } : void 0;
|
|
const resize = (0, import_ag_charts_core136.jsonDiff)(this.nodeDataDependencies, newNodeDataDependencies) != null;
|
|
if (resize) {
|
|
this._nodeDataDependencies = newNodeDataDependencies;
|
|
this.markNodeDataDirty();
|
|
}
|
|
return resize;
|
|
}
|
|
pickFocus(_opts) {
|
|
return void 0;
|
|
}
|
|
resetDatumCallbackCache() {
|
|
this.datumCallbackCache.clear();
|
|
}
|
|
cachedDatumCallback(id, fn) {
|
|
const { datumCallbackCache } = this;
|
|
const existing = datumCallbackCache.get(id);
|
|
if (existing != null)
|
|
return existing;
|
|
try {
|
|
const value = fn();
|
|
datumCallbackCache.set(id, value);
|
|
return value;
|
|
} catch (error) {
|
|
import_ag_charts_core136.Logger.error(String(error));
|
|
}
|
|
}
|
|
cachedCallWithContext(fn, params) {
|
|
return this.ctx.callbackCache.call([this.properties, this.ctx.chartService], fn, params);
|
|
}
|
|
callWithContext(fn, params) {
|
|
return (0, import_ag_charts_core136.callWithContext)([this.properties, this.ctx.chartService], fn, params);
|
|
}
|
|
formatTooltipWithContext(tooltip, content, params) {
|
|
return tooltip.formatTooltip([this.properties, this.ctx.chartService], content, params);
|
|
}
|
|
// @todo(AG-13777) - Remove this function (see CartesianSeries.ts)
|
|
minTimeInterval() {
|
|
return;
|
|
}
|
|
needsDataModelDiff() {
|
|
return !this.ctx.animationManager.isSkipped() || !!this.chart?.flashOnUpdateEnabled;
|
|
}
|
|
};
|
|
Series.className = "Series";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core136.ActionOnSet)({
|
|
changeValue: function(newVal, oldVal) {
|
|
this.onSeriesGroupingChange(oldVal, newVal);
|
|
}
|
|
})
|
|
], Series.prototype, "seriesGrouping", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/seriesAreaManager.ts
|
|
var import_ag_charts_core147 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/dom/focusIndicator.ts
|
|
var import_ag_charts_core137 = require("ag-charts-core");
|
|
var FocusIndicator = class {
|
|
constructor(swapChain) {
|
|
this.swapChain = swapChain;
|
|
this.hasBeenActivated = false;
|
|
this.div = (0, import_ag_charts_core137.createElement)("div");
|
|
this.svg = (0, import_ag_charts_core137.createSvgElement)("svg");
|
|
this.outerPath = (0, import_ag_charts_core137.createSvgElement)("path");
|
|
this.innerPath = (0, import_ag_charts_core137.createSvgElement)("path");
|
|
this.svg.append(this.outerPath);
|
|
this.svg.append(this.innerPath);
|
|
this.outerPath.classList.add("ag-charts-focus-svg-outer-path");
|
|
this.innerPath.classList.add("ag-charts-focus-svg-inner-path");
|
|
this.element = (0, import_ag_charts_core137.createElement)("div", "ag-charts-focus-indicator");
|
|
this.element.ariaHidden = "true";
|
|
this.element.append(this.svg);
|
|
this.swapChain.addListener("swap", (parent) => this.onSwap(parent));
|
|
}
|
|
clear() {
|
|
}
|
|
update(focus, rect2, clip) {
|
|
if (rect2 == null)
|
|
return;
|
|
if (focus instanceof Path) {
|
|
const transform = (localX, localY) => {
|
|
let { x, y } = Transformable.toCanvasPoint(focus, localX, localY);
|
|
x -= rect2.x ?? 0;
|
|
y -= rect2.y ?? 0;
|
|
return { x, y };
|
|
};
|
|
const d = focus.svgPathData(transform);
|
|
this.outerPath.setAttribute("d", d);
|
|
this.innerPath.setAttribute("d", d);
|
|
this.show(this.svg);
|
|
} else {
|
|
let bbox;
|
|
if (clip) {
|
|
const x0 = Math.max(focus.x - rect2.x, 0);
|
|
const y0 = Math.max(focus.y - rect2.y, 0);
|
|
const x1 = Math.min(focus.x + focus.width - rect2.x, rect2.width);
|
|
const y1 = Math.min(focus.y + focus.height - rect2.y, rect2.height);
|
|
bbox = new BBox(x0, y0, x1 - x0, y1 - y0);
|
|
} else {
|
|
bbox = new BBox(focus.x - rect2.x, focus.y - rect2.y, focus.width, focus.height);
|
|
}
|
|
(0, import_ag_charts_core137.setElementBBox)(this.div, bbox);
|
|
this.show(this.div);
|
|
}
|
|
}
|
|
onSwap(newParent) {
|
|
if (newParent === this.element.parentElement)
|
|
return;
|
|
this.element.remove();
|
|
newParent.appendChild(this.element);
|
|
this.overrideFocusVisible(this.focusVisible);
|
|
}
|
|
show(child) {
|
|
this.hasBeenActivated = true;
|
|
this.element.innerHTML = "";
|
|
this.element.append(child);
|
|
}
|
|
overrideFocusVisible(focusVisible) {
|
|
this.focusVisible = focusVisible;
|
|
const opacity = { true: "1", false: "0", undefined: "" };
|
|
const parent = this.element.parentElement;
|
|
parent?.style.setProperty("opacity", opacity[`${focusVisible}`]);
|
|
}
|
|
// Get the `:focus-visible` CSS state.
|
|
isFocusVisible(force = false) {
|
|
if (!force && !this.hasBeenActivated)
|
|
return false;
|
|
const parent = this.element.parentElement;
|
|
return parent != null && (0, import_ag_charts_core137.getWindow)().getComputedStyle(parent).opacity === "1";
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/dom/focusSwapChain.ts
|
|
var import_ag_charts_core138 = require("ag-charts-core");
|
|
var FocusSwapChain = class {
|
|
constructor(label1, label2, announcerRole, initialAltText) {
|
|
this.label1 = label1;
|
|
this.label2 = label2;
|
|
this.hasFocus = false;
|
|
this.skipDispatch = false;
|
|
this.listeners = {
|
|
blur: [],
|
|
focus: [],
|
|
swap: []
|
|
};
|
|
this.onBlur = (e) => {
|
|
(0, import_ag_charts_core138.setElementStyle)(e.target, "pointer-events", void 0);
|
|
return !this.skipDispatch && this.dispatch("blur", e);
|
|
};
|
|
this.onFocus = (e) => {
|
|
(0, import_ag_charts_core138.setElementStyle)(e.target, "pointer-events", "auto");
|
|
return !this.skipDispatch && this.dispatch("focus", e);
|
|
};
|
|
(0, import_ag_charts_core138.setAttribute)(this.label1, "id", (0, import_ag_charts_core138.createElementId)());
|
|
(0, import_ag_charts_core138.setAttribute)(this.label2, "id", (0, import_ag_charts_core138.createElementId)());
|
|
(0, import_ag_charts_core138.setElementStyle)(this.label1, "display", "none");
|
|
(0, import_ag_charts_core138.setElementStyle)(this.label2, "display", "none");
|
|
this.label1.textContent = initialAltText;
|
|
this.label2.textContent = initialAltText;
|
|
this.activeAnnouncer = this.createAnnouncer(announcerRole);
|
|
this.inactiveAnnouncer = this.createAnnouncer(announcerRole);
|
|
(0, import_ag_charts_core138.setAttribute)(this.activeAnnouncer, "tabindex", 0);
|
|
this.label2.insertAdjacentElement("afterend", this.activeAnnouncer);
|
|
this.label2.insertAdjacentElement("afterend", this.inactiveAnnouncer);
|
|
this.swap(initialAltText);
|
|
}
|
|
createAnnouncer(role) {
|
|
const announcer = (0, import_ag_charts_core138.createElement)("div");
|
|
announcer.role = role;
|
|
announcer.className = "ag-charts-swapchain";
|
|
announcer.addEventListener("blur", this.onBlur);
|
|
announcer.addEventListener("focus", this.onFocus);
|
|
return announcer;
|
|
}
|
|
destroy() {
|
|
for (const announcer of [this.activeAnnouncer, this.inactiveAnnouncer]) {
|
|
announcer.removeEventListener("blur", this.onBlur);
|
|
announcer.removeEventListener("focus", this.onFocus);
|
|
announcer.remove();
|
|
}
|
|
}
|
|
focus(opts) {
|
|
this.focusOptions = opts;
|
|
this.activeAnnouncer.focus(opts);
|
|
this.focusOptions = void 0;
|
|
}
|
|
update(newLabel) {
|
|
this.skipDispatch = true;
|
|
this.swap(newLabel);
|
|
if (this.hasFocus) {
|
|
this.activeAnnouncer.focus(this.focusOptions);
|
|
}
|
|
this.skipDispatch = false;
|
|
}
|
|
addListener(type, handler) {
|
|
this.listeners[type].push(handler);
|
|
if (type === "swap") {
|
|
const swapHandler = handler;
|
|
swapHandler(this.activeAnnouncer);
|
|
}
|
|
}
|
|
dispatch(type, param) {
|
|
if (type === "focus")
|
|
this.hasFocus = true;
|
|
else if (type === "blur")
|
|
this.hasFocus = false;
|
|
for (const fn of this.listeners[type]) {
|
|
fn(param);
|
|
}
|
|
}
|
|
swap(newLabel) {
|
|
const userTabIndex = this.activeAnnouncer.tabIndex;
|
|
this.label2.textContent = newLabel;
|
|
[this.inactiveAnnouncer, this.activeAnnouncer] = [this.activeAnnouncer, this.inactiveAnnouncer];
|
|
[this.label1, this.label2] = [this.label2, this.label1];
|
|
(0, import_ag_charts_core138.setAttributes)(this.inactiveAnnouncer, {
|
|
"aria-labelledby": this.label1.id,
|
|
"aria-hidden": true,
|
|
tabindex: void 0
|
|
});
|
|
(0, import_ag_charts_core138.setAttributes)(this.activeAnnouncer, {
|
|
"aria-labelledby": this.label1.id,
|
|
"aria-hidden": false,
|
|
tabindex: userTabIndex
|
|
});
|
|
this.dispatch("swap", this.activeAnnouncer);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/interaction/keyBindings.ts
|
|
var import_ag_charts_core139 = require("ag-charts-core");
|
|
var KEY_BINDINGS = {
|
|
arrowdown: { bindings: [{ code: "ArrowDown" }] },
|
|
arrowleft: { bindings: [{ code: "ArrowLeft" }] },
|
|
arrowright: { bindings: [{ code: "ArrowRight" }] },
|
|
arrowup: { bindings: [{ code: "ArrowUp" }] },
|
|
delete: { bindings: [{ key: "Backspace" }, { key: "Delete" }], activatesFocusIndicator: false },
|
|
redo: {
|
|
bindings: [
|
|
{ key: "y", ctrlOrMeta: true },
|
|
{ key: "z", ctrlOrMeta: true, shift: true }
|
|
],
|
|
activatesFocusIndicator: false
|
|
},
|
|
undo: { bindings: [{ key: "z", ctrlOrMeta: true }], activatesFocusIndicator: false },
|
|
submit: { bindings: [{ key: "Enter" }, { code: "Enter" }, { code: "Space" }] },
|
|
zoomin: { bindings: [{ key: "+" }, { code: "ZoomIn" }, { code: "Add" }], activatesFocusIndicator: false },
|
|
zoomout: { bindings: [{ key: "-" }, { code: "ZoomOut" }, { code: "Substract" }], activatesFocusIndicator: false }
|
|
};
|
|
function matchesKeyBinding(e, bindings) {
|
|
for (const kb of bindings) {
|
|
if ("code" in kb) {
|
|
if (kb.code === e.code)
|
|
return true;
|
|
} else {
|
|
const matches = kb.key === e.key && (kb.shift === void 0 || kb.shift === e.shiftKey) && (kb.ctrlOrMeta === void 0 || kb.ctrlOrMeta === e.ctrlKey || kb.ctrlOrMeta === e.metaKey);
|
|
if (matches)
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function mapKeyboardEventToAction(event) {
|
|
for (const [actionName, { activatesFocusIndicator = true, bindings }] of (0, import_ag_charts_core139.entries)(KEY_BINDINGS)) {
|
|
if (matchesKeyBinding(event, bindings)) {
|
|
return { name: actionName, activatesFocusIndicator };
|
|
}
|
|
}
|
|
return void 0;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/keyboardUtil.ts
|
|
function computeCenter(series, hoverRect, pick2) {
|
|
const refPoint = getDatumRefPoint(series, pick2.datum, pick2.movedBounds);
|
|
if (refPoint != null)
|
|
return { x: refPoint.canvasX, y: refPoint.canvasY };
|
|
const bboxOrPath = pick2.bounds;
|
|
if (bboxOrPath == null)
|
|
return;
|
|
if (bboxOrPath instanceof BBox) {
|
|
const { x: centerX, y: centerY } = bboxOrPath.computeCenter();
|
|
return {
|
|
x: hoverRect.x + centerX,
|
|
y: hoverRect.y + centerY
|
|
};
|
|
}
|
|
return Transformable.toCanvas(bboxOrPath).computeCenter();
|
|
}
|
|
function getPickedFocusBBox({ bounds }) {
|
|
if (bounds instanceof BBox)
|
|
return bounds;
|
|
if (bounds != null)
|
|
return Transformable.toCanvas(bounds);
|
|
return BBox.NaN;
|
|
}
|
|
function makeKeyboardPointerEvent(series, hoverRect, pick2) {
|
|
const { x: canvasX, y: canvasY } = computeCenter(series, hoverRect, pick2) ?? {};
|
|
if (canvasX !== void 0 && canvasY !== void 0) {
|
|
return { type: "keyboard", canvasX, canvasY };
|
|
}
|
|
return void 0;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/tooltip/tooltip.ts
|
|
var import_ag_charts_core145 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/tooltip/springAnimation.ts
|
|
var import_ag_charts_core140 = require("ag-charts-core");
|
|
var M = 0.1;
|
|
var K = 200;
|
|
var C = 12;
|
|
var DELTA = 0.5;
|
|
var SpringAnimation = class {
|
|
constructor() {
|
|
this.events = new import_ag_charts_core140.EventEmitter();
|
|
this.x1 = Number.NaN;
|
|
this.y1 = Number.NaN;
|
|
this.x = Number.NaN;
|
|
this.y = Number.NaN;
|
|
this.vx = 0;
|
|
this.vy = 0;
|
|
this.t0 = Number.NaN;
|
|
this.animationFrameHandle = void 0;
|
|
}
|
|
reset() {
|
|
this.x = Number.NaN;
|
|
this.y = Number.NaN;
|
|
if (this.animationFrameHandle != null) {
|
|
cancelAnimationFrame(this.animationFrameHandle);
|
|
this.animationFrameHandle = void 0;
|
|
}
|
|
}
|
|
update(x, y) {
|
|
if (Number.isNaN(this.x) || Number.isNaN(this.y)) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.vx = 0;
|
|
this.vy = 0;
|
|
this.emitUpdate();
|
|
if (this.animationFrameHandle != null) {
|
|
cancelAnimationFrame(this.animationFrameHandle);
|
|
this.animationFrameHandle = void 0;
|
|
}
|
|
return;
|
|
}
|
|
this.x1 = x;
|
|
this.y1 = y;
|
|
this.t0 = Date.now();
|
|
this.animationFrameHandle ?? (this.animationFrameHandle = requestAnimationFrame(this.onFrame.bind(this)));
|
|
}
|
|
onFrame() {
|
|
this.animationFrameHandle = void 0;
|
|
const { x1, y1, t0 } = this;
|
|
const t1 = Date.now();
|
|
const dt = t1 - t0;
|
|
this.t0 = t1;
|
|
const stepT = 1e-3;
|
|
const iterations = Math.trunc(Math.ceil(dt / (stepT * 1e3)));
|
|
let { x, y, vx, vy } = this;
|
|
for (let i = 0; i < iterations; i += 1) {
|
|
const dx = x - x1;
|
|
const dy = y - y1;
|
|
const ax = -(K * dx + C * vx) / M;
|
|
const ay = -(K * dy + C * vy) / M;
|
|
vx += ax * stepT;
|
|
vy += ay * stepT;
|
|
x += vx * stepT;
|
|
y += vy * stepT;
|
|
}
|
|
if (Math.hypot(x - x1, y - y1) < DELTA) {
|
|
this.x = this.x1;
|
|
this.y = this.y1;
|
|
this.vx = 0;
|
|
this.vy = 0;
|
|
} else {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.vx = vx;
|
|
this.vy = vy;
|
|
this.animationFrameHandle = requestAnimationFrame(this.onFrame.bind(this));
|
|
}
|
|
this.emitUpdate();
|
|
}
|
|
emitUpdate() {
|
|
this.events.emit("update", { x: this.x, y: this.y });
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/tooltip/tooltipContent.ts
|
|
var import_ag_charts_core144 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/util/sanitize.ts
|
|
var import_ag_charts_core141 = require("ag-charts-core");
|
|
var element = null;
|
|
function sanitizeHtml(text) {
|
|
const plainText = (0, import_ag_charts_core141.toPlainText)(text);
|
|
if (plainText === "")
|
|
return "";
|
|
element ?? (element = (0, import_ag_charts_core141.createElement)("div"));
|
|
element.textContent = plainText;
|
|
return element.innerHTML.replaceAll("\n", "<br>");
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/marker/marker.ts
|
|
var import_ag_charts_core143 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/marker/shapes.ts
|
|
var import_ag_charts_core142 = require("ag-charts-core");
|
|
function drawMarkerUnitPolygon(params, moves) {
|
|
const { path, size } = params;
|
|
const { x: x0, y: y0 } = params;
|
|
path.clear();
|
|
let didMove = false;
|
|
for (const [dx, dy] of moves) {
|
|
const x = x0 + (dx - 0.5) * size;
|
|
const y = y0 + (dy - 0.5) * size;
|
|
if (didMove) {
|
|
path.lineTo(x, y);
|
|
} else {
|
|
path.moveTo(x, y);
|
|
}
|
|
didMove = true;
|
|
}
|
|
path.closePath();
|
|
}
|
|
var MARKER_SHAPES = {
|
|
circle({ path, x, y, size }) {
|
|
const r = size / 2;
|
|
path.arc(x, y, r, 0, Math.PI * 2);
|
|
path.closePath();
|
|
},
|
|
cross(params) {
|
|
drawMarkerUnitPolygon(params, [
|
|
[0.25, 0],
|
|
[0.5, 0.25],
|
|
[0.75, 0],
|
|
[1, 0.25],
|
|
[0.75, 0.5],
|
|
[1, 0.75],
|
|
[0.75, 1],
|
|
[0.5, 0.75],
|
|
[0.25, 1],
|
|
[0, 0.75],
|
|
[0.25, 0.5],
|
|
[0, 0.25]
|
|
]);
|
|
},
|
|
diamond(params) {
|
|
drawMarkerUnitPolygon(params, [
|
|
[0.5, 0],
|
|
[1, 0.5],
|
|
[0.5, 1],
|
|
[0, 0.5]
|
|
]);
|
|
},
|
|
heart({ path, x, y, size }) {
|
|
const r = size / 4;
|
|
y = y + r / 2;
|
|
path.arc(x - r, y - r, r, (0, import_ag_charts_core142.toRadians)(130), (0, import_ag_charts_core142.toRadians)(330));
|
|
path.arc(x + r, y - r, r, (0, import_ag_charts_core142.toRadians)(220), (0, import_ag_charts_core142.toRadians)(50));
|
|
path.lineTo(x, y + r);
|
|
path.closePath();
|
|
},
|
|
pin({ path, x, y, size: s }) {
|
|
const cx = 0.5;
|
|
const cy = 0.5;
|
|
path.moveTo(x + (0.891 - cx) * s, y + (0.391 - cy) * s);
|
|
path.cubicCurveTo(
|
|
x + (0.891 - cx) * s,
|
|
y + (0.606 - cy) * s,
|
|
x + (0.5 - cx) * s,
|
|
y + (1 - cy) * s,
|
|
x + (0.5 - cx) * s,
|
|
y + (1 - cy) * s
|
|
);
|
|
path.cubicCurveTo(
|
|
x + (0.5 - cx) * s,
|
|
y + (1 - cy) * s,
|
|
x + (0.109 - cx) * s,
|
|
y + (0.606 - cy) * s,
|
|
x + (0.109 - cx) * s,
|
|
y + (0.391 - cy) * s
|
|
);
|
|
path.cubicCurveTo(
|
|
x + (0.109 - cx) * s,
|
|
y + (0.175 - cy) * s,
|
|
x + (0.284 - cx) * s,
|
|
y + (0 - cy) * s,
|
|
x + (0.5 - cx) * s,
|
|
y + (0 - cy) * s
|
|
);
|
|
path.cubicCurveTo(
|
|
x + (0.716 - cx) * s,
|
|
y + (0 - cy) * s,
|
|
x + (0.891 - cx) * s,
|
|
y + (0.175 - cy) * s,
|
|
x + (0.891 - cx) * s,
|
|
y + (0.391 - cy) * s
|
|
);
|
|
path.closePath();
|
|
},
|
|
plus(params) {
|
|
drawMarkerUnitPolygon(params, [
|
|
[1 / 3, 0],
|
|
[2 / 3, 0],
|
|
[2 / 3, 1 / 3],
|
|
[1, 1 / 3],
|
|
[1, 2 / 3],
|
|
[2 / 3, 2 / 3],
|
|
[2 / 3, 1],
|
|
[1 / 3, 1],
|
|
[1 / 3, 2 / 3],
|
|
[0, 2 / 3],
|
|
[0, 1 / 3],
|
|
[1 / 3, 1 / 3]
|
|
]);
|
|
},
|
|
square({ path, x, y, size, pixelRatio }) {
|
|
const hs = size / 2;
|
|
path.moveTo(align(pixelRatio, x - hs), align(pixelRatio, y - hs));
|
|
path.lineTo(align(pixelRatio, x + hs), align(pixelRatio, y - hs));
|
|
path.lineTo(align(pixelRatio, x + hs), align(pixelRatio, y + hs));
|
|
path.lineTo(align(pixelRatio, x - hs), align(pixelRatio, y + hs));
|
|
path.closePath();
|
|
},
|
|
star({ path, x, y, size }) {
|
|
const spikes = 5;
|
|
const outerRadius = size / 2;
|
|
const innerRadius = outerRadius / 2;
|
|
const rotation = Math.PI / 2;
|
|
for (let i = 0; i < spikes * 2; i++) {
|
|
const radius = i % 2 === 0 ? outerRadius : innerRadius;
|
|
const angle = i * Math.PI / spikes - rotation;
|
|
const xCoordinate = x + Math.cos(angle) * radius;
|
|
const yCoordinate = y + Math.sin(angle) * radius;
|
|
path.lineTo(xCoordinate, yCoordinate);
|
|
}
|
|
path.closePath();
|
|
},
|
|
triangle(params) {
|
|
drawMarkerUnitPolygon(params, [
|
|
[0.5, 0],
|
|
[1, 0.87],
|
|
[0, 0.87]
|
|
]);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/marker/marker.ts
|
|
var InternalMarker = class extends Path {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.shape = "square";
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.size = 12;
|
|
}
|
|
// optimised field accessor
|
|
isPointInPath(x, y) {
|
|
return this.distanceSquared(x, y) <= 0;
|
|
}
|
|
get midPoint() {
|
|
return { x: this.x, y: this.y };
|
|
}
|
|
distanceSquared(x, y) {
|
|
const anchor = Marker.anchor(this.shape);
|
|
const dx = x - this.x + (anchor.x - 0.5) * this.size;
|
|
const dy = y - this.y + (anchor.y - 0.5) * this.size;
|
|
const radius = this.size / 2;
|
|
return Math.max(dx * dx + dy * dy - radius * radius, 0);
|
|
}
|
|
updatePath() {
|
|
const { path, shape, x, y, size } = this;
|
|
const pixelRatio = this.layerManager?.canvas?.pixelRatio ?? 1;
|
|
const anchor = Marker.anchor(shape);
|
|
const drawParams = {
|
|
path,
|
|
x: x - (anchor.x - 0.5) * size,
|
|
y: y - (anchor.y - 0.5) * size,
|
|
size,
|
|
pixelRatio
|
|
};
|
|
path.clear();
|
|
if (typeof shape === "string") {
|
|
MARKER_SHAPES[shape](drawParams);
|
|
} else if (typeof shape === "function") {
|
|
shape(drawParams);
|
|
}
|
|
}
|
|
computeBBox() {
|
|
const { x, y, size } = this;
|
|
const anchor = Marker.anchor(this.shape);
|
|
return new BBox(x - size * anchor.x, y - size * anchor.y, size, size);
|
|
}
|
|
executeFill(ctx, path) {
|
|
if (!path)
|
|
return;
|
|
return super.executeFill(ctx, path);
|
|
}
|
|
executeStroke(ctx, path) {
|
|
if (!path)
|
|
return;
|
|
return super.executeStroke(ctx, path);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core143.DeclaredSceneObjectChangeDetection)({ equals: import_ag_charts_core143.TRIPLE_EQ })
|
|
], InternalMarker.prototype, "shape", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core143.DeclaredSceneChangeDetection)()
|
|
], InternalMarker.prototype, "x", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core143.DeclaredSceneChangeDetection)()
|
|
], InternalMarker.prototype, "y", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core143.DeclaredSceneChangeDetection)({ convertor: Math.abs })
|
|
], InternalMarker.prototype, "size", 2);
|
|
var Marker = class extends Rotatable(Scalable(Translatable(InternalMarker))) {
|
|
static anchor(shape) {
|
|
if (shape === "pin") {
|
|
return { x: 0.5, y: 1 };
|
|
} else if (typeof shape === "function" && "anchor" in shape) {
|
|
return shape.anchor;
|
|
}
|
|
return { x: 0.5, y: 0.5 };
|
|
}
|
|
constructor(options) {
|
|
super(options);
|
|
if (options?.shape != null) {
|
|
this.shape = options.shape;
|
|
}
|
|
}
|
|
/**
|
|
* Optimised reset for animation hot paths.
|
|
* Bypasses SceneChangeDetection decorators by writing directly to backing fields.
|
|
*
|
|
* This avoids per-property overhead from:
|
|
* - Equality checks (comparing old vs new values)
|
|
* - Change callbacks (triggering downstream updates)
|
|
* - Object.keys() iteration
|
|
*
|
|
* A single markDirty() call at the end ensures the scene graph is properly invalidated.
|
|
* WARNING: Only use for animation hot paths where performance is critical.
|
|
*/
|
|
resetAnimationProperties(x, y, size, opacity, scalingX, scalingY) {
|
|
this.__x = x;
|
|
this.__y = y;
|
|
this.__size = size;
|
|
this.__opacity = opacity;
|
|
this.resetScalingProperties(scalingX, scalingY, x, y);
|
|
this.dirtyPath = true;
|
|
this.markDirty();
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/legend/legendSymbol.ts
|
|
function legendSymbolSvg(symbol, size, lineSize = size * (5 / 3)) {
|
|
const group = new Group();
|
|
const markerStrokeWidth = Math.min(symbol.marker.strokeWidth ?? 1, 2);
|
|
const lineStrokeWidth = symbol.line?.enabled ? Math.min(symbol.line.strokeWidth, 2) : 0;
|
|
const width = Math.max(symbol.marker.enabled === false ? 0 : size, symbol.line == null ? 0 : lineSize);
|
|
const height = Math.max(symbol.marker.enabled === false ? 0 : size, lineStrokeWidth);
|
|
if (symbol.line?.enabled) {
|
|
const { stroke, strokeOpacity, lineDash } = symbol.line;
|
|
const line = new Line();
|
|
line.x1 = 0;
|
|
line.y1 = height / 2;
|
|
line.x2 = width;
|
|
line.y2 = height / 2;
|
|
line.stroke = stroke;
|
|
line.strokeOpacity = strokeOpacity;
|
|
line.strokeWidth = lineStrokeWidth;
|
|
line.lineDash = lineDash;
|
|
group.append(line);
|
|
}
|
|
if (symbol.marker.enabled !== false) {
|
|
const { shape, fill, fillOpacity, stroke, strokeOpacity, lineDash, lineDashOffset } = symbol.marker;
|
|
const marker = new Marker();
|
|
marker.shape = shape ?? "square";
|
|
marker.size = size;
|
|
marker.fill = fill;
|
|
marker.fillOpacity = fillOpacity ?? 1;
|
|
marker.stroke = stroke;
|
|
marker.strokeOpacity = strokeOpacity ?? 1;
|
|
marker.strokeWidth = markerStrokeWidth;
|
|
marker.lineDash = lineDash;
|
|
marker.lineDashOffset = lineDashOffset ?? 0;
|
|
const anchor = Marker.anchor(shape);
|
|
const x = width / 2 + (anchor.x - 0.5) * size;
|
|
const y = height / 2 + (anchor.y - 0.5) * size;
|
|
const scale2 = size / (size + markerStrokeWidth);
|
|
marker.x = x;
|
|
marker.y = y;
|
|
marker.scalingCenterX = x;
|
|
marker.scalingCenterY = y;
|
|
marker.scalingX = scale2;
|
|
marker.scalingY = scale2;
|
|
group.append(marker);
|
|
}
|
|
return Group.toSVG(group, width, height);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/tooltip/tooltipContent.ts
|
|
var DEFAULT_TOOLTIP_CLASS = "ag-charts-tooltip";
|
|
var DEFAULT_TOOLTIP_DARK_CLASS = "ag-charts-tooltip--dark";
|
|
function textOrSegmentsIsDefined(value) {
|
|
if (value == null) {
|
|
return false;
|
|
} else if (Array.isArray(value)) {
|
|
return value.some((segment) => textOrSegmentsIsDefined(segment.text));
|
|
} else {
|
|
return (0, import_ag_charts_core144.toTextString)(value).trim() !== "";
|
|
}
|
|
}
|
|
function isTooltipValueMissing(value, allowNull = false) {
|
|
if (value == null)
|
|
return !allowNull;
|
|
return typeof value === "number" && !Number.isFinite(value);
|
|
}
|
|
function hasAllMissingData(content) {
|
|
if (content.type === "raw")
|
|
return false;
|
|
if (!content.data || content.data.length === 0)
|
|
return false;
|
|
return content.data.every((datum) => datum.missing === true);
|
|
}
|
|
function aggregateTooltipContent(content) {
|
|
const out = [];
|
|
const groupedContents = /* @__PURE__ */ new Map();
|
|
for (const item of content) {
|
|
if (hasAllMissingData(item))
|
|
continue;
|
|
if (item.type === "structured") {
|
|
const { heading } = item;
|
|
const insertionTarget = textOrSegmentsIsDefined(heading) ? groupedContents.get(heading) : void 0;
|
|
const groupedItem = { type: "structured", heading, items: [item] };
|
|
if (insertionTarget == null) {
|
|
groupedContents.set(heading, groupedItem);
|
|
out.push(groupedItem);
|
|
} else {
|
|
insertionTarget.items.push(item);
|
|
}
|
|
} else {
|
|
out.push(item);
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
function tooltipContentAriaLabel(ungroupedContent) {
|
|
const content = aggregateTooltipContent(ungroupedContent);
|
|
const ariaLabel = [];
|
|
for (const c of content) {
|
|
if (c.type === "raw") {
|
|
continue;
|
|
}
|
|
if (textOrSegmentsIsDefined(c.heading)) {
|
|
ariaLabel.push((0, import_ag_charts_core144.toPlainText)(c.heading));
|
|
}
|
|
for (const i of c.items) {
|
|
if (textOrSegmentsIsDefined(i.title)) {
|
|
ariaLabel.push((0, import_ag_charts_core144.toPlainText)(i.title));
|
|
}
|
|
if (i.data) {
|
|
for (const datum of i.data) {
|
|
if (datum.missing === true)
|
|
continue;
|
|
ariaLabel.push(datum.label ?? datum.fallbackLabel, (0, import_ag_charts_core144.toPlainText)(datum.value));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ariaLabel.filter((s) => s !== "").join("; ");
|
|
}
|
|
function dataHtml(label, value, inline) {
|
|
let rowHtml = "";
|
|
if (textOrSegmentsIsDefined(label)) {
|
|
rowHtml += `<span class="${DEFAULT_TOOLTIP_CLASS}-label">${sanitizeHtml(label)}</span>`;
|
|
rowHtml += " ";
|
|
rowHtml += `<span class="${DEFAULT_TOOLTIP_CLASS}-value">${sanitizeHtml(value)}</span>`;
|
|
} else {
|
|
rowHtml += `<span class="${DEFAULT_TOOLTIP_CLASS}-label">${sanitizeHtml(value)}</span>`;
|
|
}
|
|
const rowClassNames = [`${DEFAULT_TOOLTIP_CLASS}-row`];
|
|
if (inline)
|
|
rowClassNames.push(`${DEFAULT_TOOLTIP_CLASS}-row--inline`);
|
|
rowHtml = `<div class="${rowClassNames.join(" ")}">${rowHtml}</div>`;
|
|
return rowHtml;
|
|
}
|
|
function tooltipRowContentHtml(content) {
|
|
let html = "";
|
|
if (content.data?.length && content.data.every((datum) => datum.missing === true)) {
|
|
return html;
|
|
}
|
|
const titleDefined = textOrSegmentsIsDefined(content.title);
|
|
const dataInline = !titleDefined && content.data?.length === 1;
|
|
const symbol = content.symbol == null ? void 0 : legendSymbolSvg(content.symbol, 12);
|
|
if (symbol != null && (titleDefined || content.data?.length)) {
|
|
html += `<span class="${DEFAULT_TOOLTIP_CLASS}-symbol">${symbol}</span>`;
|
|
}
|
|
if (titleDefined) {
|
|
html += `<span class="${DEFAULT_TOOLTIP_CLASS}-title">${sanitizeHtml(content.title)}</span>`;
|
|
html += " ";
|
|
}
|
|
if (content.data) {
|
|
for (const datum of content.data) {
|
|
if (datum.missing === true)
|
|
continue;
|
|
html += dataHtml(datum.label ?? datum.fallbackLabel, (0, import_ag_charts_core144.toPlainText)(datum.value), dataInline);
|
|
html += " ";
|
|
}
|
|
}
|
|
return html;
|
|
}
|
|
function tooltipPaginationContentHtml(localeManager, pagination) {
|
|
if (localeManager == null || pagination.length === 1)
|
|
return;
|
|
const text = localeManager?.t("tooltipPaginationStatus", {
|
|
index: pagination.index + 1,
|
|
count: pagination.length
|
|
});
|
|
return `<div class="${DEFAULT_TOOLTIP_CLASS}-footer">${text}</div>`;
|
|
}
|
|
function tooltipContentHtml(localeManager, content, mode, pagination) {
|
|
const singleItem = content.items.length === 1 ? content.items[0] : void 0;
|
|
let compact;
|
|
let compactTitle;
|
|
let compactFallbackLabel;
|
|
switch (mode) {
|
|
case "compact":
|
|
compact = true;
|
|
compactTitle = (0, import_ag_charts_core144.toPlainText)(singleItem?.title);
|
|
break;
|
|
case "single":
|
|
const headingDefined = textOrSegmentsIsDefined(content.heading);
|
|
compact = singleItem != null && (!headingDefined || singleItem.title == null) && singleItem.data?.length === 1 && singleItem.data[0].label == null && singleItem.data[0].value != null;
|
|
compactFallbackLabel = (0, import_ag_charts_core144.toPlainText)(headingDefined ? content.heading : singleItem?.title);
|
|
break;
|
|
case "shared":
|
|
compact = false;
|
|
}
|
|
let html = "";
|
|
if (compact && singleItem != null) {
|
|
if (textOrSegmentsIsDefined(compactTitle)) {
|
|
html += `<span class="${DEFAULT_TOOLTIP_CLASS}-title">${sanitizeHtml(compactTitle)}</span>`;
|
|
}
|
|
if (singleItem.data) {
|
|
for (const datum of singleItem.data) {
|
|
if (datum.missing === true)
|
|
continue;
|
|
html += dataHtml(datum.label ?? compactFallbackLabel, (0, import_ag_charts_core144.toPlainText)(datum.value), false);
|
|
html += " ";
|
|
}
|
|
}
|
|
} else {
|
|
if (textOrSegmentsIsDefined(content.heading)) {
|
|
html += `<span class="${DEFAULT_TOOLTIP_CLASS}-heading">${sanitizeHtml((0, import_ag_charts_core144.toPlainText)(content.heading))}</span>`;
|
|
html += " ";
|
|
}
|
|
for (const item of content.items) {
|
|
html += tooltipRowContentHtml(item);
|
|
}
|
|
}
|
|
if (html.length === 0)
|
|
return;
|
|
const paginationContent = mode !== "compact" && pagination != null ? tooltipPaginationContentHtml(localeManager, pagination) : void 0;
|
|
if (paginationContent + null) {
|
|
html += paginationContent;
|
|
}
|
|
html = `<div class="${DEFAULT_TOOLTIP_CLASS}-content">${html.trimEnd()}</div>`;
|
|
return html;
|
|
}
|
|
function tooltipPaginationHtml(localeManager, pagination) {
|
|
const paginationContent = pagination == null ? void 0 : tooltipPaginationContentHtml(localeManager, pagination);
|
|
if (paginationContent == null)
|
|
return "";
|
|
return `<div class="${DEFAULT_TOOLTIP_CLASS}-content">${paginationContent}</div>`;
|
|
}
|
|
function tooltipHtml(localeManager, content, mode, pagination) {
|
|
const aggregatedContent = aggregateTooltipContent(content);
|
|
if (aggregatedContent.length === 0)
|
|
return;
|
|
if (aggregatedContent.length === 1 && aggregatedContent[0].type === "structured") {
|
|
return tooltipContentHtml(localeManager, aggregatedContent[0], mode, pagination);
|
|
} else {
|
|
const htmlRows = aggregatedContent.map((c) => {
|
|
return c.type === "structured" ? tooltipContentHtml(localeManager, c, mode) : c.rawHtmlString;
|
|
});
|
|
if (pagination != null) {
|
|
htmlRows.push(tooltipPaginationHtml(localeManager, pagination) ?? "");
|
|
}
|
|
return htmlRows.join("");
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/tooltip/tooltip.ts
|
|
var horizontalAlignments = {
|
|
left: -1,
|
|
"top-left": -1,
|
|
"bottom-left": -1,
|
|
top: 0,
|
|
center: 0,
|
|
bottom: 0,
|
|
right: 1,
|
|
"top-right": 1,
|
|
"bottom-right": 1
|
|
};
|
|
var verticalAlignments = {
|
|
"top-left": -1,
|
|
top: -1,
|
|
"top-right": -1,
|
|
left: 0,
|
|
center: 0,
|
|
right: 0,
|
|
"bottom-left": 1,
|
|
bottom: 1,
|
|
"bottom-right": 1
|
|
};
|
|
var arrowPositions = {
|
|
left: 3 /* Right */,
|
|
"top-left": void 0,
|
|
"bottom-left": void 0,
|
|
top: 2 /* Bottom */,
|
|
center: void 0,
|
|
bottom: 1 /* Top */,
|
|
right: 0 /* Left */,
|
|
"top-right": void 0,
|
|
"bottom-right": void 0
|
|
};
|
|
var directionChecks = {
|
|
top: 2 /* Vertical */,
|
|
bottom: 2 /* Vertical */,
|
|
left: 1 /* Horizontal */,
|
|
right: 1 /* Horizontal */,
|
|
"top-right": 3 /* Both */,
|
|
"top-left": 3 /* Both */,
|
|
"bottom-right": 3 /* Both */,
|
|
"bottom-left": 3 /* Both */,
|
|
center: 0 /* None */
|
|
};
|
|
var defaultPlacements = {
|
|
pointer: "top",
|
|
node: "top",
|
|
chart: "top-left"
|
|
};
|
|
var TooltipPosition = class extends import_ag_charts_core145.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
/** The horizontal offset in pixels for the position of the tooltip. */
|
|
this.xOffset = 0;
|
|
/** The vertical offset in pixels for the position of the tooltip. */
|
|
this.yOffset = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], TooltipPosition.prototype, "xOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], TooltipPosition.prototype, "yOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], TooltipPosition.prototype, "anchorTo", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], TooltipPosition.prototype, "placement", 2);
|
|
var Tooltip = class extends import_ag_charts_core145.BaseProperties {
|
|
constructor() {
|
|
super();
|
|
this.enabled = true;
|
|
this.mode = "single";
|
|
this.delay = 0;
|
|
this.range = void 0;
|
|
this.wrapping = "hyphenate";
|
|
this.position = new TooltipPosition();
|
|
this.pagination = false;
|
|
this.darkTheme = false;
|
|
this.bounds = "extended";
|
|
this.cleanup = new import_ag_charts_core145.CleanupRegistry();
|
|
this.springAnimation = new SpringAnimation();
|
|
this.enableInteraction = false;
|
|
this.wrapTypes = ["always", "hyphenate", "on-space", "never"];
|
|
this.sizeMonitor = new SizeMonitor();
|
|
// Reading the element size is expensive, so cache the result
|
|
this._elementSize = void 0;
|
|
this._showTimeout = void 0;
|
|
this.arrowPosition = void 0;
|
|
this._visible = false;
|
|
this.positionParams = void 0;
|
|
this.localeManager = void 0;
|
|
this.cleanup.register(this.springAnimation.events.on("update", this.updateTooltipPosition.bind(this)));
|
|
}
|
|
get interactive() {
|
|
return this.enableInteraction;
|
|
}
|
|
setup(localeManager, domManager) {
|
|
if ("togglePopover" in (0, import_ag_charts_core145.getWindow)().HTMLElement.prototype) {
|
|
this.element = domManager.addChild("tooltip-container", DEFAULT_TOOLTIP_CLASS);
|
|
this.element.setAttribute("popover", "manual");
|
|
this.element.className = DEFAULT_TOOLTIP_CLASS;
|
|
this.element.style.positionAnchor = domManager.anchorName;
|
|
this.sizeMonitor.observe(this.element, (size) => {
|
|
this._elementSize = size;
|
|
this.updateTooltipPosition();
|
|
});
|
|
}
|
|
this.localeManager = localeManager;
|
|
return () => {
|
|
domManager.removeChild("tooltip-container", DEFAULT_TOOLTIP_CLASS);
|
|
this.cleanup.flush();
|
|
if (this.element) {
|
|
this.sizeMonitor.unobserve(this.element);
|
|
}
|
|
};
|
|
}
|
|
isVisible() {
|
|
return this._visible;
|
|
}
|
|
contains(node) {
|
|
return this.element?.contains(node) ?? false;
|
|
}
|
|
updateTooltipPosition() {
|
|
const { element: element2, _elementSize: elementSize, positionParams } = this;
|
|
if (element2 == null || elementSize == null || positionParams == null)
|
|
return;
|
|
const { canvasRect, relativeRect, meta } = positionParams;
|
|
const { x: canvasX, y: canvasY } = this.springAnimation;
|
|
const anchorTo = meta.position?.anchorTo ?? "pointer";
|
|
let placements2 = meta.position?.placement ?? defaultPlacements[anchorTo];
|
|
if (!Array.isArray(placements2)) {
|
|
placements2 = [placements2];
|
|
}
|
|
const xOffset = meta.position?.xOffset ?? 0;
|
|
const yOffset = meta.position?.yOffset ?? 0;
|
|
const minX = relativeRect.x;
|
|
const minY = relativeRect.y;
|
|
const maxX = relativeRect.width - elementSize.width - 1 + minX;
|
|
const maxY = relativeRect.height - elementSize.height + minY;
|
|
let i = 0;
|
|
let placement;
|
|
let position;
|
|
let constrained = false;
|
|
do {
|
|
placement = placements2[i];
|
|
i += 1;
|
|
const tooltipBounds = this.getTooltipBounds({
|
|
elementSize,
|
|
placement,
|
|
anchorTo,
|
|
canvasX,
|
|
canvasY,
|
|
yOffset,
|
|
xOffset,
|
|
canvasRect
|
|
});
|
|
position = (0, import_ag_charts_core145.calculatePlacement)(elementSize.width, elementSize.height, relativeRect, tooltipBounds);
|
|
constrained = false;
|
|
if (directionChecks[placement] & 1 /* Horizontal */) {
|
|
constrained || (constrained = position.x < minX || position.x > maxX);
|
|
}
|
|
if (directionChecks[placement] & 2 /* Vertical */) {
|
|
constrained || (constrained = position.y < minY || position.y > maxY);
|
|
}
|
|
} while (i < placements2.length && constrained);
|
|
const left = (0, import_ag_charts_core145.clamp)(minX, position.x, maxX);
|
|
const top = (0, import_ag_charts_core145.clamp)(minY, position.y, maxY);
|
|
constrained || (constrained = left !== position.x || top !== position.y);
|
|
const defaultShowArrow = anchorTo !== "chart" && !constrained && !xOffset && !yOffset;
|
|
const showArrow = meta.showArrow ?? this.showArrow ?? defaultShowArrow;
|
|
this.arrowPosition = showArrow ? arrowPositions[placement] : void 0;
|
|
this.updateClassModifiers();
|
|
element2.style.translate = `${left}px ${top}px`;
|
|
}
|
|
/**
|
|
* Shows tooltip at the given event's coordinates.
|
|
* If the `html` parameter is missing, moves the existing tooltip to the new position.
|
|
*/
|
|
show(boundingRect, canvasRect, meta, content, pagination, instantly = false) {
|
|
const { element: element2 } = this;
|
|
if (element2 != null && content != null && content.length !== 0) {
|
|
const html = tooltipHtml(this.localeManager, content, this.mode, this.pagination ? pagination : void 0);
|
|
if (html == null) {
|
|
element2.innerHTML = "";
|
|
this.toggle(false);
|
|
return;
|
|
}
|
|
element2.innerHTML = html;
|
|
} else if (element2 == null || element2.innerHTML === "") {
|
|
this.toggle(false);
|
|
return;
|
|
}
|
|
const relativeRect = {
|
|
x: boundingRect.x - canvasRect.x,
|
|
y: boundingRect.y - canvasRect.y,
|
|
width: boundingRect.width,
|
|
height: boundingRect.height
|
|
};
|
|
this.positionParams = {
|
|
canvasRect,
|
|
relativeRect,
|
|
meta
|
|
};
|
|
const anchorTo = meta.position?.anchorTo ?? "pointer";
|
|
switch (anchorTo) {
|
|
case "node":
|
|
this.springAnimation.update(meta.nodeCanvasX ?? meta.canvasX, meta.nodeCanvasY ?? meta.canvasY);
|
|
break;
|
|
case "pointer":
|
|
this.springAnimation.update(meta.canvasX, meta.canvasY);
|
|
break;
|
|
case "chart":
|
|
this.springAnimation.reset();
|
|
}
|
|
if (meta.enableInteraction) {
|
|
this.enableInteraction = true;
|
|
element2.style.pointerEvents = "auto";
|
|
element2.removeAttribute("aria-hidden");
|
|
element2.tabIndex = -1;
|
|
} else {
|
|
this.enableInteraction = false;
|
|
element2.style.pointerEvents = "none";
|
|
element2.setAttribute("aria-hidden", "true");
|
|
element2.removeAttribute("tabindex");
|
|
}
|
|
element2.style.setProperty("--top", `${canvasRect.top}px`);
|
|
element2.style.setProperty("--left", `${canvasRect.left}px`);
|
|
this.updateClassModifiers();
|
|
this.toggle(true, instantly);
|
|
}
|
|
hide() {
|
|
this.toggle(false);
|
|
}
|
|
maybeEnterInteractiveTooltip({ relatedTarget }, callback4) {
|
|
const { interactive, interactiveLeave, enabled, element: element2 } = this;
|
|
if (element2 == null)
|
|
return false;
|
|
if (interactiveLeave)
|
|
return true;
|
|
const isEntering = interactive && enabled && this.isVisible() && (0, import_ag_charts_core145.isNode)(relatedTarget) && this.contains(relatedTarget);
|
|
if (isEntering) {
|
|
this.interactiveLeave = {
|
|
callback: callback4,
|
|
listener: (popoverEvent) => {
|
|
const isLeaving = popoverEvent.relatedTarget == null || (0, import_ag_charts_core145.isNode)(popoverEvent.relatedTarget) && !this.contains(popoverEvent.relatedTarget);
|
|
if (isLeaving) {
|
|
this.popInteractiveLeaveCallback();
|
|
}
|
|
}
|
|
};
|
|
element2.addEventListener("focusout", this.interactiveLeave.listener);
|
|
element2.addEventListener("mouseout", this.interactiveLeave.listener);
|
|
}
|
|
return isEntering;
|
|
}
|
|
popInteractiveLeaveCallback() {
|
|
const { interactiveLeave, element: element2 } = this;
|
|
this.interactiveLeave = void 0;
|
|
if (interactiveLeave) {
|
|
if (element2) {
|
|
element2.removeEventListener("focusout", interactiveLeave.listener);
|
|
element2.removeEventListener("mouseout", interactiveLeave.listener);
|
|
}
|
|
interactiveLeave.callback();
|
|
}
|
|
}
|
|
toggle(visible, instantly = false) {
|
|
const { delay } = this;
|
|
if (visible && delay > 0 && !instantly) {
|
|
this._showTimeout ?? (this._showTimeout = setTimeout(() => {
|
|
this._showTimeout = void 0;
|
|
this.toggleCallback(true);
|
|
}, delay));
|
|
} else {
|
|
clearTimeout(this._showTimeout);
|
|
this._showTimeout = void 0;
|
|
this.toggleCallback(visible);
|
|
}
|
|
}
|
|
toggleCallback(visible) {
|
|
if (!this.element?.isConnected)
|
|
return;
|
|
if (this._visible === visible)
|
|
return;
|
|
this._visible = visible;
|
|
this.element.togglePopover(visible);
|
|
if (visible) {
|
|
this.updateTooltipPosition();
|
|
} else {
|
|
this.springAnimation.reset();
|
|
this.popInteractiveLeaveCallback();
|
|
}
|
|
}
|
|
updateClassModifiers() {
|
|
if (!this.element?.isConnected)
|
|
return;
|
|
const { classList } = this.element;
|
|
const toggleClass = (name, include) => classList.toggle(`${DEFAULT_TOOLTIP_CLASS}--${name}`, include);
|
|
toggleClass("no-interaction", !this.enableInteraction);
|
|
toggleClass("arrow-top", this.arrowPosition === 1 /* Top */);
|
|
toggleClass("arrow-right", this.arrowPosition === 3 /* Right */);
|
|
toggleClass("arrow-bottom", this.arrowPosition === 2 /* Bottom */);
|
|
toggleClass("arrow-left", this.arrowPosition === 0 /* Left */);
|
|
toggleClass("compact", this.mode === "compact");
|
|
classList.toggle(DEFAULT_TOOLTIP_DARK_CLASS, this.darkTheme);
|
|
for (const wrapType of this.wrapTypes) {
|
|
classList.toggle(`${DEFAULT_TOOLTIP_CLASS}--wrap-${wrapType}`, wrapType === this.wrapping);
|
|
}
|
|
}
|
|
getTooltipBounds(opts) {
|
|
const { elementSize, anchorTo, placement, canvasX, canvasY, yOffset, xOffset, canvasRect } = opts;
|
|
const { width: tooltipWidth, height: tooltipHeight } = elementSize;
|
|
const bounds = { width: tooltipWidth, height: tooltipHeight };
|
|
if (anchorTo === "node" || anchorTo === "pointer") {
|
|
const horizontalAlignment = horizontalAlignments[placement];
|
|
const verticalAlignment = verticalAlignments[placement];
|
|
bounds.top = canvasY + yOffset + tooltipHeight * (verticalAlignment - 1) / 2 + 8 * verticalAlignment;
|
|
bounds.left = canvasX + xOffset + tooltipWidth * (horizontalAlignment - 1) / 2 + 8 * horizontalAlignment;
|
|
return bounds;
|
|
}
|
|
switch (placement) {
|
|
case "top": {
|
|
bounds.top = yOffset;
|
|
bounds.left = canvasRect.width / 2 - tooltipWidth / 2 + xOffset;
|
|
return bounds;
|
|
}
|
|
case "right": {
|
|
bounds.top = canvasRect.height / 2 - tooltipHeight / 2 + yOffset;
|
|
bounds.left = canvasRect.width - tooltipWidth + xOffset;
|
|
return bounds;
|
|
}
|
|
case "left": {
|
|
bounds.top = canvasRect.height / 2 - tooltipHeight / 2 + yOffset;
|
|
bounds.left = xOffset;
|
|
return bounds;
|
|
}
|
|
case "bottom": {
|
|
bounds.top = canvasRect.height - tooltipHeight + yOffset;
|
|
bounds.left = canvasRect.width / 2 - tooltipWidth / 2 + xOffset;
|
|
return bounds;
|
|
}
|
|
case "top-left": {
|
|
bounds.top = yOffset;
|
|
bounds.left = xOffset;
|
|
return bounds;
|
|
}
|
|
case "top-right": {
|
|
bounds.top = yOffset;
|
|
bounds.left = canvasRect.width - tooltipWidth + xOffset;
|
|
return bounds;
|
|
}
|
|
case "bottom-right": {
|
|
bounds.top = canvasRect.height - tooltipHeight + yOffset;
|
|
bounds.left = canvasRect.width - tooltipWidth + xOffset;
|
|
return bounds;
|
|
}
|
|
case "bottom-left": {
|
|
bounds.top = canvasRect.height - tooltipHeight + yOffset;
|
|
bounds.left = xOffset;
|
|
return bounds;
|
|
}
|
|
}
|
|
return bounds;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "mode", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "showArrow", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "delay", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "range", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "wrapping", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "position", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "pagination", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "darkTheme", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core145.Property
|
|
], Tooltip.prototype, "bounds", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/pickManager.ts
|
|
var import_ag_charts_core146 = require("ag-charts-core");
|
|
function getItemId(node) {
|
|
if (node.datum.itemId !== void 0) {
|
|
return node.datum.itemId;
|
|
} else if (typeof node.datum.datumIndex === "number") {
|
|
return node.datum.datumIndex;
|
|
} else {
|
|
return JSON.stringify(node.datum.datumIndex);
|
|
}
|
|
}
|
|
function pickedNodesEqual(a, b) {
|
|
return a.series === b.series && (0, import_ag_charts_core146.objectsEqual)(a.datumIndex, b.datumIndex);
|
|
}
|
|
function indexOf(candidates, node) {
|
|
return node == void 0 ? -1 : candidates.findIndex((c) => pickedNodesEqual(c, node));
|
|
}
|
|
var PickManager = class {
|
|
constructor(activeManager, tooltipProperties, focusState) {
|
|
this.activeManager = activeManager;
|
|
this.tooltipProperties = tooltipProperties;
|
|
this.focusState = focusState;
|
|
this.candidates = [];
|
|
this.activeState = new StateTracker();
|
|
}
|
|
getActive() {
|
|
return this.activeState.stateValue();
|
|
}
|
|
clear() {
|
|
this.activeState.clear();
|
|
this.lastNotifiedActive = void 0;
|
|
this.candidates.length = 0;
|
|
this.pendingPickedNodes = void 0;
|
|
}
|
|
setSource(source, node) {
|
|
if (node === void 0) {
|
|
this.activeState.delete(source);
|
|
} else {
|
|
this.activeState.set(source, node);
|
|
}
|
|
this.syncActiveManager();
|
|
}
|
|
syncActiveManager() {
|
|
const resolved = this.getActive();
|
|
const prev = this.lastNotifiedActive;
|
|
if (resolved === prev)
|
|
return;
|
|
if (resolved !== void 0 && prev !== void 0 && pickedNodesEqual(resolved, prev))
|
|
return;
|
|
this.lastNotifiedActive = resolved;
|
|
if (resolved === void 0) {
|
|
this.activeManager.clear();
|
|
} else {
|
|
const seriesId = resolved.series.id;
|
|
const itemId = getItemId(resolved);
|
|
this.activeManager.update({ type: "series-node", seriesId, itemId }, resolved.datum);
|
|
}
|
|
}
|
|
popPendingPickedNodes() {
|
|
const result = this.pendingPickedNodes;
|
|
this.pendingPickedNodes = void 0;
|
|
return result;
|
|
}
|
|
// Some user interactive (e.g. mouseleave, blur) has cleared the active datum.
|
|
onClearUI() {
|
|
this.activeManager.clear();
|
|
this.clear();
|
|
}
|
|
// Active datum was cleared by ActiveManager (`setState` or legend).
|
|
onClearAPI() {
|
|
this.clear();
|
|
}
|
|
onPickedNodesHighlight(pickedNodes) {
|
|
if (pickedNodes !== void 0) {
|
|
const previousActive = this.getActive();
|
|
if (this.tooltipProperties.pagination && previousActive !== void 0) {
|
|
const tooltipMatch = pickedNodes.matches.find((m) => pickedNodesEqual(m, previousActive));
|
|
if (tooltipMatch) {
|
|
return tooltipMatch;
|
|
}
|
|
}
|
|
}
|
|
const node = pickedNodes?.matches[0];
|
|
this.setSource("highlight", node);
|
|
return node;
|
|
}
|
|
onPickedNodesTooltip(pickedNodes) {
|
|
if (pickedNodes !== void 0 && this.tooltipProperties.pagination) {
|
|
const previous = this.getActive();
|
|
const nextCandidates = pickedNodes.matches;
|
|
this.candidates = nextCandidates;
|
|
let nextIndex = indexOf(nextCandidates, previous);
|
|
if (nextIndex === -1)
|
|
nextIndex = 0;
|
|
const node2 = nextCandidates[nextIndex];
|
|
this.setSource("tooltip", node2);
|
|
const paginationState = { index: nextIndex, length: nextCandidates.length };
|
|
return { active: node2, paginationState };
|
|
}
|
|
const node = pickedNodes?.matches[0];
|
|
this.setSource("tooltip", node);
|
|
return { active: node };
|
|
}
|
|
onPickedNodesFocus(pickedFocus) {
|
|
const { series } = this.focusState;
|
|
this.clear();
|
|
if (series !== void 0 && pickedFocus !== void 0) {
|
|
const { datum, datumIndex } = pickedFocus;
|
|
this.setSource("focus", { series, datum, datumIndex });
|
|
}
|
|
}
|
|
onPickedNodesAPI(debouncedPickedNodes) {
|
|
this.pendingPickedNodes = debouncedPickedNodes;
|
|
return debouncedPickedNodes.matches[0];
|
|
}
|
|
onPickedNodesAPIDebounced() {
|
|
return { active: this.onPickedNodesHighlight(this.popPendingPickedNodes()) };
|
|
}
|
|
nextCandidate() {
|
|
if (this.tooltipProperties.pagination) {
|
|
const { candidates } = this;
|
|
const previous = this.getActive();
|
|
const hoverIndex = previous == null ? -1 : candidates.findIndex((c) => pickedNodesEqual(c, previous));
|
|
if (hoverIndex === -1)
|
|
return { active: void 0, paginationState: void 0 };
|
|
let nextIndex = hoverIndex + 1;
|
|
if (nextIndex >= candidates.length) {
|
|
nextIndex = 0;
|
|
}
|
|
const node = candidates[nextIndex];
|
|
this.setSource("tooltip", node);
|
|
const paginationState = { index: nextIndex, length: this.candidates.length };
|
|
return { active: node, paginationState };
|
|
}
|
|
return { active: this.getActive() };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/seriesAreaManager.ts
|
|
var SeriesAreaManager = class extends BaseManager {
|
|
constructor(chart) {
|
|
super();
|
|
this.chart = chart;
|
|
this.id = (0, import_ag_charts_core147.createId)(this);
|
|
this.series = [];
|
|
this.announceMode = "when-changed";
|
|
this.highlight = {
|
|
/** Last received event that still needs to be applied. */
|
|
pendingHoverEvent: void 0,
|
|
/** Last applied event. */
|
|
appliedHoverEvent: void 0,
|
|
/** Last applied event, which has been temporarily stashed during the main chart update cycle. */
|
|
stashedHoverEvent: void 0
|
|
};
|
|
this.tooltip = {
|
|
lastHover: void 0
|
|
};
|
|
this.activeState = {
|
|
lastActive: void 0
|
|
};
|
|
/**
|
|
* A11y Requirements for Tooltip/Highlight (see AG-13051 for details):
|
|
*
|
|
* - When the series-area is blurred, allow the mouse to update the tooltip/highlight.
|
|
*
|
|
* - When the series-area receives a `focus` event, use `:focus-visible` to guess the input device.
|
|
* (this is decided by the browser).
|
|
*
|
|
* - For keyboard users, `focus` and `keydown` events always updates & shows the tooltip/highlight on
|
|
* the currently (or newly) focused datum.
|
|
*
|
|
* - For keyboard users, `mousemove` events update the tooltip/highlight iff `pickNode` finds a match
|
|
* for the mouse event offsets.
|
|
*/
|
|
this.hoverDevice = "pointer";
|
|
this.focus = {
|
|
sortedSeries: [],
|
|
series: void 0,
|
|
seriesIndex: 0,
|
|
datumIndex: 0,
|
|
datum: void 0
|
|
};
|
|
this.cachedTooltipContent = void 0;
|
|
this.hoverScheduler = debouncedAnimationFrame(() => {
|
|
if (this.hoverDevice === "setState") {
|
|
return this.handleHoverFromState();
|
|
}
|
|
if (!this.tooltip.lastHover && !this.highlight.pendingHoverEvent)
|
|
return;
|
|
if (this.chart.getUpdateType() <= import_ag_charts_core147.ChartUpdateType.SERIES_UPDATE) {
|
|
this.hoverScheduler.schedule();
|
|
return;
|
|
}
|
|
if (this.highlight.pendingHoverEvent) {
|
|
this.handleHoverHighlight(false);
|
|
}
|
|
if (this.tooltip.lastHover) {
|
|
this.handleHoverTooltip(this.tooltip.lastHover, false);
|
|
}
|
|
});
|
|
this.pickManager = new PickManager(chart.ctx.activeManager, chart.tooltip, this.focus);
|
|
const initialAltText = chart.ctx.localeManager.t("ariaInitSeriesArea");
|
|
const label1 = chart.ctx.domManager.addChild("series-area", "series-area-aria-label1");
|
|
const label2 = chart.ctx.domManager.addChild("series-area", "series-area-aria-label2");
|
|
this.swapChain = new FocusSwapChain(label1, label2, "img", initialAltText);
|
|
this.swapChain.addListener("blur", (event) => this.onBlur(event));
|
|
this.swapChain.addListener("focus", () => this.onFocus());
|
|
if (chart.ctx.domManager.mode === "normal") {
|
|
this.focusIndicator = new FocusIndicator(this.swapChain);
|
|
this.focusIndicator.overrideFocusVisible(chart.mode === "integrated" ? false : void 0);
|
|
}
|
|
const { seriesDragInterpreter, seriesWidget, containerWidget } = chart.ctx.widgets;
|
|
seriesWidget.setTabIndex(-1);
|
|
this.cleanup.register(
|
|
() => chart.ctx.domManager.removeChild("series-area", "series-area-aria-label1"),
|
|
() => chart.ctx.domManager.removeChild("series-area", "series-area-aria-label2"),
|
|
seriesWidget.addListener("focus", () => this.swapChain.focus({ preventScroll: true })),
|
|
seriesWidget.addListener("mousemove", (event) => this.onHover(event, seriesWidget)),
|
|
seriesWidget.addListener("wheel", (event) => this.onWheel(event)),
|
|
seriesWidget.addListener("mouseleave", (event) => this.onLeave(event)),
|
|
seriesWidget.addListener("keydown", (event) => this.onKeyDown(event)),
|
|
seriesWidget.addListener("contextmenu", (event, current) => this.onContextMenu(event, current)),
|
|
containerWidget.addListener("contextmenu", (event, current) => this.onContextMenu(event, current)),
|
|
containerWidget.addListener("click", (event, current) => this.onClick(event, current)),
|
|
containerWidget.addListener("dblclick", (event, current) => this.onClick(event, current)),
|
|
chart.ctx.animationManager.addListener("animation-start", () => this.onAnimationStart()),
|
|
chart.ctx.eventsHub.on("active:load-memento", (event) => this.onActiveLoadMemento(event)),
|
|
chart.ctx.eventsHub.on("active:update", (event) => this.onActiveUpdate(event)),
|
|
chart.ctx.eventsHub.on("dom:resize", () => this.clearAll()),
|
|
chart.ctx.eventsHub.on("highlight:change", (event) => this.changeHighlightDatum(event)),
|
|
chart.ctx.eventsHub.on("layout:complete", (event) => this.layoutComplete(event)),
|
|
chart.ctx.updateService.addListener("pre-scene-render", () => this.preSceneRender()),
|
|
chart.ctx.updateService.addListener("update-complete", () => this.updateComplete()),
|
|
chart.ctx.eventsHub.on("zoom:change-complete", () => this.clearAll()),
|
|
chart.ctx.eventsHub.on("zoom:pan-start", () => this.clearAll())
|
|
);
|
|
if (seriesDragInterpreter) {
|
|
this.cleanup.register(
|
|
seriesDragInterpreter.events.on("drag-move", (event) => this.onDragMove(event, seriesWidget)),
|
|
seriesDragInterpreter.events.on("click", (event) => this.onClick(event, seriesWidget)),
|
|
seriesDragInterpreter.events.on("dblclick", (event) => this.onClick(event, seriesWidget))
|
|
);
|
|
}
|
|
}
|
|
get bbox() {
|
|
return (this.seriesRect ?? BBox.zero).clone();
|
|
}
|
|
isState(allowedStates) {
|
|
return this.chart.ctx.interactionManager.isState(allowedStates);
|
|
}
|
|
isIgnoredTouch(event) {
|
|
if (event.device !== "touch" || event.type === "click")
|
|
return false;
|
|
if (this.chart.ctx.chartService.touch.dragAction === "hover")
|
|
return false;
|
|
if (this.chart.ctx.chartService.touch.dragAction === "drag") {
|
|
if (this.isState(18 /* AnnotationsMoveable */)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
dataChanged() {
|
|
var _a;
|
|
this.cachedTooltipContent = void 0;
|
|
if (this.highlight.appliedHoverEvent) {
|
|
(_a = this.highlight).stashedHoverEvent ?? (_a.stashedHoverEvent = this.highlight.appliedHoverEvent);
|
|
this.clearHighlight();
|
|
}
|
|
if (this.hoverDevice !== "setState") {
|
|
this.chart.ctx.tooltipManager.removeTooltip(this.id);
|
|
this.focusIndicator?.clear();
|
|
}
|
|
}
|
|
preSceneRender() {
|
|
if (this.highlight.stashedHoverEvent != null) {
|
|
this.highlight.pendingHoverEvent = this.tooltip.lastHover ?? this.highlight.stashedHoverEvent;
|
|
this.highlight.stashedHoverEvent = void 0;
|
|
this.handleHoverHighlight(true);
|
|
}
|
|
if (this.tooltip.lastHover != null) {
|
|
this.handleHoverTooltip(this.tooltip.lastHover, true);
|
|
}
|
|
if (this.hoverDevice === "setState") {
|
|
this.refreshSetState();
|
|
}
|
|
}
|
|
updateComplete() {
|
|
if (this.isState(68 /* Focusable */) && this.focusIndicator?.isFocusVisible()) {
|
|
if (this.announceMode !== "always") {
|
|
this.announceMode = "never";
|
|
}
|
|
this.handleFocus(0, 0);
|
|
}
|
|
}
|
|
update(type, opts) {
|
|
this.chart.ctx.updateService.update(type, opts);
|
|
}
|
|
seriesChanged(series) {
|
|
this.focus.sortedSeries = [...series].sort((a, b) => {
|
|
let fpA = a.properties.focusPriority ?? Infinity;
|
|
let fpB = b.properties.focusPriority ?? Infinity;
|
|
if (fpA === fpB) {
|
|
[fpA, fpB] = [a.declarationOrder, b.declarationOrder];
|
|
}
|
|
if (fpA < fpB) {
|
|
return -1;
|
|
} else if (fpA > fpB) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
});
|
|
this.series = series;
|
|
}
|
|
layoutComplete(event) {
|
|
this.seriesRect = event.series.rect;
|
|
this.hoverRect = event.series.rect;
|
|
this.chart.ctx.widgets.seriesWidget.setBounds(event.series.rect);
|
|
if (this.chart.ctx.domManager.mode === "normal") {
|
|
this.chart.ctx.widgets.chartWidget.setBounds(event.chart);
|
|
}
|
|
}
|
|
onAnimationStart() {
|
|
if (this.hoverDevice !== "setState") {
|
|
this.clearAll();
|
|
}
|
|
}
|
|
onContextMenu(event, current) {
|
|
const { sourceEvent } = event;
|
|
if (sourceEvent.currentTarget != current.getElement())
|
|
return;
|
|
if (current !== this.chart.ctx.widgets.seriesWidget) {
|
|
if (this.isState(72 /* ContextMenuable */)) {
|
|
const { currentX: canvasX2, currentY: canvasY2 } = event;
|
|
this.chart.ctx.contextMenuRegistry.dispatchContext(
|
|
"always",
|
|
{ widgetEvent: event, canvasX: canvasX2, canvasY: canvasY2 },
|
|
void 0
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
let pickedNode;
|
|
let position;
|
|
if (this.focusIndicator?.isFocusVisible()) {
|
|
pickedNode = this.chart.ctx.highlightManager.getActiveHighlight();
|
|
if (pickedNode && this.seriesRect && pickedNode.midPoint) {
|
|
position = Transformable.toCanvasPoint(
|
|
pickedNode.series.contentGroup,
|
|
pickedNode.midPoint.x,
|
|
pickedNode.midPoint.y
|
|
);
|
|
}
|
|
} else if (this.isState(72 /* ContextMenuable */)) {
|
|
const pick2 = this.pickNodes({ x: event.currentX, y: event.currentY }, "context-menu");
|
|
if (pick2) {
|
|
this.chart.ctx.highlightManager.updateHighlight(this.id);
|
|
pickedNode = pick2.matches[0].datum;
|
|
}
|
|
}
|
|
const pickedSeries = pickedNode?.series;
|
|
this.clearAll();
|
|
const canvasX = event.currentX + current.cssLeft();
|
|
const canvasY = event.currentY + current.cssTop();
|
|
const { datumIndex } = pickedNode ?? {};
|
|
if (pickedSeries && pickedNode && datumIndex != null) {
|
|
this.chart.ctx.contextMenuRegistry.dispatchContext(
|
|
"series-node",
|
|
{ widgetEvent: event, canvasX, canvasY },
|
|
{ pickedSeries, pickedNode: { ...pickedNode, datumIndex } },
|
|
position
|
|
);
|
|
} else {
|
|
this.chart.ctx.contextMenuRegistry.dispatchContext(
|
|
"series-area",
|
|
{ widgetEvent: event, canvasX, canvasY },
|
|
void 0,
|
|
position
|
|
);
|
|
}
|
|
}
|
|
onLeave(event) {
|
|
if (!this.isState(82 /* Clickable */))
|
|
return;
|
|
const relatedTarget = event.sourceEvent.relatedTarget;
|
|
if (relatedTarget?.className === "ag-charts-text-input__textarea") {
|
|
return;
|
|
}
|
|
if (this.maybeEnterInteractiveTooltip(event.sourceEvent)) {
|
|
return;
|
|
}
|
|
this.chart.ctx.domManager.updateCursor(this.id);
|
|
if (this.hoverDevice !== "keyboard")
|
|
this.clearAll(true);
|
|
}
|
|
onWheel(_event) {
|
|
if (!this.isState(82 /* Clickable */))
|
|
return;
|
|
this.focusIndicator?.overrideFocusVisible(false);
|
|
this.hoverDevice = "pointer";
|
|
}
|
|
onDragMove(event, current) {
|
|
if (!this.isState(82 /* Clickable */))
|
|
return;
|
|
this.focusIndicator?.overrideFocusVisible(false);
|
|
this.onHoverLikeEvent(event, current);
|
|
}
|
|
onHover(event, current) {
|
|
if (!this.isState(82 /* Clickable */))
|
|
return;
|
|
this.onHoverLikeEvent(event, current);
|
|
}
|
|
onHoverLikeEvent(event, current) {
|
|
if (this.isIgnoredTouch(event))
|
|
return;
|
|
if (event.device === "touch" && this.chart.ctx.chartService.touch.dragAction === "hover") {
|
|
event.sourceEvent.preventDefault();
|
|
}
|
|
if (current !== this.chart.ctx.widgets.seriesWidget)
|
|
return;
|
|
this.tooltip.lastHover = event;
|
|
this.hoverDevice = "pointer";
|
|
this.highlight.pendingHoverEvent = event;
|
|
this.hoverScheduler.schedule();
|
|
let pick2;
|
|
if (this.isState(64 /* Default */)) {
|
|
const { currentX: x, currentY: y } = event;
|
|
pick2 = this.pickNodes({ x, y }, "event");
|
|
const matches = pick2?.matches;
|
|
const found = matches?.[0];
|
|
if (found?.series.hasEventListener("seriesNodeClick") || found?.series.hasEventListener("seriesNodeDoubleClick") || matches != null && matches.length > 1 && this.chart.tooltip.pagination) {
|
|
this.chart.ctx.domManager.updateCursor(this.id, "pointer");
|
|
} else {
|
|
this.chart.ctx.domManager.updateCursor(this.id);
|
|
}
|
|
}
|
|
const consumed = Boolean(pick2?.matches.length);
|
|
this.emitSeriesAreaHoverEvent(event, consumed);
|
|
}
|
|
onClick(event, current) {
|
|
if (event.device === "keyboard") {
|
|
return;
|
|
}
|
|
if (current === this.chart.ctx.widgets.seriesWidget && this.chart.ctx.animationManager.isActive()) {
|
|
this.chart.ctx.animationManager.skipCurrentBatch();
|
|
}
|
|
if (event.device === "touch" && current === this.chart.ctx.widgets.seriesWidget) {
|
|
this.swapChain.focus({ preventScroll: true });
|
|
}
|
|
if (!this.isState(82 /* Clickable */))
|
|
return;
|
|
if (current === this.chart.ctx.widgets.seriesWidget) {
|
|
if (!current.getElement().contains(event.sourceEvent.target)) {
|
|
return;
|
|
}
|
|
} else if (event.sourceEvent.target != current.getElement()) {
|
|
return;
|
|
}
|
|
this.focusIndicator?.overrideFocusVisible(false);
|
|
this.onHoverLikeEvent(event, current);
|
|
const isSeriesWidget = current === this.chart.ctx.widgets.seriesWidget;
|
|
if (!this.isState(64 /* Default */)) {
|
|
if (isSeriesWidget) {
|
|
this.emitSeriesAreaClickEvent(event, false);
|
|
}
|
|
return;
|
|
}
|
|
if (isSeriesWidget) {
|
|
const consumed = this.checkSeriesNodeClick(event);
|
|
if (consumed) {
|
|
this.emitSeriesAreaClickEvent(event, true);
|
|
this.update(import_ag_charts_core147.ChartUpdateType.SERIES_UPDATE);
|
|
event.sourceEvent.preventDefault();
|
|
return;
|
|
}
|
|
this.emitSeriesAreaClickEvent(event, false);
|
|
}
|
|
const newEvent = { type: event.type === "click" ? "click" : "doubleClick", event: event.sourceEvent };
|
|
this.chart.fireEvent(newEvent);
|
|
}
|
|
emitSeriesAreaHoverEvent(event, consumed) {
|
|
const { canvasX, canvasY } = this.toCanvasCoordinates(event);
|
|
const payload = { canvasX, canvasY, consumed, sourceEvent: event.sourceEvent };
|
|
this.chart.ctx.eventsHub.emit("series-area:hover", payload);
|
|
}
|
|
emitSeriesAreaClickEvent(event, consumed) {
|
|
if (!("currentX" in event))
|
|
return;
|
|
const { canvasX, canvasY } = this.toCanvasCoordinates(event);
|
|
const payload = { canvasX, canvasY, consumed, sourceEvent: event.sourceEvent };
|
|
this.chart.ctx.eventsHub.emit("series-area:click", payload);
|
|
}
|
|
toCanvasCoordinates(event) {
|
|
return {
|
|
canvasX: event.currentX + (this.hoverRect?.x ?? this.seriesRect?.x ?? 0),
|
|
canvasY: event.currentY + (this.hoverRect?.y ?? this.seriesRect?.y ?? 0)
|
|
};
|
|
}
|
|
onFocus() {
|
|
if (!this.isState(68 /* Focusable */))
|
|
return;
|
|
this.hoverDevice = this.focusIndicator?.isFocusVisible(true) ? "keyboard" : "pointer";
|
|
this.handleFocus(0, 0);
|
|
}
|
|
onBlur(event) {
|
|
if (!this.isState(68 /* Focusable */))
|
|
return;
|
|
this.hoverDevice = "pointer";
|
|
if (!this.maybeEnterInteractiveTooltip(event)) {
|
|
this.clearAll(true);
|
|
}
|
|
this.focusIndicator?.overrideFocusVisible(void 0);
|
|
}
|
|
onKeyDown(widgetEvent) {
|
|
if (!this.isState(86 /* Keyable */))
|
|
return;
|
|
const action = mapKeyboardEventToAction(widgetEvent.sourceEvent);
|
|
if (action?.activatesFocusIndicator === false) {
|
|
this.focusIndicator?.overrideFocusVisible(this.hoverDevice === "keyboard");
|
|
}
|
|
switch (action?.name) {
|
|
case "redo":
|
|
return this.chart.ctx.eventsHub.emit("series:redo", null);
|
|
case "undo":
|
|
return this.chart.ctx.eventsHub.emit("series:undo", null);
|
|
case "zoomin":
|
|
return this.chart.ctx.eventsHub.emit("series:keynav-zoom", { delta: 1, widgetEvent });
|
|
case "zoomout":
|
|
return this.chart.ctx.eventsHub.emit("series:keynav-zoom", { delta: -1, widgetEvent });
|
|
case "arrowup":
|
|
return this.onArrow(-1, 0, widgetEvent);
|
|
case "arrowdown":
|
|
return this.onArrow(1, 0, widgetEvent);
|
|
case "arrowleft":
|
|
return this.onArrow(0, -1, widgetEvent);
|
|
case "arrowright":
|
|
return this.onArrow(0, 1, widgetEvent);
|
|
case "submit":
|
|
return this.onSubmit(widgetEvent);
|
|
}
|
|
}
|
|
onArrow(seriesIndexDelta, datumIndexDelta, event) {
|
|
if (!this.isState(68 /* Focusable */))
|
|
return;
|
|
this.hoverDevice = "keyboard";
|
|
this.focusIndicator?.overrideFocusVisible(true);
|
|
this.focus.seriesIndex += seriesIndexDelta;
|
|
this.focus.datumIndex += datumIndexDelta;
|
|
this.handleFocus(seriesIndexDelta, datumIndexDelta);
|
|
event.sourceEvent.preventDefault();
|
|
this.chart.ctx.eventsHub.emit("series:focus-change", null);
|
|
}
|
|
onSubmit(event) {
|
|
if (!this.isState(68 /* Focusable */))
|
|
return;
|
|
const { series, datum } = this.focus;
|
|
const sourceEvent = event.sourceEvent;
|
|
if (series != null && datum != null) {
|
|
series.fireNodeClickEvent(sourceEvent, datum);
|
|
} else {
|
|
this.chart.fireEvent({
|
|
type: "click",
|
|
event: sourceEvent
|
|
});
|
|
}
|
|
sourceEvent.preventDefault();
|
|
}
|
|
checkSeriesNodeClick(event) {
|
|
var _a;
|
|
const pickedNodes = this.pickNodes({ x: event.currentX, y: event.currentY }, "event");
|
|
const updated = this.pickManager.onPickedNodesTooltip(pickedNodes);
|
|
if (pickedNodes === void 0 || updated.active === void 0)
|
|
return false;
|
|
const { series, datum } = updated.active;
|
|
const distance = updated.paginationState == null ? pickedNodes.distance : 0;
|
|
if (event.type === "click") {
|
|
const defaultBehavior = series.fireNodeClickEvent(event.sourceEvent, datum);
|
|
if (defaultBehavior) {
|
|
const next = this.pickManager.nextCandidate();
|
|
if (next.active !== void 0) {
|
|
const { canvasX, canvasY } = this.toCanvasCoordinates(event);
|
|
(_a = this.highlight).pendingHoverEvent ?? (_a.pendingHoverEvent = this.highlight.appliedHoverEvent);
|
|
this.handleHoverHighlight(false);
|
|
this.showTooltip(next.active, canvasX, canvasY, next.paginationState);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
if (event.type === "dblclick") {
|
|
event.preventZoomDblClick = distance === 0;
|
|
series.fireNodeDoubleClickEvent(event.sourceEvent, datum);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
handleFocus(seriesIndexDelta, datumIndexDelta) {
|
|
const overlayFocus = this.chart.overlays.getFocusInfo(this.chart.ctx.localeManager);
|
|
if (overlayFocus == null) {
|
|
if (this.handleSeriesFocus(seriesIndexDelta, datumIndexDelta) === 0 /* SUCCESS */) {
|
|
this.announceMode = "when-changed";
|
|
} else {
|
|
this.announceMode = "always";
|
|
}
|
|
} else {
|
|
this.focusIndicator?.update(overlayFocus.rect, this.seriesRect, false);
|
|
this.swapChain.update(overlayFocus.text);
|
|
this.announceMode = "always";
|
|
}
|
|
}
|
|
handleSeriesFocus(otherIndexDelta, datumIndexDelta) {
|
|
if (this.chart.chartType === "standalone") {
|
|
return this.handleSoloSeriesFocus(otherIndexDelta, datumIndexDelta);
|
|
}
|
|
const { focus } = this;
|
|
const visibleSeries = focus.sortedSeries.filter((s) => s.visible && s.focusable);
|
|
if (visibleSeries.length === 0)
|
|
return 1 /* SERIES_NOT_FOUND */;
|
|
const oldDatumIndex = focus.datumIndex - datumIndexDelta;
|
|
const oldOtherIndex = focus.seriesIndex - otherIndexDelta;
|
|
focus.seriesIndex = (0, import_ag_charts_core147.clamp)(0, focus.seriesIndex, visibleSeries.length - 1);
|
|
focus.series = visibleSeries[focus.seriesIndex];
|
|
const datumIndex = this.focus.datumIndex;
|
|
const otherIndex = this.focus.seriesIndex;
|
|
return this.updatePickedFocus(
|
|
datumIndex,
|
|
datumIndexDelta,
|
|
oldDatumIndex,
|
|
otherIndex,
|
|
otherIndexDelta,
|
|
oldOtherIndex
|
|
);
|
|
}
|
|
handleSoloSeriesFocus(otherIndexDelta, datumIndexDelta) {
|
|
this.focus.series = this.focus.sortedSeries[0];
|
|
const datumIndex = this.focus.datumIndex;
|
|
const otherIndex = this.focus.seriesIndex;
|
|
const oldDatumIndex = this.focus.datumIndex - datumIndexDelta;
|
|
const oldOtherIndex = this.focus.seriesIndex - otherIndexDelta;
|
|
return this.updatePickedFocus(
|
|
datumIndex,
|
|
datumIndexDelta,
|
|
oldDatumIndex,
|
|
otherIndex,
|
|
otherIndexDelta,
|
|
oldOtherIndex
|
|
);
|
|
}
|
|
pickFocus(series, opts) {
|
|
const pick2 = series.pickFocus(opts);
|
|
if (this.hoverDevice === "keyboard") {
|
|
this.pickManager.onPickedNodesFocus(pick2);
|
|
}
|
|
return pick2;
|
|
}
|
|
updatePickedFocus(datumIndex, datumIndexDelta, oldDatumIndex, otherIndex, otherIndexDelta, oldOtherIndex) {
|
|
const { focus, hoverRect, seriesRect } = this;
|
|
if (focus.series == null || hoverRect == null)
|
|
return 1 /* SERIES_NOT_FOUND */;
|
|
const focusInputs = { datumIndex, datumIndexDelta, otherIndex, otherIndexDelta, seriesRect };
|
|
const pick2 = this.pickFocus(focus.series, focusInputs);
|
|
if (!pick2)
|
|
return 2 /* DATUM_NOT_FOUND */;
|
|
const { datum } = pick2;
|
|
focus.datum = datum;
|
|
focus.datumIndex = pick2.datumIndex;
|
|
if (pick2.otherIndex != null) {
|
|
focus.seriesIndex = pick2.otherIndex;
|
|
}
|
|
if (this.focusIndicator?.isFocusVisible()) {
|
|
this.chart.ctx.animationManager.reset();
|
|
const focusBBox = getPickedFocusBBox(pick2);
|
|
const { x, y } = focusBBox.computeCenter();
|
|
if (!hoverRect.containsPoint(x, y)) {
|
|
const panSuccess = this.chart.ctx.zoomManager.panToBBox(hoverRect, focusBBox);
|
|
if (panSuccess) {
|
|
return 3 /* PAN_REQUIRED */;
|
|
}
|
|
}
|
|
const { x1, x2, y1, y2 } = import_ag_charts_core147.Vec4.from(focusBBox);
|
|
const nw = hoverRect.containsPoint(x1, y1);
|
|
const ne = hoverRect.containsPoint(x2, y1);
|
|
const sw = hoverRect.containsPoint(x1, y2);
|
|
const se = hoverRect.containsPoint(x2, y2);
|
|
if (!(nw || ne || sw || se)) {
|
|
const hoverBounds = import_ag_charts_core147.Vec4.from(hoverRect);
|
|
pick2.movedBounds = focusBBox.clone();
|
|
if (x1 < hoverBounds.x1 && x2 < hoverBounds.x1) {
|
|
pick2.movedBounds.x = hoverBounds.x1 - 2;
|
|
pick2.movedBounds.width = 4;
|
|
} else if (x1 > hoverBounds.x2 && x2 > hoverBounds.x2) {
|
|
pick2.movedBounds.x = hoverBounds.x2 - 2;
|
|
pick2.movedBounds.width = 4;
|
|
}
|
|
if (y1 < hoverBounds.y1 && y2 < hoverBounds.y1) {
|
|
pick2.movedBounds.y = hoverBounds.y1 - 2;
|
|
pick2.movedBounds.height = 4;
|
|
} else if (y1 > hoverBounds.y2 && y2 > hoverBounds.y2) {
|
|
pick2.movedBounds.y = hoverBounds.y2 - 2;
|
|
pick2.movedBounds.height = 4;
|
|
}
|
|
}
|
|
}
|
|
this.focusIndicator?.update(pick2.movedBounds ?? pick2.bounds, this.seriesRect, pick2.clipFocusBox);
|
|
const tooltipContent = this.getTooltipContent(focus.series, datum.datumIndex, datum, "aria-label");
|
|
const keyboardEvent = makeKeyboardPointerEvent(focus.series, hoverRect, pick2);
|
|
if (keyboardEvent != null && this.hoverDevice === "keyboard") {
|
|
this.clearCachedEvents();
|
|
const meta = TooltipManager.makeTooltipMeta(keyboardEvent, focus.series, datum, pick2.movedBounds);
|
|
this.chart.ctx.highlightManager.updateHighlight(this.id, datum);
|
|
if (this.isTooltipEnabled(focus.series)) {
|
|
this.chart.ctx.tooltipManager.updateTooltip(this.id, meta, tooltipContent);
|
|
}
|
|
}
|
|
this.maybeAnnouncePickedFocus(
|
|
datumIndexDelta,
|
|
oldDatumIndex,
|
|
otherIndexDelta,
|
|
oldOtherIndex,
|
|
pick2,
|
|
tooltipContent
|
|
);
|
|
return 0 /* SUCCESS */;
|
|
}
|
|
maybeAnnouncePickedFocus(datumIndexDelta, oldDatumIndex, otherIndexDelta, oldOtherIndex, pick2, tooltipContent) {
|
|
const { focus } = this;
|
|
let mode;
|
|
if (this.announceMode === "when-changed") {
|
|
const shouldAnnouncePick = datumIndexDelta === 0 && otherIndexDelta === 0 || oldDatumIndex !== pick2.datumIndex || oldOtherIndex !== (pick2.otherIndex ?? focus.seriesIndex);
|
|
if (shouldAnnouncePick) {
|
|
mode = "always";
|
|
} else {
|
|
mode = "never";
|
|
}
|
|
} else {
|
|
mode = this.announceMode;
|
|
}
|
|
if (mode === "always") {
|
|
this.swapChain.update(this.getDatumAriaText(pick2.datum, tooltipContent));
|
|
}
|
|
}
|
|
getDatumAriaText(datum, tooltipContent) {
|
|
const description = tooltipContent == null ? "" : tooltipContentAriaLabel(tooltipContent);
|
|
return this.chart.ctx.localeManager.t("ariaAnnounceHoverDatum", {
|
|
datum: datum.series.getDatumAriaText?.(datum, description) ?? description
|
|
});
|
|
}
|
|
clearHighlight(delayed = false) {
|
|
this.highlight.pendingHoverEvent = void 0;
|
|
this.highlight.appliedHoverEvent = void 0;
|
|
this.chart.ctx.highlightManager.updateHighlight(this.id, void 0, delayed);
|
|
}
|
|
clearTooltip(delayed = false) {
|
|
this.chart.ctx.tooltipManager.removeTooltip(this.id, void 0, delayed);
|
|
this.tooltip.lastHover = void 0;
|
|
}
|
|
clearAll(delayed = false) {
|
|
this.pickManager.onClearUI();
|
|
this.clearHighlight(delayed);
|
|
this.clearTooltip(delayed);
|
|
this.focusIndicator?.clear();
|
|
}
|
|
clearCachedEvents() {
|
|
this.tooltip.lastHover = void 0;
|
|
this.highlight.appliedHoverEvent = void 0;
|
|
this.highlight.pendingHoverEvent = void 0;
|
|
this.highlight.stashedHoverEvent = void 0;
|
|
}
|
|
handleHoverFromState() {
|
|
const { active, paginationState } = this.pickManager.onPickedNodesAPIDebounced();
|
|
if (active === void 0)
|
|
return;
|
|
this.chart.ctx.highlightManager.updateHighlight(this.id, active.datum);
|
|
const refPoint = getDatumRefPoint(active.series, active.datum, void 0);
|
|
if (this.chart.tooltip.enabled) {
|
|
if (refPoint) {
|
|
const { canvasX, canvasY } = refPoint;
|
|
this.showTooltip(active, canvasX, canvasY, paginationState);
|
|
}
|
|
}
|
|
}
|
|
handleHoverHighlight(redisplay) {
|
|
this.highlight.appliedHoverEvent = this.highlight.pendingHoverEvent;
|
|
this.highlight.pendingHoverEvent = void 0;
|
|
const event = this.highlight.appliedHoverEvent;
|
|
if (!event || !this.isState(82 /* Clickable */))
|
|
return;
|
|
const { canvasX, canvasY } = this.toCanvasCoordinates(event);
|
|
if (redisplay ? this.chart.ctx.animationManager.isActive() : !this.hoverRect?.containsPoint(canvasX, canvasY)) {
|
|
this.clearHighlight();
|
|
return;
|
|
}
|
|
const { range: range4 } = this.chart.highlight;
|
|
const intent = range4 === "tooltip" ? "highlight-tooltip" : "highlight";
|
|
const pick2 = this.pickNodes({ x: event.currentX, y: event.currentY }, intent);
|
|
const active = this.pickManager.onPickedNodesHighlight(pick2);
|
|
if (active === void 0) {
|
|
this.chart.ctx.highlightManager.updateHighlight(this.id, void 0, true);
|
|
} else {
|
|
this.chart.ctx.highlightManager.updateHighlight(this.id, active.datum, false);
|
|
}
|
|
}
|
|
handleHoverTooltip(event, redisplay) {
|
|
if (!this.isState(82 /* Clickable */))
|
|
return;
|
|
const { canvasX, canvasY } = this.toCanvasCoordinates(event);
|
|
const targetElement = event.sourceEvent.target;
|
|
if (redisplay ? this.chart.ctx.animationManager.isActive() : !this.hoverRect?.containsPoint(canvasX, canvasY)) {
|
|
if (this.hoverDevice == "pointer")
|
|
this.clearTooltip();
|
|
return;
|
|
}
|
|
if (targetElement && this.chart.tooltip.interactive && this.chart.ctx.domManager.isManagedChildDOMElement(targetElement, "canvas-overlay", DEFAULT_TOOLTIP_CLASS)) {
|
|
return;
|
|
}
|
|
const pick2 = this.pickNodes({ x: event.currentX, y: event.currentY }, "tooltip");
|
|
const { active, paginationState } = this.pickManager.onPickedNodesTooltip(pick2);
|
|
if (active === void 0) {
|
|
if (this.hoverDevice == "pointer") {
|
|
this.clearTooltip(true);
|
|
}
|
|
} else {
|
|
this.showTooltip(active, canvasX, canvasY, paginationState);
|
|
}
|
|
}
|
|
showTooltip({ series, datum, datumIndex }, canvasX, canvasY, pagination) {
|
|
const tooltipContent = this.getTooltipContent(series, datumIndex, datum, "tooltip");
|
|
const shouldUpdateTooltip = tooltipContent != null;
|
|
if (shouldUpdateTooltip) {
|
|
const meta = TooltipManager.makeTooltipMeta(
|
|
{ type: "pointermove", canvasX, canvasY },
|
|
series,
|
|
datum,
|
|
void 0
|
|
);
|
|
this.chart.ctx.tooltipManager.updateTooltip(this.id, meta, tooltipContent, pagination);
|
|
} else {
|
|
this.chart.ctx.tooltipManager.removeTooltip(this.id, void 0, true);
|
|
}
|
|
}
|
|
maybeEnterInteractiveTooltip(event) {
|
|
return this.chart.tooltip.maybeEnterInteractiveTooltip(event, () => {
|
|
this.tooltip.lastHover = void 0;
|
|
this.chart.ctx.tooltipManager.removeTooltip(this.id);
|
|
this.chart.ctx.highlightManager.updateHighlight(this.id, void 0, true);
|
|
});
|
|
}
|
|
changeHighlightDatum(event) {
|
|
const lastSeries = event.previousHighlight?.series;
|
|
const newSeries = event.currentHighlight?.series;
|
|
if (lastSeries?.properties.cursor && event.previousHighlight?.datum) {
|
|
this.chart.ctx.domManager.updateCursor(lastSeries.id);
|
|
}
|
|
if (newSeries?.properties.cursor && newSeries.properties.cursor !== "default" && event.currentHighlight?.datum) {
|
|
this.chart.ctx.domManager.updateCursor(newSeries.id, newSeries.properties.cursor);
|
|
}
|
|
if (this.hoverDevice === "setState" || newSeries == null || lastSeries == null) {
|
|
this.update(import_ag_charts_core147.ChartUpdateType.SERIES_UPDATE, { clearCallbackCache: true });
|
|
} else {
|
|
this.update(import_ag_charts_core147.ChartUpdateType.SERIES_UPDATE, {
|
|
seriesToUpdate: new Set([lastSeries, newSeries].filter(Boolean)),
|
|
clearCallbackCache: true
|
|
});
|
|
}
|
|
}
|
|
pickNodes(point, intent, exactMatchOnly) {
|
|
const reverseSeries = [...this.series].reverse();
|
|
const clickIntent = intent === "event" || intent === "context-menu";
|
|
const tooltipIntent = intent === "tooltip" || intent === "highlight-tooltip";
|
|
const getIntentRange = (series) => {
|
|
if (clickIntent)
|
|
return series.properties.nodeClickRange;
|
|
if (tooltipIntent)
|
|
return series.properties.tooltip.range;
|
|
return void 0;
|
|
};
|
|
const { x, y } = point;
|
|
const seriesContainingPoint = /* @__PURE__ */ new Set();
|
|
for (const series of reverseSeries) {
|
|
if (series.visible && series.contentGroup.visible && getIntentRange(series) === "area") {
|
|
if (series.isPointInArea?.(x, y)) {
|
|
seriesContainingPoint.add(series);
|
|
}
|
|
}
|
|
}
|
|
const hasSeriesContainingPoint = seriesContainingPoint.size > 0;
|
|
let result;
|
|
for (const series of reverseSeries) {
|
|
if (!series.visible || !series.contentGroup.visible)
|
|
continue;
|
|
if (hasSeriesContainingPoint) {
|
|
const hasAreaHit = getIntentRange(series) === "area" && seriesContainingPoint.has(series);
|
|
if (!hasAreaHit)
|
|
continue;
|
|
}
|
|
const pick2 = series.pickNodes(point, intent, exactMatchOnly);
|
|
if (pick2 == null || pick2.datums.length === 0)
|
|
continue;
|
|
const { datums, distance } = pick2;
|
|
if (pick2.datums.length === 0)
|
|
continue;
|
|
if (distance === 0) {
|
|
if (result?.distance !== 0) {
|
|
result = { matches: [], distance: 0 };
|
|
}
|
|
for (const datum of datums) {
|
|
const { datumIndex } = datum;
|
|
result.matches.push({ series, datum, datumIndex });
|
|
}
|
|
} else if (result == null || result.distance > distance) {
|
|
const [datum] = datums;
|
|
const { datumIndex } = datum;
|
|
result = { matches: [{ series, datum, datumIndex }], distance };
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
isTooltipEnabled(series) {
|
|
return series.tooltipEnabled ?? this.chart.tooltip.enabled;
|
|
}
|
|
getTooltipContent(series, datumIndex, datum, purpose) {
|
|
let result;
|
|
if (purpose === "aria-label" || this.isTooltipEnabled(series)) {
|
|
const { cachedTooltipContent } = this;
|
|
if (cachedTooltipContent?.series === series && cachedTooltipContent.datumIndex === datumIndex) {
|
|
result = cachedTooltipContent.content;
|
|
} else {
|
|
const content = this.chart.getTooltipContent(series, datumIndex, datum, purpose);
|
|
this.cachedTooltipContent = { series, datumIndex, content };
|
|
result = content;
|
|
}
|
|
purpose;
|
|
result;
|
|
} else {
|
|
this.cachedTooltipContent = void 0;
|
|
purpose;
|
|
result;
|
|
}
|
|
return result;
|
|
}
|
|
onActiveLoadMemento(event) {
|
|
switch (event.activeItem?.type) {
|
|
case void 0:
|
|
case "legend":
|
|
return this.onActiveClear();
|
|
case "series-node":
|
|
return this.onActiveDatum(event.activeItem, event);
|
|
default:
|
|
return event.activeItem?.type;
|
|
}
|
|
}
|
|
onActiveUpdate(activeItem) {
|
|
if (activeItem?.type === "legend") {
|
|
if (this.hoverDevice === "setState") {
|
|
this.clearHighlight();
|
|
this.clearTooltip();
|
|
}
|
|
this.activeState.lastActive = "legend";
|
|
}
|
|
}
|
|
onActiveClear() {
|
|
this.pickManager.onClearAPI();
|
|
this.hoverDevice = "setState";
|
|
this.activeState.lastActive = void 0;
|
|
this.clearHighlight();
|
|
this.clearTooltip();
|
|
}
|
|
refreshSetState() {
|
|
if (this.activeState.lastActive === void 0) {
|
|
this.clearAll();
|
|
} else if (this.activeState.lastActive !== "legend") {
|
|
const { seriesId, itemId } = this.activeState.lastActive;
|
|
const desiredPickedNodes = this.findPickedNodes(seriesId, itemId);
|
|
if (desiredPickedNodes) {
|
|
this.pickManager.onPickedNodesAPI(desiredPickedNodes);
|
|
this.hoverScheduler.schedule();
|
|
}
|
|
}
|
|
}
|
|
onActiveDatum(activeItem, event) {
|
|
const { seriesId, itemId } = activeItem;
|
|
const desiredPickedNodes = this.findPickedNodes(seriesId, itemId);
|
|
if (desiredPickedNodes === void 0) {
|
|
event.reject();
|
|
this.onActiveClear();
|
|
} else {
|
|
const picked = this.pickManager.onPickedNodesAPI(desiredPickedNodes);
|
|
event.setDatum(picked?.datum);
|
|
this.hoverDevice = "setState";
|
|
this.activeState.lastActive = { seriesId, itemId };
|
|
if (event.initialState) {
|
|
this.chart.ctx.scene.applyPendingResize();
|
|
this.handleHoverFromState();
|
|
} else {
|
|
this.clearCachedEvents();
|
|
this.hoverScheduler.schedule();
|
|
}
|
|
}
|
|
}
|
|
findPickedNodes(desiredSeriesId, desiredItemId) {
|
|
const desiredSeries = this.series.find((s) => s.id === desiredSeriesId);
|
|
if (desiredSeries == void 0) {
|
|
import_ag_charts_core147.Logger.warn(`Cannot find seriesId: "${desiredSeriesId}"`);
|
|
return void 0;
|
|
}
|
|
const desiredDatum = desiredSeries.findNodeDatum(desiredItemId);
|
|
if (desiredDatum == void 0) {
|
|
import_ag_charts_core147.Logger.warn(`Cannot find itemId: ${JSON.stringify(desiredItemId)}`);
|
|
return void 0;
|
|
}
|
|
const restoredPick = {
|
|
datum: desiredDatum,
|
|
datumIndex: desiredDatum.datumIndex,
|
|
series: desiredSeries
|
|
};
|
|
return { matches: [restoredPick], distance: 0 };
|
|
}
|
|
};
|
|
SeriesAreaManager.className = "SeriesAreaManager";
|
|
|
|
// packages/ag-charts-community/src/chart/series/seriesLayerManager.ts
|
|
var import_ag_charts_core148 = require("ag-charts-core");
|
|
var SERIES_THRESHOLD_FOR_AGGRESSIVE_LAYER_REDUCTION = 30;
|
|
var SeriesLayerManager = class {
|
|
constructor(seriesRoot) {
|
|
this.seriesRoot = seriesRoot;
|
|
this.groups = /* @__PURE__ */ new Map();
|
|
this.series = /* @__PURE__ */ new Map();
|
|
this.expectedSeriesCount = 1;
|
|
this.mode = "normal";
|
|
}
|
|
setSeriesCount(count) {
|
|
this.expectedSeriesCount = count;
|
|
}
|
|
getGroupIndex(seriesConfig) {
|
|
const { internalId, seriesGrouping } = seriesConfig;
|
|
return seriesGrouping?.groupIndex ?? internalId;
|
|
}
|
|
getGroupType(seriesConfig, bringToFront) {
|
|
return bringToFront ? "top" : seriesConfig.type;
|
|
}
|
|
requestGroup(seriesConfig) {
|
|
const { internalId, contentGroup: seriesContentGroup } = seriesConfig;
|
|
const bringToFront = seriesConfig.bringToFront();
|
|
const type = this.getGroupType(seriesConfig, bringToFront);
|
|
const groupIndex = this.getGroupIndex(seriesConfig);
|
|
const seriesInfo = this.series.get(internalId);
|
|
if (seriesInfo != null) {
|
|
throw new Error(`AG Charts - series already has an allocated layer: ${JSON.stringify(seriesInfo)}`);
|
|
}
|
|
if (this.series.size === 0) {
|
|
this.mode = this.expectedSeriesCount >= SERIES_THRESHOLD_FOR_AGGRESSIVE_LAYER_REDUCTION ? "aggressive-grouping" : "normal";
|
|
}
|
|
let group = this.groups.get(type);
|
|
if (group == null) {
|
|
group = /* @__PURE__ */ new Map();
|
|
this.groups.set(type, group);
|
|
}
|
|
const lookupIndex = this.lookupIdx(groupIndex);
|
|
let groupInfo = group.get(lookupIndex);
|
|
if (groupInfo == null) {
|
|
groupInfo = {
|
|
type,
|
|
id: lookupIndex,
|
|
seriesIds: [],
|
|
group: this.seriesRoot.appendChild(
|
|
new Group({
|
|
name: `${seriesConfig.contentGroup.name ?? type}-managed-layer`,
|
|
zIndex: seriesConfig.contentGroup.zIndex,
|
|
// Set in updateLayerCompositing
|
|
renderToOffscreenCanvas: false
|
|
})
|
|
)
|
|
};
|
|
group.set(lookupIndex, groupInfo);
|
|
}
|
|
this.series.set(internalId, { layerState: groupInfo, seriesConfig, bringToFront });
|
|
groupInfo.seriesIds.push(internalId);
|
|
groupInfo.group.appendChild(seriesContentGroup);
|
|
return groupInfo.group;
|
|
}
|
|
changeGroup(seriesConfig) {
|
|
const { internalId, contentGroup } = seriesConfig;
|
|
const bringToFront = seriesConfig.bringToFront();
|
|
const type = this.getGroupType(seriesConfig, bringToFront);
|
|
const oldGroup = this.series.get(internalId);
|
|
const oldType = oldGroup ? this.getGroupType(oldGroup.seriesConfig, oldGroup.bringToFront) : void 0;
|
|
const groupIndex = this.getGroupIndex(seriesConfig);
|
|
const lookupIndex = this.lookupIdx(groupIndex);
|
|
const groupInfo = this.groups.get(type)?.get(lookupIndex);
|
|
if (oldType === type && groupInfo?.seriesIds.includes(internalId) === true) {
|
|
return;
|
|
}
|
|
if (this.series.has(internalId)) {
|
|
this._releaseGroup({ internalId, contentGroup, type: oldType });
|
|
}
|
|
return this.requestGroup(seriesConfig);
|
|
}
|
|
releaseGroup(seriesConfig) {
|
|
const { internalId, contentGroup } = seriesConfig;
|
|
const type = this.getGroupType(seriesConfig, seriesConfig.bringToFront());
|
|
this._releaseGroup({ internalId, contentGroup, type });
|
|
}
|
|
_releaseGroup(seriesConfig) {
|
|
const { internalId, contentGroup, type } = seriesConfig;
|
|
if (!this.series.has(internalId)) {
|
|
throw new Error(`AG Charts - series doesn't have an allocated layer: ${internalId}`);
|
|
}
|
|
const groupInfo = this.series.get(internalId)?.layerState;
|
|
if (groupInfo) {
|
|
groupInfo.seriesIds = groupInfo.seriesIds.filter((v) => v !== internalId);
|
|
contentGroup.remove();
|
|
}
|
|
if (groupInfo?.seriesIds.length === 0) {
|
|
groupInfo.group.remove();
|
|
this.groups.get(groupInfo.type)?.delete(groupInfo.id);
|
|
this.groups.get(type)?.delete(internalId);
|
|
} else if (groupInfo != null && groupInfo.seriesIds.length > 0) {
|
|
groupInfo.group.zIndex = this.getLowestSeriesZIndex(groupInfo.seriesIds);
|
|
}
|
|
this.series.delete(internalId);
|
|
}
|
|
updateLayerCompositing() {
|
|
for (const groups of this.groups.values()) {
|
|
for (const groupInfo of groups.values()) {
|
|
const { group, seriesIds } = groupInfo;
|
|
let renderToOffscreenCanvas;
|
|
if (seriesIds.length === 0) {
|
|
renderToOffscreenCanvas = false;
|
|
} else if (seriesIds.length > 1) {
|
|
renderToOffscreenCanvas = true;
|
|
} else {
|
|
const series = this.series.get(seriesIds[0]);
|
|
renderToOffscreenCanvas = series?.seriesConfig.renderToOffscreenCanvas() === true;
|
|
}
|
|
group.renderToOffscreenCanvas = renderToOffscreenCanvas;
|
|
group.zIndex = this.getLowestSeriesZIndex(seriesIds);
|
|
}
|
|
}
|
|
}
|
|
lookupIdx(groupIndex) {
|
|
if (this.mode === "normal") {
|
|
return groupIndex;
|
|
}
|
|
if (typeof groupIndex === "string") {
|
|
groupIndex = Number(groupIndex.split("-").at(-1));
|
|
if (!Number.isFinite(groupIndex)) {
|
|
return 0;
|
|
}
|
|
}
|
|
return Math.floor(
|
|
(0, import_ag_charts_core148.clamp)(0, groupIndex / this.expectedSeriesCount, 1) * SERIES_THRESHOLD_FOR_AGGRESSIVE_LAYER_REDUCTION
|
|
);
|
|
}
|
|
destroy() {
|
|
for (const groups of this.groups.values()) {
|
|
for (const groupInfo of groups.values()) {
|
|
groupInfo.group.remove();
|
|
}
|
|
}
|
|
this.groups.clear();
|
|
this.series.clear();
|
|
}
|
|
getLowestSeriesZIndex(seriesIds) {
|
|
let lowestSeriesZIndex = void 0;
|
|
for (const seriesId of seriesIds) {
|
|
const series = this.series.get(seriesId);
|
|
const zIndex = series?.seriesConfig.contentGroup.zIndex ?? import_ag_charts_core148.SeriesZIndexMap.ANY_CONTENT;
|
|
if (lowestSeriesZIndex == null || zIndex == null) {
|
|
lowestSeriesZIndex = zIndex;
|
|
continue;
|
|
}
|
|
lowestSeriesZIndex = compareZIndex(lowestSeriesZIndex, zIndex) <= 0 ? lowestSeriesZIndex : zIndex;
|
|
}
|
|
return lowestSeriesZIndex ?? import_ag_charts_core148.SeriesZIndexMap.ANY_CONTENT;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/touch.ts
|
|
var import_ag_charts_core149 = require("ag-charts-core");
|
|
var Touch = class extends import_ag_charts_core149.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.dragAction = "drag";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core149.Property
|
|
], Touch.prototype, "dragAction", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/update/dataWindowProcessor.ts
|
|
var import_ag_charts_core150 = require("ag-charts-core");
|
|
var DataWindowProcessor = class {
|
|
constructor(chart, eventsHub, dataService, updateService, zoomManager, animationManager) {
|
|
this.chart = chart;
|
|
this.eventsHub = eventsHub;
|
|
this.dataService = dataService;
|
|
this.updateService = updateService;
|
|
this.zoomManager = zoomManager;
|
|
this.animationManager = animationManager;
|
|
this.dirtyZoom = false;
|
|
this.dirtyDataSource = false;
|
|
this.lastAxisZooms = /* @__PURE__ */ new Map();
|
|
this.cleanup = new import_ag_charts_core150.CleanupRegistry();
|
|
this.cleanup.register(
|
|
this.eventsHub.on("data:source-change", () => this.onDataSourceChange()),
|
|
this.eventsHub.on("data:load", () => this.onDataLoad()),
|
|
this.eventsHub.on("data:error", () => this.onDataError()),
|
|
this.updateService.addListener("update-complete", (e) => this.onUpdateComplete(e)),
|
|
this.eventsHub.on("zoom:change-complete", () => this.onZoomChange())
|
|
);
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
}
|
|
onDataLoad() {
|
|
this.animationManager.skip();
|
|
this.updateService.update(import_ag_charts_core150.ChartUpdateType.UPDATE_DATA);
|
|
}
|
|
onDataError() {
|
|
this.updateService.update(import_ag_charts_core150.ChartUpdateType.PERFORM_LAYOUT);
|
|
}
|
|
onDataSourceChange() {
|
|
this.dirtyDataSource = true;
|
|
}
|
|
onUpdateComplete(event) {
|
|
if (!event.apiUpdate && !this.dirtyZoom && !this.dirtyDataSource)
|
|
return;
|
|
if (event.wasShortcut)
|
|
return;
|
|
this.updateWindow(event);
|
|
}
|
|
onZoomChange() {
|
|
this.dirtyZoom = true;
|
|
}
|
|
updateWindow(event) {
|
|
if (!this.dataService.isLazy())
|
|
return;
|
|
const axis = this.getValidAxis();
|
|
let window;
|
|
let shouldRefresh = true;
|
|
if (axis) {
|
|
const zoom = this.zoomManager.getAxisZoom(axis.id);
|
|
window = this.getAxisWindow(axis, zoom);
|
|
shouldRefresh = this.shouldRefresh(event, axis, zoom);
|
|
}
|
|
this.dirtyZoom = false;
|
|
this.dirtyDataSource = false;
|
|
if (!shouldRefresh)
|
|
return;
|
|
this.dataService.load({ windowStart: window?.min, windowEnd: window?.max });
|
|
}
|
|
getValidAxis() {
|
|
return this.chart.axes.find((axis) => axis.type === "time");
|
|
}
|
|
shouldRefresh(event, axis, zoom) {
|
|
if (event.apiUpdate)
|
|
return true;
|
|
if (this.dirtyDataSource)
|
|
return true;
|
|
if (!this.dirtyZoom)
|
|
return false;
|
|
const lastZoom = this.lastAxisZooms.get(axis.id);
|
|
if (lastZoom && zoom.min === lastZoom.min && zoom.max === lastZoom.max) {
|
|
return false;
|
|
}
|
|
this.lastAxisZooms.set(axis.id, zoom);
|
|
return true;
|
|
}
|
|
getAxisWindow(axis, zoom) {
|
|
const { domain } = axis.scale;
|
|
if (!zoom || domain.length === 0 || Number.isNaN(Number(domain[0])))
|
|
return;
|
|
const diff2 = Number(domain[1]) - Number(domain[0]);
|
|
const min = new Date(Number(domain[0]) + diff2 * zoom.min);
|
|
const max = new Date(Number(domain[0]) + diff2 * zoom.max);
|
|
return { min, max };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/update/overlaysProcessor.ts
|
|
var import_ag_charts_core152 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/util/browser.ts
|
|
var import_ag_charts_core151 = require("ag-charts-core");
|
|
var isSafariRegexp = /^((?!chrome|android).)*safari/i;
|
|
var safariVersionRegexp = /Version\/(\d+(\.\d+)?)/;
|
|
var isChromeRegexp = /Chrome/;
|
|
var chromeVersionRegexp = /Chrome\/(\d+)/;
|
|
var isEdge = /Edg/;
|
|
var isOpera = /OPR/;
|
|
function isUnsupportedBrowser() {
|
|
const { userAgent } = (0, import_ag_charts_core151.getWindow)("navigator");
|
|
if (isSafariRegexp.test(userAgent)) {
|
|
const versionExec = safariVersionRegexp.exec(userAgent);
|
|
if (versionExec == null)
|
|
return false;
|
|
const version = Number.parseFloat(versionExec[1]);
|
|
const supported = Math.floor(version) > 16;
|
|
if (!supported) {
|
|
import_ag_charts_core151.Logger.warnOnce(`Unsupported Safari version: ${version}; ${userAgent}`);
|
|
}
|
|
return !supported;
|
|
} else if (isChromeRegexp.test(userAgent) && !isEdge.test(userAgent) && !isOpera.test(userAgent)) {
|
|
const versionExec = chromeVersionRegexp.exec(userAgent);
|
|
if (versionExec == null)
|
|
return false;
|
|
const version = Number.parseInt(versionExec[1], 10);
|
|
const supported = version > 126;
|
|
if (!supported) {
|
|
import_ag_charts_core151.Logger.warnOnce(`Unsupported Chrome version: ${version}; ${userAgent}`);
|
|
}
|
|
return !supported;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/update/overlaysProcessor.ts
|
|
var visibleIgnoredSeries = /* @__PURE__ */ new Set(["map-shape-background", "map-line-background"]);
|
|
var OverlaysProcessor = class {
|
|
constructor(chartLike, overlays, eventsHub, dataService, localeManager, animationManager, domManager) {
|
|
this.chartLike = chartLike;
|
|
this.overlays = overlays;
|
|
this.eventsHub = eventsHub;
|
|
this.dataService = dataService;
|
|
this.localeManager = localeManager;
|
|
this.animationManager = animationManager;
|
|
this.domManager = domManager;
|
|
this.cleanup = new import_ag_charts_core152.CleanupRegistry();
|
|
this.overlayElem = this.domManager.addChild("canvas-overlay", "overlay");
|
|
this.overlayElem.role = "status";
|
|
this.overlayElem.ariaAtomic = "false";
|
|
this.overlayElem.ariaLive = "polite";
|
|
this.overlayElem.classList.toggle(DEFAULT_OVERLAY_CLASS);
|
|
this.cleanup.register(this.eventsHub.on("layout:complete", (e) => this.onLayoutComplete(e)));
|
|
}
|
|
destroy() {
|
|
this.cleanup.flush();
|
|
this.domManager.removeChild("canvas-overlay", "overlay");
|
|
}
|
|
onLayoutComplete({ series: { rect: rect2 } }) {
|
|
const isLoading = this.dataService.isLoading();
|
|
const hasData = this.chartLike.series.some((s) => s.hasData);
|
|
const anySeriesVisible = this.chartLike.series.some((s) => s.visible && !visibleIgnoredSeries.has(s.type));
|
|
if (this.overlays.darkTheme) {
|
|
this.overlayElem.classList.add(DEFAULT_OVERLAY_DARK_CLASS);
|
|
} else {
|
|
this.overlayElem.classList.remove(DEFAULT_OVERLAY_DARK_CLASS);
|
|
}
|
|
this.overlayElem.style.left = `${rect2.x}px`;
|
|
this.overlayElem.style.top = `${rect2.y}px`;
|
|
this.overlayElem.style.width = `${rect2.width}px`;
|
|
this.overlayElem.style.height = `${rect2.height}px`;
|
|
const loadingShown = isLoading;
|
|
const noDataShown = !isLoading && !hasData;
|
|
const noVisibleSeriesShown = hasData && !anySeriesVisible;
|
|
const unsupportedBrowser = this.overlays.unsupportedBrowser.enabled && isUnsupportedBrowser();
|
|
if (loadingShown) {
|
|
this.showOverlay(this.overlays.loading, rect2);
|
|
} else {
|
|
this.hideOverlay(this.overlays.loading);
|
|
}
|
|
if (noDataShown) {
|
|
this.showOverlay(this.overlays.noData, rect2);
|
|
} else {
|
|
this.hideOverlay(this.overlays.noData);
|
|
}
|
|
if (noVisibleSeriesShown) {
|
|
this.showOverlay(this.overlays.noVisibleSeries, rect2);
|
|
} else {
|
|
this.hideOverlay(this.overlays.noVisibleSeries);
|
|
}
|
|
if (unsupportedBrowser) {
|
|
this.showOverlay(this.overlays.unsupportedBrowser, rect2);
|
|
} else {
|
|
this.hideOverlay(this.overlays.unsupportedBrowser);
|
|
}
|
|
const shown = loadingShown || noDataShown || noVisibleSeriesShown || unsupportedBrowser;
|
|
(0, import_ag_charts_core152.setAttribute)(this.overlayElem, "aria-hidden", !shown);
|
|
}
|
|
showOverlay(overlay, seriesRect) {
|
|
if (!overlay.enabled)
|
|
return;
|
|
const element2 = overlay.getElement(this.chartLike, this.animationManager, this.localeManager, seriesRect);
|
|
this.overlayElem.appendChild(element2);
|
|
}
|
|
hideOverlay(overlay) {
|
|
overlay.removeElement(() => {
|
|
this.overlayElem.innerText = "\xA0";
|
|
}, this.animationManager);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/chart.ts
|
|
var debug = import_ag_charts_core153.Debug.create(true, "opts");
|
|
var _Chart = class _Chart extends Observable {
|
|
constructor(options, resources) {
|
|
var _a;
|
|
super();
|
|
this.id = (0, import_ag_charts_core153.createId)(this);
|
|
this.seriesRoot = new TranslatableGroup({
|
|
name: `${this.id}-series-root`,
|
|
zIndex: import_ag_charts_core153.ZIndexMap.SERIES_LAYER
|
|
});
|
|
this.annotationRoot = new TranslatableGroup({
|
|
name: `${this.id}-annotation-root`,
|
|
zIndex: import_ag_charts_core153.ZIndexMap.SERIES_ANNOTATION
|
|
});
|
|
this.titleGroup = new Group({
|
|
name: "titles",
|
|
zIndex: import_ag_charts_core153.ZIndexMap.SERIES_LABEL
|
|
});
|
|
this.debug = import_ag_charts_core153.Debug.create(true, "chart");
|
|
this.extraDebugStats = {};
|
|
this.data = DataSet.empty();
|
|
this._firstAutoSize = true;
|
|
this._autoSizeNotify = new import_ag_charts_core153.AsyncAwaitQueue();
|
|
this._requiredRange = 0;
|
|
this._requiredRangeDirection = import_ag_charts_core153.ChartAxisDirection.X;
|
|
this.chartCaptions = new ChartCaptions();
|
|
this.padding = new import_ag_charts_core153.Padding(20);
|
|
this.keyboard = new Keyboard();
|
|
this.touch = new Touch();
|
|
this.mode = "standalone";
|
|
this.styleNonce = void 0;
|
|
this.formatter = void 0;
|
|
this.suppressFieldDotNotation = false;
|
|
this.loadGoogleFonts = false;
|
|
this.destroyed = false;
|
|
this.cleanup = new import_ag_charts_core153.CleanupRegistry();
|
|
this.chartAnimationPhase = "initial";
|
|
this.modulesManager = new ModulesManager();
|
|
this.processors = [];
|
|
this.queuedUserOptions = [];
|
|
this.queuedChartOptions = [];
|
|
this.firstApply = true;
|
|
this.syncStatus = "init";
|
|
// Use a wrapper to comply with the @typescript-eslint/unbound-method rule.
|
|
this.fireEventWrapper = (event) => super.fireEvent(event);
|
|
this.apiUpdate = false;
|
|
this._pendingFactoryUpdatesCount = 0;
|
|
this._performUpdateSkipAnimations = false;
|
|
this._performUpdateNotify = new import_ag_charts_core153.AsyncAwaitQueue();
|
|
this.performUpdateType = import_ag_charts_core153.ChartUpdateType.NONE;
|
|
this.runningUpdateType = import_ag_charts_core153.ChartUpdateType.NONE;
|
|
this.updateShortcutCount = 0;
|
|
this.seriesToUpdate = /* @__PURE__ */ new Set();
|
|
this.updateMutex = new Mutex();
|
|
this.clearCallbackCacheOnUpdate = false;
|
|
this.updateRequestors = {};
|
|
this.performUpdateTrigger = debouncedCallback(({ count }) => {
|
|
if (this.destroyed)
|
|
return;
|
|
this.updateMutex.acquire(this.tryPerformUpdate.bind(this, count)).catch((e) => import_ag_charts_core153.Logger.errorOnce(e));
|
|
});
|
|
this._performUpdateSplits = {};
|
|
this._previousSplit = 0;
|
|
this.axes = this.createChartAxes();
|
|
this.series = [];
|
|
this._cachedData = void 0;
|
|
this.onSeriesNodeClick = (event) => {
|
|
this.fireEvent(event);
|
|
};
|
|
this.onSeriesNodeDoubleClick = (event) => {
|
|
this.fireEvent(event);
|
|
};
|
|
this.onSeriesVisibilityChange = (event) => {
|
|
this.fireEvent(event);
|
|
};
|
|
this.seriesGroupingChanged = (event) => {
|
|
if (!(event instanceof SeriesGroupingChangedEvent))
|
|
return;
|
|
const { series, seriesGrouping } = event;
|
|
if (series.contentGroup.isRoot())
|
|
return;
|
|
const seriesContentNode = this.seriesLayerManager.changeGroup({
|
|
internalId: series.internalId,
|
|
type: series.type,
|
|
contentGroup: series.contentGroup,
|
|
bringToFront: () => series.bringToFront(),
|
|
renderToOffscreenCanvas: () => series.renderToOffscreenCanvas(),
|
|
seriesGrouping
|
|
});
|
|
if (seriesContentNode != null) {
|
|
series.attachSeries(seriesContentNode, this.seriesRoot, this.annotationRoot);
|
|
}
|
|
};
|
|
this.chartOptions = options;
|
|
const scene = resources?.scene;
|
|
const container = resources?.container ?? options.processedOptions.container ?? void 0;
|
|
const styleContainer = resources?.styleContainer ?? options.specialOverrides.styleContainer;
|
|
const skipCss = options.specialOverrides.skipCss;
|
|
if (scene) {
|
|
this._firstAutoSize = false;
|
|
this._lastAutoSize = [scene.width, scene.height, scene.pixelRatio];
|
|
}
|
|
const root = new Group({ name: "root" });
|
|
root.visible = false;
|
|
root.append(this.seriesRoot);
|
|
root.append(this.annotationRoot);
|
|
root.append(this.titleGroup);
|
|
this.titleGroup.append(this.title.node);
|
|
this.titleGroup.append(this.subtitle.node);
|
|
this.titleGroup.append(this.footnote.node);
|
|
this.tooltip = new Tooltip();
|
|
this.seriesLayerManager = new SeriesLayerManager(this.seriesRoot);
|
|
this.mode = options.userOptions.mode ?? this.mode;
|
|
this.styleNonce = options.processedOptions.styleNonce;
|
|
const ctx = this.ctx = new ChartContext(this, {
|
|
chartType: this.getChartType(),
|
|
scene,
|
|
root,
|
|
container,
|
|
styleContainer,
|
|
skipCss,
|
|
domMode: options.optionMetadata.domMode,
|
|
withDragInterpretation: options.optionMetadata.withDragInterpretation ?? true,
|
|
syncManager: new SyncManager(this),
|
|
fireEvent: (event) => this.fireEvent(event),
|
|
updateCallback: (type, opts) => this.update(type, opts),
|
|
updateMutex: this.updateMutex
|
|
});
|
|
if (options.optionMetadata.presetType === "sparkline") {
|
|
ctx.highlightManager.unhighlightDelay = 0;
|
|
ctx.tooltipManager.removeDelay = 0;
|
|
}
|
|
this.cleanup.register(ctx.eventsHub.on("dom:resize", () => this.parentResize(ctx.domManager.containerSize)));
|
|
this.overlays = new ChartOverlays();
|
|
(_a = this.overlays.loading).renderer ?? (_a.renderer = () => getLoadingSpinner(this.overlays.loading.getText(ctx.localeManager), ctx.animationManager.defaultDuration));
|
|
this.processors = [
|
|
new DataWindowProcessor(
|
|
this,
|
|
ctx.eventsHub,
|
|
ctx.dataService,
|
|
ctx.updateService,
|
|
ctx.zoomManager,
|
|
ctx.animationManager
|
|
),
|
|
new OverlaysProcessor(
|
|
this,
|
|
this.overlays,
|
|
ctx.eventsHub,
|
|
ctx.dataService,
|
|
ctx.localeManager,
|
|
ctx.animationManager,
|
|
ctx.domManager
|
|
)
|
|
];
|
|
this.highlight = new ChartHighlight();
|
|
this.container = container;
|
|
const moduleContext = this.getModuleContext();
|
|
this.background = import_ag_charts_core153.enterpriseRegistry.createBackground?.(moduleContext) ?? new Background(moduleContext);
|
|
this.foreground = import_ag_charts_core153.enterpriseRegistry.createForeground?.(moduleContext);
|
|
this.seriesArea = new SeriesArea(moduleContext);
|
|
ctx.domManager.setDataBoolean("animating", false);
|
|
ctx.domManager.setDataNumber("animationTimeMs", 0);
|
|
this.seriesAreaManager = new SeriesAreaManager(this.initSeriesAreaDependencies());
|
|
this.cleanup.register(
|
|
ctx.layoutManager.registerElement(0 /* Caption */, (e) => {
|
|
e.layoutBox.shrink(this.padding.toJson());
|
|
this.chartCaptions.positionCaptions(e);
|
|
}),
|
|
ctx.eventsHub.on("layout:complete", (e) => this.chartCaptions.positionAbsoluteCaptions(e)),
|
|
ctx.eventsHub.on("data:load", (event) => {
|
|
this.data = new DataSet(event.data);
|
|
}),
|
|
this.title.registerInteraction(moduleContext, "beforebegin"),
|
|
this.subtitle.registerInteraction(moduleContext, "beforebegin"),
|
|
this.footnote.registerInteraction(moduleContext, "afterend"),
|
|
() => this.title.destroy(),
|
|
() => this.subtitle.destroy(),
|
|
() => this.footnote.destroy(),
|
|
Widget.addWindowEvent("page-left", () => this.destroy()),
|
|
ctx.animationManager.addListener("animation-frame", () => {
|
|
this.update(import_ag_charts_core153.ChartUpdateType.SCENE_RENDER);
|
|
ctx.domManager.setDataNumber("animationTimeMs", ctx.animationManager.getCumulativeAnimationTime());
|
|
}),
|
|
ctx.animationManager.addListener("animation-start", () => ctx.domManager.setDataBoolean("animating", true)),
|
|
ctx.animationManager.addListener("animation-stop", () => {
|
|
ctx.domManager.setDataBoolean("animating", false);
|
|
ctx.domManager.setDataNumber("animationTimeMs", ctx.animationManager.getCumulativeAnimationTime());
|
|
}),
|
|
ctx.eventsHub.on("zoom:change-complete", () => {
|
|
for (const s of this.series) {
|
|
s.animationState?.transition("updateData");
|
|
}
|
|
const skipAnimations = this.chartAnimationPhase !== "initial";
|
|
this.update(import_ag_charts_core153.ChartUpdateType.PERFORM_LAYOUT, { forceNodeDataRefresh: true, skipAnimations });
|
|
})
|
|
);
|
|
this.parentResize(ctx.domManager.containerSize);
|
|
}
|
|
static getInstance(element2) {
|
|
return _Chart.chartsInstances.get(element2);
|
|
}
|
|
/** NOTE: This is exposed for use by Integrated charts only. */
|
|
get canvasElement() {
|
|
return this.ctx.scene.canvas.element;
|
|
}
|
|
download(fileName, fileFormat) {
|
|
this.ctx.scene.download(fileName, fileFormat);
|
|
}
|
|
getCanvasDataURL(fileFormat) {
|
|
return this.ctx.scene.getDataURL(fileFormat);
|
|
}
|
|
toSVG() {
|
|
return this.ctx.scene.toSVG();
|
|
}
|
|
get seriesAreaBoundingBox() {
|
|
return this.seriesAreaManager.bbox;
|
|
}
|
|
getOptions() {
|
|
return this.queuedUserOptions.at(-1) ?? this.chartOptions.userOptions;
|
|
}
|
|
getChartOptions() {
|
|
return this.queuedChartOptions.at(-1) ?? this.chartOptions;
|
|
}
|
|
isDataTransactionSupported() {
|
|
return true;
|
|
}
|
|
overrideFocusVisible(visible) {
|
|
this.seriesAreaManager.focusIndicator?.overrideFocusVisible(visible);
|
|
}
|
|
fireEvent(event) {
|
|
(0, import_ag_charts_core153.callWithContext)(this, this.fireEventWrapper, event);
|
|
}
|
|
initSeriesAreaDependencies() {
|
|
const { ctx, tooltip, highlight: highlight5, overlays, seriesRoot, mode } = this;
|
|
const chartType = this.getChartType();
|
|
const fireEvent = this.fireEvent.bind(this);
|
|
const getUpdateType = () => this.performUpdateType;
|
|
const getTooltipContent = (series, datumIndex, removeThisDatum, purpose) => this.getTooltipContent(series, datumIndex, removeThisDatum, purpose);
|
|
return {
|
|
fireEvent,
|
|
getUpdateType,
|
|
getTooltipContent,
|
|
chartType,
|
|
ctx,
|
|
tooltip,
|
|
highlight: highlight5,
|
|
overlays,
|
|
seriesRoot,
|
|
mode
|
|
};
|
|
}
|
|
getModuleContext() {
|
|
return this.ctx;
|
|
}
|
|
getTooltipContent(series, datumIndex, removeMeDatum, purpose) {
|
|
const useTooltip = purpose === "aria-label" || series.properties.tooltip.enabled !== false;
|
|
const baseTooltipContent = useTooltip ? series.getTooltipContent(datumIndex, removeMeDatum) : void 0;
|
|
const tooltipContent = baseTooltipContent == null ? [] : [baseTooltipContent];
|
|
if (this.tooltip.mode !== "shared" || this.series.length === 1) {
|
|
return tooltipContent;
|
|
}
|
|
const categoryValue = series.getCategoryValue(datumIndex);
|
|
if (categoryValue == null)
|
|
return tooltipContent;
|
|
return this.series.flatMap((s) => {
|
|
if (s === series)
|
|
return tooltipContent;
|
|
if (!s.isEnabled() || s.properties.tooltip.enabled === false)
|
|
return [];
|
|
const seriesDatumIndex = s.datumIndexForCategoryValue(categoryValue);
|
|
const seriesTooltipContent = seriesDatumIndex == null ? void 0 : s.getTooltipContent(seriesDatumIndex, void 0);
|
|
if (seriesTooltipContent == null)
|
|
return [];
|
|
return [seriesTooltipContent];
|
|
});
|
|
}
|
|
getCaptionText() {
|
|
return [this.title, this.subtitle, this.footnote].filter((caption) => caption.enabled && caption.text).map((caption) => caption.text).join(". ");
|
|
}
|
|
getAriaLabel() {
|
|
return this.ctx.localeManager.t("ariaAnnounceChart", { seriesCount: this.series.length });
|
|
}
|
|
refreshSeriesUserVisibility(outdatedOptions, seriesWithUserVisibility) {
|
|
for (let i = 0; i < this.series.length; i++) {
|
|
const src = this.series[i];
|
|
const dst = outdatedOptions.processedOptions.series?.[i];
|
|
if (seriesWithUserVisibility.identifiers.has(src.id) || seriesWithUserVisibility.indices.has(i)) {
|
|
if (dst !== void 0 && "visible" in dst) {
|
|
dst.visible = src.visible;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
resetAnimations() {
|
|
this.chartAnimationPhase = "initial";
|
|
for (const series of this.series) {
|
|
series.resetAnimation(this.chartAnimationPhase);
|
|
}
|
|
for (const axis of this.axes) {
|
|
axis.resetAnimation(this.chartAnimationPhase);
|
|
}
|
|
this.animationRect = void 0;
|
|
this.ctx.animationManager.reset();
|
|
}
|
|
skipAnimations() {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this._performUpdateSkipAnimations = true;
|
|
}
|
|
detachAndClear() {
|
|
this.container = void 0;
|
|
this.ctx.scene.clearCanvas();
|
|
}
|
|
destroy(opts) {
|
|
if (this.destroyed) {
|
|
return;
|
|
}
|
|
const keepTransferableResources = opts?.keepTransferableResources;
|
|
let result;
|
|
this.performUpdateType = import_ag_charts_core153.ChartUpdateType.NONE;
|
|
this.cleanup.flush();
|
|
for (const p of this.processors) {
|
|
p.destroy();
|
|
}
|
|
this.overlays.destroy();
|
|
this.modulesManager.destroy();
|
|
this.background.destroy();
|
|
this.foreground?.destroy();
|
|
this.seriesArea.destroy();
|
|
if (keepTransferableResources) {
|
|
this.ctx.scene.strip();
|
|
result = {
|
|
container: this.container,
|
|
scene: this.ctx.scene
|
|
};
|
|
} else {
|
|
this.ctx.scene.destroy();
|
|
this.container = void 0;
|
|
}
|
|
this.destroySeries(this.series);
|
|
this.seriesLayerManager.destroy();
|
|
this.axes.destroy();
|
|
this.animationRect = void 0;
|
|
this.ctx.destroy();
|
|
this.destroyed = true;
|
|
Object.freeze(this);
|
|
return result;
|
|
}
|
|
requestFactoryUpdate(cb) {
|
|
if (this.destroyed)
|
|
return;
|
|
this._pendingFactoryUpdatesCount++;
|
|
this.updateMutex.acquire(async () => {
|
|
if (this.destroyed)
|
|
return;
|
|
try {
|
|
await cb(this);
|
|
} finally {
|
|
if (!this.destroyed) {
|
|
this._pendingFactoryUpdatesCount--;
|
|
}
|
|
}
|
|
}).catch((e) => import_ag_charts_core153.Logger.errorOnce(e));
|
|
}
|
|
clearCallbackCache() {
|
|
this.ctx.callbackCache.invalidateCache();
|
|
for (const series of this.series) {
|
|
series.resetDatumCallbackCache();
|
|
}
|
|
}
|
|
update(type = import_ag_charts_core153.ChartUpdateType.FULL, opts) {
|
|
if (this.destroyed)
|
|
return;
|
|
const {
|
|
forceNodeDataRefresh = false,
|
|
skipAnimations,
|
|
seriesToUpdate = this.series,
|
|
newAnimationBatch,
|
|
apiUpdate = false,
|
|
clearCallbackCache = false
|
|
} = opts ?? {};
|
|
this.apiUpdate = apiUpdate;
|
|
this.ctx.widgets.seriesWidget.setDragTouchEnabled(this.touch.dragAction !== "none");
|
|
if (forceNodeDataRefresh) {
|
|
for (const series of this.series) {
|
|
series.markNodeDataDirty();
|
|
}
|
|
}
|
|
for (const series of seriesToUpdate) {
|
|
this.seriesToUpdate.add(series);
|
|
}
|
|
if (skipAnimations) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this._performUpdateSkipAnimations = true;
|
|
}
|
|
if (newAnimationBatch && this.ctx.animationManager.isActive()) {
|
|
this._performUpdateSkipAnimations = true;
|
|
}
|
|
if (type === import_ag_charts_core153.ChartUpdateType.FULL || clearCallbackCache) {
|
|
this.clearCallbackCacheOnUpdate = true;
|
|
}
|
|
if (this.debug.check()) {
|
|
let stack = new Error("Stack trace for update tracking").stack ?? "<unknown>";
|
|
stack = stack.replaceAll(/\([^)]*/g, "");
|
|
this.updateRequestors[stack] = type;
|
|
}
|
|
if (type < this.performUpdateType) {
|
|
this.performUpdateType = type;
|
|
this.ctx.domManager.setDataBoolean("updatePending", true);
|
|
this.performUpdateTrigger.schedule(opts?.backOffMs);
|
|
}
|
|
}
|
|
updateSplits(splitName) {
|
|
const splits = this._performUpdateSplits;
|
|
splits[splitName] ?? (splits[splitName] = 0);
|
|
splits[splitName] += performance.now() - this._previousSplit;
|
|
this._previousSplit = performance.now();
|
|
}
|
|
async tryPerformUpdate(count) {
|
|
try {
|
|
await this.performUpdate(count);
|
|
} catch (error) {
|
|
import_ag_charts_core153.Logger.error("update error", error, error.stack);
|
|
}
|
|
}
|
|
async performUpdate(count) {
|
|
const { performUpdateType, extraDebugStats, _performUpdateSplits: splits, ctx } = this;
|
|
const seriesToUpdate = [...this.seriesToUpdate];
|
|
if (this.clearCallbackCacheOnUpdate) {
|
|
this.clearCallbackCacheOnUpdate = false;
|
|
this.clearCallbackCache();
|
|
}
|
|
this.performUpdateType = import_ag_charts_core153.ChartUpdateType.NONE;
|
|
this.seriesToUpdate.clear();
|
|
this.runningUpdateType = performUpdateType;
|
|
if (this.updateShortcutCount === 0 && performUpdateType < import_ag_charts_core153.ChartUpdateType.SCENE_RENDER) {
|
|
ctx.animationManager.startBatch(this._performUpdateSkipAnimations);
|
|
ctx.animationManager.onBatchStop(() => this.chartAnimationPhase = "ready");
|
|
}
|
|
this.ctx.scene.updateDebugFlags();
|
|
this.debug("Chart.performUpdate() - start", import_ag_charts_core153.ChartUpdateType[performUpdateType]);
|
|
this._previousSplit = performance.now();
|
|
splits.start ?? (splits.start = this._previousSplit);
|
|
switch (performUpdateType) {
|
|
case import_ag_charts_core153.ChartUpdateType.FULL:
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.FULL))
|
|
break;
|
|
this.ctx.updateService.dispatchPreDomUpdate();
|
|
this.updateDOM();
|
|
case import_ag_charts_core153.ChartUpdateType.UPDATE_DATA:
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.UPDATE_DATA))
|
|
break;
|
|
this.updateData();
|
|
this.updateSplits("\u2B07\uFE0F");
|
|
case import_ag_charts_core153.ChartUpdateType.PROCESS_DATA:
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.PROCESS_DATA))
|
|
break;
|
|
await this.processData();
|
|
this.seriesAreaManager.dataChanged();
|
|
if (this.pendingLocaleText) {
|
|
const localeModule = this.modulesManager.getModule("locale");
|
|
if (localeModule && "localeText" in localeModule) {
|
|
localeModule.localeText = this.pendingLocaleText;
|
|
}
|
|
this.pendingLocaleText = void 0;
|
|
}
|
|
this.updateSplits("\u{1F4CA}");
|
|
case import_ag_charts_core153.ChartUpdateType.PROCESS_DOMAIN:
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.PROCESS_DOMAIN))
|
|
break;
|
|
await this.processDomains();
|
|
this.updateSplits("\u26F0\uFE0F");
|
|
case import_ag_charts_core153.ChartUpdateType.PROCESS_RANGE:
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.PROCESS_RANGE))
|
|
break;
|
|
this.processRanges();
|
|
this.updateSplits("\u{1F4D0}");
|
|
case import_ag_charts_core153.ChartUpdateType.PERFORM_LAYOUT:
|
|
await this.checkFirstAutoSize();
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.PERFORM_LAYOUT))
|
|
break;
|
|
await this.processLayout();
|
|
this.updateSplits("\u2316");
|
|
case import_ag_charts_core153.ChartUpdateType.PRE_SERIES_UPDATE:
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.PRE_SERIES_UPDATE))
|
|
break;
|
|
this.preSeriesUpdate();
|
|
this.updateSplits("\u2753");
|
|
case import_ag_charts_core153.ChartUpdateType.SERIES_UPDATE: {
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.SERIES_UPDATE))
|
|
break;
|
|
this.seriesRoot.renderToOffscreenCanvas = this.highlight.drawingMode === "cutout";
|
|
await this.updateSeries(seriesToUpdate);
|
|
this.updateAriaLabels();
|
|
this.seriesLayerManager.updateLayerCompositing();
|
|
this.updateSplits("\u{1F914}");
|
|
}
|
|
case import_ag_charts_core153.ChartUpdateType.PRE_SCENE_RENDER:
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.PRE_SCENE_RENDER))
|
|
break;
|
|
ctx.updateService.dispatchPreSceneRender();
|
|
this.updateSplits("\u2196");
|
|
case import_ag_charts_core153.ChartUpdateType.SCENE_RENDER:
|
|
if (this.checkUpdateShortcut(import_ag_charts_core153.ChartUpdateType.SCENE_RENDER))
|
|
break;
|
|
ctx.animationManager.endBatch();
|
|
extraDebugStats["updateShortcutCount"] = this.updateShortcutCount;
|
|
ctx.scene.render({
|
|
debugSplitTimes: splits,
|
|
extraDebugStats,
|
|
seriesRect: this.seriesRect,
|
|
debugColors: this.getDebugColors()
|
|
});
|
|
this.extraDebugStats = {};
|
|
for (const key of Object.keys(splits)) {
|
|
delete splits[key];
|
|
}
|
|
this.ctx.domManager.incrementDataCounter("sceneRenders");
|
|
this.ctx.domManager.postRenderUpdate();
|
|
case import_ag_charts_core153.ChartUpdateType.NONE:
|
|
this.updateShortcutCount = 0;
|
|
this.updateRequestors = {};
|
|
this._performUpdateSkipAnimations = false;
|
|
ctx.animationManager.endBatch();
|
|
}
|
|
if (!this.destroyed) {
|
|
ctx.updateService.dispatchUpdateComplete(this.apiUpdate, this.updateShortcutCount > 0);
|
|
this.apiUpdate = false;
|
|
this.ctx.domManager.setDataBoolean("updatePending", false);
|
|
this.runningUpdateType = import_ag_charts_core153.ChartUpdateType.NONE;
|
|
this.syncStatus = "ready";
|
|
}
|
|
this._performUpdateNotify.notify();
|
|
const end2 = performance.now();
|
|
this.debug("Chart.performUpdate() - end", {
|
|
chart: this,
|
|
durationMs: (0, import_ag_charts_core153.roundTo)(end2 - splits["start"]),
|
|
count,
|
|
performUpdateType: import_ag_charts_core153.ChartUpdateType[performUpdateType]
|
|
});
|
|
}
|
|
updateThemeClassName() {
|
|
const themeClassNamePrefix = "ag-charts-theme-";
|
|
const validThemeClassNames = [`${themeClassNamePrefix}default`, `${themeClassNamePrefix}default-dark`];
|
|
let themeClassName = validThemeClassNames[0];
|
|
let isDark = false;
|
|
let { theme } = this.chartOptions.processedOptions;
|
|
while (typeof theme !== "string" && theme != null) {
|
|
theme = theme.baseTheme;
|
|
}
|
|
if (typeof theme === "string") {
|
|
themeClassName = theme.replace("ag-", themeClassNamePrefix);
|
|
isDark = theme.includes("-dark");
|
|
}
|
|
if (!validThemeClassNames.includes(themeClassName)) {
|
|
themeClassName = isDark ? validThemeClassNames[1] : validThemeClassNames[0];
|
|
}
|
|
this.ctx.domManager.setThemeClass(themeClassName);
|
|
}
|
|
updateDOM() {
|
|
this.updateThemeClassName();
|
|
const { enabled, tabIndex } = this.keyboard;
|
|
this.ctx.domManager.setTabGuardIndex(enabled ? tabIndex ?? 0 : -1);
|
|
this.ctx.domManager.setThemeParameters(this.chartOptions.themeParameters);
|
|
}
|
|
updateAriaLabels() {
|
|
this.ctx.domManager.updateCanvasLabel(this.getAriaLabel());
|
|
}
|
|
checkUpdateShortcut(checkUpdateType) {
|
|
const maxShortcuts = 3;
|
|
if (this.destroyed)
|
|
return true;
|
|
if (this.updateShortcutCount > maxShortcuts) {
|
|
import_ag_charts_core153.Logger.warn(
|
|
`exceeded the maximum number of simultaneous updates (${maxShortcuts + 1}), discarding changes and rendering`,
|
|
this.updateRequestors
|
|
);
|
|
return false;
|
|
}
|
|
if (this.performUpdateType <= checkUpdateType) {
|
|
this.debug("Chart.checkUpdateShortcut() - BLOCKED AT: ", import_ag_charts_core153.ChartUpdateType[checkUpdateType]);
|
|
this.updateShortcutCount++;
|
|
return true;
|
|
}
|
|
this.debug("Chart.checkUpdateShortcut() - PROCEEDING TO: ", import_ag_charts_core153.ChartUpdateType[checkUpdateType]);
|
|
return false;
|
|
}
|
|
async checkFirstAutoSize() {
|
|
if (this.width != null && this.height != null) {
|
|
} else if (!this._lastAutoSize) {
|
|
const success = await this._autoSizeNotify.waitForCompletion(500);
|
|
if (!success) {
|
|
this.debug("Chart.checkFirstAutoSize() - timeout for first size update.");
|
|
}
|
|
}
|
|
}
|
|
createChartAxes() {
|
|
return new ChartAxes();
|
|
}
|
|
onAxisChange(newValue, oldValue) {
|
|
if (oldValue == null && newValue.length === 0)
|
|
return;
|
|
this.ctx.axisManager.updateAxes(oldValue ?? [], newValue);
|
|
}
|
|
onSeriesChange(newValue, oldValue) {
|
|
const seriesToDestroy = oldValue?.filter((series) => !newValue.includes(series)) ?? [];
|
|
this.destroySeries(seriesToDestroy);
|
|
this.seriesLayerManager?.setSeriesCount(newValue.length);
|
|
for (const series of newValue) {
|
|
if (oldValue?.includes(series))
|
|
continue;
|
|
const seriesContentNode = this.seriesLayerManager.requestGroup(series);
|
|
series.attachSeries(seriesContentNode, this.seriesRoot, this.annotationRoot);
|
|
series.chart = {};
|
|
Object.defineProperty(series.chart, "mode", {
|
|
get: () => this.mode
|
|
});
|
|
Object.defineProperty(series.chart, "isMiniChart", {
|
|
get: () => false
|
|
});
|
|
Object.defineProperty(series.chart, "flashOnUpdateEnabled", {
|
|
get: () => !!this.modulesManager.getModule("flashOnUpdate")?.enabled
|
|
});
|
|
Object.defineProperty(series.chart, "seriesRect", {
|
|
get: () => this.seriesRect
|
|
});
|
|
series.resetAnimation(this.chartAnimationPhase);
|
|
this.addSeriesListeners(series);
|
|
}
|
|
this.seriesAreaManager?.seriesChanged(newValue);
|
|
}
|
|
destroySeries(allSeries) {
|
|
if (allSeries) {
|
|
for (const series of allSeries) {
|
|
series.removeEventListener("seriesNodeClick", this.onSeriesNodeClick);
|
|
series.removeEventListener("seriesNodeDoubleClick", this.onSeriesNodeDoubleClick);
|
|
series.removeEventListener("groupingChanged", this.seriesGroupingChanged);
|
|
series.destroy();
|
|
this.seriesLayerManager.releaseGroup(series);
|
|
series.detachSeries(void 0, this.seriesRoot, this.annotationRoot);
|
|
series.chart = void 0;
|
|
}
|
|
}
|
|
}
|
|
addSeriesListeners(series) {
|
|
if (this.hasEventListener("seriesNodeClick")) {
|
|
series.addEventListener("seriesNodeClick", this.onSeriesNodeClick);
|
|
}
|
|
if (this.hasEventListener("seriesNodeDoubleClick")) {
|
|
series.addEventListener("seriesNodeDoubleClick", this.onSeriesNodeDoubleClick);
|
|
}
|
|
if (this.hasEventListener("seriesVisibilityChange")) {
|
|
series.addEventListener("seriesVisibilityChange", this.onSeriesVisibilityChange);
|
|
}
|
|
series.addEventListener("groupingChanged", this.seriesGroupingChanged);
|
|
}
|
|
assignSeriesToAxes() {
|
|
for (const axis of this.axes) {
|
|
let seriesPredicateFn2 = function(s) {
|
|
return s.axes[axis.direction] === axis;
|
|
};
|
|
var seriesPredicateFn = seriesPredicateFn2;
|
|
axis.boundSeries = this.series.filter(seriesPredicateFn2);
|
|
}
|
|
}
|
|
assignAxesToSeries() {
|
|
for (const series of this.series) {
|
|
for (const direction of series.directions) {
|
|
const seriesAxisId = series.getKeyAxis(direction) ?? direction;
|
|
const newAxis = this.axes.findById(seriesAxisId);
|
|
if (!newAxis) {
|
|
import_ag_charts_core153.Logger.warnOnce(
|
|
`no matching axis for direction [${direction}] and id [${seriesAxisId}]; check series and axes configuration.`
|
|
);
|
|
return;
|
|
}
|
|
series.axes[direction] = newAxis;
|
|
}
|
|
}
|
|
}
|
|
parentResize(size) {
|
|
if (size == null || this.width != null && this.height != null)
|
|
return;
|
|
let { width, height } = size;
|
|
const { pixelRatio } = size;
|
|
width = Math.floor(width);
|
|
height = Math.floor(height);
|
|
if (width === 0 && height === 0)
|
|
return;
|
|
const [autoWidth = 0, autoHeight = 0, autoPixelRatio = 1] = this._lastAutoSize ?? [];
|
|
if (autoWidth === width && autoHeight === height && autoPixelRatio === pixelRatio)
|
|
return;
|
|
this._lastAutoSize = [width, height, pixelRatio];
|
|
this.resize("SizeMonitor", {});
|
|
}
|
|
resize(source, opts) {
|
|
const { scene, animationManager } = this.ctx;
|
|
const { inWidth, inHeight, inMinWidth, inMinHeight, inOverrideDevicePixelRatio } = opts;
|
|
this.ctx.domManager.setSizeOptions(
|
|
inMinWidth ?? this.minWidth,
|
|
inMinHeight ?? this.minHeight,
|
|
inWidth ?? this.width,
|
|
inHeight ?? this.height
|
|
);
|
|
const width = inWidth ?? this.width ?? this._lastAutoSize?.[0];
|
|
const height = inHeight ?? this.height ?? this._lastAutoSize?.[1];
|
|
const pixelRatio = inOverrideDevicePixelRatio ?? this.overrideDevicePixelRatio ?? this._lastAutoSize?.[2];
|
|
this.debug(`Chart.resize() from ${source}`, {
|
|
width,
|
|
height,
|
|
pixelRatio,
|
|
stack: new Error("Stack trace for resize tracking").stack
|
|
});
|
|
if (width == null || height == null || !(0, import_ag_charts_core153.isFiniteNumber)(width) || !(0, import_ag_charts_core153.isFiniteNumber)(height))
|
|
return;
|
|
if (scene.resize(width, height, pixelRatio)) {
|
|
animationManager.reset();
|
|
let skipAnimations = true;
|
|
if ((this.width == null || this.height == null) && this._firstAutoSize) {
|
|
skipAnimations = false;
|
|
this._firstAutoSize = false;
|
|
}
|
|
let updateType = import_ag_charts_core153.ChartUpdateType.PERFORM_LAYOUT;
|
|
for (const axis of this.axes) {
|
|
const axisUpdateType = axis.getUpdateTypeOnResize();
|
|
if (axisUpdateType < updateType) {
|
|
updateType = axisUpdateType;
|
|
}
|
|
}
|
|
this.update(updateType, { forceNodeDataRefresh: true, skipAnimations });
|
|
this._autoSizeNotify.notify();
|
|
}
|
|
}
|
|
updateData() {
|
|
this.ctx.eventsHub.emit("data:update", this.data);
|
|
}
|
|
async processData() {
|
|
if (this.series.some((s) => s.canHaveAxes)) {
|
|
this.assignAxesToSeries();
|
|
this.assignSeriesToAxes();
|
|
}
|
|
const dataController = new DataController(this.mode, this.suppressFieldDotNotation, this.ctx.eventsHub);
|
|
const promises = [];
|
|
for (const series of this.series) {
|
|
promises.push(series.processData(dataController) ?? Promise.resolve());
|
|
}
|
|
for (const module2 of this.modulesManager.modules()) {
|
|
if (module2?.processData) {
|
|
promises.push(module2.processData(dataController) ?? Promise.resolve());
|
|
}
|
|
}
|
|
this._cachedData = dataController.execute(this._cachedData);
|
|
this.updateSplits("\u{1F3ED}");
|
|
await Promise.all(promises);
|
|
this.updateLegends();
|
|
}
|
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
async processDomains() {
|
|
for (const axis of this.axes) {
|
|
axis.processData();
|
|
}
|
|
for (const series of this.series) {
|
|
series.updatedDomains();
|
|
}
|
|
}
|
|
processRanges() {
|
|
var _a;
|
|
const seriesRanges = {};
|
|
const chartRanges = {};
|
|
const seriesTypes = /* @__PURE__ */ new Map();
|
|
this._requiredRangeDirection = import_ag_charts_core153.ChartAxisDirection.X;
|
|
for (const series of this.series) {
|
|
if (!series.visible)
|
|
continue;
|
|
seriesRanges[_a = series.type] ?? (seriesRanges[_a] = []);
|
|
series.getMinimumRangeSeries(seriesRanges[series.type]);
|
|
if (series.resolveKeyDirection(import_ag_charts_core153.ChartAxisDirection.X) === import_ag_charts_core153.ChartAxisDirection.Y) {
|
|
this._requiredRangeDirection = import_ag_charts_core153.ChartAxisDirection.Y;
|
|
}
|
|
if (!seriesTypes.has(series.type)) {
|
|
seriesTypes.set(series.type, series);
|
|
}
|
|
}
|
|
for (const [type, firstSeries] of seriesTypes) {
|
|
chartRanges[type] = firstSeries.getMinimumRangeChart(seriesRanges[type]);
|
|
}
|
|
if (Object.keys(chartRanges).length === 0) {
|
|
this._requiredRange = 0;
|
|
} else {
|
|
this._requiredRange = Math.ceil(Math.max(...Object.values(chartRanges)));
|
|
}
|
|
for (const axis of this.axes) {
|
|
axis.requiredRange = this._requiredRange;
|
|
}
|
|
}
|
|
updateLegends(initialStateLegend) {
|
|
for (const module2 of import_ag_charts_core153.ModuleRegistry.listModulesByType(import_ag_charts_core153.ModuleType.Plugin)) {
|
|
switch (module2.name) {
|
|
case "legend":
|
|
this.setCategoryLegendData(initialStateLegend);
|
|
break;
|
|
case "gradientLegend":
|
|
const moduleInstance = this.modulesManager.getModule("gradientLegend");
|
|
moduleInstance.data = this.series.filter((s) => s.properties.showInLegend).flatMap((s) => s.getLegendData("gradient"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
setCategoryLegendData(initialState) {
|
|
const { legendManager, stateManager } = this.ctx;
|
|
if (initialState) {
|
|
for (const s of this.series) {
|
|
const seriesState = initialState.find((init) => init.seriesId === s.id);
|
|
s.onLegendInitialState("category", seriesState);
|
|
}
|
|
}
|
|
const legendData = this.series.flatMap((s) => {
|
|
const seriesLegendData = s.getLegendData("category");
|
|
legendManager.updateData(s.id, seriesLegendData);
|
|
return seriesLegendData;
|
|
});
|
|
if (initialState) {
|
|
stateManager.setStateAndRestore(legendManager, initialState);
|
|
return;
|
|
}
|
|
if (this.mode !== "integrated") {
|
|
const seriesMarkerFills = {};
|
|
const seriesMap = new Map(this.series.map((s) => [s.id, s]));
|
|
for (const {
|
|
seriesId,
|
|
symbol: { marker },
|
|
label
|
|
} of legendData.filter((d) => !d.hideInLegend)) {
|
|
if (marker.fill == null)
|
|
continue;
|
|
const series = seriesMap.get(seriesId);
|
|
if (!series?.hasData)
|
|
continue;
|
|
const seriesType = series.type;
|
|
const markerFill = seriesMarkerFills[seriesType] ?? (seriesMarkerFills[seriesType] = /* @__PURE__ */ new Map());
|
|
if (markerFill.has(label.text)) {
|
|
if (markerFill.get(label.text) !== marker.fill) {
|
|
import_ag_charts_core153.Logger.warnOnce(
|
|
`legend item '${(0, import_ag_charts_core153.toPlainText)(label.text)}' has multiple fill colours, this may cause unexpected behaviour.`
|
|
);
|
|
}
|
|
} else {
|
|
markerFill.set(label.text, marker.fill);
|
|
}
|
|
}
|
|
}
|
|
legendManager.update();
|
|
}
|
|
async processLayout() {
|
|
const oldRect = this.animationRect;
|
|
const { width, height } = this.ctx.scene;
|
|
const ctx = this.ctx.layoutManager.createContext(width, height);
|
|
await this.performLayout(ctx);
|
|
if (oldRect && !this.animationRect?.equals(oldRect)) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
}
|
|
this.debug("Chart.performUpdate() - seriesRect", this.seriesRect);
|
|
}
|
|
getDebugColors() {
|
|
const bg = this.background.fill;
|
|
if (!bg)
|
|
return void 0;
|
|
try {
|
|
const color8 = import_ag_charts_core153.Color.fromString(bg);
|
|
const [lightness] = import_ag_charts_core153.Color.RGBtoOKLCH(color8.r, color8.g, color8.b);
|
|
return { background: bg, foreground: lightness > 0.5 ? "black" : "white" };
|
|
} catch {
|
|
return { background: bg };
|
|
}
|
|
}
|
|
preSeriesUpdate() {
|
|
const { _requiredRange, seriesRect } = this;
|
|
if (seriesRect == null)
|
|
return;
|
|
const dimension = this._requiredRangeDirection === import_ag_charts_core153.ChartAxisDirection.X ? seriesRect.width : seriesRect.height;
|
|
const requiredRangeRatio = _requiredRange / dimension || 0;
|
|
this.ctx.updateService.dispatchPreSeriesUpdate(requiredRangeRatio, this._requiredRangeDirection);
|
|
}
|
|
async updateSeries(seriesToUpdate) {
|
|
const { seriesRect } = this;
|
|
function seriesUpdate(series) {
|
|
return series.update({ seriesRect });
|
|
}
|
|
await Promise.all(seriesToUpdate.map(seriesUpdate).filter((p) => p != null));
|
|
this.ctx.seriesLabelLayoutManager.updateLabels(
|
|
this.series.filter((s) => s.visible && s.usesPlacedLabels),
|
|
this.padding,
|
|
this.seriesRect
|
|
);
|
|
}
|
|
async waitForUpdate(timeoutMs, failOnTimeout) {
|
|
const agChartsDebugTimeout = (0, import_ag_charts_core153.getWindow)("agChartsDebugTimeout");
|
|
if (agChartsDebugTimeout == null) {
|
|
timeoutMs ?? (timeoutMs = 1e4);
|
|
failOnTimeout ?? (failOnTimeout = false);
|
|
} else {
|
|
timeoutMs = agChartsDebugTimeout;
|
|
failOnTimeout ?? (failOnTimeout = true);
|
|
}
|
|
const start = performance.now();
|
|
while (this._pendingFactoryUpdatesCount > 0 || this.performUpdateType !== import_ag_charts_core153.ChartUpdateType.NONE || this.runningUpdateType !== import_ag_charts_core153.ChartUpdateType.NONE || this.ctx.scene.waitingForUpdate() || this.data.hasPendingTransactions()) {
|
|
if (this.destroyed)
|
|
break;
|
|
if (this._pendingFactoryUpdatesCount > 0) {
|
|
await this.updateMutex.waitForClearAcquireQueue();
|
|
}
|
|
if (this.performUpdateType !== import_ag_charts_core153.ChartUpdateType.NONE || this.runningUpdateType !== import_ag_charts_core153.ChartUpdateType.NONE || this.data.hasPendingTransactions()) {
|
|
await this._performUpdateNotify.waitForCompletion();
|
|
}
|
|
if (performance.now() - start > timeoutMs) {
|
|
const message = `Chart.waitForUpdate() timeout of ${timeoutMs} reached - first chart update taking too long.`;
|
|
if (failOnTimeout) {
|
|
throw new Error(message);
|
|
} else {
|
|
import_ag_charts_core153.Logger.warnOnce(message);
|
|
}
|
|
}
|
|
if ((0, import_ag_charts_core153.isInputPending)()) {
|
|
await (0, import_ag_charts_core153.pause)();
|
|
}
|
|
if (this.ctx.scene.waitingForUpdate()) {
|
|
await (0, import_ag_charts_core153.pause)(50);
|
|
}
|
|
}
|
|
}
|
|
filterMiniChartSeries(series) {
|
|
return series?.filter((s) => s.showInMiniChart !== false);
|
|
}
|
|
applyOptions(newChartOptions) {
|
|
if (newChartOptions.seriesWithUserVisibility) {
|
|
this.refreshSeriesUserVisibility(this.chartOptions, newChartOptions.seriesWithUserVisibility);
|
|
}
|
|
const minimumUpdateType = import_ag_charts_core153.ChartUpdateType.PERFORM_LAYOUT;
|
|
const deltaOptions = this.firstApply ? newChartOptions.processedOptions : newChartOptions.diffOptions(this.chartOptions);
|
|
if (deltaOptions == null || Object.keys(deltaOptions).length === 0) {
|
|
debug("Chart.applyOptions() - no delta, forcing re-layout", deltaOptions);
|
|
this.update(minimumUpdateType, { apiUpdate: true, newAnimationBatch: true });
|
|
return;
|
|
}
|
|
const oldOpts = this.firstApply ? {} : this.chartOptions.processedOptions;
|
|
const newOpts = newChartOptions.processedOptions;
|
|
debug("Chart.applyOptions() - applying delta", deltaOptions);
|
|
const modulesChanged = this.applyModules();
|
|
const skip = [
|
|
"type",
|
|
"data",
|
|
"series",
|
|
"listeners",
|
|
"preset",
|
|
"theme",
|
|
"legend.listeners",
|
|
"navigator.miniChart.series",
|
|
"navigator.miniChart.label",
|
|
"locale.localeText",
|
|
"axes",
|
|
"topology",
|
|
"nodes",
|
|
"initialState",
|
|
"styleContainer",
|
|
"formatter",
|
|
"displayNullData"
|
|
];
|
|
if ("listeners" in deltaOptions) {
|
|
this.registerListeners(this, deltaOptions.listeners);
|
|
}
|
|
(0, import_ag_charts_core153.jsonApply)(this, deltaOptions, { skip });
|
|
let forceNodeDataRefresh = false;
|
|
let seriesStatus = "no-op";
|
|
if (deltaOptions.series != null) {
|
|
seriesStatus = this.applySeries(this, deltaOptions.series, oldOpts?.series);
|
|
forceNodeDataRefresh = true;
|
|
}
|
|
if (seriesStatus === "replaced") {
|
|
this.resetAnimations();
|
|
}
|
|
if (this.applyAxes(this, newOpts, oldOpts, seriesStatus, [])) {
|
|
forceNodeDataRefresh = true;
|
|
}
|
|
const { userDeltaKeys } = newChartOptions;
|
|
const userExplicitlyPassedData = userDeltaKeys === void 0 || userDeltaKeys.has("data");
|
|
if (deltaOptions.data && userExplicitlyPassedData) {
|
|
const suppliedData = deltaOptions.data;
|
|
const userOptionsData = newChartOptions.userOptions.data;
|
|
const needsClone = Array.isArray(suppliedData) && suppliedData !== userOptionsData;
|
|
const dataForDataSet = needsClone ? suppliedData.slice() : suppliedData;
|
|
this.data = new DataSet(dataForDataSet);
|
|
}
|
|
if ("legend" in deltaOptions && deltaOptions.legend && "listeners" in deltaOptions.legend && this.modulesManager.isEnabled("legend")) {
|
|
const legendListeners = deltaOptions.legend.listeners;
|
|
if (legendListeners) {
|
|
Object.assign(this.legend.listeners, legendListeners);
|
|
} else {
|
|
this.legend.listeners.clear();
|
|
}
|
|
}
|
|
if (deltaOptions.locale?.localeText) {
|
|
this.pendingLocaleText = deltaOptions.locale?.localeText;
|
|
}
|
|
this.chartOptions = newChartOptions;
|
|
const navigatorModule = this.modulesManager.getModule("navigator");
|
|
const zoomModule = this.modulesManager.getModule("zoom");
|
|
const scrollbarModule = this.modulesManager.getModule("scrollbar");
|
|
if (!navigatorModule?.enabled && !zoomModule?.enabled && !scrollbarModule?.enabled) {
|
|
this.ctx.zoomManager.updateZoom(
|
|
{ source: "chart-update", sourceDetail: "internal-applyOptions" },
|
|
{ x: { min: 0, max: 1 } }
|
|
);
|
|
}
|
|
const miniChart = navigatorModule?.miniChart;
|
|
const miniChartSeries = newOpts.navigator?.miniChart?.series ?? newOpts.series;
|
|
if (miniChart?.enabled === true && miniChartSeries != null) {
|
|
this.applyMiniChartOptions(miniChart, miniChartSeries, newOpts, oldOpts);
|
|
} else if (miniChart?.enabled === false) {
|
|
miniChart.series = [];
|
|
miniChart.axes = [];
|
|
}
|
|
this.ctx.annotationManager.setAnnotationStyles(newChartOptions.annotationThemes);
|
|
forceNodeDataRefresh || (forceNodeDataRefresh = this.shouldForceNodeDataRefresh(deltaOptions, seriesStatus));
|
|
const majorChange = forceNodeDataRefresh || modulesChanged;
|
|
const updateType = majorChange ? import_ag_charts_core153.ChartUpdateType.FULL : minimumUpdateType;
|
|
this.maybeResetAnimations(seriesStatus);
|
|
if (this.shouldClearLegendData(newOpts, oldOpts, seriesStatus)) {
|
|
this.ctx.legendManager.clearData();
|
|
}
|
|
this.applyInitialState(newOpts);
|
|
this.ctx.formatManager.setFormatter(newOpts.formatter);
|
|
debug("Chart.applyOptions() - update type", import_ag_charts_core153.ChartUpdateType[updateType], {
|
|
seriesStatus,
|
|
forceNodeDataRefresh
|
|
});
|
|
if (newChartOptions.optionsProcessingTime !== void 0) {
|
|
this._performUpdateSplits["\u2699\uFE0F"] = newChartOptions.optionsProcessingTime;
|
|
const optionsStartTime = performance.now() - newChartOptions.optionsProcessingTime;
|
|
this._performUpdateSplits.start = optionsStartTime;
|
|
}
|
|
this.update(updateType, {
|
|
apiUpdate: true,
|
|
forceNodeDataRefresh,
|
|
newAnimationBatch: true,
|
|
clearCallbackCache: true
|
|
});
|
|
this.firstApply = false;
|
|
}
|
|
applyInitialState(options) {
|
|
const { activeManager, annotationManager, chartTypeOriginator, historyManager, stateManager, zoomManager } = this.ctx;
|
|
const { initialState } = options;
|
|
if ("annotations" in options && options.annotations?.enabled && initialState?.annotations != null) {
|
|
const annotations = initialState.annotations.map((annotation) => {
|
|
const annotationTheme = annotationManager.getAnnotationTypeStyles(annotation.type);
|
|
return (0, import_ag_charts_core153.mergeDefaults)(annotation, annotationTheme);
|
|
});
|
|
stateManager.setState(annotationManager, annotations);
|
|
}
|
|
if (initialState?.chartType != null) {
|
|
stateManager.setState(chartTypeOriginator, initialState.chartType);
|
|
}
|
|
if ((options.navigator?.enabled || options.zoom?.enabled || options.scrollbar?.enabled) && initialState?.zoom != null) {
|
|
stateManager.setState(zoomManager, initialState.zoom);
|
|
}
|
|
if (initialState?.active != null) {
|
|
stateManager.setState(activeManager, initialState.active);
|
|
}
|
|
if (initialState?.legend != null) {
|
|
this.updateLegends(initialState.legend);
|
|
}
|
|
if (initialState != null) {
|
|
historyManager.clear();
|
|
}
|
|
}
|
|
maybeResetAnimations(seriesStatus) {
|
|
if (this.mode !== "standalone")
|
|
return;
|
|
switch (seriesStatus) {
|
|
case "series-grouping-change":
|
|
case "replaced":
|
|
this.resetAnimations();
|
|
break;
|
|
default:
|
|
}
|
|
}
|
|
shouldForceNodeDataRefresh(deltaOptions, seriesStatus) {
|
|
const seriesDataUpdate = !!deltaOptions.data || seriesStatus === "data-change" || seriesStatus === "replaced";
|
|
const optionsHaveLegend = ["legend", "gradientLegend"].some(
|
|
(legendKey) => deltaOptions[legendKey] != null
|
|
);
|
|
const otherRefreshUpdate = deltaOptions.title != null && deltaOptions.subtitle != null || deltaOptions.formatter != null;
|
|
return seriesDataUpdate || optionsHaveLegend || otherRefreshUpdate;
|
|
}
|
|
shouldClearLegendData(options, oldOpts, seriesStatus) {
|
|
const seriesChanged = seriesStatus === "replaced" || seriesStatus === "series-count-changed" || seriesStatus === "series-grouping-change" || seriesStatus === "updated" && (options.series?.length !== oldOpts.series?.length || !options.series?.every((s, i) => s.type === oldOpts.series?.[i].type));
|
|
const legendRemoved = oldOpts.legend != null && oldOpts.legend.enabled !== false && (options.legend == null || options.legend.enabled === false);
|
|
return seriesChanged || legendRemoved;
|
|
}
|
|
applyMiniChartOptions(miniChart, miniChartSeries, completeOptions, oldOpts) {
|
|
const oldSeries = oldOpts?.navigator?.miniChart?.series ?? oldOpts?.series;
|
|
const miniChartSeriesStatus = this.applySeries(
|
|
miniChart,
|
|
this.filterMiniChartSeries(miniChartSeries),
|
|
this.filterMiniChartSeries(oldSeries)
|
|
);
|
|
this.applyAxes(miniChart, completeOptions, oldOpts, miniChartSeriesStatus, [
|
|
"tick",
|
|
"thickness",
|
|
"title",
|
|
"crosshair",
|
|
"gridLine",
|
|
"label"
|
|
]);
|
|
const series = miniChart.series;
|
|
for (const s of series) {
|
|
s.properties.id = void 0;
|
|
}
|
|
const axes = miniChart.axes;
|
|
const horizontalAxis = axes.find((axis) => axis.direction === import_ag_charts_core153.ChartAxisDirection.X);
|
|
for (const axis of axes) {
|
|
axis.nice = false;
|
|
axis.gridLine.enabled = false;
|
|
axis.label.enabled = axis === horizontalAxis;
|
|
axis.tick.enabled = false;
|
|
axis.interactionEnabled = false;
|
|
}
|
|
if (horizontalAxis != null) {
|
|
const miniChartOpts = completeOptions.navigator?.miniChart;
|
|
const labelOptions = miniChartOpts?.label;
|
|
const intervalOptions = miniChartOpts?.label?.interval;
|
|
horizontalAxis.line.enabled = false;
|
|
horizontalAxis.label.set(
|
|
(0, import_ag_charts_core153.without)(labelOptions, [
|
|
"interval",
|
|
"autoRotate",
|
|
"autoRotateAngle",
|
|
"itemStyler",
|
|
"minSpacing",
|
|
"rotation"
|
|
])
|
|
);
|
|
if (horizontalAxis.type === "grouped-category") {
|
|
horizontalAxis.label.enabled = false;
|
|
horizontalAxis.label.rotation = 0;
|
|
const { depthOptions } = horizontalAxis;
|
|
if (depthOptions.length === 0) {
|
|
depthOptions.set([{ label: { enabled: true } }]);
|
|
} else {
|
|
for (let i = 1; i < depthOptions.length; i++) {
|
|
depthOptions[i].label.enabled = false;
|
|
}
|
|
}
|
|
} else if (horizontalAxis.type === "time" || horizontalAxis.type === "unit-time" || horizontalAxis.type === "ordinal-time") {
|
|
horizontalAxis.parentLevel.enabled = false;
|
|
}
|
|
horizontalAxis.interval.step = intervalOptions?.step;
|
|
horizontalAxis.interval.values = intervalOptions?.values;
|
|
horizontalAxis.interval.minSpacing = intervalOptions?.minSpacing;
|
|
horizontalAxis.interval.maxSpacing = intervalOptions?.maxSpacing;
|
|
}
|
|
}
|
|
applyModules() {
|
|
const { type: chartType } = this.constructor;
|
|
let modulesChanged = false;
|
|
for (const module2 of import_ag_charts_core153.ModuleRegistry.listModulesByType(import_ag_charts_core153.ModuleType.Plugin)) {
|
|
const shouldBeEnabled = !module2.chartType || module2.chartType === chartType;
|
|
if (shouldBeEnabled === this.modulesManager.isEnabled(module2.name))
|
|
continue;
|
|
if (shouldBeEnabled) {
|
|
const moduleInstance = module2.create(this.getModuleContext());
|
|
this.modulesManager.addModule(module2.name, moduleInstance);
|
|
this[module2.name] = moduleInstance;
|
|
} else {
|
|
this.modulesManager.removeModule(module2.name);
|
|
delete this[module2.name];
|
|
}
|
|
modulesChanged = true;
|
|
}
|
|
return modulesChanged;
|
|
}
|
|
initSeriesDeclarationOrder(series) {
|
|
for (let idx = 0; idx < series.length; idx++) {
|
|
series[idx].setSeriesIndex(idx);
|
|
}
|
|
}
|
|
applySeries(chart, optSeries, oldOptSeries) {
|
|
if (!optSeries) {
|
|
return "no-change";
|
|
}
|
|
const matchResult = matchSeriesOptions(chart.series, optSeries, oldOptSeries);
|
|
if (matchResult.status === "no-overlap") {
|
|
debug(`Chart.applySeries() - creating new series instances, status: ${matchResult.status}`, matchResult);
|
|
const chartSeries = optSeries.map((opts) => this.createSeries(opts));
|
|
this.initSeriesDeclarationOrder(chartSeries);
|
|
chart.series = chartSeries;
|
|
return "replaced";
|
|
}
|
|
debug(`Chart.applySeries() - matchResult`, matchResult);
|
|
const seriesInstances = [];
|
|
let dataChanged = false;
|
|
let groupingChanged = false;
|
|
let isUpdated = false;
|
|
let seriesCountChanged = false;
|
|
const changes = matchResult.changes.toSorted((a, b) => a.targetIdx - b.targetIdx);
|
|
for (const change of changes) {
|
|
groupingChanged || (groupingChanged = change.status === "series-grouping");
|
|
dataChanged || (dataChanged = change.diff?.data != null);
|
|
isUpdated || (isUpdated = change.status !== "no-op");
|
|
seriesCountChanged || (seriesCountChanged = change.status === "add" || change.status === "remove");
|
|
switch (change.status) {
|
|
case "add": {
|
|
const newSeries = this.createSeries(change.opts);
|
|
seriesInstances.push(newSeries);
|
|
debug(`Chart.applySeries() - created new series`, newSeries);
|
|
break;
|
|
}
|
|
case "remove":
|
|
debug(`Chart.applySeries() - removing series at previous idx ${change.idx}`, change.series);
|
|
break;
|
|
case "no-op":
|
|
seriesInstances.push(change.series);
|
|
debug(`Chart.applySeries() - no change to series at previous idx ${change.idx}`, change.series);
|
|
break;
|
|
case "series-grouping":
|
|
case "update":
|
|
default: {
|
|
const { series, diff: diff2, idx } = change;
|
|
debug(`Chart.applySeries() - applying series diff previous idx ${idx}`, diff2, series);
|
|
this.applySeriesValues(series, diff2);
|
|
series.markNodeDataDirty();
|
|
seriesInstances.push(series);
|
|
}
|
|
}
|
|
}
|
|
this.initSeriesDeclarationOrder(seriesInstances);
|
|
debug(`Chart.applySeries() - final series instances`, seriesInstances);
|
|
chart.series = seriesInstances;
|
|
if (groupingChanged) {
|
|
return "series-grouping-change";
|
|
}
|
|
if (seriesCountChanged) {
|
|
return "series-count-changed";
|
|
}
|
|
if (dataChanged) {
|
|
return "data-change";
|
|
}
|
|
return isUpdated ? "updated" : "no-op";
|
|
}
|
|
applyAxes(chart, options, oldOpts, seriesStatus, skip = []) {
|
|
if (!("axes" in options) || !options.axes) {
|
|
return false;
|
|
}
|
|
skip = ["type", ...skip];
|
|
const axes = options.axes;
|
|
const forceRecreate = seriesStatus === "replaced";
|
|
const matchingTypes = !forceRecreate && chart.axes.matches(axes);
|
|
if (matchingTypes && isAgCartesianChartOptions(oldOpts)) {
|
|
for (const axis of chart.axes) {
|
|
const previousOpts = oldOpts.axes?.[axis.id] ?? {};
|
|
const axisDiff = (0, import_ag_charts_core153.jsonDiff)(previousOpts, axes[axis.id]);
|
|
debug(`Chart.applyAxes() - applying axis diff idx ${axis.id}`, axisDiff);
|
|
(0, import_ag_charts_core153.jsonApply)(axis, axisDiff, { skip });
|
|
}
|
|
return true;
|
|
}
|
|
debug(`Chart.applyAxes() - creating new axes instances; seriesStatus: ${seriesStatus}`);
|
|
chart.axes = this.createAxes(axes, skip);
|
|
return true;
|
|
}
|
|
createSeries(seriesOptions) {
|
|
const seriesModule = import_ag_charts_core153.ModuleRegistry.getSeriesModule(seriesOptions.type);
|
|
const seriesInstance = seriesModule.create(this.getModuleContext());
|
|
this.applySeriesOptionModules(seriesInstance, seriesOptions);
|
|
this.applySeriesValues(seriesInstance, seriesOptions);
|
|
return seriesInstance;
|
|
}
|
|
applySeriesOptionModules(series, options) {
|
|
const moduleContext = series.createModuleContext();
|
|
const moduleMap = series.getModuleMap();
|
|
for (const module2 of import_ag_charts_core153.ModuleRegistry.listModulesByType(import_ag_charts_core153.ModuleType.SeriesPlugin)) {
|
|
if (module2.name in options && (module2.seriesTypes?.includes(series.type) ?? true)) {
|
|
moduleMap.addModule(module2.name, module2.create(moduleContext));
|
|
}
|
|
}
|
|
}
|
|
applySeriesValues(target, options) {
|
|
const moduleMap = target.getModuleMap();
|
|
const { type, data, listeners, seriesGrouping, showInMiniChart, ...seriesOptions } = options;
|
|
for (const module2 of import_ag_charts_core153.ModuleRegistry.listModulesByType(import_ag_charts_core153.ModuleType.SeriesPlugin)) {
|
|
if (module2.name in seriesOptions) {
|
|
const moduleInstance = moduleMap.getModule(module2.name);
|
|
if (moduleInstance) {
|
|
const moduleOptions = seriesOptions[module2.name];
|
|
moduleInstance.properties.set(moduleOptions);
|
|
delete seriesOptions[module2.name];
|
|
}
|
|
}
|
|
}
|
|
if (seriesOptions.visible != null) {
|
|
target.visible = seriesOptions.visible;
|
|
}
|
|
target.properties.set(seriesOptions);
|
|
if ("data" in options) {
|
|
target.setOptionsData(data == null ? void 0 : DataSet.wrap(data));
|
|
}
|
|
if ("listeners" in options) {
|
|
this.registerListeners(target, listeners);
|
|
if (this.series.includes(target)) {
|
|
this.addSeriesListeners(target);
|
|
}
|
|
}
|
|
if ("seriesGrouping" in options) {
|
|
if (seriesGrouping == null) {
|
|
target.seriesGrouping = void 0;
|
|
} else {
|
|
target.seriesGrouping = { ...target.seriesGrouping, ...seriesGrouping };
|
|
}
|
|
}
|
|
}
|
|
createAxes(options, skip) {
|
|
const newAxes = this.createChartAxes();
|
|
const moduleContext = this.getModuleContext();
|
|
for (const [id, axisOptions] of (0, import_ag_charts_core153.entries)(options)) {
|
|
const axis = import_ag_charts_core153.ModuleRegistry.getAxisModule(axisOptions.type).create(moduleContext);
|
|
axis.id = id;
|
|
this.applyAxisModules(axis, axisOptions);
|
|
(0, import_ag_charts_core153.jsonApply)(axis, axisOptions, { skip });
|
|
newAxes.push(axis);
|
|
}
|
|
guessInvalidPositions(newAxes);
|
|
return newAxes;
|
|
}
|
|
applyAxisModules(axis, options) {
|
|
const moduleContext = axis.createModuleContext();
|
|
const moduleMap = axis.getModuleMap();
|
|
for (const module2 of import_ag_charts_core153.ModuleRegistry.listModulesByType(import_ag_charts_core153.ModuleType.AxisPlugin)) {
|
|
const shouldBeEnabled = options[module2.name] != null;
|
|
if (shouldBeEnabled === moduleMap.isEnabled(module2.name))
|
|
continue;
|
|
if (shouldBeEnabled) {
|
|
moduleMap.addModule(module2.name, module2.create(moduleContext));
|
|
axis[module2.name] = moduleMap.getModule(module2.name);
|
|
} else {
|
|
moduleMap.removeModule(module2.name);
|
|
delete axis[module2.name];
|
|
}
|
|
}
|
|
}
|
|
registerListeners(source, listeners) {
|
|
source.clearEventListeners();
|
|
if (listeners && typeof listeners === "object") {
|
|
for (const [property, listener] of (0, import_ag_charts_core153.entries)(listeners)) {
|
|
if (listener == null) {
|
|
continue;
|
|
}
|
|
source.addEventListener(property, listener);
|
|
}
|
|
}
|
|
}
|
|
async applyTransaction(transaction) {
|
|
await this.updateMutex.acquire(() => {
|
|
this.data.addTransaction(transaction);
|
|
this.update(import_ag_charts_core153.ChartUpdateType.UPDATE_DATA, {
|
|
apiUpdate: true,
|
|
skipAnimations: true
|
|
});
|
|
});
|
|
await this.waitForUpdate();
|
|
}
|
|
onSyncActiveClear() {
|
|
this.seriesAreaManager.onActiveClear();
|
|
}
|
|
};
|
|
_Chart.className = "Chart";
|
|
_Chart.chartsInstances = /* @__PURE__ */ new WeakMap();
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ActionOnSet)({
|
|
newValue(value) {
|
|
if (this.destroyed)
|
|
return;
|
|
this.ctx.domManager.setContainer(value);
|
|
_Chart.chartsInstances.set(value, this);
|
|
},
|
|
oldValue(value) {
|
|
_Chart.chartsInstances.delete(value);
|
|
}
|
|
})
|
|
], _Chart.prototype, "container", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ActionOnSet)({
|
|
newValue(value) {
|
|
this.resize("width option", { inWidth: value });
|
|
}
|
|
})
|
|
], _Chart.prototype, "width", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ActionOnSet)({
|
|
newValue(value) {
|
|
this.resize("height option", { inHeight: value });
|
|
}
|
|
})
|
|
], _Chart.prototype, "height", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ActionOnSet)({
|
|
newValue(value) {
|
|
this.resize("minWidth option", { inMinWidth: value });
|
|
}
|
|
})
|
|
], _Chart.prototype, "minWidth", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ActionOnSet)({
|
|
newValue(value) {
|
|
this.resize("minHeight option", { inMinHeight: value });
|
|
}
|
|
})
|
|
], _Chart.prototype, "minHeight", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ActionOnSet)({
|
|
newValue(value) {
|
|
this.resize("overrideDevicePixelRatio option", { inOverrideDevicePixelRatio: value });
|
|
}
|
|
})
|
|
], _Chart.prototype, "overrideDevicePixelRatio", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core153.Property
|
|
], _Chart.prototype, "padding", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core153.Property
|
|
], _Chart.prototype, "keyboard", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core153.Property
|
|
], _Chart.prototype, "touch", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core153.Property
|
|
], _Chart.prototype, "mode", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core153.Property
|
|
], _Chart.prototype, "styleNonce", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ProxyProperty)("chartCaptions.title")
|
|
], _Chart.prototype, "title", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ProxyProperty)("chartCaptions.subtitle")
|
|
], _Chart.prototype, "subtitle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ProxyProperty)("chartCaptions.footnote")
|
|
], _Chart.prototype, "footnote", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core153.Property
|
|
], _Chart.prototype, "formatter", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core153.Property
|
|
], _Chart.prototype, "suppressFieldDotNotation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core153.Property
|
|
], _Chart.prototype, "loadGoogleFonts", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ActionOnSet)({
|
|
changeValue(newValue, oldValue) {
|
|
this.onAxisChange(newValue, oldValue);
|
|
}
|
|
})
|
|
], _Chart.prototype, "axes", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core153.ActionOnSet)({
|
|
changeValue(newValue, oldValue) {
|
|
this.onSeriesChange(newValue, oldValue);
|
|
}
|
|
})
|
|
], _Chart.prototype, "series", 2);
|
|
var Chart = _Chart;
|
|
|
|
// packages/ag-charts-community/src/chart/chartProxy.ts
|
|
var import_ag_charts_core185 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/module/optionsModule.ts
|
|
var import_ag_charts_core184 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/factory/processModuleOptions.ts
|
|
var import_ag_charts_core155 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/themes/chartTheme.ts
|
|
var import_ag_charts_core154 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/module/coreModulesTypes.ts
|
|
function paletteType(partial) {
|
|
if (partial?.up || partial?.down || partial?.neutral) {
|
|
return "user-full";
|
|
} else if (partial?.fills || partial?.strokes) {
|
|
return "user-indexed";
|
|
}
|
|
return "inbuilt";
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/themes/defaultColors.ts
|
|
var DEFAULT_FILLS = {
|
|
BLUE: "#5090dc",
|
|
ORANGE: "#ffa03a",
|
|
GREEN: "#459d55",
|
|
CYAN: "#34bfe1",
|
|
YELLOW: "#e1cc00",
|
|
VIOLET: "#9669cb",
|
|
GRAY: "#b5b5b5",
|
|
MAGENTA: "#bd5aa7",
|
|
BROWN: "#8a6224",
|
|
RED: "#ef5452"
|
|
};
|
|
var DEFAULT_STROKES = {
|
|
BLUE: "#2b5c95",
|
|
ORANGE: "#cc6f10",
|
|
GREEN: "#1e652e",
|
|
CYAN: "#18859e",
|
|
YELLOW: "#a69400",
|
|
VIOLET: "#603c88",
|
|
GRAY: "#575757",
|
|
MAGENTA: "#7d2f6d",
|
|
BROWN: "#4f3508",
|
|
RED: "#a82529"
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/chartTheme.ts
|
|
var DEFAULT_BACKGROUND_FILL = "white";
|
|
var PRESET_OVERRIDES_TYPES = {
|
|
"radial-gauge": true,
|
|
"linear-gauge": true
|
|
};
|
|
function hasUserOptionLessThan1(key) {
|
|
return {
|
|
$some: [
|
|
{
|
|
$and: [
|
|
{
|
|
$or: [
|
|
{ $isSeriesType: "line" },
|
|
{ $isSeriesType: "scatter" },
|
|
{ $isSeriesType: "area" },
|
|
{ $isSeriesType: "radar" },
|
|
{ $isSeriesType: "rangeArea" }
|
|
]
|
|
},
|
|
{
|
|
$isUserOption: [
|
|
`/series/$index/${key}`,
|
|
{ $lessThan: [{ $path: `/series/$index/${key}` }, 1] },
|
|
false
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{ $path: "/series" }
|
|
]
|
|
};
|
|
}
|
|
function isPresetOverridesType(type) {
|
|
return PRESET_OVERRIDES_TYPES[type] === true;
|
|
}
|
|
var _ChartTheme = class _ChartTheme {
|
|
static getDefaultColors() {
|
|
return {
|
|
fills: DEFAULT_FILLS,
|
|
fillsFallback: Object.values(DEFAULT_FILLS),
|
|
strokes: DEFAULT_STROKES,
|
|
sequentialColors: (0, import_ag_charts_core154.getSequentialColors)(DEFAULT_FILLS),
|
|
divergingColors: [DEFAULT_FILLS.ORANGE, DEFAULT_FILLS.YELLOW, DEFAULT_FILLS.GREEN],
|
|
hierarchyColors: ["#fff", "#e0e5ea", "#c1ccd5", "#a3b4c1", "#859cad"],
|
|
secondSequentialColors: import_ag_charts_core154.Color.interpolate(
|
|
[
|
|
import_ag_charts_core154.Color.fromHexString(DEFAULT_FILLS.BLUE),
|
|
import_ag_charts_core154.Color.fromHexString("#cbdef5")
|
|
// TODO: Color.lighten(DEFAULT_FILLS.BLUE, ?)
|
|
],
|
|
8
|
|
).map((color8) => color8.toString()),
|
|
secondDivergingColors: [DEFAULT_FILLS.GREEN, DEFAULT_FILLS.YELLOW, DEFAULT_FILLS.RED],
|
|
secondHierarchyColors: ["#fff", "#c5cbd1", "#a4b1bd", "#8498a9", "#648096"],
|
|
up: { fill: DEFAULT_FILLS.GREEN, stroke: DEFAULT_STROKES.GREEN },
|
|
down: { fill: DEFAULT_FILLS.RED, stroke: DEFAULT_STROKES.RED },
|
|
neutral: { fill: DEFAULT_FILLS.GRAY, stroke: DEFAULT_STROKES.GRAY },
|
|
altUp: { fill: DEFAULT_FILLS.BLUE, stroke: DEFAULT_STROKES.BLUE },
|
|
altDown: { fill: DEFAULT_FILLS.ORANGE, stroke: DEFAULT_STROKES.ORANGE },
|
|
altNeutral: { fill: DEFAULT_FILLS.GRAY, stroke: DEFAULT_STROKES.GRAY }
|
|
};
|
|
}
|
|
static getDefaultPublicParameters() {
|
|
return {
|
|
accentColor: "#2196f3",
|
|
axisColor: { $foregroundBackgroundMix: 0.325 },
|
|
backgroundColor: DEFAULT_BACKGROUND_FILL,
|
|
borderColor: { $foregroundOpacity: 0.15 },
|
|
borderRadius: 4,
|
|
chartBackgroundColor: { $ref: "backgroundColor" },
|
|
chartPadding: 20,
|
|
focusShadow: "0 0 0 3px var(--ag-charts-accent-color)",
|
|
foregroundColor: "#181d1f",
|
|
fontFamily: "Verdana, sans-serif",
|
|
fontSize: import_ag_charts_core154.BASE_FONT_SIZE,
|
|
fontWeight: 400,
|
|
gridLineColor: { $foregroundBackgroundMix: 0.1 },
|
|
popupShadow: "0 0 16px rgba(0, 0, 0, 0.15)",
|
|
subtleTextColor: { $mix: [{ $ref: "textColor" }, { $ref: "chartBackgroundColor" }, 0.38] },
|
|
textColor: { $ref: "foregroundColor" },
|
|
separationLinesColor: { $foregroundBackgroundMix: 0.17 },
|
|
chromeBackgroundColor: { $foregroundBackgroundMix: 0.02 },
|
|
chromeFontFamily: { $ref: "fontFamily" },
|
|
chromeFontSize: { $ref: "fontSize" },
|
|
chromeFontWeight: { $ref: "fontWeight" },
|
|
chromeTextColor: { $ref: "foregroundColor" },
|
|
chromeSubtleTextColor: { $mix: [{ $ref: "chromeTextColor" }, { $ref: "backgroundColor" }, 0.38] },
|
|
buttonBackgroundColor: { $ref: "backgroundColor" },
|
|
buttonBorder: true,
|
|
buttonFontWeight: 400,
|
|
buttonTextColor: { $ref: "textColor" },
|
|
inputBackgroundColor: { $ref: "backgroundColor" },
|
|
inputBorder: true,
|
|
inputTextColor: { $ref: "textColor" },
|
|
menuBackgroundColor: { $ref: "chromeBackgroundColor" },
|
|
menuBorder: true,
|
|
menuTextColor: { $ref: "chromeTextColor" },
|
|
panelBackgroundColor: { $ref: "chromeBackgroundColor" },
|
|
panelSubtleTextColor: { $ref: "chromeSubtleTextColor" },
|
|
tooltipBackgroundColor: { $ref: "chromeBackgroundColor" },
|
|
tooltipBorder: true,
|
|
tooltipTextColor: { $ref: "chromeTextColor" },
|
|
tooltipSubtleTextColor: { $ref: "chromeSubtleTextColor" },
|
|
crosshairLabelBackgroundColor: { $ref: "foregroundColor" },
|
|
crosshairLabelTextColor: { $ref: "chartBackgroundColor" }
|
|
};
|
|
}
|
|
static getAxisDefaults({ title, time: time3 }) {
|
|
return (0, import_ag_charts_core154.mergeDefaults)(
|
|
title && {
|
|
title: {
|
|
enabled: false,
|
|
text: "Axis Title",
|
|
spacing: 25,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $rem: import_ag_charts_core154.FONT_SIZE_RATIO.MEDIUM },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "textColor" }
|
|
}
|
|
},
|
|
time3 && {
|
|
parentLevel: {
|
|
enabled: false,
|
|
label: {
|
|
// TODO: { $merge: [{ $path: '../../label' }, { fontWeight: 'bold' }]}
|
|
enabled: { $path: "../../label/enabled" },
|
|
border: {
|
|
enabled: {
|
|
$or: [
|
|
{ $isUserOption: ["../border", true, false] },
|
|
{ $path: "../../../label/border/enabled" }
|
|
]
|
|
},
|
|
strokeWidth: { $path: "../../../label/border/strokeWidth" },
|
|
stroke: { $path: "../../../label/border/stroke" }
|
|
},
|
|
fill: { $path: "../../label/fill" },
|
|
fontSize: { $path: "../../label/fontSize" },
|
|
fontFamily: { $path: "../../label/fontFamily" },
|
|
fontWeight: "bold",
|
|
spacing: { $path: "../../label/spacing" },
|
|
color: { $path: "../../label/color" },
|
|
cornerRadius: { $path: "../../label/cornerRadius" },
|
|
padding: { $path: "../../label/padding" },
|
|
avoidCollisions: { $path: "../../label/avoidCollisions" }
|
|
},
|
|
tick: {
|
|
enabled: { $path: "../../tick/enabled" },
|
|
width: { $path: "../../tick/width" },
|
|
size: { $path: "../../tick/size" },
|
|
stroke: { $path: "../../tick/stroke" }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
label: {
|
|
enabled: true,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
spacing: 11,
|
|
color: { $ref: "textColor" },
|
|
avoidCollisions: true,
|
|
cornerRadius: 4,
|
|
border: {
|
|
enabled: { $isUserOption: ["../border", true, false] },
|
|
strokeWidth: 1,
|
|
stroke: { $foregroundOpacity: 0.08 }
|
|
},
|
|
padding: {
|
|
$if: [
|
|
{ $eq: [{ $path: "./border/enabled" }, true] },
|
|
{ left: 12, right: 12, top: 8, bottom: 8 },
|
|
void 0
|
|
]
|
|
}
|
|
},
|
|
line: {
|
|
enabled: true,
|
|
width: 1,
|
|
stroke: { $ref: "axisColor" }
|
|
},
|
|
tick: {
|
|
enabled: false,
|
|
size: 6,
|
|
width: 1,
|
|
stroke: { $ref: "axisColor" }
|
|
},
|
|
gridLine: {
|
|
enabled: true,
|
|
width: 1,
|
|
style: {
|
|
$apply: [
|
|
{
|
|
fillOpacity: 1,
|
|
stroke: { $ref: "gridLineColor" },
|
|
strokeWidth: { $path: "../../width" },
|
|
lineDash: []
|
|
},
|
|
[
|
|
{
|
|
fillOpacity: 1,
|
|
stroke: { $ref: "gridLineColor" },
|
|
strokeWidth: { $path: "../../width" },
|
|
lineDash: []
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
crossLines: {
|
|
$apply: [
|
|
{
|
|
enabled: true,
|
|
fill: { $ref: "foregroundColor" },
|
|
stroke: { $ref: "foregroundColor" },
|
|
fillOpacity: 0.08,
|
|
strokeWidth: 1,
|
|
label: {
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
padding: 5,
|
|
color: { $ref: "textColor" },
|
|
border: {
|
|
enabled: false,
|
|
stroke: { $ref: "foregroundColor" },
|
|
strokeOpacity: 1,
|
|
strokeWidth: { $isUserOption: ["./stroke", 1, 0] }
|
|
}
|
|
}
|
|
},
|
|
void 0,
|
|
// TODO: can we just infer this common path?
|
|
// `axisType` path is relative to the axis that is currently being resolved
|
|
// e.g. `/axes/x/crossLines/[variables]` + `../type` = `/axes/x/type`
|
|
{ $pathString: ["/common/axes/$axisType/crossLines", { axisType: { $path: ["../type"] } }] },
|
|
{
|
|
$pathString: [
|
|
"/$seriesType/axes/$axisType/crossLines",
|
|
{
|
|
seriesType: { $path: ["/series/0/type", "line"] },
|
|
axisType: { $path: ["../type"] }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
);
|
|
}
|
|
getChartDefaults() {
|
|
return {
|
|
minHeight: 300,
|
|
minWidth: 300,
|
|
background: { visible: true, fill: { $ref: "chartBackgroundColor" } },
|
|
padding: {
|
|
top: { $ref: "chartPadding" },
|
|
right: { $ref: "chartPadding" },
|
|
bottom: { $ref: "chartPadding" },
|
|
left: { $ref: "chartPadding" }
|
|
},
|
|
seriesArea: {
|
|
border: {
|
|
enabled: false,
|
|
stroke: { $ref: "foregroundColor" },
|
|
strokeOpacity: 1,
|
|
strokeWidth: 1
|
|
},
|
|
cornerRadius: 4,
|
|
padding: { $if: [{ $eq: [{ $path: "./border/enabled" }, true] }, 5, 0] }
|
|
},
|
|
keyboard: { enabled: true },
|
|
title: {
|
|
enabled: false,
|
|
text: "Title",
|
|
spacing: { $if: [{ $path: "../subtitle/enabled" }, 10, 20] },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $rem: import_ag_charts_core154.FONT_SIZE_RATIO.LARGEST },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "textColor" },
|
|
wrapping: "hyphenate",
|
|
layoutStyle: import_ag_charts_core154.DEFAULT_CAPTION_LAYOUT_STYLE,
|
|
textAlign: import_ag_charts_core154.DEFAULT_CAPTION_ALIGNMENT
|
|
},
|
|
subtitle: {
|
|
enabled: false,
|
|
text: "Subtitle",
|
|
spacing: 20,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $rem: import_ag_charts_core154.FONT_SIZE_RATIO.MEDIUM },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "subtleTextColor" },
|
|
wrapping: "hyphenate",
|
|
layoutStyle: import_ag_charts_core154.DEFAULT_CAPTION_LAYOUT_STYLE,
|
|
textAlign: import_ag_charts_core154.DEFAULT_CAPTION_ALIGNMENT
|
|
},
|
|
footnote: {
|
|
enabled: false,
|
|
text: "Footnote",
|
|
spacing: 20,
|
|
fontSize: { $rem: import_ag_charts_core154.FONT_SIZE_RATIO.MEDIUM },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "subtleTextColor" },
|
|
wrapping: "hyphenate",
|
|
layoutStyle: import_ag_charts_core154.DEFAULT_CAPTION_LAYOUT_STYLE,
|
|
textAlign: import_ag_charts_core154.DEFAULT_CAPTION_ALIGNMENT
|
|
},
|
|
highlight: {
|
|
drawingMode: {
|
|
$if: [
|
|
{
|
|
$or: [
|
|
hasUserOptionLessThan1("highlight/highlightedItem/opacity"),
|
|
hasUserOptionLessThan1("highlight/unhighlightedItem/opacity"),
|
|
hasUserOptionLessThan1("highlight/highlightedSeries/opacity"),
|
|
hasUserOptionLessThan1("highlight/unhighlightedSeries/opacity"),
|
|
hasUserOptionLessThan1("fillOpacity"),
|
|
hasUserOptionLessThan1("marker/fillOpacity")
|
|
]
|
|
},
|
|
"overlap",
|
|
"cutout"
|
|
]
|
|
}
|
|
},
|
|
tooltip: {
|
|
enabled: true,
|
|
darkTheme: import_ag_charts_core154.IS_DARK_THEME,
|
|
delay: 0,
|
|
pagination: false,
|
|
mode: {
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{
|
|
$and: [
|
|
{ $isChartType: "cartesian" },
|
|
{ $not: { $hasSeriesType: "bubble" } },
|
|
{ $not: { $hasSeriesType: "scatter" } },
|
|
{ $greaterThan: [{ $size: { $path: "/series" } }, 1] },
|
|
{ $lessThan: [{ $size: { $path: "/series" } }, 4] }
|
|
]
|
|
},
|
|
{
|
|
$and: [
|
|
{ $isChartType: "polar" },
|
|
{ $greaterThan: [{ $size: { $path: "/series" } }, 1] },
|
|
{ $lessThan: [{ $size: { $path: "/series" } }, 4] }
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"shared",
|
|
"single"
|
|
]
|
|
}
|
|
},
|
|
overlays: { darkTheme: import_ag_charts_core154.IS_DARK_THEME },
|
|
listeners: {},
|
|
// TODO: remove this
|
|
series: {
|
|
tooltip: {
|
|
range: {
|
|
$if: [
|
|
{ $eq: [{ $path: ["/tooltip/range", "exact"] }, "area"] },
|
|
"exact",
|
|
{ $path: ["/tooltip/range", "exact"] }
|
|
]
|
|
},
|
|
position: {
|
|
anchorTo: { $path: ["/tooltip/position/anchorTo", "pointer"] },
|
|
placement: { $path: ["/tooltip/position/placement", void 0] },
|
|
xOffset: { $path: ["/tooltip/position/xOffset", 0] },
|
|
yOffset: { $path: ["/tooltip/position/yOffset", 0] }
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
constructor(options = {}) {
|
|
const { overrides, palette, params } = (0, import_ag_charts_core154.deepClone)(options);
|
|
const defaults = this.createChartConfigPerChartType(this.getDefaults());
|
|
const presets = {};
|
|
if (overrides) {
|
|
this.processOverrides(presets, overrides);
|
|
}
|
|
const { fills, strokes, sequentialColors, ...otherColors } = this.getDefaultColors();
|
|
this.palette = (0, import_ag_charts_core154.deepFreeze)(
|
|
(0, import_ag_charts_core154.mergeDefaults)(palette, {
|
|
fills: Object.values(fills),
|
|
strokes: Object.values(strokes),
|
|
sequentialColors: Object.values(sequentialColors),
|
|
...otherColors
|
|
})
|
|
);
|
|
this.paletteType = paletteType(palette);
|
|
this.params = (0, import_ag_charts_core154.mergeDefaults)(params, this.getPublicParameters());
|
|
this.config = (0, import_ag_charts_core154.deepFreeze)((0, import_ag_charts_core154.deepClone)(defaults));
|
|
this.overrides = (0, import_ag_charts_core154.deepFreeze)(overrides);
|
|
this.presets = (0, import_ag_charts_core154.deepFreeze)(presets);
|
|
}
|
|
processOverrides(presets, overrides) {
|
|
for (const s of import_ag_charts_core154.ModuleRegistry.listModulesByType(import_ag_charts_core154.ModuleType.Series)) {
|
|
const seriesType = s.name;
|
|
const seriesOverrides = overrides[seriesType];
|
|
if (isPresetOverridesType(seriesType)) {
|
|
presets[seriesType] = seriesOverrides;
|
|
delete overrides[seriesType];
|
|
}
|
|
}
|
|
}
|
|
createChartConfigPerChartType(config) {
|
|
var _a;
|
|
for (const chartModule of import_ag_charts_core154.ModuleRegistry.listModulesByType(import_ag_charts_core154.ModuleType.Chart)) {
|
|
for (const seriesModule of import_ag_charts_core154.ModuleRegistry.listModulesByType(import_ag_charts_core154.ModuleType.Series)) {
|
|
if (seriesModule.chartType !== chartModule.name)
|
|
continue;
|
|
config[_a = seriesModule.name] ?? (config[_a] = chartModule.themeTemplate);
|
|
}
|
|
}
|
|
return config;
|
|
}
|
|
getDefaults() {
|
|
const getOverridesByType = (chartType, seriesTypes) => {
|
|
const result = {};
|
|
const chartTypeDefaults = (0, import_ag_charts_core154.mergeDefaults)(
|
|
{ axes: {} },
|
|
...Array.from(import_ag_charts_core154.ModuleRegistry.listModulesByType(import_ag_charts_core154.ModuleType.Plugin), (p) => ({
|
|
[p.name]: p.themeTemplate
|
|
})),
|
|
import_ag_charts_core154.ModuleRegistry.getChartModule(chartType)?.themeTemplate,
|
|
this.getChartDefaults()
|
|
);
|
|
for (const seriesType of seriesTypes) {
|
|
result[seriesType] = (0, import_ag_charts_core154.mergeDefaults)(
|
|
getSeriesThemeTemplate(seriesType),
|
|
result[seriesType] ?? chartTypeDefaults
|
|
);
|
|
const { axes } = result[seriesType];
|
|
for (const axisModule of import_ag_charts_core154.ModuleRegistry.listModulesByType(import_ag_charts_core154.ModuleType.Axis)) {
|
|
axes[axisModule.name] = (0, import_ag_charts_core154.mergeDefaults)(
|
|
axes[axisModule.name],
|
|
!axisModule.chartType || axisModule.chartType === chartType ? getAxisThemeTemplate(axisModule.name) : null,
|
|
_ChartTheme.axisDefault[axisModule.name]
|
|
);
|
|
}
|
|
if (seriesType === "map-shape-background" || seriesType === "map-line-background") {
|
|
delete result[seriesType].series.tooltip;
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
const seriesModules = [...import_ag_charts_core154.ModuleRegistry.listModulesByType(import_ag_charts_core154.ModuleType.Series)];
|
|
const seriesByChartType = (0, import_ag_charts_core154.groupBy)(seriesModules, (s) => s.chartType || "unknown");
|
|
return (0, import_ag_charts_core154.mergeDefaults)(
|
|
...Object.keys(seriesByChartType).map(
|
|
(chartType) => getOverridesByType(chartType, seriesByChartType[chartType]?.map((s) => s.name) ?? [])
|
|
)
|
|
);
|
|
}
|
|
static applyTemplateTheme(node, _other, params) {
|
|
if ((0, import_ag_charts_core154.isArray)(node)) {
|
|
for (let i = 0; i < node.length; i++) {
|
|
const symbol = node[i];
|
|
if (typeof symbol === "symbol" && params?.has(symbol)) {
|
|
node[i] = params.get(symbol);
|
|
}
|
|
}
|
|
} else {
|
|
for (const name of Object.keys(node)) {
|
|
const value = node[name];
|
|
if (typeof value === "symbol" && params?.has(value)) {
|
|
node[name] = params.get(value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
templateTheme(themeTemplate7, clone = true) {
|
|
const themeInstance = clone ? (0, import_ag_charts_core154.deepClone)(themeTemplate7) : themeTemplate7;
|
|
const params = this.getTemplateParameters();
|
|
(0, import_ag_charts_core154.jsonWalk)(themeInstance, _ChartTheme.applyTemplateTheme, void 0, void 0, params);
|
|
return themeInstance;
|
|
}
|
|
getDefaultColors() {
|
|
return _ChartTheme.getDefaultColors();
|
|
}
|
|
getPublicParameters() {
|
|
return _ChartTheme.getDefaultPublicParameters();
|
|
}
|
|
// Private parameters that are not exposed in the themes API.
|
|
getTemplateParameters() {
|
|
const params = /* @__PURE__ */ new Map();
|
|
params.set(import_ag_charts_core154.IS_DARK_THEME, false);
|
|
params.set(import_ag_charts_core154.DEFAULT_SHADOW_COLOUR, "#00000080");
|
|
params.set(import_ag_charts_core154.DEFAULT_SPARKLINE_CROSSHAIR_STROKE, "#aaa");
|
|
params.set(import_ag_charts_core154.DEFAULT_CAPTION_LAYOUT_STYLE, "block");
|
|
params.set(import_ag_charts_core154.DEFAULT_CAPTION_ALIGNMENT, "center");
|
|
params.set(import_ag_charts_core154.DEFAULT_FIBONACCI_STROKES, [
|
|
"#797b86",
|
|
"#e24c4a",
|
|
"#f49d2d",
|
|
"#65ab58",
|
|
"#409682",
|
|
"#4db9d2",
|
|
"#5090dc",
|
|
"#3068f9",
|
|
"#e24c4a",
|
|
"#913aac",
|
|
"#d93e64"
|
|
]);
|
|
params.set(import_ag_charts_core154.DEFAULT_POLAR_SERIES_STROKE, DEFAULT_BACKGROUND_FILL);
|
|
params.set(import_ag_charts_core154.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, DEFAULT_FILLS.BLUE);
|
|
params.set(import_ag_charts_core154.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, DEFAULT_FILLS.BLUE);
|
|
params.set(import_ag_charts_core154.DEFAULT_TEXT_ANNOTATION_COLOR, DEFAULT_FILLS.BLUE);
|
|
params.set(import_ag_charts_core154.DEFAULT_ANNOTATION_HANDLE_FILL, DEFAULT_BACKGROUND_FILL);
|
|
params.set(import_ag_charts_core154.DEFAULT_ANNOTATION_STATISTICS_FILL, "#fafafa");
|
|
params.set(import_ag_charts_core154.DEFAULT_ANNOTATION_STATISTICS_STROKE, "#ddd");
|
|
params.set(import_ag_charts_core154.DEFAULT_ANNOTATION_STATISTICS_COLOR, "#000");
|
|
params.set(import_ag_charts_core154.DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE, "#181d1f");
|
|
params.set(import_ag_charts_core154.DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL, "#e35c5c");
|
|
params.set(import_ag_charts_core154.DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE, "#e35c5c");
|
|
params.set(import_ag_charts_core154.DEFAULT_TEXTBOX_FILL, "#fafafa");
|
|
params.set(import_ag_charts_core154.DEFAULT_TEXTBOX_STROKE, "#ddd");
|
|
params.set(import_ag_charts_core154.DEFAULT_TEXTBOX_COLOR, "#000");
|
|
params.set(import_ag_charts_core154.DEFAULT_TOOLBAR_POSITION, "top");
|
|
const defaultColors = this.getDefaultColors();
|
|
params.set(import_ag_charts_core154.PALETTE_UP_STROKE, this.palette.up?.stroke ?? defaultColors.up.stroke);
|
|
params.set(import_ag_charts_core154.PALETTE_UP_FILL, this.palette.up?.fill ?? defaultColors.up.fill);
|
|
params.set(import_ag_charts_core154.PALETTE_DOWN_STROKE, this.palette.down?.stroke ?? defaultColors.down.stroke);
|
|
params.set(import_ag_charts_core154.PALETTE_DOWN_FILL, this.palette.down?.fill ?? defaultColors.down.fill);
|
|
params.set(import_ag_charts_core154.PALETTE_NEUTRAL_STROKE, this.palette.neutral?.stroke ?? defaultColors.neutral.stroke);
|
|
params.set(import_ag_charts_core154.PALETTE_NEUTRAL_FILL, this.palette.neutral?.fill ?? defaultColors.neutral.fill);
|
|
params.set(import_ag_charts_core154.PALETTE_ALT_UP_STROKE, this.palette.altUp?.stroke ?? defaultColors.up.stroke);
|
|
params.set(import_ag_charts_core154.PALETTE_ALT_UP_FILL, this.palette.altUp?.fill ?? defaultColors.up.fill);
|
|
params.set(import_ag_charts_core154.PALETTE_ALT_DOWN_STROKE, this.palette.altDown?.stroke ?? defaultColors.down.stroke);
|
|
params.set(import_ag_charts_core154.PALETTE_ALT_DOWN_FILL, this.palette.altDown?.fill ?? defaultColors.down.fill);
|
|
params.set(import_ag_charts_core154.PALETTE_ALT_NEUTRAL_FILL, this.palette.altNeutral?.fill ?? defaultColors.altNeutral.fill);
|
|
params.set(import_ag_charts_core154.PALETTE_ALT_NEUTRAL_STROKE, this.palette.altNeutral?.stroke ?? defaultColors.altNeutral.stroke);
|
|
return params;
|
|
}
|
|
};
|
|
_ChartTheme.axisDefault = {
|
|
[import_ag_charts_core154.CARTESIAN_AXIS_TYPE.NUMBER]: _ChartTheme.getAxisDefaults({ title: true, time: false }),
|
|
[import_ag_charts_core154.CARTESIAN_AXIS_TYPE.LOG]: _ChartTheme.getAxisDefaults({ title: true, time: false }),
|
|
[import_ag_charts_core154.CARTESIAN_AXIS_TYPE.CATEGORY]: _ChartTheme.getAxisDefaults({ title: true, time: false }),
|
|
[import_ag_charts_core154.CARTESIAN_AXIS_TYPE.GROUPED_CATEGORY]: _ChartTheme.getAxisDefaults({ title: true, time: false }),
|
|
[import_ag_charts_core154.CARTESIAN_AXIS_TYPE.TIME]: _ChartTheme.getAxisDefaults({ title: true, time: true }),
|
|
[import_ag_charts_core154.CARTESIAN_AXIS_TYPE.UNIT_TIME]: _ChartTheme.getAxisDefaults({ title: true, time: true }),
|
|
[import_ag_charts_core154.CARTESIAN_AXIS_TYPE.ORDINAL_TIME]: _ChartTheme.getAxisDefaults({ title: true, time: true }),
|
|
[import_ag_charts_core154.POLAR_AXIS_TYPE.ANGLE_CATEGORY]: _ChartTheme.getAxisDefaults({ title: false, time: false }),
|
|
[import_ag_charts_core154.POLAR_AXIS_TYPE.ANGLE_NUMBER]: _ChartTheme.getAxisDefaults({ title: false, time: false }),
|
|
[import_ag_charts_core154.POLAR_AXIS_TYPE.RADIUS_CATEGORY]: _ChartTheme.getAxisDefaults({ title: true, time: false }),
|
|
[import_ag_charts_core154.POLAR_AXIS_TYPE.RADIUS_NUMBER]: _ChartTheme.getAxisDefaults({ title: true, time: false })
|
|
};
|
|
var ChartTheme = _ChartTheme;
|
|
function getAxisThemeTemplate(axisType) {
|
|
let themeTemplate7 = import_ag_charts_core154.ModuleRegistry.getAxisModule(axisType)?.themeTemplate ?? {};
|
|
for (const module2 of import_ag_charts_core154.ModuleRegistry.listModulesByType(import_ag_charts_core154.ModuleType.AxisPlugin)) {
|
|
if (module2.axisTypes?.includes(axisType) ?? true) {
|
|
themeTemplate7 = (0, import_ag_charts_core154.mergeDefaults)({ [module2.name]: module2.themeTemplate }, themeTemplate7);
|
|
}
|
|
}
|
|
return themeTemplate7;
|
|
}
|
|
function getSeriesThemeTemplate(seriesType) {
|
|
let themeTemplate7 = import_ag_charts_core154.ModuleRegistry.getSeriesModule(seriesType)?.themeTemplate ?? {};
|
|
for (const module2 of import_ag_charts_core154.ModuleRegistry.listModulesByType(import_ag_charts_core154.ModuleType.SeriesPlugin)) {
|
|
if (module2.seriesTypes?.includes(seriesType) ?? true) {
|
|
themeTemplate7 = (0, import_ag_charts_core154.mergeDefaults)({ series: { [module2.name]: module2.themeTemplate } }, themeTemplate7);
|
|
}
|
|
}
|
|
return themeTemplate7;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/factory/processModuleOptions.ts
|
|
var SkippedModules = /* @__PURE__ */ new Set(["foreground"]);
|
|
function sanitizeThemeModules(theme) {
|
|
const missingModules = /* @__PURE__ */ new Map();
|
|
for (const [name, { type }] of ExpectedModules) {
|
|
if (import_ag_charts_core155.ModuleRegistry.hasModule(name))
|
|
continue;
|
|
if (missingModules.has(type)) {
|
|
missingModules.get(type).add(name);
|
|
} else {
|
|
missingModules.set(type, /* @__PURE__ */ new Set([name]));
|
|
}
|
|
}
|
|
if (missingModules.size === 0)
|
|
return theme;
|
|
function prunePlugins(target) {
|
|
const missingPlugins = missingModules.get(import_ag_charts_core155.ModuleType.Plugin);
|
|
if (!(0, import_ag_charts_core155.isObject)(target) || !missingPlugins)
|
|
return;
|
|
for (const pluginName of missingPlugins) {
|
|
if (pluginName in target && target[pluginName].enabled !== true) {
|
|
delete target[pluginName];
|
|
}
|
|
}
|
|
}
|
|
function pruneSeriesPlugins(target) {
|
|
const missingSeriesPlugins = missingModules.get(import_ag_charts_core155.ModuleType.SeriesPlugin);
|
|
if (!(0, import_ag_charts_core155.isObject)(target) || !missingSeriesPlugins)
|
|
return;
|
|
for (const pluginName of missingSeriesPlugins) {
|
|
if (pluginName in target) {
|
|
delete target[pluginName];
|
|
}
|
|
}
|
|
}
|
|
function pruneAxisPlugins(target) {
|
|
const missingAxisPlugins = missingModules.get(import_ag_charts_core155.ModuleType.AxisPlugin);
|
|
if (!(0, import_ag_charts_core155.isObject)(target) || !missingAxisPlugins)
|
|
return;
|
|
for (const pluginName of missingAxisPlugins) {
|
|
if (pluginName in target && target[pluginName].enabled !== true) {
|
|
delete target[pluginName];
|
|
}
|
|
}
|
|
}
|
|
function pruneAxes(axes) {
|
|
if (!(0, import_ag_charts_core155.isObject)(axes))
|
|
return;
|
|
for (const axisName of Object.keys(axes)) {
|
|
if (missingModules.get(import_ag_charts_core155.ModuleType.Axis)?.has(axisName)) {
|
|
delete axes[axisName];
|
|
continue;
|
|
}
|
|
pruneAxisPlugins(axes[axisName]);
|
|
}
|
|
}
|
|
function pruneSeriesEntry(entry) {
|
|
if (!(0, import_ag_charts_core155.isObject)(entry))
|
|
return;
|
|
pruneAxes(entry.axes);
|
|
prunePlugins(entry);
|
|
pruneSeriesPlugins(entry.series);
|
|
}
|
|
const config = (0, import_ag_charts_core155.deepClone)(theme.config);
|
|
const overrides = (0, import_ag_charts_core155.deepClone)(theme.overrides);
|
|
const presets = (0, import_ag_charts_core155.deepClone)(theme.presets);
|
|
for (const seriesType of Object.keys(config)) {
|
|
if (missingModules.get(import_ag_charts_core155.ModuleType.Series)?.has(seriesType)) {
|
|
delete config[seriesType];
|
|
continue;
|
|
}
|
|
pruneSeriesEntry(config[seriesType]);
|
|
}
|
|
if ((0, import_ag_charts_core155.isObject)(overrides)) {
|
|
const overridesObj = overrides;
|
|
if ((0, import_ag_charts_core155.isObject)(overridesObj.common)) {
|
|
pruneAxes(overridesObj.common.axes);
|
|
prunePlugins(overridesObj.common);
|
|
}
|
|
for (const seriesType of Object.keys(overridesObj)) {
|
|
if (seriesType === "common")
|
|
continue;
|
|
if (missingModules.get(import_ag_charts_core155.ModuleType.Series)?.has(seriesType)) {
|
|
delete overridesObj[seriesType];
|
|
continue;
|
|
}
|
|
pruneSeriesEntry(overridesObj[seriesType]);
|
|
}
|
|
}
|
|
if ((0, import_ag_charts_core155.isObject)(presets)) {
|
|
const presetsObj = presets;
|
|
for (const presetName of Object.keys(presetsObj)) {
|
|
if (missingModules.get(import_ag_charts_core155.ModuleType.Preset)?.has(presetName) || missingModules.get(import_ag_charts_core155.ModuleType.Series)?.has(presetName)) {
|
|
delete presetsObj[presetName];
|
|
continue;
|
|
}
|
|
prunePlugins(presetsObj[presetName]);
|
|
pruneAxes(presetsObj[presetName]?.axes);
|
|
}
|
|
}
|
|
return Object.create(theme, {
|
|
config: { value: (0, import_ag_charts_core155.deepFreeze)(config), enumerable: true },
|
|
overrides: { value: (0, import_ag_charts_core155.isObject)(overrides) ? (0, import_ag_charts_core155.deepFreeze)(overrides) : overrides, enumerable: true },
|
|
presets: { value: (0, import_ag_charts_core155.isObject)(presets) ? (0, import_ag_charts_core155.deepFreeze)(presets) : presets, enumerable: true }
|
|
});
|
|
}
|
|
function processModuleOptions(chartType, options, additionalMissingModules) {
|
|
const missingModules = (0, import_ag_charts_core155.unique)(removeUnregisteredModuleOptions(chartType, options).concat(additionalMissingModules));
|
|
if (!missingModules.length)
|
|
return;
|
|
const installationReferenceUrl = import_ag_charts_core155.ModuleRegistry.isIntegrated() ? "https://www.ag-grid.com/data-grid/integrated-charts-installation/" : "https://www.ag-grid.com/charts/r/module-registry/";
|
|
const missingOptions = (0, import_ag_charts_core155.groupBy)(missingModules, (module2) => module2.enterprise ? "enterprise" : "community");
|
|
if (missingModules.length) {
|
|
const packageName = import_ag_charts_core155.ModuleRegistry.isEnterprise() || missingOptions.enterprise?.length ? "enterprise" : "community";
|
|
import_ag_charts_core155.Logger.errorOnce(
|
|
[
|
|
"required modules are not registered. Check if you have registered the modules:",
|
|
"",
|
|
import_ag_charts_core155.ModuleRegistry.isUmd() ? `Install and register 'ag-charts-enterprise' before creating the chart.` : createRegistrySnippet(missingModules.map(formatMissingModuleName), packageName),
|
|
"",
|
|
`See ${installationReferenceUrl} for more details.`
|
|
].join("\n")
|
|
);
|
|
}
|
|
}
|
|
function formatMissingModuleName(module2) {
|
|
return module2.moduleId ?? module2.name;
|
|
}
|
|
function formatImportItem(name) {
|
|
return ` ${name},`;
|
|
}
|
|
function formatImports(imports, packageName) {
|
|
return imports.length ? `import {
|
|
${imports.map(formatImportItem).join("\n")}
|
|
} from 'ag-charts-${packageName}';` : null;
|
|
}
|
|
function createRegistrySnippet(moduleNames, packageName) {
|
|
const imports = formatImports(["ModuleRegistry"].concat(moduleNames), packageName);
|
|
const moduleList = moduleNames.map(formatImportItem).join("\n");
|
|
return `${imports}
|
|
|
|
ModuleRegistry.registerModules([
|
|
${moduleList}
|
|
]);`;
|
|
}
|
|
function removeUnregisteredModuleOptions(chartType, options) {
|
|
const missingModules = /* @__PURE__ */ new Map();
|
|
const optionsAxes = "axes" in options && (0, import_ag_charts_core155.isObject)(options.axes) ? options.axes : {};
|
|
const axisTypesInOptions = new Set(
|
|
Object.values(optionsAxes).map((axis) => axis?.type).filter(import_ag_charts_core155.isDefined)
|
|
);
|
|
const seriesTypesInOptions = new Set(options.series?.map((series) => series.type).filter(import_ag_charts_core155.isDefined));
|
|
function addMissingModule(module2) {
|
|
missingModules.set(module2.name, module2);
|
|
}
|
|
for (const module2 of ExpectedModules.values()) {
|
|
if (import_ag_charts_core155.ModuleRegistry.hasModule(module2.name))
|
|
continue;
|
|
if (SkippedModules.has(module2.name))
|
|
continue;
|
|
if (chartType && module2.chartType && chartType !== module2.chartType)
|
|
continue;
|
|
switch (module2.type) {
|
|
case "chart":
|
|
break;
|
|
case "axis":
|
|
if (axisTypesInOptions.has(module2.name)) {
|
|
for (const key of Object.keys(optionsAxes)) {
|
|
if (optionsAxes?.[key].type === module2.name) {
|
|
delete optionsAxes[key];
|
|
}
|
|
}
|
|
addMissingModule(module2);
|
|
}
|
|
break;
|
|
case "series":
|
|
if (seriesTypesInOptions.has(module2.name)) {
|
|
options.series = options.series.filter((series) => series.type !== module2.name);
|
|
addMissingModule(module2);
|
|
}
|
|
break;
|
|
case "plugin":
|
|
const optionsKey = module2.name;
|
|
const pluginValue = options[optionsKey];
|
|
if ((0, import_ag_charts_core155.isObject)(pluginValue)) {
|
|
if (pluginValue.enabled !== false) {
|
|
addMissingModule(module2);
|
|
}
|
|
delete options[optionsKey];
|
|
}
|
|
break;
|
|
case "axis:plugin":
|
|
for (const axis of Object.values(optionsAxes)) {
|
|
const axisModuleKey = module2.name;
|
|
if (axis?.[axisModuleKey]) {
|
|
if (axis[axisModuleKey].enabled !== false) {
|
|
addMissingModule(module2);
|
|
}
|
|
delete axis[axisModuleKey];
|
|
}
|
|
}
|
|
break;
|
|
case "series:plugin":
|
|
for (const series of options.series ?? []) {
|
|
if (series[module2.name]) {
|
|
delete series[module2.name];
|
|
addMissingModule(module2);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
for (const seriesType of seriesTypesInOptions) {
|
|
const expectedSeriesModule = ExpectedModules.get(seriesType);
|
|
if (expectedSeriesModule?.type === import_ag_charts_core155.ModuleType.Series && !import_ag_charts_core155.ModuleRegistry.hasModule(expectedSeriesModule.name) && !missingModules.has(expectedSeriesModule.name)) {
|
|
options.series = options.series.filter((series) => series.type !== expectedSeriesModule.name);
|
|
addMissingModule(expectedSeriesModule);
|
|
}
|
|
}
|
|
return Array.from(missingModules.values());
|
|
}
|
|
function removeIncompatibleModuleOptions(chartType, options) {
|
|
const hasAxesOptions = "axes" in options && (0, import_ag_charts_core155.isObject)(options.axes);
|
|
const hasSeriesOptions = "series" in options && (0, import_ag_charts_core155.isArray)(options.series);
|
|
const matchChartType = (module2) => chartType == null || !module2.chartType || module2.chartType === chartType;
|
|
const incompatibleModules = [];
|
|
for (const module2 of import_ag_charts_core155.ModuleRegistry.listModules()) {
|
|
if (import_ag_charts_core155.ModuleRegistry.isModuleType(import_ag_charts_core155.ModuleType.Plugin, module2)) {
|
|
if (!matchChartType(module2)) {
|
|
delete options[module2.name];
|
|
incompatibleModules.push(module2.name);
|
|
}
|
|
} else if (import_ag_charts_core155.ModuleRegistry.isModuleType(import_ag_charts_core155.ModuleType.AxisPlugin, module2)) {
|
|
if (hasAxesOptions && !matchChartType(module2)) {
|
|
for (const axis of Object.values(options.axes)) {
|
|
delete axis[module2.name];
|
|
}
|
|
incompatibleModules.push(module2.name);
|
|
}
|
|
} else if (import_ag_charts_core155.ModuleRegistry.isModuleType(import_ag_charts_core155.ModuleType.SeriesPlugin, module2)) {
|
|
if (hasSeriesOptions && !matchChartType(module2)) {
|
|
for (const series of options.series) {
|
|
delete series[module2.name];
|
|
}
|
|
incompatibleModules.push(module2.name);
|
|
}
|
|
}
|
|
}
|
|
return incompatibleModules;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/mapping/themes.ts
|
|
var import_ag_charts_core180 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/themes/darkTheme.ts
|
|
var import_ag_charts_core156 = require("ag-charts-core");
|
|
var DEFAULT_DARK_BACKGROUND_FILL = "#192232";
|
|
var DEFAULT_DARK_FILLS = {
|
|
BLUE: "#5090dc",
|
|
ORANGE: "#ffa03a",
|
|
GREEN: "#459d55",
|
|
CYAN: "#34bfe1",
|
|
YELLOW: "#e1cc00",
|
|
VIOLET: "#9669cb",
|
|
GRAY: "#b5b5b5",
|
|
MAGENTA: "#bd5aa7",
|
|
BROWN: "#8a6224",
|
|
RED: "#ef5452"
|
|
};
|
|
var DEFAULT_DARK_STROKES = {
|
|
BLUE: "#74a8e6",
|
|
ORANGE: "#ffbe70",
|
|
GREEN: "#6cb176",
|
|
CYAN: "#75d4ef",
|
|
YELLOW: "#f6e559",
|
|
VIOLET: "#aa86d8",
|
|
GRAY: "#a1a1a1",
|
|
MAGENTA: "#ce7ab9",
|
|
BROWN: "#997b52",
|
|
RED: "#ff7872"
|
|
};
|
|
var DarkTheme = class extends ChartTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
fills: DEFAULT_DARK_FILLS,
|
|
fillsFallback: Object.values(DEFAULT_DARK_FILLS),
|
|
strokes: DEFAULT_DARK_STROKES,
|
|
sequentialColors: (0, import_ag_charts_core156.getSequentialColors)(DEFAULT_DARK_FILLS),
|
|
divergingColors: [DEFAULT_DARK_FILLS.ORANGE, DEFAULT_DARK_FILLS.YELLOW, DEFAULT_DARK_FILLS.GREEN],
|
|
hierarchyColors: ["#192834", "#253746", "#324859", "#3f596c", "#4d6a80"],
|
|
secondSequentialColors: [
|
|
"#5090dc",
|
|
"#4882c6",
|
|
"#4073b0",
|
|
"#38659a",
|
|
"#305684",
|
|
"#28486e",
|
|
"#203a58",
|
|
"#182b42"
|
|
],
|
|
secondDivergingColors: [DEFAULT_DARK_FILLS.GREEN, DEFAULT_DARK_FILLS.YELLOW, DEFAULT_DARK_FILLS.RED],
|
|
secondHierarchyColors: ["#192834", "#3b5164", "#496275", "#577287", "#668399"],
|
|
up: { fill: DEFAULT_DARK_FILLS.GREEN, stroke: DEFAULT_DARK_STROKES.GREEN },
|
|
down: { fill: DEFAULT_DARK_FILLS.RED, stroke: DEFAULT_DARK_STROKES.RED },
|
|
neutral: { fill: DEFAULT_DARK_FILLS.GRAY, stroke: DEFAULT_DARK_STROKES.GRAY },
|
|
altUp: { fill: DEFAULT_DARK_FILLS.BLUE, stroke: DEFAULT_DARK_STROKES.BLUE },
|
|
altDown: { fill: DEFAULT_DARK_FILLS.ORANGE, stroke: DEFAULT_DARK_STROKES.ORANGE },
|
|
altNeutral: { fill: DEFAULT_DARK_FILLS.GRAY, stroke: DEFAULT_DARK_STROKES.GRAY }
|
|
};
|
|
}
|
|
getPublicParameters() {
|
|
return {
|
|
...super.getPublicParameters(),
|
|
axisColor: { $foregroundBackgroundMix: 0.737 },
|
|
backgroundColor: DEFAULT_DARK_BACKGROUND_FILL,
|
|
borderColor: { $foregroundBackgroundMix: 0.216 },
|
|
chromeBackgroundColor: { $foregroundBackgroundMix: 0.07 },
|
|
foregroundColor: "#fff",
|
|
gridLineColor: { $foregroundBackgroundMix: 0.257 },
|
|
popupShadow: "0 0 16px rgba(0, 0, 0, 0.33)",
|
|
subtleTextColor: { $mix: [{ $ref: "textColor" }, { $ref: "chartBackgroundColor" }, 0.57] },
|
|
separationLinesColor: { $foregroundBackgroundMix: 0.44 },
|
|
crosshairLabelBackgroundColor: { $foregroundBackgroundMix: 0.65 }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core156.IS_DARK_THEME, true);
|
|
params.set(import_ag_charts_core156.DEFAULT_POLAR_SERIES_STROKE, DEFAULT_DARK_BACKGROUND_FILL);
|
|
params.set(import_ag_charts_core156.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, DEFAULT_DARK_FILLS.BLUE);
|
|
params.set(import_ag_charts_core156.DEFAULT_TEXT_ANNOTATION_COLOR, "#fff");
|
|
params.set(import_ag_charts_core156.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, DEFAULT_DARK_FILLS.BLUE);
|
|
params.set(import_ag_charts_core156.DEFAULT_ANNOTATION_HANDLE_FILL, DEFAULT_DARK_BACKGROUND_FILL);
|
|
params.set(import_ag_charts_core156.DEFAULT_ANNOTATION_STATISTICS_FILL, "#28313e");
|
|
params.set(import_ag_charts_core156.DEFAULT_ANNOTATION_STATISTICS_STROKE, "#4b525d");
|
|
params.set(import_ag_charts_core156.DEFAULT_ANNOTATION_STATISTICS_COLOR, "#fff");
|
|
params.set(import_ag_charts_core156.DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE, "#fff");
|
|
params.set(import_ag_charts_core156.DEFAULT_TEXTBOX_FILL, "#28313e");
|
|
params.set(import_ag_charts_core156.DEFAULT_TEXTBOX_STROKE, "#4b525d");
|
|
params.set(import_ag_charts_core156.DEFAULT_TEXTBOX_COLOR, "#fff");
|
|
return params;
|
|
}
|
|
constructor(options) {
|
|
super(options);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/financialDark.ts
|
|
var import_ag_charts_core157 = require("ag-charts-core");
|
|
var FINANCIAL_DARK_FILLS = {
|
|
GREEN: "#089981",
|
|
RED: "#F23645",
|
|
BLUE: "#5090dc",
|
|
GRAY: "#A9A9A9"
|
|
};
|
|
var FINANCIAL_DARK_STROKES = {
|
|
GREEN: "#089981",
|
|
RED: "#F23645",
|
|
BLUE: "#5090dc",
|
|
GRAY: "#909090"
|
|
};
|
|
var FinancialDark = class extends DarkTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
...super.getDefaultColors(),
|
|
fills: { ...FINANCIAL_DARK_FILLS },
|
|
fillsFallback: Object.values({ ...FINANCIAL_DARK_FILLS }),
|
|
strokes: { ...FINANCIAL_DARK_STROKES },
|
|
sequentialColors: (0, import_ag_charts_core157.getSequentialColors)(FINANCIAL_DARK_FILLS),
|
|
divergingColors: [FINANCIAL_DARK_FILLS.GREEN, FINANCIAL_DARK_FILLS.BLUE, FINANCIAL_DARK_FILLS.RED],
|
|
// hierarchyColors: [],
|
|
secondSequentialColors: [
|
|
"#5090dc",
|
|
"#4882c6",
|
|
"#4073b0",
|
|
"#38659a",
|
|
"#305684",
|
|
"#28486e",
|
|
"#203a58",
|
|
"#182b42"
|
|
],
|
|
// secondDivergingColors: [],
|
|
// secondHierarchyColors: [],
|
|
up: { fill: FINANCIAL_DARK_FILLS.GREEN, stroke: FINANCIAL_DARK_STROKES.GREEN },
|
|
down: { fill: FINANCIAL_DARK_FILLS.RED, stroke: FINANCIAL_DARK_STROKES.RED },
|
|
neutral: { fill: FINANCIAL_DARK_FILLS.BLUE, stroke: FINANCIAL_DARK_STROKES.BLUE },
|
|
altUp: { fill: FINANCIAL_DARK_FILLS.GREEN, stroke: FINANCIAL_DARK_STROKES.GREEN },
|
|
altDown: { fill: FINANCIAL_DARK_FILLS.RED, stroke: FINANCIAL_DARK_STROKES.RED },
|
|
altNeutral: { fill: FINANCIAL_DARK_FILLS.GRAY, stroke: FINANCIAL_DARK_STROKES.GRAY }
|
|
};
|
|
}
|
|
getPublicParameters() {
|
|
return {
|
|
...super.getPublicParameters(),
|
|
chartPadding: 0,
|
|
gridLineColor: { $foregroundBackgroundMix: 0.12 }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core157.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, FINANCIAL_DARK_FILLS.BLUE);
|
|
params.set(import_ag_charts_core157.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, FINANCIAL_DARK_FILLS.BLUE);
|
|
params.set(import_ag_charts_core157.DEFAULT_CAPTION_LAYOUT_STYLE, "overlay");
|
|
params.set(import_ag_charts_core157.DEFAULT_CAPTION_ALIGNMENT, "left");
|
|
params.set(import_ag_charts_core157.DEFAULT_TOOLBAR_POSITION, "bottom");
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/financialLight.ts
|
|
var import_ag_charts_core158 = require("ag-charts-core");
|
|
var FINANCIAL_LIGHT_FILLS = {
|
|
GREEN: "#089981",
|
|
RED: "#F23645",
|
|
BLUE: "#5090dc",
|
|
GRAY: "#A9A9A9"
|
|
};
|
|
var FINANCIAL_LIGHT_STROKES = {
|
|
GREEN: "#089981",
|
|
RED: "#F23645",
|
|
BLUE: "#5090dc",
|
|
GRAY: "#909090"
|
|
};
|
|
var FinancialLight = class extends ChartTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
...super.getDefaultColors(),
|
|
fills: { ...FINANCIAL_LIGHT_FILLS },
|
|
fillsFallback: Object.values({ ...FINANCIAL_LIGHT_FILLS }),
|
|
strokes: { ...FINANCIAL_LIGHT_STROKES },
|
|
sequentialColors: (0, import_ag_charts_core158.getSequentialColors)(FINANCIAL_LIGHT_FILLS),
|
|
divergingColors: [FINANCIAL_LIGHT_FILLS.GREEN, FINANCIAL_LIGHT_FILLS.BLUE, FINANCIAL_LIGHT_FILLS.RED],
|
|
// hierarchyColors: [],
|
|
// secondSequentialColors: [],
|
|
// secondDivergingColors: [],
|
|
// secondHierarchyColors: [],
|
|
up: { fill: FINANCIAL_LIGHT_FILLS.GREEN, stroke: FINANCIAL_LIGHT_STROKES.GREEN },
|
|
down: { fill: FINANCIAL_LIGHT_FILLS.RED, stroke: FINANCIAL_LIGHT_STROKES.RED },
|
|
neutral: { fill: FINANCIAL_LIGHT_FILLS.BLUE, stroke: FINANCIAL_LIGHT_STROKES.BLUE },
|
|
altUp: { fill: FINANCIAL_LIGHT_FILLS.GREEN, stroke: FINANCIAL_LIGHT_STROKES.GREEN },
|
|
altDown: { fill: FINANCIAL_LIGHT_FILLS.RED, stroke: FINANCIAL_LIGHT_STROKES.RED },
|
|
altNeutral: { fill: FINANCIAL_LIGHT_FILLS.GRAY, stroke: FINANCIAL_LIGHT_STROKES.GRAY }
|
|
};
|
|
}
|
|
getPublicParameters() {
|
|
return {
|
|
...super.getPublicParameters(),
|
|
chartPadding: 0,
|
|
gridLineColor: { $foregroundBackgroundMix: 0.06 }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core158.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, FINANCIAL_LIGHT_FILLS.BLUE);
|
|
params.set(import_ag_charts_core158.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, FINANCIAL_LIGHT_FILLS.BLUE);
|
|
params.set(import_ag_charts_core158.DEFAULT_CAPTION_LAYOUT_STYLE, "overlay");
|
|
params.set(import_ag_charts_core158.DEFAULT_CAPTION_ALIGNMENT, "left");
|
|
params.set(import_ag_charts_core158.DEFAULT_TOOLBAR_POSITION, "bottom");
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/materialDark.ts
|
|
var import_ag_charts_core159 = require("ag-charts-core");
|
|
var MATERIAL_DARK_FILLS = {
|
|
BLUE: "#2196F3",
|
|
ORANGE: "#FF9800",
|
|
GREEN: "#4CAF50",
|
|
CYAN: "#00BCD4",
|
|
YELLOW: "#FFEB3B",
|
|
VIOLET: "#7E57C2",
|
|
GRAY: "#9E9E9E",
|
|
MAGENTA: "#F06292",
|
|
BROWN: "#795548",
|
|
RED: "#F44336"
|
|
};
|
|
var MATERIAL_DARK_STROKES = {
|
|
BLUE: "#90CAF9",
|
|
ORANGE: "#FFCC80",
|
|
GREEN: "#A5D6A7",
|
|
CYAN: "#80DEEA",
|
|
YELLOW: "#FFF9C4",
|
|
VIOLET: "#B39DDB",
|
|
GRAY: "#E0E0E0",
|
|
MAGENTA: "#F48FB1",
|
|
BROWN: "#A1887F",
|
|
RED: "#EF9A9A"
|
|
};
|
|
var MaterialDark = class extends DarkTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
...super.getDefaultColors(),
|
|
fills: MATERIAL_DARK_FILLS,
|
|
fillsFallback: Object.values(MATERIAL_DARK_FILLS),
|
|
strokes: MATERIAL_DARK_STROKES,
|
|
sequentialColors: (0, import_ag_charts_core159.getSequentialColors)(MATERIAL_DARK_FILLS),
|
|
divergingColors: [MATERIAL_DARK_FILLS.ORANGE, MATERIAL_DARK_FILLS.YELLOW, MATERIAL_DARK_FILLS.GREEN],
|
|
// hierarchyColors: [],
|
|
secondSequentialColors: [
|
|
"#2196f3",
|
|
// 500
|
|
"#208FEC",
|
|
// (interpolated)
|
|
"#1E88E5",
|
|
// 600
|
|
"#1C7FDC",
|
|
// (interpolated)
|
|
"#1976d2",
|
|
// 700
|
|
"#176EC9",
|
|
// (interpolated)
|
|
"#1565c0"
|
|
// 800
|
|
],
|
|
secondDivergingColors: [MATERIAL_DARK_FILLS.GREEN, MATERIAL_DARK_FILLS.YELLOW, MATERIAL_DARK_FILLS.RED],
|
|
// secondHierarchyColors: [],
|
|
up: { fill: MATERIAL_DARK_FILLS.GREEN, stroke: MATERIAL_DARK_STROKES.GREEN },
|
|
down: { fill: MATERIAL_DARK_FILLS.RED, stroke: MATERIAL_DARK_STROKES.RED },
|
|
neutral: { fill: MATERIAL_DARK_FILLS.GRAY, stroke: MATERIAL_DARK_STROKES.GRAY },
|
|
altUp: { fill: MATERIAL_DARK_FILLS.BLUE, stroke: MATERIAL_DARK_STROKES.BLUE },
|
|
altDown: { fill: MATERIAL_DARK_FILLS.RED, stroke: MATERIAL_DARK_STROKES.RED },
|
|
altNeutral: { fill: MATERIAL_DARK_FILLS.GRAY, stroke: MATERIAL_DARK_STROKES.GRAY }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core159.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, MATERIAL_DARK_FILLS.BLUE);
|
|
params.set(import_ag_charts_core159.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, MATERIAL_DARK_FILLS.BLUE);
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/materialLight.ts
|
|
var import_ag_charts_core160 = require("ag-charts-core");
|
|
var MATERIAL_LIGHT_FILLS = {
|
|
BLUE: "#2196F3",
|
|
ORANGE: "#FF9800",
|
|
GREEN: "#4CAF50",
|
|
CYAN: "#00BCD4",
|
|
YELLOW: "#FFEB3B",
|
|
VIOLET: "#7E57C2",
|
|
GRAY: "#9E9E9E",
|
|
MAGENTA: "#F06292",
|
|
BROWN: "#795548",
|
|
RED: "#F44336"
|
|
};
|
|
var MATERIAL_LIGHT_STROKES = {
|
|
BLUE: "#1565C0",
|
|
ORANGE: "#E65100",
|
|
GREEN: "#2E7D32",
|
|
CYAN: "#00838F",
|
|
YELLOW: "#F9A825",
|
|
VIOLET: "#4527A0",
|
|
GRAY: "#616161",
|
|
MAGENTA: "#C2185B",
|
|
BROWN: "#4E342E",
|
|
RED: "#B71C1C"
|
|
};
|
|
var MaterialLight = class extends ChartTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
...super.getDefaultColors(),
|
|
fills: MATERIAL_LIGHT_FILLS,
|
|
fillsFallback: Object.values(MATERIAL_LIGHT_FILLS),
|
|
strokes: MATERIAL_LIGHT_STROKES,
|
|
sequentialColors: (0, import_ag_charts_core160.getSequentialColors)(MATERIAL_LIGHT_FILLS),
|
|
divergingColors: [MATERIAL_LIGHT_FILLS.ORANGE, MATERIAL_LIGHT_FILLS.YELLOW, MATERIAL_LIGHT_FILLS.GREEN],
|
|
// hierarchyColors: [],
|
|
secondSequentialColors: [
|
|
"#2196f3",
|
|
// 500
|
|
"#329EF4",
|
|
// (interpolated)
|
|
"#42a5f5",
|
|
// 400
|
|
"#53ADF6",
|
|
// (interpolated)
|
|
"#64b5f6",
|
|
// 300
|
|
"#7AC0F8",
|
|
// (interpolated)
|
|
"#90caf9"
|
|
// 200
|
|
],
|
|
secondDivergingColors: [MATERIAL_LIGHT_FILLS.GREEN, MATERIAL_LIGHT_FILLS.YELLOW, MATERIAL_LIGHT_FILLS.RED],
|
|
// secondHierarchyColors: [],
|
|
up: { fill: MATERIAL_LIGHT_FILLS.GREEN, stroke: MATERIAL_LIGHT_STROKES.GREEN },
|
|
down: { fill: MATERIAL_LIGHT_FILLS.RED, stroke: MATERIAL_LIGHT_STROKES.RED },
|
|
neutral: { fill: MATERIAL_LIGHT_FILLS.GRAY, stroke: MATERIAL_LIGHT_STROKES.GRAY },
|
|
altUp: { fill: MATERIAL_LIGHT_FILLS.BLUE, stroke: MATERIAL_LIGHT_STROKES.BLUE },
|
|
altDown: { fill: MATERIAL_LIGHT_FILLS.RED, stroke: MATERIAL_LIGHT_STROKES.RED },
|
|
altNeutral: { fill: MATERIAL_LIGHT_FILLS.GRAY, stroke: MATERIAL_LIGHT_STROKES.GRAY }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core160.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, MATERIAL_LIGHT_FILLS.BLUE);
|
|
params.set(import_ag_charts_core160.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, MATERIAL_LIGHT_FILLS.BLUE);
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/polychromaDark.ts
|
|
var import_ag_charts_core161 = require("ag-charts-core");
|
|
var POLYCHROMA_DARK_FILLS = {
|
|
BLUE: "#436ff4",
|
|
PURPLE: "#9a7bff",
|
|
MAGENTA: "#d165d2",
|
|
PINK: "#f0598b",
|
|
RED: "#f47348",
|
|
ORANGE: "#f2a602",
|
|
YELLOW: "#e9e201",
|
|
GREEN: "#21b448",
|
|
CYAN: "#00b9a2",
|
|
MODERATE_BLUE: "#00aee4",
|
|
GRAY: "#bbbbbb"
|
|
};
|
|
var POLYCHROMA_DARK_STROKES = {
|
|
BLUE: "#6698ff",
|
|
PURPLE: "#c0a3ff",
|
|
MAGENTA: "#fc8dfc",
|
|
PINK: "#ff82b1",
|
|
RED: "#ff9b70",
|
|
ORANGE: "#ffcf4e",
|
|
YELLOW: "#ffff58",
|
|
GREEN: "#58dd70",
|
|
CYAN: "#51e2c9",
|
|
MODERATE_BLUE: "#4fd7ff",
|
|
GRAY: "#eeeeee"
|
|
};
|
|
var PolychromaDark = class extends DarkTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
fills: POLYCHROMA_DARK_FILLS,
|
|
fillsFallback: Object.values(POLYCHROMA_DARK_FILLS),
|
|
strokes: POLYCHROMA_DARK_STROKES,
|
|
sequentialColors: (0, import_ag_charts_core161.getSequentialColors)(POLYCHROMA_DARK_FILLS),
|
|
divergingColors: [POLYCHROMA_DARK_FILLS.BLUE, POLYCHROMA_DARK_FILLS.RED],
|
|
hierarchyColors: [],
|
|
secondSequentialColors: [
|
|
POLYCHROMA_DARK_FILLS.BLUE,
|
|
POLYCHROMA_DARK_FILLS.PURPLE,
|
|
POLYCHROMA_DARK_FILLS.MAGENTA,
|
|
POLYCHROMA_DARK_FILLS.PINK,
|
|
POLYCHROMA_DARK_FILLS.RED,
|
|
POLYCHROMA_DARK_FILLS.ORANGE,
|
|
POLYCHROMA_DARK_FILLS.YELLOW,
|
|
POLYCHROMA_DARK_FILLS.GREEN
|
|
],
|
|
secondDivergingColors: [POLYCHROMA_DARK_FILLS.BLUE, POLYCHROMA_DARK_FILLS.RED],
|
|
secondHierarchyColors: [],
|
|
up: { fill: POLYCHROMA_DARK_FILLS.GREEN, stroke: POLYCHROMA_DARK_STROKES.GREEN },
|
|
down: { fill: POLYCHROMA_DARK_FILLS.RED, stroke: POLYCHROMA_DARK_STROKES.RED },
|
|
neutral: { fill: POLYCHROMA_DARK_FILLS.GRAY, stroke: POLYCHROMA_DARK_STROKES.GRAY },
|
|
altUp: { fill: POLYCHROMA_DARK_FILLS.BLUE, stroke: POLYCHROMA_DARK_STROKES.BLUE },
|
|
altDown: { fill: POLYCHROMA_DARK_FILLS.RED, stroke: POLYCHROMA_DARK_STROKES.RED },
|
|
altNeutral: { fill: POLYCHROMA_DARK_FILLS.GRAY, stroke: POLYCHROMA_DARK_STROKES.GRAY }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core161.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, POLYCHROMA_DARK_FILLS.BLUE);
|
|
params.set(import_ag_charts_core161.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, POLYCHROMA_DARK_FILLS.BLUE);
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/polychromaLight.ts
|
|
var import_ag_charts_core162 = require("ag-charts-core");
|
|
var POLYCHROMA_LIGHT_FILLS = {
|
|
BLUE: "#436ff4",
|
|
PURPLE: "#9a7bff",
|
|
MAGENTA: "#d165d2",
|
|
PINK: "#f0598b",
|
|
RED: "#f47348",
|
|
ORANGE: "#f2a602",
|
|
YELLOW: "#e9e201",
|
|
GREEN: "#21b448",
|
|
CYAN: "#00b9a2",
|
|
MODERATE_BLUE: "#00aee4",
|
|
GRAY: "#bbbbbb"
|
|
};
|
|
var POLYCHROMA_LIGHT_STROKES = {
|
|
BLUE: "#2346c9",
|
|
PURPLE: "#7653d4",
|
|
MAGENTA: "#a73da9",
|
|
PINK: "#c32d66",
|
|
RED: "#c84b1c",
|
|
ORANGE: "#c87f00",
|
|
YELLOW: "#c1b900",
|
|
GREEN: "#008c1c",
|
|
CYAN: "#00927c",
|
|
MODERATE_BLUE: "#0087bb",
|
|
GRAY: "#888888"
|
|
};
|
|
var PolychromaLight = class extends ChartTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
...super.getDefaultColors(),
|
|
fills: POLYCHROMA_LIGHT_FILLS,
|
|
fillsFallback: Object.values(POLYCHROMA_LIGHT_FILLS),
|
|
strokes: POLYCHROMA_LIGHT_STROKES,
|
|
sequentialColors: (0, import_ag_charts_core162.getSequentialColors)(POLYCHROMA_LIGHT_FILLS),
|
|
divergingColors: [POLYCHROMA_LIGHT_FILLS.BLUE, POLYCHROMA_LIGHT_FILLS.RED],
|
|
hierarchyColors: [],
|
|
secondSequentialColors: [
|
|
POLYCHROMA_LIGHT_FILLS.BLUE,
|
|
POLYCHROMA_LIGHT_FILLS.PURPLE,
|
|
POLYCHROMA_LIGHT_FILLS.MAGENTA,
|
|
POLYCHROMA_LIGHT_FILLS.PINK,
|
|
POLYCHROMA_LIGHT_FILLS.RED,
|
|
POLYCHROMA_LIGHT_FILLS.ORANGE,
|
|
POLYCHROMA_LIGHT_FILLS.YELLOW,
|
|
POLYCHROMA_LIGHT_FILLS.GREEN
|
|
],
|
|
secondDivergingColors: [POLYCHROMA_LIGHT_FILLS.BLUE, POLYCHROMA_LIGHT_FILLS.RED],
|
|
secondHierarchyColors: [],
|
|
up: { fill: POLYCHROMA_LIGHT_FILLS.GREEN, stroke: POLYCHROMA_LIGHT_STROKES.GREEN },
|
|
down: { fill: POLYCHROMA_LIGHT_FILLS.RED, stroke: POLYCHROMA_LIGHT_STROKES.RED },
|
|
neutral: { fill: POLYCHROMA_LIGHT_FILLS.GRAY, stroke: POLYCHROMA_LIGHT_STROKES.GRAY },
|
|
altUp: { fill: POLYCHROMA_LIGHT_FILLS.BLUE, stroke: POLYCHROMA_LIGHT_STROKES.BLUE },
|
|
altDown: { fill: POLYCHROMA_LIGHT_FILLS.RED, stroke: POLYCHROMA_LIGHT_STROKES.RED },
|
|
altNeutral: { fill: POLYCHROMA_LIGHT_FILLS.GRAY, stroke: POLYCHROMA_LIGHT_STROKES.GRAY }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core162.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, POLYCHROMA_LIGHT_FILLS.BLUE);
|
|
params.set(import_ag_charts_core162.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, POLYCHROMA_LIGHT_FILLS.BLUE);
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/sheetsDark.ts
|
|
var import_ag_charts_core163 = require("ag-charts-core");
|
|
var SHEETS_DARK_FILLS = {
|
|
BLUE: "#4472C4",
|
|
ORANGE: "#ED7D31",
|
|
GRAY: "#A5A5A5",
|
|
YELLOW: "#FFC000",
|
|
MODERATE_BLUE: "#5B9BD5",
|
|
GREEN: "#70AD47",
|
|
DARK_GRAY: "#7B7B7B",
|
|
DARK_BLUE: "#264478",
|
|
VERY_DARK_GRAY: "#636363",
|
|
DARK_YELLOW: "#997300"
|
|
};
|
|
var SHEETS_DARK_STROKES = {
|
|
BLUE: "#6899ee",
|
|
ORANGE: "#ffa55d",
|
|
GRAY: "#cdcdcd",
|
|
YELLOW: "#ffea53",
|
|
MODERATE_BLUE: "#82c3ff",
|
|
GREEN: "#96d56f",
|
|
DARK_GRAY: "#a1a1a1",
|
|
DARK_BLUE: "#47689f",
|
|
VERY_DARK_GRAY: "#878787",
|
|
DARK_YELLOW: "#c0993d"
|
|
};
|
|
var SheetsDark = class extends DarkTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
...super.getDefaultColors(),
|
|
fills: { ...SHEETS_DARK_FILLS, RED: SHEETS_DARK_FILLS.ORANGE },
|
|
fillsFallback: Object.values({ ...SHEETS_DARK_FILLS, RED: SHEETS_DARK_FILLS.ORANGE }),
|
|
strokes: { ...SHEETS_DARK_STROKES, RED: SHEETS_DARK_STROKES.ORANGE },
|
|
sequentialColors: (0, import_ag_charts_core163.getSequentialColors)({ ...SHEETS_DARK_FILLS, RED: SHEETS_DARK_FILLS.ORANGE }),
|
|
divergingColors: [SHEETS_DARK_FILLS.ORANGE, SHEETS_DARK_FILLS.YELLOW, SHEETS_DARK_FILLS.GREEN],
|
|
// hierarchyColors: [],
|
|
secondSequentialColors: [
|
|
"#5090dc",
|
|
"#4882c6",
|
|
"#4073b0",
|
|
"#38659a",
|
|
"#305684",
|
|
"#28486e",
|
|
"#203a58",
|
|
"#182b42"
|
|
],
|
|
secondDivergingColors: [SHEETS_DARK_FILLS.GREEN, SHEETS_DARK_FILLS.YELLOW, SHEETS_DARK_FILLS.ORANGE],
|
|
// secondHierarchyColors: [],
|
|
up: { fill: SHEETS_DARK_FILLS.GREEN, stroke: SHEETS_DARK_STROKES.GREEN },
|
|
down: { fill: SHEETS_DARK_FILLS.ORANGE, stroke: SHEETS_DARK_STROKES.ORANGE },
|
|
neutral: { fill: SHEETS_DARK_FILLS.GRAY, stroke: SHEETS_DARK_STROKES.GRAY },
|
|
altUp: { fill: SHEETS_DARK_FILLS.BLUE, stroke: SHEETS_DARK_STROKES.BLUE },
|
|
altDown: { fill: SHEETS_DARK_FILLS.ORANGE, stroke: SHEETS_DARK_STROKES.ORANGE },
|
|
altNeutral: { fill: SHEETS_DARK_FILLS.GRAY, stroke: SHEETS_DARK_STROKES.GRAY }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core163.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, SHEETS_DARK_FILLS.BLUE);
|
|
params.set(import_ag_charts_core163.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, SHEETS_DARK_FILLS.BLUE);
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/sheetsLight.ts
|
|
var import_ag_charts_core164 = require("ag-charts-core");
|
|
var SHEETS_LIGHT_FILLS = {
|
|
BLUE: "#5281d5",
|
|
ORANGE: "#ff8d44",
|
|
GRAY: "#b5b5b5",
|
|
YELLOW: "#ffd02f",
|
|
MODERATE_BLUE: "#6aabe6",
|
|
GREEN: "#7fbd57",
|
|
DARK_GRAY: "#8a8a8a",
|
|
DARK_BLUE: "#335287",
|
|
VERY_DARK_GRAY: "#717171",
|
|
DARK_YELLOW: "#a98220"
|
|
};
|
|
var SHEETS_LIGHT_STROKES = {
|
|
BLUE: "#214d9b",
|
|
ORANGE: "#c25600",
|
|
GRAY: "#7f7f7f",
|
|
YELLOW: "#d59800",
|
|
MODERATE_BLUE: "#3575ac",
|
|
GREEN: "#4b861a",
|
|
DARK_GRAY: "#575757",
|
|
DARK_BLUE: "#062253",
|
|
VERY_DARK_GRAY: "#414141",
|
|
DARK_YELLOW: "#734f00"
|
|
};
|
|
var SheetsLight = class extends ChartTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
...super.getDefaultColors(),
|
|
fills: { ...SHEETS_LIGHT_FILLS, RED: SHEETS_LIGHT_FILLS.ORANGE },
|
|
fillsFallback: Object.values({ ...SHEETS_LIGHT_FILLS, RED: SHEETS_LIGHT_FILLS.ORANGE }),
|
|
strokes: { ...SHEETS_LIGHT_STROKES, RED: SHEETS_LIGHT_STROKES.ORANGE },
|
|
sequentialColors: (0, import_ag_charts_core164.getSequentialColors)({ ...SHEETS_LIGHT_FILLS, RED: SHEETS_LIGHT_FILLS.ORANGE }),
|
|
divergingColors: [SHEETS_LIGHT_FILLS.ORANGE, SHEETS_LIGHT_FILLS.YELLOW, SHEETS_LIGHT_FILLS.GREEN],
|
|
// hierarchyColors: [],
|
|
secondSequentialColors: [
|
|
"#5090dc",
|
|
"#629be0",
|
|
"#73a6e3",
|
|
"#85b1e7",
|
|
"#96bcea",
|
|
"#a8c8ee",
|
|
"#b9d3f1",
|
|
"#cbdef5"
|
|
],
|
|
secondDivergingColors: [SHEETS_LIGHT_FILLS.GREEN, SHEETS_LIGHT_FILLS.YELLOW, SHEETS_LIGHT_FILLS.ORANGE],
|
|
secondHierarchyColors: [],
|
|
up: { fill: SHEETS_LIGHT_FILLS.GREEN, stroke: SHEETS_LIGHT_STROKES.GREEN },
|
|
down: { fill: SHEETS_LIGHT_FILLS.ORANGE, stroke: SHEETS_LIGHT_STROKES.ORANGE },
|
|
neutral: { fill: SHEETS_LIGHT_STROKES.GRAY, stroke: SHEETS_LIGHT_STROKES.GRAY },
|
|
altUp: { fill: SHEETS_LIGHT_FILLS.BLUE, stroke: SHEETS_LIGHT_STROKES.BLUE },
|
|
altDown: { fill: SHEETS_LIGHT_FILLS.ORANGE, stroke: SHEETS_LIGHT_STROKES.ORANGE },
|
|
altNeutral: { fill: SHEETS_LIGHT_FILLS.GRAY, stroke: SHEETS_LIGHT_STROKES.GRAY }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core164.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, SHEETS_LIGHT_FILLS.BLUE);
|
|
params.set(import_ag_charts_core164.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, SHEETS_LIGHT_FILLS.BLUE);
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/themeOptionsDef.ts
|
|
var import_ag_charts_core177 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/axesOptionsDefs.ts
|
|
var import_ag_charts_core165 = require("ag-charts-core");
|
|
var timeIntervalUnit = (0, import_ag_charts_core165.union)("millisecond", "second", "minute", "hour", "day", "month", "year");
|
|
var timeIntervalDefs = {
|
|
unit: (0, import_ag_charts_core165.required)(timeIntervalUnit),
|
|
step: import_ag_charts_core165.positiveNumberNonZero,
|
|
epoch: import_ag_charts_core165.date,
|
|
utc: import_ag_charts_core165.boolean
|
|
};
|
|
timeIntervalDefs.every = import_ag_charts_core165.callback;
|
|
var timeInterval = (0, import_ag_charts_core165.optionsDefs)(timeIntervalDefs, "a time interval object");
|
|
var commonCrossLineLabelOptionsDefs = {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
text: import_ag_charts_core165.string,
|
|
padding: import_ag_charts_core165.number,
|
|
border: import_ag_charts_core165.borderOptionsDef,
|
|
cornerRadius: import_ag_charts_core165.number,
|
|
...import_ag_charts_core165.fontOptionsDef,
|
|
...import_ag_charts_core165.fillOptionsDef
|
|
};
|
|
var commonCrossLineOptionsDefs = (0, import_ag_charts_core165.attachDescription)(
|
|
{
|
|
enabled: import_ag_charts_core165.boolean,
|
|
type: (0, import_ag_charts_core165.required)((0, import_ag_charts_core165.union)("line", "range")),
|
|
range: (0, import_ag_charts_core165.and)(
|
|
(0, import_ag_charts_core165.attachDescription)((_, { options }) => options.type === "range", "crossLine type to be 'range'"),
|
|
(0, import_ag_charts_core165.arrayOf)(import_ag_charts_core165.defined),
|
|
(0, import_ag_charts_core165.arrayLength)(2, 2)
|
|
),
|
|
value: (0, import_ag_charts_core165.and)(
|
|
(0, import_ag_charts_core165.attachDescription)((_, { options }) => options.type === "line", "crossLine type to be 'line'"),
|
|
import_ag_charts_core165.defined
|
|
),
|
|
label: commonCrossLineLabelOptionsDefs,
|
|
fill: import_ag_charts_core165.color,
|
|
fillOpacity: import_ag_charts_core165.ratio,
|
|
...import_ag_charts_core165.strokeOptionsDef,
|
|
...import_ag_charts_core165.lineDashOptionsDef
|
|
},
|
|
"cross-line options"
|
|
);
|
|
var cartesianCrossLineOptionsDefs = {
|
|
...commonCrossLineOptionsDefs,
|
|
label: {
|
|
...commonCrossLineLabelOptionsDefs,
|
|
position: (0, import_ag_charts_core165.union)(
|
|
"top",
|
|
"left",
|
|
"right",
|
|
"bottom",
|
|
"top-left",
|
|
"top-right",
|
|
"bottom-left",
|
|
"bottom-right",
|
|
"inside",
|
|
"inside-left",
|
|
"inside-right",
|
|
"inside-top",
|
|
"inside-bottom",
|
|
"inside-top-left",
|
|
"inside-bottom-left",
|
|
"inside-top-right",
|
|
"inside-bottom-right"
|
|
),
|
|
rotation: import_ag_charts_core165.number
|
|
}
|
|
};
|
|
var commonAxisLabelOptionsDefs = {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
rotation: import_ag_charts_core165.number,
|
|
avoidCollisions: import_ag_charts_core165.boolean,
|
|
minSpacing: import_ag_charts_core165.positiveNumber,
|
|
spacing: import_ag_charts_core165.positiveNumber,
|
|
formatter: (0, import_ag_charts_core165.callbackOf)(import_ag_charts_core165.textOrSegments),
|
|
itemStyler: (0, import_ag_charts_core165.callbackDefs)({
|
|
...import_ag_charts_core165.fontOptionsDef,
|
|
...import_ag_charts_core165.labelBoxOptionsDef,
|
|
spacing: import_ag_charts_core165.number
|
|
}),
|
|
...import_ag_charts_core165.fontOptionsDef,
|
|
...import_ag_charts_core165.labelBoxOptionsDef
|
|
};
|
|
var cartesianAxisLabelOptionsDefs = {
|
|
autoRotate: import_ag_charts_core165.boolean,
|
|
autoRotateAngle: import_ag_charts_core165.number,
|
|
wrapping: (0, import_ag_charts_core165.union)("never", "always", "hyphenate", "on-space"),
|
|
truncate: import_ag_charts_core165.boolean,
|
|
...commonAxisLabelOptionsDefs
|
|
};
|
|
var cartesianNumericAxisLabel = {
|
|
format: import_ag_charts_core165.numberFormatValidator,
|
|
...cartesianAxisLabelOptionsDefs
|
|
};
|
|
var cartesianTimeAxisLabel = {
|
|
format: (0, import_ag_charts_core165.or)(import_ag_charts_core165.string, import_ag_charts_core165.object),
|
|
...cartesianAxisLabelOptionsDefs
|
|
};
|
|
var cartesianAxisTick = {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
width: import_ag_charts_core165.positiveNumber,
|
|
size: import_ag_charts_core165.positiveNumber,
|
|
stroke: import_ag_charts_core165.color
|
|
};
|
|
var cartesianTimeAxisParentLevel = {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
label: cartesianTimeAxisLabel,
|
|
tick: cartesianAxisTick
|
|
};
|
|
var commonAxisIntervalOptionsDefs = {
|
|
values: (0, import_ag_charts_core165.arrayOf)(import_ag_charts_core165.defined),
|
|
minSpacing: import_ag_charts_core165.positiveNumber
|
|
};
|
|
var commonAxisOptionsDefs = {
|
|
reverse: import_ag_charts_core165.boolean,
|
|
gridLine: {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
width: import_ag_charts_core165.positiveNumber,
|
|
style: (0, import_ag_charts_core165.arrayOfDefs)(
|
|
{
|
|
fill: import_ag_charts_core165.color,
|
|
fillOpacity: import_ag_charts_core165.positiveNumber,
|
|
stroke: (0, import_ag_charts_core165.or)(import_ag_charts_core165.color, import_ag_charts_core165.themeOperator),
|
|
strokeWidth: import_ag_charts_core165.positiveNumber,
|
|
lineDash: (0, import_ag_charts_core165.arrayOf)(import_ag_charts_core165.positiveNumber)
|
|
},
|
|
"a grid-line style object array"
|
|
)
|
|
},
|
|
interval: commonAxisIntervalOptionsDefs,
|
|
label: commonAxisLabelOptionsDefs,
|
|
line: {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
width: import_ag_charts_core165.positiveNumber,
|
|
stroke: import_ag_charts_core165.color
|
|
},
|
|
tick: cartesianAxisTick,
|
|
context: () => true
|
|
};
|
|
commonAxisOptionsDefs.layoutConstraints = (0, import_ag_charts_core165.undocumented)({
|
|
stacked: (0, import_ag_charts_core165.required)(import_ag_charts_core165.boolean),
|
|
align: (0, import_ag_charts_core165.required)((0, import_ag_charts_core165.union)("start", "end")),
|
|
unit: (0, import_ag_charts_core165.required)((0, import_ag_charts_core165.union)("percent", "px")),
|
|
width: (0, import_ag_charts_core165.required)(import_ag_charts_core165.positiveNumber)
|
|
});
|
|
var cartesianAxisOptionsDefs = {
|
|
...commonAxisOptionsDefs,
|
|
crossAt: {
|
|
value: (0, import_ag_charts_core165.required)((0, import_ag_charts_core165.or)(import_ag_charts_core165.number, import_ag_charts_core165.date, import_ag_charts_core165.string, (0, import_ag_charts_core165.arrayOf)(import_ag_charts_core165.string))),
|
|
sticky: import_ag_charts_core165.boolean
|
|
},
|
|
crossLines: (0, import_ag_charts_core165.arrayOfDefs)(cartesianCrossLineOptionsDefs, "a cross-line options array"),
|
|
position: (0, import_ag_charts_core165.union)("top", "right", "bottom", "left"),
|
|
thickness: import_ag_charts_core165.positiveNumber,
|
|
maxThicknessRatio: import_ag_charts_core165.ratio,
|
|
title: {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
text: import_ag_charts_core165.textOrSegments,
|
|
spacing: import_ag_charts_core165.positiveNumber,
|
|
formatter: (0, import_ag_charts_core165.callbackOf)(import_ag_charts_core165.textOrSegments),
|
|
...import_ag_charts_core165.fontOptionsDef
|
|
}
|
|
};
|
|
cartesianAxisOptionsDefs.title._enabledFromTheme = (0, import_ag_charts_core165.undocumented)(import_ag_charts_core165.boolean);
|
|
var cartesianAxisBandHighlightOptions = {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
...import_ag_charts_core165.fillOptionsDef,
|
|
...import_ag_charts_core165.strokeOptionsDef,
|
|
...import_ag_charts_core165.lineDashOptionsDef
|
|
};
|
|
function cartesianAxisCrosshairOptions(canFormat, timeFormat) {
|
|
const baseCrosshairLabel = {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
xOffset: import_ag_charts_core165.number,
|
|
yOffset: import_ag_charts_core165.number,
|
|
formatter: (0, import_ag_charts_core165.callbackOf)(import_ag_charts_core165.string),
|
|
renderer: (0, import_ag_charts_core165.callbackOf)(
|
|
(0, import_ag_charts_core165.or)(
|
|
import_ag_charts_core165.string,
|
|
(0, import_ag_charts_core165.optionsDefs)(
|
|
{
|
|
text: import_ag_charts_core165.string,
|
|
color: import_ag_charts_core165.color,
|
|
backgroundColor: import_ag_charts_core165.color,
|
|
opacity: import_ag_charts_core165.ratio
|
|
},
|
|
"crosshair label renderer result object"
|
|
)
|
|
)
|
|
)
|
|
};
|
|
let crosshairLabel;
|
|
if (canFormat) {
|
|
crosshairLabel = {
|
|
...baseCrosshairLabel,
|
|
format: timeFormat ? (0, import_ag_charts_core165.or)(
|
|
import_ag_charts_core165.string,
|
|
(0, import_ag_charts_core165.optionsDefs)({
|
|
millisecond: import_ag_charts_core165.string,
|
|
second: import_ag_charts_core165.string,
|
|
hour: import_ag_charts_core165.string,
|
|
day: import_ag_charts_core165.string,
|
|
month: import_ag_charts_core165.string,
|
|
year: import_ag_charts_core165.string
|
|
})
|
|
) : import_ag_charts_core165.string
|
|
};
|
|
}
|
|
return {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
snap: import_ag_charts_core165.boolean,
|
|
label: crosshairLabel ?? baseCrosshairLabel,
|
|
...import_ag_charts_core165.strokeOptionsDef,
|
|
...import_ag_charts_core165.lineDashOptionsDef
|
|
};
|
|
}
|
|
function continuousAxisOptions(validDatum, supportTimeInterval) {
|
|
return {
|
|
min: (0, import_ag_charts_core165.and)(validDatum, (0, import_ag_charts_core165.lessThan)("max")),
|
|
max: (0, import_ag_charts_core165.and)(validDatum, (0, import_ag_charts_core165.greaterThan)("min")),
|
|
preferredMin: (0, import_ag_charts_core165.and)(validDatum, (0, import_ag_charts_core165.lessThan)("preferredMax"), (0, import_ag_charts_core165.lessThan)("max")),
|
|
preferredMax: (0, import_ag_charts_core165.and)(validDatum, (0, import_ag_charts_core165.greaterThan)("preferredMin"), (0, import_ag_charts_core165.greaterThan)("min")),
|
|
nice: import_ag_charts_core165.boolean,
|
|
interval: {
|
|
step: supportTimeInterval ? (0, import_ag_charts_core165.or)(import_ag_charts_core165.positiveNumberNonZero, timeIntervalUnit, timeInterval) : import_ag_charts_core165.positiveNumberNonZero,
|
|
values: (0, import_ag_charts_core165.arrayOf)(validDatum),
|
|
minSpacing: (0, import_ag_charts_core165.and)(import_ag_charts_core165.positiveNumber, (0, import_ag_charts_core165.lessThan)("maxSpacing")),
|
|
maxSpacing: (0, import_ag_charts_core165.and)(import_ag_charts_core165.positiveNumber, (0, import_ag_charts_core165.greaterThan)("minSpacing"))
|
|
}
|
|
};
|
|
}
|
|
var discreteTimeAxisIntervalOptionsDefs = {
|
|
step: (0, import_ag_charts_core165.or)(import_ag_charts_core165.positiveNumberNonZero, timeIntervalUnit, timeInterval),
|
|
values: (0, import_ag_charts_core165.arrayOf)((0, import_ag_charts_core165.or)(import_ag_charts_core165.number, import_ag_charts_core165.date)),
|
|
minSpacing: (0, import_ag_charts_core165.and)(import_ag_charts_core165.positiveNumber, (0, import_ag_charts_core165.lessThan)("maxSpacing")),
|
|
maxSpacing: (0, import_ag_charts_core165.and)(import_ag_charts_core165.positiveNumber, (0, import_ag_charts_core165.greaterThan)("minSpacing")),
|
|
placement: (0, import_ag_charts_core165.union)("on", "between")
|
|
};
|
|
var categoryAxisOptionsDefs = {
|
|
...cartesianAxisOptionsDefs,
|
|
type: (0, import_ag_charts_core165.constant)("category"),
|
|
label: cartesianAxisLabelOptionsDefs,
|
|
paddingInner: import_ag_charts_core165.ratio,
|
|
paddingOuter: import_ag_charts_core165.ratio,
|
|
groupPaddingInner: import_ag_charts_core165.ratio,
|
|
crosshair: cartesianAxisCrosshairOptions(),
|
|
bandAlignment: (0, import_ag_charts_core165.union)("justify", "start", "center", "end"),
|
|
bandHighlight: cartesianAxisBandHighlightOptions,
|
|
interval: {
|
|
...commonAxisIntervalOptionsDefs,
|
|
placement: (0, import_ag_charts_core165.union)("on", "between")
|
|
}
|
|
};
|
|
var groupedCategoryAxisOptionsDefs = {
|
|
...cartesianAxisOptionsDefs,
|
|
type: (0, import_ag_charts_core165.constant)("grouped-category"),
|
|
label: cartesianAxisLabelOptionsDefs,
|
|
crosshair: cartesianAxisCrosshairOptions(),
|
|
bandHighlight: cartesianAxisBandHighlightOptions,
|
|
paddingInner: import_ag_charts_core165.ratio,
|
|
groupPaddingInner: import_ag_charts_core165.ratio,
|
|
depthOptions: (0, import_ag_charts_core165.arrayOfDefs)(
|
|
{
|
|
label: {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
avoidCollisions: import_ag_charts_core165.boolean,
|
|
wrapping: (0, import_ag_charts_core165.union)("never", "always", "hyphenate", "on-space"),
|
|
truncate: import_ag_charts_core165.boolean,
|
|
rotation: import_ag_charts_core165.number,
|
|
spacing: import_ag_charts_core165.number,
|
|
...import_ag_charts_core165.fontOptionsDef,
|
|
...import_ag_charts_core165.labelBoxOptionsDef
|
|
},
|
|
tick: {
|
|
enabled: import_ag_charts_core165.boolean,
|
|
stroke: import_ag_charts_core165.color,
|
|
width: import_ag_charts_core165.positiveNumber
|
|
}
|
|
},
|
|
"depth options objects array"
|
|
)
|
|
};
|
|
var numberAxisOptionsDefs = {
|
|
...cartesianAxisOptionsDefs,
|
|
...continuousAxisOptions(import_ag_charts_core165.number),
|
|
type: (0, import_ag_charts_core165.constant)("number"),
|
|
label: cartesianNumericAxisLabel,
|
|
crosshair: cartesianAxisCrosshairOptions(true)
|
|
};
|
|
var logAxisOptionsDefs = {
|
|
...cartesianAxisOptionsDefs,
|
|
...continuousAxisOptions(import_ag_charts_core165.number),
|
|
type: (0, import_ag_charts_core165.constant)("log"),
|
|
base: (0, import_ag_charts_core165.and)(
|
|
import_ag_charts_core165.positiveNumberNonZero,
|
|
(0, import_ag_charts_core165.attachDescription)((value) => value !== 1, "not equal to 1")
|
|
),
|
|
label: cartesianNumericAxisLabel,
|
|
crosshair: cartesianAxisCrosshairOptions(true)
|
|
};
|
|
var timeAxisOptionsDefs = {
|
|
...cartesianAxisOptionsDefs,
|
|
...continuousAxisOptions((0, import_ag_charts_core165.or)(import_ag_charts_core165.number, import_ag_charts_core165.date), true),
|
|
type: (0, import_ag_charts_core165.constant)("time"),
|
|
label: cartesianTimeAxisLabel,
|
|
parentLevel: cartesianTimeAxisParentLevel,
|
|
crosshair: cartesianAxisCrosshairOptions(true, true)
|
|
};
|
|
var unitTimeAxisOptionsDefs = {
|
|
...cartesianAxisOptionsDefs,
|
|
type: (0, import_ag_charts_core165.constant)("unit-time"),
|
|
unit: (0, import_ag_charts_core165.or)(timeInterval, timeIntervalUnit),
|
|
label: cartesianTimeAxisLabel,
|
|
parentLevel: cartesianTimeAxisParentLevel,
|
|
paddingInner: import_ag_charts_core165.ratio,
|
|
paddingOuter: import_ag_charts_core165.ratio,
|
|
groupPaddingInner: import_ag_charts_core165.ratio,
|
|
crosshair: cartesianAxisCrosshairOptions(true, true),
|
|
bandAlignment: (0, import_ag_charts_core165.union)("justify", "start", "center", "end"),
|
|
bandHighlight: cartesianAxisBandHighlightOptions,
|
|
min: (0, import_ag_charts_core165.and)((0, import_ag_charts_core165.or)(import_ag_charts_core165.number, import_ag_charts_core165.date), (0, import_ag_charts_core165.lessThan)("max")),
|
|
max: (0, import_ag_charts_core165.and)((0, import_ag_charts_core165.or)(import_ag_charts_core165.number, import_ag_charts_core165.date), (0, import_ag_charts_core165.greaterThan)("min")),
|
|
preferredMin: (0, import_ag_charts_core165.and)((0, import_ag_charts_core165.or)(import_ag_charts_core165.number, import_ag_charts_core165.date), (0, import_ag_charts_core165.lessThan)("preferredMax"), (0, import_ag_charts_core165.lessThan)("max")),
|
|
preferredMax: (0, import_ag_charts_core165.and)((0, import_ag_charts_core165.or)(import_ag_charts_core165.number, import_ag_charts_core165.date), (0, import_ag_charts_core165.greaterThan)("preferredMin"), (0, import_ag_charts_core165.greaterThan)("min")),
|
|
interval: discreteTimeAxisIntervalOptionsDefs
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/axesOptionsEnterpriseDefs.ts
|
|
var import_ag_charts_core166 = require("ag-charts-core");
|
|
var ordinalTimeAxisOptionsDefs = {
|
|
...cartesianAxisOptionsDefs,
|
|
type: (0, import_ag_charts_core166.constant)("ordinal-time"),
|
|
paddingInner: import_ag_charts_core166.ratio,
|
|
paddingOuter: import_ag_charts_core166.ratio,
|
|
groupPaddingInner: import_ag_charts_core166.ratio,
|
|
label: cartesianTimeAxisLabel,
|
|
parentLevel: cartesianTimeAxisParentLevel,
|
|
interval: discreteTimeAxisIntervalOptionsDefs,
|
|
crosshair: cartesianAxisCrosshairOptions(true, true),
|
|
bandHighlight: cartesianAxisBandHighlightOptions,
|
|
bandAlignment: (0, import_ag_charts_core166.union)("justify", "start", "center", "end")
|
|
};
|
|
var angleNumberAxisOptionsDefs = {
|
|
...commonAxisOptionsDefs,
|
|
...continuousAxisOptions(import_ag_charts_core166.number),
|
|
type: (0, import_ag_charts_core166.constant)("angle-number"),
|
|
crossLines: (0, import_ag_charts_core166.arrayOfDefs)(commonCrossLineOptionsDefs),
|
|
startAngle: import_ag_charts_core166.number,
|
|
endAngle: import_ag_charts_core166.number,
|
|
label: {
|
|
...commonAxisLabelOptionsDefs,
|
|
orientation: (0, import_ag_charts_core166.union)("fixed", "parallel", "perpendicular"),
|
|
format: import_ag_charts_core166.numberFormatValidator
|
|
}
|
|
};
|
|
var angleCategoryAxisOptionsDefs = {
|
|
...commonAxisOptionsDefs,
|
|
type: (0, import_ag_charts_core166.constant)("angle-category"),
|
|
shape: (0, import_ag_charts_core166.union)("polygon", "circle"),
|
|
crossLines: (0, import_ag_charts_core166.arrayOfDefs)(commonCrossLineOptionsDefs),
|
|
startAngle: import_ag_charts_core166.number,
|
|
endAngle: import_ag_charts_core166.number,
|
|
paddingInner: import_ag_charts_core166.ratio,
|
|
groupPaddingInner: import_ag_charts_core166.ratio,
|
|
label: {
|
|
...commonAxisLabelOptionsDefs,
|
|
orientation: (0, import_ag_charts_core166.union)("fixed", "parallel", "perpendicular")
|
|
}
|
|
};
|
|
angleCategoryAxisOptionsDefs.innerRadiusRatio = import_ag_charts_core166.ratio;
|
|
var radiusNumberAxisOptionsDefs = {
|
|
...commonAxisOptionsDefs,
|
|
...continuousAxisOptions(import_ag_charts_core166.number),
|
|
type: (0, import_ag_charts_core166.constant)("radius-number"),
|
|
shape: (0, import_ag_charts_core166.union)("polygon", "circle"),
|
|
positionAngle: import_ag_charts_core166.number,
|
|
innerRadiusRatio: import_ag_charts_core166.ratio,
|
|
crossLines: (0, import_ag_charts_core166.arrayOfDefs)(
|
|
{
|
|
...commonCrossLineOptionsDefs,
|
|
label: {
|
|
...commonCrossLineLabelOptionsDefs,
|
|
positionAngle: import_ag_charts_core166.number
|
|
}
|
|
},
|
|
"cross-line options"
|
|
),
|
|
title: {
|
|
enabled: import_ag_charts_core166.boolean,
|
|
text: import_ag_charts_core166.textOrSegments,
|
|
spacing: import_ag_charts_core166.positiveNumber,
|
|
formatter: (0, import_ag_charts_core166.callbackOf)(import_ag_charts_core166.textOrSegments),
|
|
...import_ag_charts_core166.fontOptionsDef
|
|
},
|
|
label: {
|
|
...commonAxisLabelOptionsDefs,
|
|
format: import_ag_charts_core166.numberFormatValidator
|
|
}
|
|
};
|
|
var radiusCategoryAxisOptionsDefs = {
|
|
...commonAxisOptionsDefs,
|
|
type: (0, import_ag_charts_core166.constant)("radius-category"),
|
|
positionAngle: import_ag_charts_core166.number,
|
|
innerRadiusRatio: import_ag_charts_core166.ratio,
|
|
paddingInner: import_ag_charts_core166.ratio,
|
|
paddingOuter: import_ag_charts_core166.ratio,
|
|
groupPaddingInner: import_ag_charts_core166.ratio,
|
|
label: commonAxisLabelOptionsDefs,
|
|
crossLines: (0, import_ag_charts_core166.arrayOfDefs)(
|
|
{
|
|
...commonCrossLineOptionsDefs,
|
|
label: {
|
|
...commonCrossLineLabelOptionsDefs,
|
|
positionAngle: import_ag_charts_core166.number
|
|
}
|
|
},
|
|
"cross-line options"
|
|
),
|
|
title: {
|
|
enabled: import_ag_charts_core166.boolean,
|
|
text: import_ag_charts_core166.textOrSegments,
|
|
spacing: import_ag_charts_core166.positiveNumber,
|
|
formatter: (0, import_ag_charts_core166.callbackOf)(import_ag_charts_core166.textOrSegments),
|
|
...import_ag_charts_core166.fontOptionsDef
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/areaSeriesOptionsDef.ts
|
|
var import_ag_charts_core167 = require("ag-charts-core");
|
|
var highlight = (0, import_ag_charts_core167.multiSeriesHighlightOptionsDef)(import_ag_charts_core167.shapeHighlightOptionsDef, import_ag_charts_core167.shapeHighlightOptionsDef);
|
|
var areaStyler = (0, import_ag_charts_core167.callbackDefs)({
|
|
...import_ag_charts_core167.strokeOptionsDef,
|
|
...import_ag_charts_core167.fillOptionsDef,
|
|
...import_ag_charts_core167.lineDashOptionsDef,
|
|
marker: import_ag_charts_core167.markerStyleOptionsDefs
|
|
});
|
|
var areaSeriesThemeableOptionsDef = {
|
|
showInMiniChart: import_ag_charts_core167.boolean,
|
|
connectMissingData: import_ag_charts_core167.boolean,
|
|
interpolation: import_ag_charts_core167.interpolationOptionsDefs,
|
|
label: import_ag_charts_core167.seriesLabelOptionsDefs,
|
|
styler: areaStyler,
|
|
marker: import_ag_charts_core167.markerOptionsDefs,
|
|
tooltip: import_ag_charts_core167.tooltipOptionsDefsWithArea,
|
|
shadow: import_ag_charts_core167.shadowOptionsDefs,
|
|
...import_ag_charts_core167.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core167.fillOptionsDef,
|
|
...import_ag_charts_core167.strokeOptionsDef,
|
|
...import_ag_charts_core167.lineDashOptionsDef,
|
|
highlight,
|
|
segmentation: import_ag_charts_core167.shapeSegmentation
|
|
};
|
|
var areaSeriesOptionsDef = {
|
|
...areaSeriesThemeableOptionsDef,
|
|
...import_ag_charts_core167.commonSeriesOptionsDefs,
|
|
highlight,
|
|
type: (0, import_ag_charts_core167.required)((0, import_ag_charts_core167.constant)("area")),
|
|
xKey: (0, import_ag_charts_core167.required)(import_ag_charts_core167.string),
|
|
yKey: (0, import_ag_charts_core167.required)(import_ag_charts_core167.string),
|
|
xKeyAxis: import_ag_charts_core167.string,
|
|
yKeyAxis: import_ag_charts_core167.string,
|
|
xName: import_ag_charts_core167.string,
|
|
yName: import_ag_charts_core167.string,
|
|
legendItemName: import_ag_charts_core167.string,
|
|
stacked: import_ag_charts_core167.boolean,
|
|
stackGroup: import_ag_charts_core167.string,
|
|
normalizedTo: import_ag_charts_core167.number
|
|
};
|
|
areaSeriesOptionsDef.yFilterKey = (0, import_ag_charts_core167.undocumented)(import_ag_charts_core167.string);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/barSeriesOptionsDef.ts
|
|
var import_ag_charts_core168 = require("ag-charts-core");
|
|
var highlight2 = (0, import_ag_charts_core168.multiSeriesHighlightOptionsDef)(import_ag_charts_core168.barHighlightOptionsDef, import_ag_charts_core168.barHighlightOptionsDef);
|
|
var barStyler = (0, import_ag_charts_core168.callbackDefs)({
|
|
...import_ag_charts_core168.fillOptionsDef,
|
|
...import_ag_charts_core168.strokeOptionsDef,
|
|
...import_ag_charts_core168.lineDashOptionsDef,
|
|
cornerRadius: import_ag_charts_core168.positiveNumber
|
|
});
|
|
var barSeriesThemeableOptionsDef = {
|
|
direction: (0, import_ag_charts_core168.union)("horizontal", "vertical"),
|
|
showInMiniChart: import_ag_charts_core168.boolean,
|
|
cornerRadius: import_ag_charts_core168.positiveNumber,
|
|
styler: barStyler,
|
|
itemStyler: barStyler,
|
|
crisp: import_ag_charts_core168.boolean,
|
|
label: {
|
|
...import_ag_charts_core168.seriesLabelOptionsDefs,
|
|
placement: (0, import_ag_charts_core168.union)("inside-center", "inside-start", "inside-end", "outside-start", "outside-end"),
|
|
spacing: import_ag_charts_core168.positiveNumber
|
|
},
|
|
errorBar: import_ag_charts_core168.errorBarThemeableOptionsDefs,
|
|
shadow: import_ag_charts_core168.shadowOptionsDefs,
|
|
tooltip: import_ag_charts_core168.tooltipOptionsDefs,
|
|
...import_ag_charts_core168.commonSeriesThemeableOptionsDefs,
|
|
highlight: highlight2,
|
|
...import_ag_charts_core168.fillOptionsDef,
|
|
...import_ag_charts_core168.strokeOptionsDef,
|
|
...import_ag_charts_core168.lineDashOptionsDef,
|
|
segmentation: import_ag_charts_core168.shapeSegmentation,
|
|
width: import_ag_charts_core168.positiveNumberNonZero,
|
|
widthRatio: import_ag_charts_core168.ratio
|
|
};
|
|
barSeriesThemeableOptionsDef.sparklineMode = (0, import_ag_charts_core168.undocumented)(import_ag_charts_core168.boolean);
|
|
var barSeriesOptionsDef = {
|
|
...barSeriesThemeableOptionsDef,
|
|
...import_ag_charts_core168.commonSeriesOptionsDefs,
|
|
highlight: highlight2,
|
|
type: (0, import_ag_charts_core168.required)((0, import_ag_charts_core168.constant)("bar")),
|
|
xKey: (0, import_ag_charts_core168.required)(import_ag_charts_core168.string),
|
|
yKey: (0, import_ag_charts_core168.required)(import_ag_charts_core168.string),
|
|
xKeyAxis: import_ag_charts_core168.string,
|
|
yKeyAxis: import_ag_charts_core168.string,
|
|
xName: import_ag_charts_core168.string,
|
|
yName: import_ag_charts_core168.string,
|
|
direction: (0, import_ag_charts_core168.union)("horizontal", "vertical"),
|
|
grouped: import_ag_charts_core168.boolean,
|
|
stacked: import_ag_charts_core168.boolean,
|
|
stackGroup: import_ag_charts_core168.string,
|
|
normalizedTo: import_ag_charts_core168.number,
|
|
legendItemName: import_ag_charts_core168.string,
|
|
errorBar: import_ag_charts_core168.errorBarOptionsDefs
|
|
};
|
|
barSeriesOptionsDef.yFilterKey = (0, import_ag_charts_core168.undocumented)(import_ag_charts_core168.string);
|
|
barSeriesOptionsDef.pickOutsideVisibleMinorAxis = (0, import_ag_charts_core168.undocumented)(import_ag_charts_core168.boolean);
|
|
barSeriesOptionsDef.focusPriority = (0, import_ag_charts_core168.undocumented)(import_ag_charts_core168.number);
|
|
barSeriesOptionsDef.simpleItemStyler = (0, import_ag_charts_core168.undocumented)(import_ag_charts_core168.callback);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/bubbleSeriesOptionsDef.ts
|
|
var import_ag_charts_core169 = require("ag-charts-core");
|
|
var bubbleSeriesThemeableOptionsDef = {
|
|
title: import_ag_charts_core169.string,
|
|
domain: (0, import_ag_charts_core169.arrayOf)(import_ag_charts_core169.number),
|
|
maxSize: import_ag_charts_core169.positiveNumber,
|
|
showInMiniChart: import_ag_charts_core169.boolean,
|
|
label: {
|
|
placement: (0, import_ag_charts_core169.union)("top", "right", "bottom", "left"),
|
|
...import_ag_charts_core169.seriesLabelOptionsDefs
|
|
},
|
|
tooltip: import_ag_charts_core169.tooltipOptionsDefs,
|
|
styler: (0, import_ag_charts_core169.callbackDefs)({
|
|
...import_ag_charts_core169.markerOptionsDefs,
|
|
maxSize: import_ag_charts_core169.positiveNumber
|
|
}),
|
|
maxRenderedItems: import_ag_charts_core169.number,
|
|
...import_ag_charts_core169.commonSeriesThemeableOptionsDefs,
|
|
...(0, import_ag_charts_core169.without)(import_ag_charts_core169.markerOptionsDefs, ["enabled"]),
|
|
highlight: (0, import_ag_charts_core169.multiSeriesHighlightOptionsDef)(import_ag_charts_core169.shapeHighlightOptionsDef, import_ag_charts_core169.shapeHighlightOptionsDef)
|
|
};
|
|
var bubbleSeriesOptionsDef = {
|
|
...bubbleSeriesThemeableOptionsDef,
|
|
...import_ag_charts_core169.commonSeriesOptionsDefs,
|
|
type: (0, import_ag_charts_core169.required)((0, import_ag_charts_core169.constant)("bubble")),
|
|
xKey: (0, import_ag_charts_core169.required)(import_ag_charts_core169.string),
|
|
yKey: (0, import_ag_charts_core169.required)(import_ag_charts_core169.string),
|
|
sizeKey: (0, import_ag_charts_core169.required)(import_ag_charts_core169.string),
|
|
labelKey: import_ag_charts_core169.string,
|
|
xName: import_ag_charts_core169.string,
|
|
yName: import_ag_charts_core169.string,
|
|
sizeName: import_ag_charts_core169.string,
|
|
labelName: import_ag_charts_core169.string,
|
|
legendItemName: import_ag_charts_core169.string,
|
|
xKeyAxis: import_ag_charts_core169.string,
|
|
yKeyAxis: import_ag_charts_core169.string,
|
|
highlight: (0, import_ag_charts_core169.multiSeriesHighlightOptionsDef)(import_ag_charts_core169.shapeHighlightOptionsDef, import_ag_charts_core169.shapeHighlightOptionsDef)
|
|
};
|
|
bubbleSeriesOptionsDef.xFilterKey = (0, import_ag_charts_core169.undocumented)(import_ag_charts_core169.string);
|
|
bubbleSeriesOptionsDef.yFilterKey = (0, import_ag_charts_core169.undocumented)(import_ag_charts_core169.string);
|
|
bubbleSeriesOptionsDef.sizeFilterKey = (0, import_ag_charts_core169.undocumented)(import_ag_charts_core169.string);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/histogramSeriesOptionsDef.ts
|
|
var import_ag_charts_core170 = require("ag-charts-core");
|
|
var histogramSeriesThemeableOptionsDef = {
|
|
showInMiniChart: import_ag_charts_core170.boolean,
|
|
cornerRadius: import_ag_charts_core170.positiveNumber,
|
|
label: import_ag_charts_core170.seriesLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core170.tooltipOptionsDefs,
|
|
shadow: import_ag_charts_core170.shadowOptionsDefs,
|
|
...import_ag_charts_core170.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core170.fillOptionsDef,
|
|
...import_ag_charts_core170.strokeOptionsDef,
|
|
...import_ag_charts_core170.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core170.multiSeriesHighlightOptionsDef)(import_ag_charts_core170.shapeHighlightOptionsDef, import_ag_charts_core170.shapeHighlightOptionsDef),
|
|
areaPlot: import_ag_charts_core170.boolean,
|
|
aggregation: (0, import_ag_charts_core170.union)("count", "sum", "mean"),
|
|
bins: (0, import_ag_charts_core170.arrayOf)((0, import_ag_charts_core170.arrayOf)(import_ag_charts_core170.number)),
|
|
binCount: import_ag_charts_core170.positiveNumber
|
|
};
|
|
var histogramSeriesOptionsDef = {
|
|
...import_ag_charts_core170.commonSeriesOptionsDefs,
|
|
...histogramSeriesThemeableOptionsDef,
|
|
type: (0, import_ag_charts_core170.required)((0, import_ag_charts_core170.constant)("histogram")),
|
|
xKey: (0, import_ag_charts_core170.required)(import_ag_charts_core170.string),
|
|
yKey: import_ag_charts_core170.string,
|
|
xKeyAxis: import_ag_charts_core170.string,
|
|
yKeyAxis: import_ag_charts_core170.string,
|
|
xName: import_ag_charts_core170.string,
|
|
yName: import_ag_charts_core170.string
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineSeriesOptionsDef.ts
|
|
var import_ag_charts_core171 = require("ag-charts-core");
|
|
var highlight3 = (0, import_ag_charts_core171.multiSeriesHighlightOptionsDef)(import_ag_charts_core171.shapeHighlightOptionsDef, import_ag_charts_core171.lineHighlightOptionsDef);
|
|
var lineStyler = (0, import_ag_charts_core171.callbackDefs)({
|
|
...import_ag_charts_core171.strokeOptionsDef,
|
|
...import_ag_charts_core171.lineDashOptionsDef,
|
|
marker: import_ag_charts_core171.markerStyleOptionsDefs
|
|
});
|
|
var lineSeriesThemeableOptionsDef = {
|
|
title: import_ag_charts_core171.string,
|
|
showInMiniChart: import_ag_charts_core171.boolean,
|
|
connectMissingData: import_ag_charts_core171.boolean,
|
|
interpolation: import_ag_charts_core171.interpolationOptionsDefs,
|
|
label: import_ag_charts_core171.seriesLabelOptionsDefs,
|
|
styler: lineStyler,
|
|
marker: import_ag_charts_core171.markerOptionsDefs,
|
|
tooltip: import_ag_charts_core171.tooltipOptionsDefs,
|
|
errorBar: import_ag_charts_core171.errorBarThemeableOptionsDefs,
|
|
...import_ag_charts_core171.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core171.strokeOptionsDef,
|
|
...import_ag_charts_core171.lineDashOptionsDef,
|
|
highlight: highlight3,
|
|
segmentation: import_ag_charts_core171.lineSegmentation
|
|
};
|
|
lineSeriesThemeableOptionsDef.sparklineMode = (0, import_ag_charts_core171.undocumented)(import_ag_charts_core171.boolean);
|
|
var lineSeriesOptionsDef = {
|
|
...lineSeriesThemeableOptionsDef,
|
|
...import_ag_charts_core171.commonSeriesOptionsDefs,
|
|
highlight: highlight3,
|
|
type: (0, import_ag_charts_core171.required)((0, import_ag_charts_core171.constant)("line")),
|
|
xKey: (0, import_ag_charts_core171.required)(import_ag_charts_core171.string),
|
|
yKey: (0, import_ag_charts_core171.required)(import_ag_charts_core171.string),
|
|
xKeyAxis: import_ag_charts_core171.string,
|
|
yKeyAxis: import_ag_charts_core171.string,
|
|
xName: import_ag_charts_core171.string,
|
|
yName: import_ag_charts_core171.string,
|
|
stacked: import_ag_charts_core171.boolean,
|
|
stackGroup: import_ag_charts_core171.string,
|
|
normalizedTo: import_ag_charts_core171.number,
|
|
legendItemName: import_ag_charts_core171.string,
|
|
errorBar: import_ag_charts_core171.errorBarOptionsDefs
|
|
};
|
|
lineSeriesOptionsDef.yFilterKey = (0, import_ag_charts_core171.undocumented)(import_ag_charts_core171.string);
|
|
lineSeriesOptionsDef.pickOutsideVisibleMinorAxis = (0, import_ag_charts_core171.undocumented)(import_ag_charts_core171.boolean);
|
|
lineSeriesOptionsDef.focusPriority = (0, import_ag_charts_core171.undocumented)(import_ag_charts_core171.number);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/scatterSeriesOptionsDef.ts
|
|
var import_ag_charts_core172 = require("ag-charts-core");
|
|
var scatterSeriesThemeableOptionsDef = {
|
|
title: import_ag_charts_core172.string,
|
|
showInMiniChart: import_ag_charts_core172.boolean,
|
|
label: {
|
|
placement: (0, import_ag_charts_core172.union)("top", "right", "bottom", "left"),
|
|
...import_ag_charts_core172.seriesLabelOptionsDefs
|
|
},
|
|
tooltip: import_ag_charts_core172.tooltipOptionsDefs,
|
|
errorBar: import_ag_charts_core172.errorBarThemeableOptionsDefs,
|
|
styler: (0, import_ag_charts_core172.callbackDefs)(import_ag_charts_core172.markerOptionsDefs),
|
|
maxRenderedItems: import_ag_charts_core172.number,
|
|
...import_ag_charts_core172.commonSeriesThemeableOptionsDefs,
|
|
...(0, import_ag_charts_core172.without)(import_ag_charts_core172.markerOptionsDefs, ["enabled"]),
|
|
highlight: (0, import_ag_charts_core172.multiSeriesHighlightOptionsDef)(import_ag_charts_core172.shapeHighlightOptionsDef, import_ag_charts_core172.shapeHighlightOptionsDef)
|
|
};
|
|
var scatterSeriesOptionsDef = {
|
|
...scatterSeriesThemeableOptionsDef,
|
|
...import_ag_charts_core172.commonSeriesOptionsDefs,
|
|
type: (0, import_ag_charts_core172.required)((0, import_ag_charts_core172.constant)("scatter")),
|
|
xKey: (0, import_ag_charts_core172.required)(import_ag_charts_core172.string),
|
|
yKey: (0, import_ag_charts_core172.required)(import_ag_charts_core172.string),
|
|
labelKey: import_ag_charts_core172.string,
|
|
xName: import_ag_charts_core172.string,
|
|
yName: import_ag_charts_core172.string,
|
|
labelName: import_ag_charts_core172.string,
|
|
legendItemName: import_ag_charts_core172.string,
|
|
xKeyAxis: import_ag_charts_core172.string,
|
|
yKeyAxis: import_ag_charts_core172.string,
|
|
errorBar: import_ag_charts_core172.errorBarOptionsDefs,
|
|
highlight: (0, import_ag_charts_core172.multiSeriesHighlightOptionsDef)(import_ag_charts_core172.shapeHighlightOptionsDef, import_ag_charts_core172.shapeHighlightOptionsDef)
|
|
};
|
|
scatterSeriesOptionsDef.xFilterKey = (0, import_ag_charts_core172.undocumented)(import_ag_charts_core172.string);
|
|
scatterSeriesOptionsDef.yFilterKey = (0, import_ag_charts_core172.undocumented)(import_ag_charts_core172.string);
|
|
scatterSeriesOptionsDef.sizeFilterKey = (0, import_ag_charts_core172.undocumented)(import_ag_charts_core172.string);
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/donutSeriesOptionsDef.ts
|
|
var import_ag_charts_core174 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/pieSeriesOptionsDef.ts
|
|
var import_ag_charts_core173 = require("ag-charts-core");
|
|
var highlight4 = (0, import_ag_charts_core173.multiSeriesHighlightOptionsDef)(import_ag_charts_core173.shapeHighlightOptionsDef, import_ag_charts_core173.shapeHighlightOptionsDef);
|
|
var pieSeriesThemeableOptionsDef = {
|
|
...import_ag_charts_core173.commonSeriesThemeableOptionsDefs,
|
|
radiusMin: import_ag_charts_core173.positiveNumber,
|
|
radiusMax: import_ag_charts_core173.positiveNumber,
|
|
rotation: import_ag_charts_core173.number,
|
|
outerRadiusOffset: import_ag_charts_core173.number,
|
|
outerRadiusRatio: import_ag_charts_core173.ratio,
|
|
hideZeroValueSectorsInLegend: import_ag_charts_core173.boolean,
|
|
sectorSpacing: import_ag_charts_core173.positiveNumber,
|
|
cornerRadius: import_ag_charts_core173.positiveNumber,
|
|
itemStyler: (0, import_ag_charts_core173.callbackDefs)({
|
|
...import_ag_charts_core173.fillOptionsDef,
|
|
...import_ag_charts_core173.strokeOptionsDef,
|
|
...import_ag_charts_core173.lineDashOptionsDef,
|
|
cornerRadius: import_ag_charts_core173.positiveNumber
|
|
}),
|
|
title: {
|
|
enabled: import_ag_charts_core173.boolean,
|
|
text: import_ag_charts_core173.string,
|
|
showInLegend: import_ag_charts_core173.boolean,
|
|
spacing: import_ag_charts_core173.positiveNumber,
|
|
...import_ag_charts_core173.fontOptionsDef
|
|
},
|
|
calloutLabel: {
|
|
enabled: import_ag_charts_core173.boolean,
|
|
offset: import_ag_charts_core173.number,
|
|
minAngle: import_ag_charts_core173.positiveNumber,
|
|
avoidCollisions: import_ag_charts_core173.boolean,
|
|
formatter: (0, import_ag_charts_core173.callbackOf)(import_ag_charts_core173.textOrSegments),
|
|
format: import_ag_charts_core173.string,
|
|
itemStyler: (0, import_ag_charts_core173.callbackDefs)({
|
|
enabled: import_ag_charts_core173.boolean,
|
|
...import_ag_charts_core173.labelBoxOptionsDef,
|
|
...import_ag_charts_core173.fontOptionsDef
|
|
}),
|
|
...import_ag_charts_core173.labelBoxOptionsDef,
|
|
...import_ag_charts_core173.fontOptionsDef
|
|
},
|
|
sectorLabel: {
|
|
enabled: import_ag_charts_core173.boolean,
|
|
positionOffset: import_ag_charts_core173.number,
|
|
positionRatio: import_ag_charts_core173.ratio,
|
|
formatter: (0, import_ag_charts_core173.callbackOf)(import_ag_charts_core173.textOrSegments),
|
|
format: import_ag_charts_core173.string,
|
|
itemStyler: (0, import_ag_charts_core173.callbackDefs)({
|
|
enabled: import_ag_charts_core173.boolean,
|
|
...import_ag_charts_core173.labelBoxOptionsDef,
|
|
...import_ag_charts_core173.fontOptionsDef
|
|
}),
|
|
...import_ag_charts_core173.labelBoxOptionsDef,
|
|
...import_ag_charts_core173.fontOptionsDef
|
|
},
|
|
calloutLine: {
|
|
colors: (0, import_ag_charts_core173.arrayOf)(import_ag_charts_core173.color),
|
|
length: import_ag_charts_core173.positiveNumber,
|
|
strokeWidth: import_ag_charts_core173.positiveNumber,
|
|
itemStyler: (0, import_ag_charts_core173.callbackDefs)({
|
|
color: import_ag_charts_core173.color,
|
|
length: import_ag_charts_core173.positiveNumber,
|
|
strokeWidth: import_ag_charts_core173.positiveNumber
|
|
})
|
|
},
|
|
fills: (0, import_ag_charts_core173.arrayOf)(import_ag_charts_core173.colorUnion),
|
|
strokes: (0, import_ag_charts_core173.arrayOf)(import_ag_charts_core173.color),
|
|
tooltip: import_ag_charts_core173.tooltipOptionsDefs,
|
|
shadow: import_ag_charts_core173.shadowOptionsDefs,
|
|
highlight: highlight4,
|
|
...import_ag_charts_core173.lineDashOptionsDef,
|
|
...(0, import_ag_charts_core173.without)(import_ag_charts_core173.fillOptionsDef, ["fill"]),
|
|
...(0, import_ag_charts_core173.without)(import_ag_charts_core173.strokeOptionsDef, ["stroke"])
|
|
};
|
|
var pieSeriesOptionsDef = {
|
|
...pieSeriesThemeableOptionsDef,
|
|
...import_ag_charts_core173.commonSeriesOptionsDefs,
|
|
type: (0, import_ag_charts_core173.required)((0, import_ag_charts_core173.constant)("pie")),
|
|
angleKey: (0, import_ag_charts_core173.required)(import_ag_charts_core173.string),
|
|
radiusKey: import_ag_charts_core173.string,
|
|
calloutLabelKey: import_ag_charts_core173.string,
|
|
sectorLabelKey: import_ag_charts_core173.string,
|
|
legendItemKey: import_ag_charts_core173.string,
|
|
angleName: import_ag_charts_core173.string,
|
|
radiusName: import_ag_charts_core173.string,
|
|
calloutLabelName: import_ag_charts_core173.string,
|
|
sectorLabelName: import_ag_charts_core173.string,
|
|
highlight: highlight4
|
|
};
|
|
pieSeriesOptionsDef.angleFilterKey = (0, import_ag_charts_core173.undocumented)(import_ag_charts_core173.string);
|
|
pieSeriesOptionsDef.defaultColorRange = (0, import_ag_charts_core173.undocumented)((0, import_ag_charts_core173.arrayOf)((0, import_ag_charts_core173.arrayOf)(import_ag_charts_core173.color)));
|
|
pieSeriesOptionsDef.defaultPatternFills = (0, import_ag_charts_core173.undocumented)((0, import_ag_charts_core173.arrayOf)(import_ag_charts_core173.color));
|
|
pieSeriesOptionsDef.title._enabledFromTheme = (0, import_ag_charts_core173.undocumented)(import_ag_charts_core173.boolean);
|
|
pieSeriesOptionsDef.calloutLabel._enabledFromTheme = (0, import_ag_charts_core173.undocumented)(import_ag_charts_core173.boolean);
|
|
pieSeriesOptionsDef.sectorLabel._enabledFromTheme = (0, import_ag_charts_core173.undocumented)(import_ag_charts_core173.boolean);
|
|
pieSeriesOptionsDef.angleKeyAxis = (0, import_ag_charts_core173.undocumented)(import_ag_charts_core173.string);
|
|
pieSeriesOptionsDef.radiusKeyAxis = (0, import_ag_charts_core173.undocumented)(import_ag_charts_core173.string);
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/donutSeriesOptionsDef.ts
|
|
var donutSeriesThemeableOptionsDef = {
|
|
...pieSeriesThemeableOptionsDef,
|
|
innerRadiusOffset: import_ag_charts_core174.number,
|
|
innerRadiusRatio: import_ag_charts_core174.ratio,
|
|
innerCircle: {
|
|
fill: import_ag_charts_core174.string,
|
|
fillOpacity: import_ag_charts_core174.ratio
|
|
},
|
|
innerLabels: {
|
|
spacing: import_ag_charts_core174.positiveNumber,
|
|
...import_ag_charts_core174.fontOptionsDef,
|
|
...import_ag_charts_core174.labelBoxOptionsDef
|
|
}
|
|
};
|
|
var donutSeriesOptionsDef = {
|
|
...donutSeriesThemeableOptionsDef,
|
|
...pieSeriesOptionsDef,
|
|
type: (0, import_ag_charts_core174.required)((0, import_ag_charts_core174.constant)("donut")),
|
|
innerLabels: (0, import_ag_charts_core174.arrayOfDefs)(
|
|
{
|
|
text: (0, import_ag_charts_core174.required)(import_ag_charts_core174.string),
|
|
spacing: import_ag_charts_core174.positiveNumber,
|
|
...import_ag_charts_core174.fontOptionsDef,
|
|
...import_ag_charts_core174.labelBoxOptionsDef
|
|
},
|
|
"inner label options array"
|
|
)
|
|
};
|
|
donutSeriesOptionsDef.angleFilterKey = (0, import_ag_charts_core174.undocumented)(import_ag_charts_core174.string);
|
|
|
|
// packages/ag-charts-community/src/chart/themes/annotationOptionsDef.ts
|
|
var import_ag_charts_core175 = require("ag-charts-core");
|
|
var annotationLineOptionsDef = {
|
|
lineStyle: (0, import_ag_charts_core175.union)("solid", "dashed", "dotted"),
|
|
...import_ag_charts_core175.lineDashOptionsDef
|
|
};
|
|
var annotationHandleStylesDefs = {
|
|
...import_ag_charts_core175.fillOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef,
|
|
...import_ag_charts_core175.lineDashOptionsDef
|
|
};
|
|
var annotationTextStylesDef = {
|
|
visible: import_ag_charts_core175.boolean,
|
|
locked: import_ag_charts_core175.boolean,
|
|
readOnly: import_ag_charts_core175.boolean,
|
|
handle: annotationHandleStylesDefs,
|
|
...import_ag_charts_core175.fontOptionsDef
|
|
};
|
|
var annotationLineTextDefs = {
|
|
position: (0, import_ag_charts_core175.union)("top", "center", "bottom"),
|
|
alignment: (0, import_ag_charts_core175.union)("left", "center", "right"),
|
|
...import_ag_charts_core175.fontOptionsDef
|
|
};
|
|
var annotationChannelTextDefs = {
|
|
position: (0, import_ag_charts_core175.union)("top", "inside", "bottom"),
|
|
alignment: (0, import_ag_charts_core175.union)("left", "center", "right"),
|
|
...import_ag_charts_core175.fontOptionsDef
|
|
};
|
|
var annotationAxisLabelOptionsDef = {
|
|
enabled: import_ag_charts_core175.boolean,
|
|
cornerRadius: import_ag_charts_core175.positiveNumber,
|
|
...import_ag_charts_core175.fontOptionsDef,
|
|
...import_ag_charts_core175.fillOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef,
|
|
...import_ag_charts_core175.lineDashOptionsDef
|
|
};
|
|
var annotationChannelMiddleDefs = {
|
|
visible: import_ag_charts_core175.boolean,
|
|
...annotationLineOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef
|
|
};
|
|
var annotationMeasurerStatisticsOptionsDefs = {
|
|
divider: import_ag_charts_core175.strokeOptionsDef,
|
|
...import_ag_charts_core175.fillOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef,
|
|
...import_ag_charts_core175.fontOptionsDef
|
|
};
|
|
var annotationQuickMeasurerDirectionStylesDefs = {
|
|
handle: annotationHandleStylesDefs,
|
|
statistics: annotationMeasurerStatisticsOptionsDefs,
|
|
...annotationLineOptionsDef,
|
|
...import_ag_charts_core175.fillOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef
|
|
};
|
|
var annotationLineStyleDefs = {
|
|
visible: import_ag_charts_core175.boolean,
|
|
locked: import_ag_charts_core175.boolean,
|
|
readOnly: import_ag_charts_core175.boolean,
|
|
extendStart: import_ag_charts_core175.boolean,
|
|
extendEnd: import_ag_charts_core175.boolean,
|
|
handle: annotationHandleStylesDefs,
|
|
text: annotationLineTextDefs,
|
|
...annotationLineOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef
|
|
};
|
|
var annotationCrossLineStyleDefs = {
|
|
visible: import_ag_charts_core175.boolean,
|
|
locked: import_ag_charts_core175.boolean,
|
|
readOnly: import_ag_charts_core175.boolean,
|
|
axisLabel: annotationAxisLabelOptionsDef,
|
|
handle: annotationHandleStylesDefs,
|
|
text: annotationLineTextDefs,
|
|
...annotationLineOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef
|
|
};
|
|
var annotationChannelStyleDefs = {
|
|
visible: import_ag_charts_core175.boolean,
|
|
locked: import_ag_charts_core175.boolean,
|
|
readOnly: import_ag_charts_core175.boolean,
|
|
extendStart: import_ag_charts_core175.boolean,
|
|
extendEnd: import_ag_charts_core175.boolean,
|
|
handle: annotationHandleStylesDefs,
|
|
text: annotationChannelTextDefs,
|
|
background: import_ag_charts_core175.fillOptionsDef,
|
|
...annotationLineOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef
|
|
};
|
|
var annotationDisjointChannelStyleDefs = {
|
|
...annotationChannelStyleDefs
|
|
};
|
|
var annotationParallelChannelStyleDefs = {
|
|
...annotationChannelStyleDefs,
|
|
middle: annotationChannelMiddleDefs
|
|
};
|
|
var annotationFibonacciStylesDefs = {
|
|
label: import_ag_charts_core175.fontOptionsDef,
|
|
showFill: import_ag_charts_core175.boolean,
|
|
isMultiColor: import_ag_charts_core175.boolean,
|
|
strokes: (0, import_ag_charts_core175.arrayOf)(import_ag_charts_core175.color),
|
|
rangeStroke: import_ag_charts_core175.color,
|
|
bands: (0, import_ag_charts_core175.union)(4, 6, 10),
|
|
...annotationLineStyleDefs
|
|
};
|
|
var annotationCalloutStylesDefs = {
|
|
...import_ag_charts_core175.fillOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef,
|
|
...annotationTextStylesDef
|
|
};
|
|
var annotationCommentStylesDefs = {
|
|
...import_ag_charts_core175.fillOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef,
|
|
...annotationTextStylesDef
|
|
};
|
|
var annotationNoteStylesDefs = {
|
|
...import_ag_charts_core175.fillOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef,
|
|
...annotationTextStylesDef,
|
|
background: {
|
|
...import_ag_charts_core175.fillOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef
|
|
}
|
|
};
|
|
var annotationShapeStylesDefs = {
|
|
visible: import_ag_charts_core175.boolean,
|
|
locked: import_ag_charts_core175.boolean,
|
|
readOnly: import_ag_charts_core175.boolean,
|
|
handle: annotationHandleStylesDefs,
|
|
...import_ag_charts_core175.fillOptionsDef
|
|
};
|
|
var annotationMeasurerStylesDefs = {
|
|
visible: import_ag_charts_core175.boolean,
|
|
locked: import_ag_charts_core175.boolean,
|
|
readOnly: import_ag_charts_core175.boolean,
|
|
extendStart: import_ag_charts_core175.boolean,
|
|
extendEnd: import_ag_charts_core175.boolean,
|
|
handle: annotationHandleStylesDefs,
|
|
text: annotationLineTextDefs,
|
|
background: import_ag_charts_core175.fillOptionsDef,
|
|
statistics: annotationMeasurerStatisticsOptionsDefs,
|
|
...annotationLineOptionsDef,
|
|
...import_ag_charts_core175.strokeOptionsDef
|
|
};
|
|
var annotationQuickMeasurerStylesDefs = {
|
|
visible: import_ag_charts_core175.boolean,
|
|
up: annotationQuickMeasurerDirectionStylesDefs,
|
|
down: annotationQuickMeasurerDirectionStylesDefs
|
|
};
|
|
var annotationOptionsDef = {
|
|
enabled: import_ag_charts_core175.boolean,
|
|
axesButtons: {
|
|
enabled: import_ag_charts_core175.boolean,
|
|
axes: (0, import_ag_charts_core175.union)("x", "y", "xy")
|
|
},
|
|
toolbar: {
|
|
enabled: import_ag_charts_core175.boolean,
|
|
padding: import_ag_charts_core175.positiveNumber,
|
|
buttons: (0, import_ag_charts_core175.arrayOfDefs)(
|
|
{
|
|
...import_ag_charts_core175.toolbarButtonOptionsDefs,
|
|
value: (0, import_ag_charts_core175.union)(
|
|
"line-menu",
|
|
"fibonacci-menu",
|
|
"text-menu",
|
|
"shape-menu",
|
|
"measurer-menu",
|
|
"line",
|
|
"horizontal-line",
|
|
"vertical-line",
|
|
"parallel-channel",
|
|
"disjoint-channel",
|
|
"fibonacci-retracement",
|
|
"fibonacci-retracement-trend-based",
|
|
"text",
|
|
"comment",
|
|
"callout",
|
|
"note",
|
|
"clear"
|
|
)
|
|
},
|
|
"annotation toolbar buttons array"
|
|
)
|
|
},
|
|
optionsToolbar: {
|
|
enabled: import_ag_charts_core175.boolean,
|
|
buttons: (0, import_ag_charts_core175.arrayOf)(
|
|
(0, import_ag_charts_core175.or)(
|
|
(0, import_ag_charts_core175.optionsDefs)({
|
|
...import_ag_charts_core175.toolbarButtonOptionsDefs,
|
|
value: (0, import_ag_charts_core175.required)(
|
|
(0, import_ag_charts_core175.union)(
|
|
"line-stroke-width",
|
|
"line-style-type",
|
|
"line-color",
|
|
"fill-color",
|
|
"text-color",
|
|
"text-size",
|
|
"delete",
|
|
"settings"
|
|
)
|
|
)
|
|
}),
|
|
(0, import_ag_charts_core175.optionsDefs)({
|
|
...import_ag_charts_core175.toolbarButtonOptionsDefs,
|
|
value: (0, import_ag_charts_core175.required)((0, import_ag_charts_core175.union)("lock")),
|
|
checkedOverrides: import_ag_charts_core175.toolbarButtonOptionsDefs
|
|
})
|
|
)
|
|
)
|
|
}
|
|
};
|
|
annotationOptionsDef.data = (0, import_ag_charts_core175.undocumented)(import_ag_charts_core175.array);
|
|
annotationOptionsDef.xKey = (0, import_ag_charts_core175.undocumented)(import_ag_charts_core175.string);
|
|
annotationOptionsDef.volumeKey = (0, import_ag_charts_core175.undocumented)(import_ag_charts_core175.string);
|
|
annotationOptionsDef.snap = (0, import_ag_charts_core175.undocumented)(import_ag_charts_core175.boolean);
|
|
|
|
// packages/ag-charts-community/src/chart/themes/enterpriseThemeableOptionsDef.ts
|
|
var import_ag_charts_core176 = require("ag-charts-core");
|
|
var hierarchyHighlightStyleOptionsDef = {
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
opacity: import_ag_charts_core176.ratio
|
|
};
|
|
var boxPlotStyleOptionsDef = {
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
whisker: {
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
cap: {
|
|
lengthRatio: import_ag_charts_core176.ratio
|
|
}
|
|
};
|
|
var boxPlotHighlightStyleOptionsDef = {
|
|
...boxPlotStyleOptionsDef,
|
|
opacity: import_ag_charts_core176.ratio
|
|
};
|
|
var boxPlotStyler = (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
whisker: {
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
cap: {
|
|
lengthRatio: import_ag_charts_core176.ratio
|
|
}
|
|
});
|
|
var boxPlotSeriesThemeableOptionsDef = {
|
|
direction: (0, import_ag_charts_core176.union)("horizontal", "vertical"),
|
|
showInMiniChart: import_ag_charts_core176.boolean,
|
|
styler: boxPlotStyler,
|
|
itemStyler: boxPlotStyler,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...boxPlotStyleOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(boxPlotHighlightStyleOptionsDef, boxPlotHighlightStyleOptionsDef),
|
|
segmentation: import_ag_charts_core176.shapeSegmentation,
|
|
width: import_ag_charts_core176.positiveNumberNonZero,
|
|
widthRatio: import_ag_charts_core176.ratio
|
|
};
|
|
var candlestickSeriesItemOptionsDef = {
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
wick: {
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
};
|
|
var candlestickHighlightStyleOptionsDef = {
|
|
...candlestickSeriesItemOptionsDef,
|
|
opacity: import_ag_charts_core176.ratio
|
|
};
|
|
var candlestickSeriesThemeableOptionsDef = {
|
|
item: {
|
|
up: candlestickSeriesItemOptionsDef,
|
|
down: candlestickSeriesItemOptionsDef
|
|
},
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
wick: {
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}
|
|
}),
|
|
showInMiniChart: import_ag_charts_core176.boolean,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(candlestickHighlightStyleOptionsDef, candlestickHighlightStyleOptionsDef)
|
|
};
|
|
var chordSeriesThemeableOptionsDef = {
|
|
fills: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.colorUnion),
|
|
strokes: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
label: {
|
|
spacing: import_ag_charts_core176.positiveNumber,
|
|
maxWidth: import_ag_charts_core176.positiveNumber,
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs
|
|
},
|
|
link: {
|
|
tension: import_ag_charts_core176.ratio,
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
tension: import_ag_charts_core176.ratio
|
|
}),
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
node: {
|
|
width: import_ag_charts_core176.positiveNumber,
|
|
spacing: import_ag_charts_core176.positiveNumber,
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs
|
|
};
|
|
var coneFunnelSeriesThemeableOptionsDef = {
|
|
direction: (0, import_ag_charts_core176.union)("horizontal", "vertical"),
|
|
fills: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.colorUnion),
|
|
strokes: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
label: {
|
|
spacing: import_ag_charts_core176.positiveNumber,
|
|
placement: (0, import_ag_charts_core176.union)("before", "middle", "after"),
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs
|
|
},
|
|
stageLabel: {
|
|
placement: (0, import_ag_charts_core176.union)("before", "after"),
|
|
format: import_ag_charts_core176.numberFormatValidator,
|
|
...commonAxisLabelOptionsDefs
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.commonSeriesThemeableOptionsDefs, ["showInLegend"]),
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.fillOptionsDef, ["fill"]),
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.strokeOptionsDef, ["stroke"]),
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.highlightOptionsDef)(import_ag_charts_core176.lineHighlightOptionsDef)
|
|
};
|
|
var funnelSeriesThemeableOptionsDef = {
|
|
direction: (0, import_ag_charts_core176.union)("horizontal", "vertical"),
|
|
fills: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.colorUnion),
|
|
strokes: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
spacingRatio: import_ag_charts_core176.ratio,
|
|
crisp: import_ag_charts_core176.boolean,
|
|
dropOff: {
|
|
enabled: import_ag_charts_core176.boolean,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
stageLabel: {
|
|
placement: (0, import_ag_charts_core176.union)("before", "after"),
|
|
format: import_ag_charts_core176.numberFormatValidator,
|
|
...commonAxisLabelOptionsDefs
|
|
},
|
|
label: import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
shadow: import_ag_charts_core176.shadowOptionsDefs,
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.commonSeriesThemeableOptionsDefs, ["showInLegend"]),
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.fillOptionsDef, ["fill"]),
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.strokeOptionsDef, ["stroke"]),
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
};
|
|
var heatmapSeriesThemeableOptionsDef = {
|
|
title: import_ag_charts_core176.string,
|
|
textAlign: (0, import_ag_charts_core176.union)("left", "center", "right"),
|
|
verticalAlign: (0, import_ag_charts_core176.union)("top", "middle", "bottom"),
|
|
itemPadding: import_ag_charts_core176.positiveNumber,
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef
|
|
}),
|
|
showInMiniChart: import_ag_charts_core176.boolean,
|
|
label: import_ag_charts_core176.autoSizedLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.strokeOptionsDef
|
|
};
|
|
var ohlcSeriesThemeableOptionsDef = {
|
|
showInMiniChart: import_ag_charts_core176.boolean,
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
item: {
|
|
up: {
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
down: {
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.lineHighlightOptionsDef, import_ag_charts_core176.lineHighlightOptionsDef)
|
|
};
|
|
var mapLineSeriesThemeableOptionsDef = {
|
|
maxStrokeWidth: import_ag_charts_core176.positiveNumber,
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
sizeDomain: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.positiveNumber),
|
|
label: import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.lineHighlightOptionsDef, import_ag_charts_core176.lineHighlightOptionsDef)
|
|
};
|
|
var mapLineBackgroundSeriesThemeableOptionsDef = {
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
};
|
|
var mapMarkerSeriesThemeableOptionsDef = {
|
|
colorRange: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
maxSize: import_ag_charts_core176.positiveNumber,
|
|
sizeDomain: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.positiveNumber),
|
|
label: {
|
|
placement: (0, import_ag_charts_core176.union)("top", "bottom", "left", "right"),
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.markerOptionsDefs, ["enabled"]),
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.shapeHighlightOptionsDef, import_ag_charts_core176.shapeHighlightOptionsDef)
|
|
};
|
|
var mapShapeSeriesThemeableOptionsDef = {
|
|
colorRange: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
padding: import_ag_charts_core176.positiveNumber,
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
label: import_ag_charts_core176.autoSizedLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.shapeHighlightOptionsDef, import_ag_charts_core176.shapeHighlightOptionsDef)
|
|
};
|
|
var mapShapeBackgroundSeriesThemeableOptionsDef = {
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
};
|
|
var radialSeriesStylerDef = (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber
|
|
});
|
|
var nightingaleSeriesThemeableOptionsDef = {
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
styler: radialSeriesStylerDef,
|
|
itemStyler: radialSeriesStylerDef,
|
|
label: import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.barHighlightOptionsDef, import_ag_charts_core176.barHighlightOptionsDef)
|
|
};
|
|
var pyramidSeriesThemeableOptionsDef = {
|
|
direction: (0, import_ag_charts_core176.union)("horizontal", "vertical"),
|
|
aspectRatio: import_ag_charts_core176.positiveNumber,
|
|
spacing: import_ag_charts_core176.positiveNumber,
|
|
reverse: import_ag_charts_core176.boolean,
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
fills: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.colorUnion),
|
|
strokes: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
label: import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
stageLabel: {
|
|
spacing: import_ag_charts_core176.positiveNumber,
|
|
placement: (0, import_ag_charts_core176.union)("before", "after"),
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
shadow: import_ag_charts_core176.shadowOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.fillOptionsDef, ["fill"]),
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.strokeOptionsDef, ["stroke"]),
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
};
|
|
var radarAreaSeriesThemeableOptionsDef = {
|
|
connectMissingData: import_ag_charts_core176.boolean,
|
|
marker: import_ag_charts_core176.markerOptionsDefs,
|
|
styler: (0, import_ag_charts_core176.callbackDefs)({
|
|
marker: import_ag_charts_core176.markerStyleOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
label: import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.shapeHighlightOptionsDef, import_ag_charts_core176.shapeHighlightOptionsDef)
|
|
};
|
|
var radarLineSeriesThemeableOptionsDef = {
|
|
connectMissingData: import_ag_charts_core176.boolean,
|
|
marker: import_ag_charts_core176.markerOptionsDefs,
|
|
styler: (0, import_ag_charts_core176.callbackDefs)({
|
|
marker: import_ag_charts_core176.markerStyleOptionsDefs,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
label: import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.shapeHighlightOptionsDef, import_ag_charts_core176.lineHighlightOptionsDef)
|
|
};
|
|
var radialBarSeriesThemeableOptionsDef = {
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
styler: radialSeriesStylerDef,
|
|
itemStyler: radialSeriesStylerDef,
|
|
label: import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.barHighlightOptionsDef, import_ag_charts_core176.barHighlightOptionsDef)
|
|
};
|
|
var radialColumnSeriesThemeableOptionsDef = {
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
columnWidthRatio: import_ag_charts_core176.ratio,
|
|
maxColumnWidthRatio: import_ag_charts_core176.ratio,
|
|
styler: radialSeriesStylerDef,
|
|
itemStyler: radialSeriesStylerDef,
|
|
label: import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.barHighlightOptionsDef, import_ag_charts_core176.barHighlightOptionsDef)
|
|
};
|
|
var rangeAreaSeriesLineThemeableOptionsDef = {
|
|
marker: import_ag_charts_core176.markerOptionsDefs,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
};
|
|
var rangeAreaSeriesItemLineThemeableOptionsDef = {
|
|
marker: {
|
|
enabled: import_ag_charts_core176.boolean,
|
|
...import_ag_charts_core176.markerStyleOptionsDefs
|
|
},
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
};
|
|
var rangeAreaSeriesLineStyleDef = {
|
|
marker: import_ag_charts_core176.markerStyleOptionsDefs,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
};
|
|
var rangeAreaSeriesThemeableOptionsDef = {
|
|
showInMiniChart: import_ag_charts_core176.boolean,
|
|
connectMissingData: import_ag_charts_core176.boolean,
|
|
interpolation: import_ag_charts_core176.interpolationOptionsDefs,
|
|
label: {
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
placement: (0, import_ag_charts_core176.union)("inside", "outside"),
|
|
spacing: import_ag_charts_core176.positiveNumber
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
shadow: import_ag_charts_core176.shadowOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...rangeAreaSeriesLineThemeableOptionsDef,
|
|
item: {
|
|
low: { ...rangeAreaSeriesItemLineThemeableOptionsDef },
|
|
high: { ...rangeAreaSeriesItemLineThemeableOptionsDef }
|
|
},
|
|
styler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
item: {
|
|
low: { ...rangeAreaSeriesLineStyleDef },
|
|
high: { ...rangeAreaSeriesLineStyleDef }
|
|
}
|
|
}),
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.shapeHighlightOptionsDef, import_ag_charts_core176.shapeHighlightOptionsDef),
|
|
segmentation: import_ag_charts_core176.shapeSegmentation,
|
|
invertedStyle: {
|
|
enabled: import_ag_charts_core176.boolean,
|
|
...import_ag_charts_core176.fillOptionsDef
|
|
}
|
|
};
|
|
var rangeBarStyleCallback = (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber
|
|
});
|
|
var rangeBarSeriesThemeableOptionsDef = {
|
|
direction: (0, import_ag_charts_core176.union)("horizontal", "vertical"),
|
|
grouped: import_ag_charts_core176.boolean,
|
|
showInMiniChart: import_ag_charts_core176.boolean,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
styler: rangeBarStyleCallback,
|
|
itemStyler: rangeBarStyleCallback,
|
|
label: {
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
placement: (0, import_ag_charts_core176.union)("inside", "outside"),
|
|
spacing: import_ag_charts_core176.positiveNumber
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
shadow: import_ag_charts_core176.shadowOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
highlight: (0, import_ag_charts_core176.multiSeriesHighlightOptionsDef)(import_ag_charts_core176.barHighlightOptionsDef, import_ag_charts_core176.barHighlightOptionsDef),
|
|
segmentation: import_ag_charts_core176.shapeSegmentation,
|
|
width: import_ag_charts_core176.positiveNumberNonZero,
|
|
widthRatio: import_ag_charts_core176.ratio
|
|
};
|
|
var sankeySeriesThemeableOptionsDef = {
|
|
fills: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.colorUnion),
|
|
strokes: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
label: {
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
spacing: import_ag_charts_core176.positiveNumber,
|
|
placement: (0, import_ag_charts_core176.union)("left", "right", "center"),
|
|
edgePlacement: (0, import_ag_charts_core176.union)("inside", "outside")
|
|
},
|
|
link: {
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
node: {
|
|
width: import_ag_charts_core176.positiveNumber,
|
|
spacing: import_ag_charts_core176.positiveNumber,
|
|
minSpacing: (0, import_ag_charts_core176.and)(import_ag_charts_core176.positiveNumber, (0, import_ag_charts_core176.lessThanOrEqual)("spacing")),
|
|
alignment: (0, import_ag_charts_core176.union)("left", "center", "right", "justify"),
|
|
verticalAlignment: (0, import_ag_charts_core176.union)("top", "bottom", "center"),
|
|
sort: (0, import_ag_charts_core176.union)("data", "ascending", "descending", "auto"),
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
}),
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs
|
|
};
|
|
var sunburstSeriesThemeableOptionsDef = {
|
|
fills: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.colorUnion),
|
|
strokes: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
colorRange: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
sectorSpacing: import_ag_charts_core176.positiveNumber,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
padding: import_ag_charts_core176.positiveNumber,
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef
|
|
}),
|
|
label: {
|
|
spacing: import_ag_charts_core176.positiveNumber,
|
|
...import_ag_charts_core176.autoSizedLabelOptionsDefs
|
|
},
|
|
secondaryLabel: import_ag_charts_core176.autoSizedLabelOptionsDefs,
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.commonSeriesThemeableOptionsDefs, ["highlight", "showInLegend"]),
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.fillOptionsDef, ["fill"]),
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.strokeOptionsDef, ["stroke"]),
|
|
highlight: {
|
|
highlightedItem: hierarchyHighlightStyleOptionsDef,
|
|
highlightedBranch: hierarchyHighlightStyleOptionsDef,
|
|
unhighlightedItem: hierarchyHighlightStyleOptionsDef,
|
|
unhighlightedBranch: hierarchyHighlightStyleOptionsDef
|
|
}
|
|
};
|
|
var treemapSeriesThemeableOptionsDef = {
|
|
fills: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.colorUnion),
|
|
strokes: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
colorRange: (0, import_ag_charts_core176.arrayOf)(import_ag_charts_core176.color),
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef
|
|
}),
|
|
group: {
|
|
gap: import_ag_charts_core176.positiveNumber,
|
|
padding: import_ag_charts_core176.positiveNumber,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
textAlign: (0, import_ag_charts_core176.union)("left", "center", "right"),
|
|
interactive: import_ag_charts_core176.boolean,
|
|
highlight: {
|
|
highlightedItem: hierarchyHighlightStyleOptionsDef,
|
|
unhighlightedItem: hierarchyHighlightStyleOptionsDef
|
|
},
|
|
label: {
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
spacing: import_ag_charts_core176.positiveNumber
|
|
},
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef
|
|
},
|
|
tile: {
|
|
gap: import_ag_charts_core176.positiveNumber,
|
|
padding: import_ag_charts_core176.positiveNumber,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
textAlign: (0, import_ag_charts_core176.union)("left", "center", "right"),
|
|
verticalAlign: (0, import_ag_charts_core176.union)("top", "middle", "bottom"),
|
|
label: {
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
spacing: import_ag_charts_core176.positiveNumber,
|
|
lineHeight: import_ag_charts_core176.positiveNumber,
|
|
minimumFontSize: import_ag_charts_core176.positiveNumber,
|
|
wrapping: (0, import_ag_charts_core176.union)("never", "always", "hyphenate", "on-space"),
|
|
overflowStrategy: (0, import_ag_charts_core176.union)("ellipsis", "hide")
|
|
},
|
|
secondaryLabel: {
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
lineHeight: import_ag_charts_core176.positiveNumber,
|
|
minimumFontSize: import_ag_charts_core176.positiveNumber,
|
|
wrapping: (0, import_ag_charts_core176.union)("never", "always", "hyphenate", "on-space"),
|
|
overflowStrategy: (0, import_ag_charts_core176.union)("ellipsis", "hide")
|
|
},
|
|
highlight: {
|
|
highlightedItem: hierarchyHighlightStyleOptionsDef,
|
|
highlightedBranch: hierarchyHighlightStyleOptionsDef,
|
|
unhighlightedItem: hierarchyHighlightStyleOptionsDef,
|
|
unhighlightedBranch: hierarchyHighlightStyleOptionsDef
|
|
},
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
...(0, import_ag_charts_core176.without)(import_ag_charts_core176.commonSeriesThemeableOptionsDefs, ["highlight", "showInLegend"])
|
|
};
|
|
var waterfallSeriesItemOptionsDef = {
|
|
name: import_ag_charts_core176.string,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber,
|
|
itemStyler: (0, import_ag_charts_core176.callbackDefs)({
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef,
|
|
cornerRadius: import_ag_charts_core176.positiveNumber
|
|
}),
|
|
label: {
|
|
...import_ag_charts_core176.seriesLabelOptionsDefs,
|
|
placement: (0, import_ag_charts_core176.union)("inside-start", "inside-center", "inside-end", "outside-start", "outside-end"),
|
|
spacing: import_ag_charts_core176.positiveNumber
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
shadow: import_ag_charts_core176.shadowOptionsDefs,
|
|
...import_ag_charts_core176.fillOptionsDef,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
};
|
|
var waterfallSeriesThemeableOptionsDef = {
|
|
direction: (0, import_ag_charts_core176.union)("horizontal", "vertical"),
|
|
showInMiniChart: import_ag_charts_core176.boolean,
|
|
item: {
|
|
positive: waterfallSeriesItemOptionsDef,
|
|
negative: waterfallSeriesItemOptionsDef,
|
|
total: waterfallSeriesItemOptionsDef
|
|
},
|
|
line: {
|
|
enabled: import_ag_charts_core176.boolean,
|
|
...import_ag_charts_core176.strokeOptionsDef,
|
|
...import_ag_charts_core176.lineDashOptionsDef
|
|
},
|
|
tooltip: import_ag_charts_core176.tooltipOptionsDefs,
|
|
width: import_ag_charts_core176.positiveNumberNonZero,
|
|
widthRatio: import_ag_charts_core176.ratio,
|
|
...import_ag_charts_core176.commonSeriesThemeableOptionsDefs
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/themeOptionsDef.ts
|
|
var serializableDate = (0, import_ag_charts_core177.optionsDefs)(
|
|
{
|
|
__type: (0, import_ag_charts_core177.required)((0, import_ag_charts_core177.constant)("date")),
|
|
value: (0, import_ag_charts_core177.or)(import_ag_charts_core177.string, import_ag_charts_core177.number)
|
|
},
|
|
"a serializable date object"
|
|
);
|
|
var navigatorHandleOptionsDef = {
|
|
width: import_ag_charts_core177.positiveNumber,
|
|
height: import_ag_charts_core177.positiveNumber,
|
|
grip: import_ag_charts_core177.boolean,
|
|
fill: import_ag_charts_core177.color,
|
|
stroke: import_ag_charts_core177.color,
|
|
strokeWidth: import_ag_charts_core177.positiveNumber,
|
|
cornerRadius: import_ag_charts_core177.positiveNumber
|
|
};
|
|
var navigatorOptionsDef = {
|
|
enabled: import_ag_charts_core177.boolean,
|
|
height: import_ag_charts_core177.positiveNumber,
|
|
spacing: import_ag_charts_core177.positiveNumber,
|
|
cornerRadius: import_ag_charts_core177.number,
|
|
mask: {
|
|
fill: import_ag_charts_core177.color,
|
|
fillOpacity: import_ag_charts_core177.ratio,
|
|
stroke: import_ag_charts_core177.color,
|
|
strokeWidth: import_ag_charts_core177.positiveNumber
|
|
},
|
|
minHandle: navigatorHandleOptionsDef,
|
|
maxHandle: navigatorHandleOptionsDef,
|
|
miniChart: {
|
|
enabled: import_ag_charts_core177.boolean,
|
|
padding: {
|
|
top: import_ag_charts_core177.positiveNumber,
|
|
bottom: import_ag_charts_core177.positiveNumber
|
|
},
|
|
label: {
|
|
enabled: import_ag_charts_core177.boolean,
|
|
avoidCollisions: import_ag_charts_core177.boolean,
|
|
spacing: import_ag_charts_core177.positiveNumber,
|
|
format: import_ag_charts_core177.numberFormatValidator,
|
|
formatter: (0, import_ag_charts_core177.callbackOf)(import_ag_charts_core177.textOrSegments),
|
|
interval: {
|
|
minSpacing: import_ag_charts_core177.positiveNumber,
|
|
maxSpacing: import_ag_charts_core177.positiveNumber,
|
|
values: import_ag_charts_core177.array,
|
|
step: import_ag_charts_core177.number
|
|
},
|
|
...import_ag_charts_core177.fontOptionsDef
|
|
},
|
|
series: import_ag_charts_core177.defined
|
|
}
|
|
};
|
|
var scrollbarTrackOptionsDef = {
|
|
...import_ag_charts_core177.fillOptionsDef,
|
|
...import_ag_charts_core177.strokeOptionsDef,
|
|
...import_ag_charts_core177.lineDashOptionsDef,
|
|
cornerRadius: import_ag_charts_core177.positiveNumber,
|
|
opacity: import_ag_charts_core177.ratio
|
|
};
|
|
var scrollbarThumbOptionsDef = {
|
|
...scrollbarTrackOptionsDef,
|
|
minSize: import_ag_charts_core177.positiveNumber,
|
|
hoverStyle: {
|
|
fill: import_ag_charts_core177.fillOptionsDef.fill,
|
|
stroke: import_ag_charts_core177.strokeOptionsDef.stroke
|
|
}
|
|
};
|
|
var scrollbarBaseOptionsDef = {
|
|
enabled: import_ag_charts_core177.boolean,
|
|
thickness: import_ag_charts_core177.positiveNumber,
|
|
spacing: import_ag_charts_core177.positiveNumber,
|
|
tickSpacing: import_ag_charts_core177.positiveNumber,
|
|
visible: (0, import_ag_charts_core177.union)("auto", "always", "never"),
|
|
placement: (0, import_ag_charts_core177.union)("outer", "inner"),
|
|
track: scrollbarTrackOptionsDef,
|
|
thumb: scrollbarThumbOptionsDef
|
|
};
|
|
var scrollbarHorizontalOrientationOptionsDef = {
|
|
...scrollbarBaseOptionsDef,
|
|
position: (0, import_ag_charts_core177.union)("top", "bottom")
|
|
};
|
|
var scrollbarVerticalOrientationOptionsDef = {
|
|
...scrollbarBaseOptionsDef,
|
|
position: (0, import_ag_charts_core177.union)("left", "right")
|
|
};
|
|
var scrollbarOptionsDef = {
|
|
enabled: import_ag_charts_core177.boolean,
|
|
thickness: import_ag_charts_core177.positiveNumber,
|
|
spacing: import_ag_charts_core177.positiveNumber,
|
|
tickSpacing: import_ag_charts_core177.positiveNumber,
|
|
visible: (0, import_ag_charts_core177.union)("auto", "always", "never"),
|
|
placement: (0, import_ag_charts_core177.union)("outer", "inner"),
|
|
track: scrollbarTrackOptionsDef,
|
|
thumb: scrollbarThumbOptionsDef,
|
|
horizontal: scrollbarHorizontalOrientationOptionsDef,
|
|
vertical: scrollbarVerticalOrientationOptionsDef
|
|
};
|
|
var cartesianCrossLineThemeableOptionsDefs = (0, import_ag_charts_core177.without)(cartesianCrossLineOptionsDefs, ["type", "value", "range"]);
|
|
var cartesianAxesThemeDef = {
|
|
number: {
|
|
...(0, import_ag_charts_core177.without)(numberAxisOptionsDefs, ["type", "crossLines"]),
|
|
top: (0, import_ag_charts_core177.without)(numberAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
right: (0, import_ag_charts_core177.without)(numberAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
bottom: (0, import_ag_charts_core177.without)(numberAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
left: (0, import_ag_charts_core177.without)(numberAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
crossLines: cartesianCrossLineThemeableOptionsDefs
|
|
},
|
|
log: {
|
|
...(0, import_ag_charts_core177.without)(logAxisOptionsDefs, ["type", "crossLines"]),
|
|
top: (0, import_ag_charts_core177.without)(logAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
right: (0, import_ag_charts_core177.without)(logAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
bottom: (0, import_ag_charts_core177.without)(logAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
left: (0, import_ag_charts_core177.without)(logAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
crossLines: cartesianCrossLineThemeableOptionsDefs
|
|
},
|
|
category: {
|
|
...(0, import_ag_charts_core177.without)(categoryAxisOptionsDefs, ["type", "crossLines"]),
|
|
top: (0, import_ag_charts_core177.without)(categoryAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
right: (0, import_ag_charts_core177.without)(categoryAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
bottom: (0, import_ag_charts_core177.without)(categoryAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
left: (0, import_ag_charts_core177.without)(categoryAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
crossLines: cartesianCrossLineThemeableOptionsDefs
|
|
},
|
|
time: {
|
|
...(0, import_ag_charts_core177.without)(timeAxisOptionsDefs, ["type", "crossLines"]),
|
|
top: (0, import_ag_charts_core177.without)(timeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
right: (0, import_ag_charts_core177.without)(timeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
bottom: (0, import_ag_charts_core177.without)(timeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
left: (0, import_ag_charts_core177.without)(timeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
crossLines: cartesianCrossLineThemeableOptionsDefs
|
|
},
|
|
"unit-time": {
|
|
...(0, import_ag_charts_core177.without)(unitTimeAxisOptionsDefs, ["type", "crossLines"]),
|
|
top: (0, import_ag_charts_core177.without)(unitTimeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
right: (0, import_ag_charts_core177.without)(unitTimeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
bottom: (0, import_ag_charts_core177.without)(unitTimeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
left: (0, import_ag_charts_core177.without)(unitTimeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
crossLines: cartesianCrossLineThemeableOptionsDefs
|
|
},
|
|
"grouped-category": {
|
|
...(0, import_ag_charts_core177.without)(groupedCategoryAxisOptionsDefs, ["type"]),
|
|
top: (0, import_ag_charts_core177.without)(groupedCategoryAxisOptionsDefs, ["type", "position"]),
|
|
right: (0, import_ag_charts_core177.without)(groupedCategoryAxisOptionsDefs, ["type", "position"]),
|
|
bottom: (0, import_ag_charts_core177.without)(groupedCategoryAxisOptionsDefs, ["type", "position"]),
|
|
left: (0, import_ag_charts_core177.without)(groupedCategoryAxisOptionsDefs, ["type", "position"]),
|
|
crossLines: cartesianCrossLineThemeableOptionsDefs
|
|
},
|
|
"ordinal-time": {
|
|
...(0, import_ag_charts_core177.without)(ordinalTimeAxisOptionsDefs, ["type", "crossLines"]),
|
|
top: (0, import_ag_charts_core177.without)(ordinalTimeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
right: (0, import_ag_charts_core177.without)(ordinalTimeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
bottom: (0, import_ag_charts_core177.without)(ordinalTimeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
left: (0, import_ag_charts_core177.without)(ordinalTimeAxisOptionsDefs, ["type", "crossLines", "position"]),
|
|
crossLines: cartesianCrossLineThemeableOptionsDefs
|
|
}
|
|
};
|
|
var polarAxesThemeDef = {
|
|
"angle-category": {
|
|
...(0, import_ag_charts_core177.without)(angleCategoryAxisOptionsDefs, ["type", "crossLines"]),
|
|
crossLines: (0, import_ag_charts_core177.without)(commonCrossLineOptionsDefs, ["type"])
|
|
},
|
|
"angle-number": {
|
|
...(0, import_ag_charts_core177.without)(angleNumberAxisOptionsDefs, ["type", "crossLines"]),
|
|
crossLines: (0, import_ag_charts_core177.without)(commonCrossLineOptionsDefs, ["type"])
|
|
},
|
|
"radius-category": {
|
|
...(0, import_ag_charts_core177.without)(radiusCategoryAxisOptionsDefs, ["type", "crossLines"]),
|
|
crossLines: {
|
|
...(0, import_ag_charts_core177.without)(commonCrossLineOptionsDefs, ["type"]),
|
|
label: {
|
|
...commonCrossLineLabelOptionsDefs,
|
|
positionAngle: import_ag_charts_core177.number
|
|
}
|
|
}
|
|
},
|
|
"radius-number": {
|
|
...(0, import_ag_charts_core177.without)(radiusNumberAxisOptionsDefs, ["type", "crossLines"]),
|
|
crossLines: {
|
|
...(0, import_ag_charts_core177.without)(commonCrossLineOptionsDefs, ["type"]),
|
|
label: {
|
|
...commonCrossLineLabelOptionsDefs,
|
|
positionAngle: import_ag_charts_core177.number
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var undocumentedSeriesOptionsDef = {
|
|
visible: (0, import_ag_charts_core177.undocumented)(import_ag_charts_core177.boolean)
|
|
};
|
|
var themeOverridesOptionsDef = {
|
|
common: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
axes: {
|
|
...cartesianAxesThemeDef,
|
|
...polarAxesThemeDef
|
|
},
|
|
annotations: {
|
|
...annotationOptionsDef,
|
|
line: annotationLineStyleDefs,
|
|
"horizontal-line": annotationCrossLineStyleDefs,
|
|
"vertical-line": annotationCrossLineStyleDefs,
|
|
"disjoint-channel": annotationDisjointChannelStyleDefs,
|
|
"parallel-channel": annotationParallelChannelStyleDefs,
|
|
"fibonacci-retracement": annotationFibonacciStylesDefs,
|
|
"fibonacci-retracement-trend-based": annotationFibonacciStylesDefs,
|
|
callout: annotationCalloutStylesDefs,
|
|
comment: annotationCommentStylesDefs,
|
|
note: annotationNoteStylesDefs,
|
|
text: annotationTextStylesDef,
|
|
arrow: annotationLineStyleDefs,
|
|
"arrow-up": annotationShapeStylesDefs,
|
|
"arrow-down": annotationShapeStylesDefs,
|
|
"date-range": annotationMeasurerStylesDefs,
|
|
"price-range": annotationMeasurerStylesDefs,
|
|
"date-price-range": annotationMeasurerStylesDefs,
|
|
"quick-date-price-range": annotationQuickMeasurerStylesDefs
|
|
},
|
|
chartToolbar: {
|
|
enabled: import_ag_charts_core177.boolean
|
|
},
|
|
initialState: {
|
|
legend: (0, import_ag_charts_core177.arrayOfDefs)(
|
|
{
|
|
visible: import_ag_charts_core177.boolean,
|
|
seriesId: import_ag_charts_core177.string,
|
|
itemId: import_ag_charts_core177.string,
|
|
legendItemName: import_ag_charts_core177.string
|
|
},
|
|
"legend state array"
|
|
),
|
|
zoom: {
|
|
rangeX: {
|
|
start: (0, import_ag_charts_core177.or)(import_ag_charts_core177.number, serializableDate),
|
|
end: (0, import_ag_charts_core177.or)(import_ag_charts_core177.number, serializableDate)
|
|
},
|
|
rangeY: {
|
|
start: (0, import_ag_charts_core177.or)(import_ag_charts_core177.number, serializableDate),
|
|
end: (0, import_ag_charts_core177.or)(import_ag_charts_core177.number, serializableDate)
|
|
},
|
|
ratioX: {
|
|
start: import_ag_charts_core177.ratio,
|
|
end: import_ag_charts_core177.ratio
|
|
},
|
|
ratioY: {
|
|
start: import_ag_charts_core177.ratio,
|
|
end: import_ag_charts_core177.ratio
|
|
},
|
|
autoScaledAxes: (0, import_ag_charts_core177.arrayOf)((0, import_ag_charts_core177.constant)("y"))
|
|
}
|
|
}
|
|
},
|
|
line: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: lineSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
scatter: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: scatterSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef,
|
|
// @ts-expect-error undocumented option - required by grid
|
|
paired: (0, import_ag_charts_core177.undocumented)(import_ag_charts_core177.boolean)
|
|
},
|
|
bubble: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: bubbleSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
area: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: areaSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
bar: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: barSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"box-plot": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: boxPlotSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
candlestick: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: candlestickSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"cone-funnel": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: coneFunnelSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
funnel: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: funnelSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
ohlc: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: ohlcSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
histogram: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: (0, import_ag_charts_core177.without)(cartesianAxesThemeDef, ["category", "grouped-category", "unit-time", "ordinal-time"]),
|
|
series: histogramSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
heatmap: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: heatmapSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
waterfall: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: waterfallSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"range-bar": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: rangeBarSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"range-area": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: cartesianAxesThemeDef,
|
|
series: rangeAreaSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
scrollbar: scrollbarOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
donut: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: donutSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
pie: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: pieSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"radar-line": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: polarAxesThemeDef,
|
|
series: radarLineSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"radar-area": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: polarAxesThemeDef,
|
|
series: radarAreaSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"radial-bar": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: polarAxesThemeDef,
|
|
series: radialBarSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"radial-column": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: polarAxesThemeDef,
|
|
series: radialColumnSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
nightingale: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
axes: polarAxesThemeDef,
|
|
series: nightingaleSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
sunburst: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: sunburstSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
treemap: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: treemapSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"map-shape": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: mapShapeSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"map-line": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: mapLineSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"map-marker": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: mapMarkerSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"map-shape-background": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: mapShapeBackgroundSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"map-line-background": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: mapLineBackgroundSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
sankey: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: sankeySeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
chord: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: chordSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
pyramid: {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
series: pyramidSeriesThemeableOptionsDef,
|
|
navigator: navigatorOptionsDef,
|
|
...undocumentedSeriesOptionsDef
|
|
},
|
|
"radial-gauge": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
...import_ag_charts_core177.radialGaugeSeriesThemeableOptionsDef,
|
|
targets: (0, import_ag_charts_core177.without)(import_ag_charts_core177.radialGaugeTargetOptionsDef, ["value"]),
|
|
tooltip: {
|
|
...import_ag_charts_core177.radialGaugeSeriesThemeableOptionsDef.tooltip,
|
|
...import_ag_charts_core177.commonChartOptionsDefs.tooltip
|
|
}
|
|
},
|
|
"linear-gauge": {
|
|
...import_ag_charts_core177.commonChartOptionsDefs,
|
|
...import_ag_charts_core177.linearGaugeSeriesThemeableOptionsDef,
|
|
targets: (0, import_ag_charts_core177.without)(import_ag_charts_core177.linearGaugeTargetOptionsDef, ["value"]),
|
|
tooltip: {
|
|
...import_ag_charts_core177.linearGaugeSeriesThemeableOptionsDef.tooltip,
|
|
...import_ag_charts_core177.commonChartOptionsDefs.tooltip
|
|
}
|
|
}
|
|
};
|
|
function mapValues(object5, mapper) {
|
|
const result = {};
|
|
for (const key of Reflect.ownKeys(object5)) {
|
|
result[key] = mapper(object5[key], key, object5);
|
|
}
|
|
return result;
|
|
}
|
|
var themeOverridesOptionsWithOperatorsDef = mapValues(
|
|
themeOverridesOptionsDef,
|
|
function themeOperatorMapper(value, key) {
|
|
if ((0, import_ag_charts_core177.isSymbol)(key))
|
|
return value;
|
|
if ((0, import_ag_charts_core177.isFunction)(value)) {
|
|
return (0, import_ag_charts_core177.or)(value, import_ag_charts_core177.themeOperator, import_ag_charts_core177.isSymbol);
|
|
} else if ((0, import_ag_charts_core177.isObject)(value)) {
|
|
return (0, import_ag_charts_core177.or)(
|
|
(0, import_ag_charts_core177.optionsDefs)(
|
|
import_ag_charts_core177.unionSymbol in value ? mapValues(value, (val) => (0, import_ag_charts_core177.isObject)(val) ? mapValues(val, themeOperatorMapper) : val) : mapValues(value, themeOperatorMapper)
|
|
),
|
|
import_ag_charts_core177.themeOperator,
|
|
import_ag_charts_core177.isSymbol
|
|
);
|
|
}
|
|
throw new Error(`Invalid theme override value: ${String(value)}`);
|
|
}
|
|
);
|
|
|
|
// packages/ag-charts-community/src/chart/themes/vividDark.ts
|
|
var import_ag_charts_core178 = require("ag-charts-core");
|
|
var VIVID_DARK_FILLS = {
|
|
BLUE: "#0083ff",
|
|
ORANGE: "#ff6600",
|
|
GREEN: "#00af00",
|
|
CYAN: "#00ccff",
|
|
YELLOW: "#f7c700",
|
|
VIOLET: "#ac26ff",
|
|
GRAY: "#a7a7b7",
|
|
MAGENTA: "#e800c5",
|
|
BROWN: "#b54300",
|
|
RED: "#ff0000"
|
|
};
|
|
var VIVID_DARK_STROKES = {
|
|
BLUE: "#67b7ff",
|
|
ORANGE: "#ffc24d",
|
|
GREEN: "#5cc86f",
|
|
CYAN: "#54ebff",
|
|
VIOLET: "#fff653",
|
|
YELLOW: "#c18aff",
|
|
GRAY: "#aeaeae",
|
|
MAGENTA: "#f078d4",
|
|
BROWN: "#ba8438",
|
|
RED: "#ff726e"
|
|
};
|
|
var VividDark = class extends DarkTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
fills: VIVID_DARK_FILLS,
|
|
fillsFallback: Object.values(VIVID_DARK_FILLS),
|
|
strokes: VIVID_DARK_STROKES,
|
|
sequentialColors: (0, import_ag_charts_core178.getSequentialColors)(VIVID_DARK_FILLS),
|
|
divergingColors: [VIVID_DARK_FILLS.ORANGE, VIVID_DARK_FILLS.YELLOW, VIVID_DARK_FILLS.GREEN],
|
|
hierarchyColors: [],
|
|
secondSequentialColors: [
|
|
"#0083ff",
|
|
"#0076e6",
|
|
"#0069cc",
|
|
"#005cb3",
|
|
"#004f99",
|
|
"#004280",
|
|
"#003466",
|
|
"#00274c"
|
|
],
|
|
secondDivergingColors: [VIVID_DARK_FILLS.GREEN, VIVID_DARK_FILLS.YELLOW, VIVID_DARK_FILLS.RED],
|
|
secondHierarchyColors: [],
|
|
up: { fill: VIVID_DARK_FILLS.GREEN, stroke: VIVID_DARK_STROKES.GREEN },
|
|
down: { fill: VIVID_DARK_FILLS.RED, stroke: VIVID_DARK_STROKES.RED },
|
|
neutral: { fill: VIVID_DARK_FILLS.GRAY, stroke: VIVID_DARK_STROKES.GRAY },
|
|
altUp: { fill: VIVID_DARK_FILLS.BLUE, stroke: VIVID_DARK_STROKES.BLUE },
|
|
altDown: { fill: VIVID_DARK_FILLS.ORANGE, stroke: VIVID_DARK_STROKES.ORANGE },
|
|
altNeutral: { fill: VIVID_DARK_FILLS.GRAY, stroke: VIVID_DARK_STROKES.GRAY }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core178.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, VIVID_DARK_FILLS.BLUE);
|
|
params.set(import_ag_charts_core178.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, VIVID_DARK_FILLS.BLUE);
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/themes/vividLight.ts
|
|
var import_ag_charts_core179 = require("ag-charts-core");
|
|
var VIVID_FILLS = {
|
|
BLUE: "#0083ff",
|
|
ORANGE: "#ff6600",
|
|
GREEN: "#00af00",
|
|
CYAN: "#00ccff",
|
|
YELLOW: "#f7c700",
|
|
VIOLET: "#ac26ff",
|
|
GRAY: "#a7a7b7",
|
|
MAGENTA: "#e800c5",
|
|
BROWN: "#b54300",
|
|
RED: "#ff0000"
|
|
};
|
|
var VIVID_STROKES = {
|
|
BLUE: "#0f68c0",
|
|
ORANGE: "#d47100",
|
|
GREEN: "#007922",
|
|
CYAN: "#009ac2",
|
|
VIOLET: "#bca400",
|
|
YELLOW: "#753cac",
|
|
GRAY: "#646464",
|
|
MAGENTA: "#9b2685",
|
|
BROWN: "#6c3b00",
|
|
RED: "#cb0021"
|
|
};
|
|
var VividLight = class extends ChartTheme {
|
|
getDefaultColors() {
|
|
return {
|
|
...super.getDefaultColors(),
|
|
fills: VIVID_FILLS,
|
|
fillsFallback: Object.values(VIVID_FILLS),
|
|
strokes: VIVID_STROKES,
|
|
sequentialColors: (0, import_ag_charts_core179.getSequentialColors)(VIVID_FILLS),
|
|
divergingColors: [VIVID_FILLS.ORANGE, VIVID_FILLS.YELLOW, VIVID_FILLS.GREEN],
|
|
hierarchyColors: [],
|
|
secondSequentialColors: [
|
|
"#0083ff",
|
|
"#1a8fff",
|
|
"#339cff",
|
|
"#4da8ff",
|
|
"#66b5ff",
|
|
"#80c1ff",
|
|
"#99cdff",
|
|
"#b3daff"
|
|
],
|
|
secondDivergingColors: [VIVID_FILLS.GREEN, VIVID_FILLS.YELLOW, VIVID_FILLS.RED],
|
|
secondHierarchyColors: [],
|
|
up: { fill: VIVID_FILLS.GREEN, stroke: VIVID_STROKES.GREEN },
|
|
down: { fill: VIVID_FILLS.RED, stroke: VIVID_STROKES.RED },
|
|
neutral: { fill: VIVID_FILLS.GRAY, stroke: VIVID_STROKES.GRAY },
|
|
altUp: { fill: VIVID_FILLS.BLUE, stroke: VIVID_STROKES.BLUE },
|
|
altDown: { fill: VIVID_FILLS.ORANGE, stroke: VIVID_STROKES.ORANGE },
|
|
altNeutral: { fill: VIVID_FILLS.GRAY, stroke: VIVID_STROKES.GRAY }
|
|
};
|
|
}
|
|
getTemplateParameters() {
|
|
const params = super.getTemplateParameters();
|
|
params.set(import_ag_charts_core179.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR, VIVID_FILLS.BLUE);
|
|
params.set(import_ag_charts_core179.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL, VIVID_FILLS.BLUE);
|
|
return params;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/mapping/themes.ts
|
|
var lightTheme = (0, import_ag_charts_core180.simpleMemorize)(() => new ChartTheme());
|
|
var themeCacheDebug = import_ag_charts_core180.Debug.create(true, "perf");
|
|
var cacheCallback = (status, fn, keys) => {
|
|
themeCacheDebug(`[CACHE] ChartTheme`, status, fn.name, keys);
|
|
};
|
|
var themes = {
|
|
// darkThemes,
|
|
"ag-default-dark": (0, import_ag_charts_core180.simpleMemorize)(() => new DarkTheme()),
|
|
"ag-sheets-dark": (0, import_ag_charts_core180.simpleMemorize)(() => new SheetsDark(), cacheCallback),
|
|
"ag-polychroma-dark": (0, import_ag_charts_core180.simpleMemorize)(() => new PolychromaDark(), cacheCallback),
|
|
"ag-vivid-dark": (0, import_ag_charts_core180.simpleMemorize)(() => new VividDark(), cacheCallback),
|
|
"ag-material-dark": (0, import_ag_charts_core180.simpleMemorize)(() => new MaterialDark(), cacheCallback),
|
|
"ag-financial-dark": (0, import_ag_charts_core180.simpleMemorize)(() => new FinancialDark(), cacheCallback),
|
|
// lightThemes,
|
|
"ag-default": lightTheme,
|
|
"ag-sheets": (0, import_ag_charts_core180.simpleMemorize)(() => new SheetsLight(), cacheCallback),
|
|
"ag-polychroma": (0, import_ag_charts_core180.simpleMemorize)(() => new PolychromaLight(), cacheCallback),
|
|
"ag-vivid": (0, import_ag_charts_core180.simpleMemorize)(() => new VividLight(), cacheCallback),
|
|
"ag-material": (0, import_ag_charts_core180.simpleMemorize)(() => new MaterialLight(), cacheCallback),
|
|
"ag-financial": (0, import_ag_charts_core180.simpleMemorize)(() => new FinancialLight(), cacheCallback)
|
|
};
|
|
var getChartTheme = (0, import_ag_charts_core180.simpleMemorize)(createChartTheme, cacheCallback);
|
|
function createChartTheme(value) {
|
|
if (value instanceof ChartTheme) {
|
|
return value;
|
|
} else if (!validateStructure(value)) {
|
|
return lightTheme();
|
|
}
|
|
if (value == null || typeof value === "string") {
|
|
const stockTheme = themes[value ?? "ag-default"];
|
|
if (stockTheme) {
|
|
return stockTheme();
|
|
}
|
|
throw new Error(`Cannot find theme \`${value}\`.`);
|
|
}
|
|
const { cleared, invalid } = (0, import_ag_charts_core180.validate)(reduceThemeOptions(value), themeOptionsDef, "theme");
|
|
for (const error of invalid) {
|
|
import_ag_charts_core180.Logger.warnOnce(String(error));
|
|
}
|
|
const baseTheme = cleared?.baseTheme ? getChartTheme(cleared.baseTheme) : lightTheme();
|
|
return cleared ? new baseTheme.constructor(cleared) : baseTheme;
|
|
}
|
|
function reduceThemeOptions(options) {
|
|
if (!(0, import_ag_charts_core180.isObject)(options) || !(0, import_ag_charts_core180.isObject)(options.baseTheme))
|
|
return options;
|
|
let maybeNested = options;
|
|
let palette;
|
|
let params;
|
|
const overrides = [];
|
|
while (typeof maybeNested === "object") {
|
|
palette ?? (palette = maybeNested.palette);
|
|
params ?? (params = maybeNested.params);
|
|
if (maybeNested.overrides) {
|
|
overrides.push(maybeNested.overrides);
|
|
}
|
|
maybeNested = maybeNested.baseTheme;
|
|
}
|
|
return {
|
|
baseTheme: maybeNested,
|
|
overrides: (0, import_ag_charts_core180.mergeDefaults)(...overrides),
|
|
params,
|
|
palette
|
|
};
|
|
}
|
|
var themeOptionsDef = {
|
|
baseTheme: (0, import_ag_charts_core180.or)(import_ag_charts_core180.string, import_ag_charts_core180.object),
|
|
overrides: themeOverridesOptionsWithOperatorsDef,
|
|
params: {
|
|
accentColor: import_ag_charts_core180.color,
|
|
axisColor: import_ag_charts_core180.color,
|
|
backgroundColor: import_ag_charts_core180.color,
|
|
borderColor: import_ag_charts_core180.color,
|
|
borderRadius: import_ag_charts_core180.number,
|
|
chartBackgroundColor: import_ag_charts_core180.color,
|
|
chartPadding: import_ag_charts_core180.number,
|
|
focusShadow: import_ag_charts_core180.string,
|
|
foregroundColor: import_ag_charts_core180.color,
|
|
fontFamily: import_ag_charts_core180.fontFamilyFull,
|
|
fontSize: import_ag_charts_core180.number,
|
|
fontWeight: import_ag_charts_core180.fontWeight,
|
|
gridLineColor: import_ag_charts_core180.color,
|
|
popupShadow: import_ag_charts_core180.string,
|
|
subtleTextColor: import_ag_charts_core180.color,
|
|
textColor: import_ag_charts_core180.color,
|
|
separationLinesColor: import_ag_charts_core180.color,
|
|
chromeBackgroundColor: import_ag_charts_core180.color,
|
|
chromeFontFamily: import_ag_charts_core180.fontFamilyFull,
|
|
chromeFontSize: import_ag_charts_core180.number,
|
|
chromeFontWeight: import_ag_charts_core180.fontWeight,
|
|
chromeSubtleTextColor: import_ag_charts_core180.color,
|
|
chromeTextColor: import_ag_charts_core180.color,
|
|
buttonBackgroundColor: import_ag_charts_core180.color,
|
|
buttonBorder: import_ag_charts_core180.boolean,
|
|
buttonFontWeight: import_ag_charts_core180.fontWeight,
|
|
buttonTextColor: import_ag_charts_core180.color,
|
|
inputBackgroundColor: import_ag_charts_core180.color,
|
|
inputBorder: import_ag_charts_core180.boolean,
|
|
inputTextColor: import_ag_charts_core180.color,
|
|
menuBackgroundColor: import_ag_charts_core180.color,
|
|
menuBorder: import_ag_charts_core180.boolean,
|
|
menuTextColor: import_ag_charts_core180.color,
|
|
panelBackgroundColor: import_ag_charts_core180.color,
|
|
panelSubtleTextColor: import_ag_charts_core180.color,
|
|
tooltipBackgroundColor: import_ag_charts_core180.color,
|
|
tooltipBorder: import_ag_charts_core180.boolean,
|
|
tooltipTextColor: import_ag_charts_core180.color,
|
|
tooltipSubtleTextColor: import_ag_charts_core180.color,
|
|
crosshairLabelBackgroundColor: import_ag_charts_core180.color,
|
|
crosshairLabelTextColor: import_ag_charts_core180.color
|
|
},
|
|
palette: {
|
|
fills: (0, import_ag_charts_core180.arrayOf)(import_ag_charts_core180.colorUnion),
|
|
strokes: (0, import_ag_charts_core180.arrayOf)(import_ag_charts_core180.color),
|
|
up: { fill: (0, import_ag_charts_core180.or)(import_ag_charts_core180.color, import_ag_charts_core180.gradientStrict), stroke: import_ag_charts_core180.color },
|
|
down: { fill: (0, import_ag_charts_core180.or)(import_ag_charts_core180.color, import_ag_charts_core180.gradientStrict), stroke: import_ag_charts_core180.color },
|
|
neutral: { fill: (0, import_ag_charts_core180.or)(import_ag_charts_core180.color, import_ag_charts_core180.gradientStrict), stroke: import_ag_charts_core180.color }
|
|
}
|
|
};
|
|
var themeNameValidator = (0, import_ag_charts_core180.union)(
|
|
"ag-default",
|
|
"ag-default-dark",
|
|
"ag-sheets",
|
|
"ag-sheets-dark",
|
|
"ag-polychroma",
|
|
"ag-polychroma-dark",
|
|
"ag-vivid",
|
|
"ag-vivid-dark",
|
|
"ag-material",
|
|
"ag-material-dark",
|
|
"ag-financial",
|
|
"ag-financial-dark"
|
|
);
|
|
function validateStructure(value) {
|
|
const { invalid } = (0, import_ag_charts_core180.validate)(
|
|
{ theme: value },
|
|
{ theme: (0, import_ag_charts_core180.or)(themeNameValidator, import_ag_charts_core180.object) }
|
|
);
|
|
for (const error of invalid) {
|
|
import_ag_charts_core180.Logger.warnOnce(String(error));
|
|
}
|
|
return invalid.length === 0;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/module/optionsGraph.ts
|
|
var import_ag_charts_core183 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/module/optionsGraphOperations.ts
|
|
var import_ag_charts_core182 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/module/optionsGraphUtils.ts
|
|
var import_ag_charts_core181 = require("ag-charts-core");
|
|
var PATH_EDGE = "path";
|
|
var PATH_ARRAY_EDGE = "pathArray";
|
|
var DEFAULTS_EDGE = "default";
|
|
var OVERRIDES_EDGE = "override";
|
|
var USER_OPTIONS_EDGE = "user";
|
|
var USER_PARTIAL_OPTIONS_EDGE = "userPartial";
|
|
var OPERATION_EDGE = "operation";
|
|
var OPERATION_VALUE_EDGE = "operationValue";
|
|
var DEPENDENCY_EDGE = "dependency";
|
|
var AUTO_ENABLE_EDGE = "autoEnable";
|
|
var AUTO_ENABLE_VALUE_EDGE = "autoEnableValue";
|
|
var PRUNE_EDGE = "prune";
|
|
var CHILDREN_SOURCE_EDGE = "childrenSource";
|
|
function isRatio(value) {
|
|
return (0, import_ag_charts_core181.isNumber)(value) && value >= 0 && value <= 1;
|
|
}
|
|
function hasPathSafe(object5, path) {
|
|
let result = object5;
|
|
for (const part of path) {
|
|
const isPartKey = typeof part === "string" && result != null && (typeof result === "object" || Array.isArray(result)) && part in result;
|
|
if (!isPartKey)
|
|
return false;
|
|
result = result[part];
|
|
}
|
|
return true;
|
|
}
|
|
function getPathSafe(object5, path) {
|
|
let result = object5;
|
|
for (const part of path) {
|
|
const isPartKey = typeof part === "string" && result != null && (typeof result === "object" || Array.isArray(result)) && part in result;
|
|
if (!isPartKey)
|
|
return;
|
|
result = result[part];
|
|
}
|
|
return result;
|
|
}
|
|
function setPathSafe(object5, path, value) {
|
|
const pathLength = path.length;
|
|
if (pathLength === 0)
|
|
return;
|
|
let result = object5;
|
|
const lastIndex = pathLength - 1;
|
|
const lastPart = path[lastIndex];
|
|
for (let i = 0; i < lastIndex; i++) {
|
|
const part = path[i];
|
|
const nextPart = path[i + 1];
|
|
let currentValue = result[part];
|
|
if (currentValue == null || !(0, import_ag_charts_core181.isObjectLike)(currentValue)) {
|
|
currentValue = Number.isNaN(Number(nextPart)) ? {} : [];
|
|
result[part] = currentValue;
|
|
}
|
|
result = currentValue;
|
|
}
|
|
result[lastPart] = value;
|
|
}
|
|
var DIGITS_ONLY_REGEX = /^\d+$/;
|
|
function getPathLastIndexIndex(pathArray, offset = 0) {
|
|
let count = 0;
|
|
for (let i = pathArray.length - 1; i >= 0; i--) {
|
|
const part = pathArray[i];
|
|
if (DIGITS_ONLY_REGEX.test(part)) {
|
|
count++;
|
|
if (count > offset)
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
function getPathLastIndex(pathArray, offset = 0) {
|
|
const indexIndex = getPathLastIndexIndex(pathArray, offset);
|
|
return Number(pathArray[indexIndex]);
|
|
}
|
|
function resolvePath(currentPath, path, variables) {
|
|
const relativePathParts = path.split("/");
|
|
let resolvedPath = [...currentPath];
|
|
if (path.startsWith("/")) {
|
|
resolvedPath = [];
|
|
relativePathParts.shift();
|
|
}
|
|
let prevPartWasTwoDots = false;
|
|
for (const part of relativePathParts) {
|
|
if (part === "..") {
|
|
resolvedPath.pop();
|
|
if (!prevPartWasTwoDots)
|
|
resolvedPath.pop();
|
|
} else if (part === ".") {
|
|
resolvedPath.pop();
|
|
} else if (part === "$index") {
|
|
const index = getPathLastIndex(currentPath);
|
|
if (Number.isNaN(index))
|
|
return UNRESOLVABLE_PATH;
|
|
resolvedPath.push(`${index}`);
|
|
} else if (part === "$prevIndex") {
|
|
const index = getPathLastIndex(currentPath);
|
|
if (Number.isNaN(index) || Number(index) <= 0)
|
|
return UNRESOLVABLE_PATH;
|
|
resolvedPath.push(`${Number(index) - 1}`);
|
|
} else if (part.startsWith("$")) {
|
|
const variable = variables?.[part.slice(1)];
|
|
if (variable == null)
|
|
return UNRESOLVABLE_PATH;
|
|
resolvedPath.push(variable);
|
|
} else if (part.length !== 0) {
|
|
resolvedPath.push(part);
|
|
}
|
|
prevPartWasTwoDots = part === "..";
|
|
}
|
|
return resolvedPath;
|
|
}
|
|
var UNRESOLVABLE_PATH = Symbol("unresolvable-path");
|
|
var RESOLVED_TO_BRANCH = Symbol("resolved-to-branch");
|
|
|
|
// packages/ag-charts-community/src/module/optionsGraphOperations.ts
|
|
function getOperation(value, keys) {
|
|
if (value == null || typeof value !== "object" || Array.isArray(value))
|
|
return;
|
|
keys ?? (keys = Object.keys(value));
|
|
if (keys.length === 0)
|
|
return;
|
|
const operation = keys[0];
|
|
if (!operationTypes.has(operation))
|
|
return;
|
|
return {
|
|
operation,
|
|
values: Array.isArray(value[operation]) ? value[operation] : [value[operation]]
|
|
};
|
|
}
|
|
function getOperationTargetVertex(graph, vertex, valueVertex) {
|
|
const operation = getOperation(graph.getVertexValue(valueVertex));
|
|
switch (operation?.operation) {
|
|
case "$path" /* Path */: {
|
|
const [relativePath] = operation.values;
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const path = resolvePath(pathArray, relativePath);
|
|
if (path === UNRESOLVABLE_PATH)
|
|
return;
|
|
return graph.findVertexAtPath(path);
|
|
}
|
|
case "$value" /* Value */:
|
|
return vertex;
|
|
}
|
|
}
|
|
var cacheOperations = {
|
|
$cacheMax: cacheMaxOperation
|
|
};
|
|
function cacheMaxOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const cached = graph.getCachedValue(pathArray, "$cacheMax" /* CacheMax */);
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
if (typeof value !== "number")
|
|
return cached;
|
|
if (typeof cached !== "number") {
|
|
graph.setCachedValue(pathArray, "$cacheMax" /* CacheMax */, value);
|
|
return value;
|
|
}
|
|
const maxValue = Math.max(cached, value);
|
|
graph.setCachedValue(pathArray, "$cacheMax" /* CacheMax */, maxValue);
|
|
return maxValue;
|
|
}
|
|
var chartOperations = {
|
|
$hasSeriesType: { dependencies: seriesTypeDependencyFactory, resolve: hasSeriesTypeOperation },
|
|
$isChartType: { dependencies: seriesTypeDependencyFactory, resolve: isChartTypeOperation },
|
|
$isSeriesType: { dependencies: seriesTypeDependencyFactory, resolve: isSeriesTypeOperation }
|
|
};
|
|
function seriesTypeDependencyFactory(graph, vertex, _values) {
|
|
const dependencyVertex = graph.findVertexAtPath(["series", "0", "type"]);
|
|
if (dependencyVertex) {
|
|
graph.addEdge(vertex, dependencyVertex, DEPENDENCY_EDGE);
|
|
}
|
|
}
|
|
function hasSeriesTypeOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
const series = graph.getResolvedPath(["series"]);
|
|
if (!Array.isArray(series))
|
|
return false;
|
|
for (const s of series) {
|
|
if (s.type === value)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function isSeriesTypeOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
const seriesType = graph.getResolvedPath(["series", "0", "type"]);
|
|
return seriesType === value;
|
|
}
|
|
function isChartTypeOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
const seriesType = graph.getResolvedPath(["series", "0", "type"]);
|
|
if (typeof seriesType !== "string")
|
|
return false;
|
|
const seriesModule = import_ag_charts_core182.ModuleRegistry.getSeriesModule(seriesType);
|
|
if (seriesModule == null)
|
|
return false;
|
|
switch (value) {
|
|
case "cartesian":
|
|
return seriesModule.chartType === "cartesian";
|
|
case "polar":
|
|
return seriesModule.chartType === "polar";
|
|
case "standalone":
|
|
return seriesModule.chartType === "standalone";
|
|
}
|
|
return false;
|
|
}
|
|
var colorOperations = {
|
|
$foregroundBackgroundMix: foregroundBackgroundMixOperation,
|
|
$foregroundOpacity: foregroundOpacityOperation,
|
|
$interpolate: interpolateOperation,
|
|
$isGradient: isGradientOperation,
|
|
$isImage: isImageOperation,
|
|
$isPattern: isPatternOperation,
|
|
$mix: mixOperation
|
|
};
|
|
function foregroundBackgroundMixOperation(graph, vertex, values) {
|
|
const [foregroundRatioVertex] = values;
|
|
const foregroundRatio = graph.resolveVertexValue(vertex, foregroundRatioVertex);
|
|
const foregroundColor = graph.getParamValue("foregroundColor");
|
|
const backgroundColor = graph.getParamValue("backgroundColor");
|
|
if (typeof foregroundColor === "string" && typeof backgroundColor === "string" && isRatio(foregroundRatio)) {
|
|
return import_ag_charts_core182.Color.mix(
|
|
import_ag_charts_core182.Color.fromString(foregroundColor),
|
|
import_ag_charts_core182.Color.fromString(backgroundColor),
|
|
1 - foregroundRatio
|
|
).toString();
|
|
}
|
|
import_ag_charts_core182.Debug.inDevelopmentMode(
|
|
() => import_ag_charts_core182.Logger.warnOnce(
|
|
`\`$foregroundBackgroundMix\` json operation failed on [${String(foregroundRatio)}}}] at [${graph.getPathArray(vertex).join(".")}], expecting a number between 0 and 1.`
|
|
)
|
|
);
|
|
}
|
|
function foregroundOpacityOperation(graph, vertex, values) {
|
|
const [opacityVertex] = values;
|
|
const opacity = graph.resolveVertexValue(vertex, opacityVertex);
|
|
const foregroundColor = graph.getParamValue("foregroundColor");
|
|
if (typeof foregroundColor === "string" && isRatio(opacity)) {
|
|
const color8 = import_ag_charts_core182.Color.fromString(foregroundColor);
|
|
return new import_ag_charts_core182.Color(color8.r, color8.g, color8.b, opacity).toString();
|
|
}
|
|
import_ag_charts_core182.Debug.inDevelopmentMode(
|
|
() => import_ag_charts_core182.Logger.warnOnce(
|
|
`\`$foregroundOpacity\` json operation failed on [${String(opacity)}}}] at [${graph.getPathArray(vertex).join(".")}], expecting a number between 0 and 1.`
|
|
)
|
|
);
|
|
}
|
|
function interpolateOperation(graph, vertex, values) {
|
|
const [colorsVertex, countVertex] = values;
|
|
const colors = graph.resolveVertexValue(vertex, colorsVertex);
|
|
const count = graph.resolveVertexValue(vertex, countVertex);
|
|
if (!(0, import_ag_charts_core182.isArray)(colors) || !(0, import_ag_charts_core182.isNumber)(count))
|
|
return;
|
|
return import_ag_charts_core182.Color.interpolate(
|
|
colors.map((color8) => import_ag_charts_core182.Color.fromString(color8)),
|
|
count
|
|
).map((color8) => color8.toString());
|
|
}
|
|
function isGradientOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
return (0, import_ag_charts_core182.isGradientFill)(value);
|
|
}
|
|
function isImageOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
return (0, import_ag_charts_core182.isImageFill)(value);
|
|
}
|
|
function isPatternOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
return (0, import_ag_charts_core182.isPatternFill)(value);
|
|
}
|
|
function mixOperation(graph, vertex, values) {
|
|
const [colorAVertex, colorBVertex, ratioVertex] = values;
|
|
const colorA = graph.resolveVertexValue(vertex, colorAVertex);
|
|
const colorB = graph.resolveVertexValue(vertex, colorBVertex);
|
|
const ratio10 = graph.resolveVertexValue(vertex, ratioVertex);
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const warningPrefix = `\`$mix\` json operation failed on [${String(colorA)}, ${String(colorB)}, ${String(ratio10)}] at [${pathArray.join(".")}], expecting`;
|
|
const warningMessage = `${warningPrefix} two colors and a number between 0 and 1.`;
|
|
if (typeof colorB !== "string" || !isRatio(ratio10)) {
|
|
import_ag_charts_core182.Debug.inDevelopmentMode(() => import_ag_charts_core182.Logger.warnOnce(warningMessage));
|
|
return;
|
|
}
|
|
if (typeof colorA === "string") {
|
|
try {
|
|
return import_ag_charts_core182.Color.mix(import_ag_charts_core182.Color.fromString(colorA), import_ag_charts_core182.Color.fromString(colorB), ratio10).toString();
|
|
} catch {
|
|
import_ag_charts_core182.Debug.inDevelopmentMode(() => import_ag_charts_core182.Logger.warnOnce(warningMessage));
|
|
return;
|
|
}
|
|
}
|
|
if (!(0, import_ag_charts_core182.isGradientFill)(colorA)) {
|
|
import_ag_charts_core182.Debug.inDevelopmentMode(() => import_ag_charts_core182.Logger.warnOnce(warningMessage));
|
|
return;
|
|
}
|
|
let colorStops = colorA.colorStops;
|
|
try {
|
|
colorStops = colorStops?.map((value) => {
|
|
let color8;
|
|
if (typeof value.color === "string") {
|
|
color8 = import_ag_charts_core182.Color.mix(import_ag_charts_core182.Color.fromString(value.color), import_ag_charts_core182.Color.fromString(colorB), ratio10).toString();
|
|
}
|
|
return { ...value, color: color8 };
|
|
});
|
|
} catch {
|
|
import_ag_charts_core182.Debug.inDevelopmentMode(
|
|
() => import_ag_charts_core182.Logger.warnOnce(`${warningPrefix} a gradient, a color and a number between 0 and 1.`)
|
|
);
|
|
return;
|
|
}
|
|
return { ...colorA, colorStops };
|
|
}
|
|
var fontOperations = {
|
|
$rem: remOperation
|
|
};
|
|
function remOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.getVertexValue(valueVertex);
|
|
const fontSize = graph.getParamValue("fontSize");
|
|
if (typeof fontSize === "number" && typeof value === "number") {
|
|
return Math.round(value * fontSize);
|
|
}
|
|
import_ag_charts_core182.Debug.inDevelopmentMode(
|
|
() => import_ag_charts_core182.Logger.warnOnce(
|
|
`\`$rem\` json operation failed on [${String(value)}] at [${graph.getPathArray(vertex).join(".")}], expecting a number.`
|
|
)
|
|
);
|
|
}
|
|
var logicOperations = {
|
|
$and: andOperation,
|
|
$eq: eqOperation,
|
|
$every: everyOperation,
|
|
$greaterThan: greaterThanOperation,
|
|
$if: ifOperation,
|
|
$lessThan: lessThanOperation,
|
|
$not: notOperation,
|
|
$or: orOperation,
|
|
$some: someOperation,
|
|
$switch: switchOperation
|
|
};
|
|
function andOperation(graph, vertex, values) {
|
|
for (const valueVertex of values) {
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
if (values.length === 1 && Array.isArray(value)) {
|
|
return value.every((v) => Boolean(v));
|
|
}
|
|
if (!value)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function eqOperation(graph, vertex, values) {
|
|
let compare;
|
|
let first8 = true;
|
|
for (const valueVertex of values) {
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
if (first8) {
|
|
compare = value;
|
|
first8 = false;
|
|
} else if (value !== compare) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function everyOperation(graph, vertex, values) {
|
|
const [mapOperationVertex, mapValuesVertex] = values;
|
|
const mapOperationValue = graph.getVertexValue(mapOperationVertex);
|
|
const mapValues3 = graph.resolveVertexValue(vertex, mapValuesVertex);
|
|
if (!Array.isArray(mapValues3))
|
|
return;
|
|
let index = 0;
|
|
for (const value of mapValues3) {
|
|
const resolved = graph.graftAndResolveOrphanValue(vertex, `${index}`, mapOperationValue, value);
|
|
if (!resolved)
|
|
return false;
|
|
index++;
|
|
}
|
|
return true;
|
|
}
|
|
function greaterThanOperation(graph, vertex, values) {
|
|
const [value, compare] = values;
|
|
return graph.resolveVertexValue(vertex, value) > graph.resolveVertexValue(vertex, compare);
|
|
}
|
|
function ifOperation(graph, vertex, values) {
|
|
const [conditionVertex, thenVertex, elseVertex] = values;
|
|
const condition = graph.resolveVertexValue(vertex, conditionVertex);
|
|
const valueVertex = condition ? thenVertex : elseVertex;
|
|
const neighbours = graph.neighboursWithEdgeValue(valueVertex, PATH_EDGE);
|
|
if (neighbours) {
|
|
for (const neighbour of neighbours) {
|
|
graph.addEdge(vertex, neighbour, PATH_EDGE);
|
|
}
|
|
}
|
|
return graph.resolveVertexValue(vertex, valueVertex);
|
|
}
|
|
function lessThanOperation(graph, vertex, values) {
|
|
const [value, compare] = values;
|
|
return graph.resolveVertexValue(vertex, value) < graph.resolveVertexValue(vertex, compare);
|
|
}
|
|
function notOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
if (!valueVertex)
|
|
return;
|
|
return !graph.resolveVertexValue(vertex, valueVertex);
|
|
}
|
|
function orOperation(graph, vertex, values) {
|
|
for (const valueVertex of values) {
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
if (values.length === 1 && Array.isArray(value)) {
|
|
return value.some((v) => Boolean(v));
|
|
}
|
|
if (value)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function someOperation(graph, vertex, values) {
|
|
const [mapOperationVertex, mapValuesVertex] = values;
|
|
const mapOperationValue = graph.getVertexValue(mapOperationVertex);
|
|
const mapValues3 = graph.resolveVertexValue(vertex, mapValuesVertex);
|
|
if (!Array.isArray(mapValues3))
|
|
return;
|
|
let index = 0;
|
|
for (const value of mapValues3) {
|
|
const resolved = graph.graftAndResolveOrphanValue(vertex, `${index}`, mapOperationValue, value);
|
|
if (resolved)
|
|
return true;
|
|
index++;
|
|
}
|
|
return false;
|
|
}
|
|
function switchOperation(graph, vertex, values) {
|
|
const [conditionValueVertex, defaultValueVertex, ...caseVertices] = values;
|
|
const conditionValue = graph.resolveVertexValue(vertex, conditionValueVertex);
|
|
for (const caseVertex of caseVertices) {
|
|
const caseValue = graph.getVertexValue(caseVertex);
|
|
if (!Array.isArray(caseValue))
|
|
continue;
|
|
const [caseConditionValue, caseResultValue] = caseValue;
|
|
if (conditionValue === caseConditionValue || Array.isArray(caseConditionValue) && caseConditionValue.includes(conditionValue)) {
|
|
return caseResultValue;
|
|
}
|
|
}
|
|
return graph.resolveVertexValue(vertex, defaultValueVertex);
|
|
}
|
|
var locationOperations = {
|
|
$isUserOption: isUserOptionOperation,
|
|
$palette: paletteOperation,
|
|
$mapPalette: mapPaletteOperation,
|
|
$path: {
|
|
dependencies: pathOperationDependenciesFactory,
|
|
resolve: pathOperation
|
|
},
|
|
$pathString: {
|
|
dependencies: pathOperationDependenciesFactory,
|
|
resolve: pathStringOperation
|
|
},
|
|
$ref: refOperation
|
|
};
|
|
function isUserOptionOperation(graph, vertex, values) {
|
|
const [relativePathVertices, thenVertex, elseVertex] = values;
|
|
const children = graph.neighboursWithEdgeValue(relativePathVertices, PATH_EDGE);
|
|
if (children) {
|
|
for (const child of children) {
|
|
const relativePathVertex = graph.findNeighbour(child, DEFAULTS_EDGE);
|
|
if (relativePathVertex && isUserOptionCheck(graph, vertex, relativePathVertex)) {
|
|
return graph.resolveVertexValue(vertex, thenVertex);
|
|
}
|
|
}
|
|
} else if (isUserOptionCheck(graph, vertex, relativePathVertices)) {
|
|
return graph.resolveVertexValue(vertex, thenVertex);
|
|
}
|
|
return graph.resolveVertexValue(vertex, elseVertex);
|
|
}
|
|
function isUserOptionCheck(graph, vertex, relativePathVertex) {
|
|
const relativePath = graph.resolveVertexValue(vertex, relativePathVertex);
|
|
if (!(0, import_ag_charts_core182.isString)(relativePath)) {
|
|
throw new Error(`\`$isUserOption\` json operation failed on [${String(relativePath)}], expecting a string.`);
|
|
}
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const path = resolvePath(pathArray, relativePath);
|
|
if (path === UNRESOLVABLE_PATH)
|
|
return false;
|
|
return graph.hasUserOption(path);
|
|
}
|
|
var PALETTE_INDEX_KEYS = /* @__PURE__ */ new Set(["fill", "fillFallback", "stroke", "gradient", "range2"]);
|
|
function paletteOperation(graph, vertex, values) {
|
|
const [keyVertex] = values;
|
|
const key = graph.resolveVertexValue(vertex, keyVertex);
|
|
if (!(0, import_ag_charts_core182.isString)(key))
|
|
return;
|
|
if (PALETTE_INDEX_KEYS.has(key)) {
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const index = getPathLastIndex(pathArray);
|
|
if (Number.isNaN(index))
|
|
return;
|
|
switch (key) {
|
|
case "fill":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.fills, 1, index)[0];
|
|
case "fillFallback":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.fillsFallback, 1, index)[0];
|
|
case "stroke":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.strokes, 1, index)[0];
|
|
case "gradient":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.sequentialColors, 1, index)[0];
|
|
case "range2":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.fills, 2, index);
|
|
}
|
|
return;
|
|
}
|
|
if (key === "gradients") {
|
|
return graph.palette.sequentialColors;
|
|
}
|
|
if (key === "type") {
|
|
return graph.paletteType;
|
|
}
|
|
const value = getPathSafe(graph.palette, key.split("."));
|
|
if (Array.isArray(value))
|
|
return [...value];
|
|
if (typeof value === "object")
|
|
return { ...value };
|
|
return value;
|
|
}
|
|
function mapPaletteOperation(graph, vertex, values) {
|
|
const [keyVertex] = values;
|
|
const key = graph.resolveVertexValue(vertex, keyVertex);
|
|
if (!(0, import_ag_charts_core182.isString)(key))
|
|
return;
|
|
if (PALETTE_INDEX_KEYS.has(key)) {
|
|
const pathArray = graph.getPathArray(vertex);
|
|
let index = getPathLastIndex(pathArray);
|
|
let ignoreIndexOffset = 0;
|
|
const path = ["series", "0", "type"];
|
|
for (let i = 0; i < index; i++) {
|
|
path[1] = `${i}`;
|
|
const siblingSeriesType = graph.getResolvedPath(path);
|
|
if ("map-shape-background" === siblingSeriesType || "map-line-background" === siblingSeriesType) {
|
|
ignoreIndexOffset++;
|
|
}
|
|
}
|
|
index -= ignoreIndexOffset;
|
|
if (Number.isNaN(index))
|
|
return;
|
|
switch (key) {
|
|
case "fill":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.fills, 1, index)[0];
|
|
case "fillFallback":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.fillsFallback, 1, index)[0];
|
|
case "stroke":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.strokes, 1, index)[0];
|
|
case "gradient":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.sequentialColors, 1, index)[0];
|
|
case "range2":
|
|
return (0, import_ag_charts_core182.circularSliceArray)(graph.palette.fills, 2, index);
|
|
}
|
|
return;
|
|
}
|
|
if (key === "gradients") {
|
|
return graph.palette.sequentialColors;
|
|
}
|
|
if (key === "type") {
|
|
return graph.paletteType;
|
|
}
|
|
const value = getPathSafe(graph.palette, key.split("."));
|
|
if (Array.isArray(value))
|
|
return [...value];
|
|
if (typeof value === "object")
|
|
return { ...value };
|
|
return value;
|
|
}
|
|
function pathOperationDependenciesFactory(graph, vertex, values) {
|
|
const [relativePathVertex] = values;
|
|
const relativePath = graph.getVertexValue(relativePathVertex);
|
|
if ((0, import_ag_charts_core182.isString)(relativePath)) {
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const path = resolvePath(pathArray, relativePath);
|
|
if (path === UNRESOLVABLE_PATH) {
|
|
return;
|
|
}
|
|
const dependencyVertex = graph.findVertexAtPath(path);
|
|
if (dependencyVertex) {
|
|
graph.addEdge(vertex, dependencyVertex, DEPENDENCY_EDGE);
|
|
}
|
|
}
|
|
}
|
|
function pathOperation(graph, vertex, values) {
|
|
const hasDefaultValue = values.length > 1;
|
|
const hasCustomBranch = values.length > 2;
|
|
const [relativePathVertex, defaultValueVertex, customBranchVertex] = values;
|
|
const relativePath = graph.resolveVertexValue(vertex, relativePathVertex);
|
|
const customBranch = hasCustomBranch ? graph.resolveVertexValue(vertex, customBranchVertex) : null;
|
|
if (!(0, import_ag_charts_core182.isString)(relativePath)) {
|
|
throw new Error(`\`$path\` json operation failed on [${String(relativePath)}], expecting a string.`);
|
|
}
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const path = resolvePath(pathArray, relativePath);
|
|
if (path === UNRESOLVABLE_PATH) {
|
|
return;
|
|
}
|
|
const resolved = customBranch ? getPathSafe(customBranch, path) : graph.getResolvedPath(path);
|
|
if (resolved != null) {
|
|
return resolved;
|
|
}
|
|
if (hasDefaultValue) {
|
|
return graph.resolveVertexValue(vertex, defaultValueVertex);
|
|
}
|
|
}
|
|
function pathStringOperation(graph, vertex, values) {
|
|
const [relativePathVertex, variablesVertex] = values;
|
|
const relativePath = graph.resolveVertexValue(vertex, relativePathVertex);
|
|
if (!(0, import_ag_charts_core182.isString)(relativePath)) {
|
|
throw new Error(`\`$path\` json operation failed on [${String(relativePath)}], expecting a string.`);
|
|
}
|
|
let variables;
|
|
if (variablesVertex) {
|
|
variables = graph.graftAndResolveOrphan(vertex, variablesVertex);
|
|
}
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const path = resolvePath(pathArray, relativePath, variables);
|
|
if (path === UNRESOLVABLE_PATH) {
|
|
throw new Error(`Unresolvable path [${relativePath}] at [${pathArray.join(".")}]`);
|
|
}
|
|
return path;
|
|
}
|
|
function refOperation(graph, _vertex, values) {
|
|
const [value] = values;
|
|
const paramKey = graph.getVertexValue(value);
|
|
return graph.getParamValue(paramKey);
|
|
}
|
|
var transformOperations = {
|
|
$apply: applyOperation,
|
|
$applyCycle: applyCycleOperation,
|
|
$applySwitch: applySwitchOperation,
|
|
$applyTheme: applyThemeOperation,
|
|
$clone: cloneOperation,
|
|
$findFirstSiblingNotOperation: findFirstSiblingNotOperationOperation,
|
|
$map: mapOperation,
|
|
$merge: mergeOperation,
|
|
$omit: omitOperation,
|
|
$size: sizeOperation,
|
|
$shallow: shallowOperation,
|
|
$shallowSimple: shallowSimpleOperation,
|
|
$value: valueOperation
|
|
};
|
|
function applyOperation(graph, vertex, values) {
|
|
const [objectVertex, defaultValueVertex, overridesPathVertex1, overridesPathVertex2] = values;
|
|
const object5 = graph.getVertexValue(objectVertex);
|
|
if (!(0, import_ag_charts_core182.isPlainObject)(object5))
|
|
return;
|
|
const defaultValue = defaultValueVertex ? graph.getVertexValue(defaultValueVertex) : void 0;
|
|
const children = graph.neighboursWithEdgeValue(vertex, PATH_EDGE);
|
|
const hasChildren = children && children.length > 0;
|
|
if (!hasChildren && defaultValue == null) {
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
const overridesPath1 = overridesPathVertex1 ? graph.resolveVertexValue(vertex, overridesPathVertex1) : void 0;
|
|
const overridesPath2 = overridesPathVertex2 ? graph.resolveVertexValue(vertex, overridesPathVertex2) : void 0;
|
|
if (!hasChildren && defaultValue != null) {
|
|
if (getOperation(defaultValue)) {
|
|
const resolvedDefaultValue = graph.resolveVertexValue(vertex, defaultValueVertex);
|
|
if ((0, import_ag_charts_core182.isPlainObject)(resolvedDefaultValue)) {
|
|
graph.graftObject(vertex, resolvedDefaultValue, [overridesPath1, overridesPath2]);
|
|
}
|
|
} else {
|
|
graph.graftObject(vertex, defaultValue, [overridesPath1, overridesPath2]);
|
|
}
|
|
}
|
|
if (!hasChildren)
|
|
return RESOLVED_TO_BRANCH;
|
|
for (const child of children) {
|
|
const childNeighbours = graph.neighboursWithEdgeValue(child, PATH_EDGE);
|
|
if (!childNeighbours || childNeighbours.length === 0) {
|
|
const stubVertex = graph.addVertex({});
|
|
graph.addEdge(child, stubVertex, DEFAULTS_EDGE);
|
|
} else {
|
|
graph.graftObject(child, object5, [overridesPath1, overridesPath2]);
|
|
}
|
|
}
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
function applyCycleOperation(graph, vertex, values) {
|
|
const [sizeVertex, defaultValuesVertex, operationVertex] = values;
|
|
const size = graph.resolveVertexValue(vertex, sizeVertex);
|
|
if (typeof size !== "number")
|
|
return;
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const userOption = graph.dangerouslyGetUserOption(pathArray);
|
|
const hasThemeOverride = graph.hasThemeOverride(pathArray);
|
|
const graftEdge = userOption == null ? void 0 : USER_OPTIONS_EDGE;
|
|
const cycledValues = userOption ?? graph.resolveVertexValue(vertex, defaultValuesVertex);
|
|
if (!Array.isArray(cycledValues))
|
|
return;
|
|
const operation = operationVertex ? graph.getVertexValue(operationVertex) : void 0;
|
|
for (let index = 0; index < size; index++) {
|
|
const value = cycledValues[index % cycledValues.length];
|
|
if (value == null)
|
|
continue;
|
|
if (userOption || !hasThemeOverride) {
|
|
graph.graftValue(vertex, `${index}`, value, void 0, graftEdge);
|
|
}
|
|
if (operation) {
|
|
graph.graftValue(vertex, `${index}`, operation, value, graftEdge);
|
|
}
|
|
}
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
function applySwitchOperation(graph, vertex, values) {
|
|
const [conditionValueVertex, defaultValueVertex, ...caseVertices] = values;
|
|
const conditionValue = graph.resolveVertexValue(vertex, conditionValueVertex);
|
|
for (const caseVertex of caseVertices) {
|
|
const caseValue = graph.getVertexValue(caseVertex);
|
|
if (!Array.isArray(caseValue))
|
|
continue;
|
|
const [caseConditionValue, caseResultValue] = caseValue;
|
|
if (conditionValue === caseConditionValue || Array.isArray(caseConditionValue) && caseConditionValue.includes(conditionValue)) {
|
|
graph.graftObject(vertex, caseResultValue, [], DEFAULTS_EDGE);
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
}
|
|
return graph.resolveVertexValue(vertex, defaultValueVertex);
|
|
}
|
|
function applyThemeOperation(graph, vertex, values) {
|
|
const [fromPathVertex, variablesVertex, ignorePathsVertex] = values;
|
|
let fromPaths = graph.getVertexValue(fromPathVertex);
|
|
if (typeof fromPaths === "string") {
|
|
fromPaths = [fromPaths];
|
|
}
|
|
if (!Array.isArray(fromPaths))
|
|
return;
|
|
const children = graph.neighboursWithEdgeValue(vertex, PATH_EDGE);
|
|
const ignorePathsValue = ignorePathsVertex ? graph.getVertexValue(ignorePathsVertex) : [];
|
|
const ignorePaths = Array.isArray(ignorePathsValue) ? new Set(ignorePathsValue) : /* @__PURE__ */ new Set();
|
|
if (!children)
|
|
return RESOLVED_TO_BRANCH;
|
|
for (const child of children) {
|
|
const variables = graph.graftAndResolveOrphan(child, variablesVertex);
|
|
for (const fromPath of fromPaths) {
|
|
const fromPathResolved = resolvePath([], fromPath, variables);
|
|
if (fromPathResolved === UNRESOLVABLE_PATH) {
|
|
continue;
|
|
}
|
|
graph.graftConfig(child, fromPathResolved, ignorePaths);
|
|
}
|
|
}
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
function cloneOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
if (!(0, import_ag_charts_core182.isPlainObject)(value))
|
|
return;
|
|
graph.graftObject(vertex, value, void 0, USER_OPTIONS_EDGE);
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
function findFirstSiblingNotOperationOperation(graph, vertex, values) {
|
|
const [defaultValueVertex] = values;
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const parentPathArray = resolvePath(pathArray, "..");
|
|
if (parentPathArray === UNRESOLVABLE_PATH)
|
|
return;
|
|
const parentVertex = graph.findVertexAtPath(parentPathArray);
|
|
if (!parentVertex) {
|
|
return graph.resolveVertexValue(vertex, defaultValueVertex);
|
|
}
|
|
const siblings = graph.neighboursWithEdgeValue(parentVertex, PATH_EDGE);
|
|
if (siblings) {
|
|
for (const sibling of siblings) {
|
|
const siblingPathArray = graph.getPathArray(sibling);
|
|
if (siblingPathArray[parentPathArray.length] === pathArray[parentPathArray.length])
|
|
continue;
|
|
const siblingChildPathArray = siblingPathArray.concat(pathArray.slice(parentPathArray.length + 1));
|
|
const siblingChildVertex = graph.findVertexAtPath(siblingChildPathArray);
|
|
if (!siblingChildVertex)
|
|
continue;
|
|
const siblingChildUserOptionsValue = graph.findNeighbourValue(siblingChildVertex, USER_OPTIONS_EDGE);
|
|
if (siblingChildUserOptionsValue != null) {
|
|
return siblingChildUserOptionsValue;
|
|
}
|
|
const siblingChildOverridesValue = graph.findNeighbourValue(siblingChildVertex, OVERRIDES_EDGE);
|
|
if (siblingChildOverridesValue != null) {
|
|
return siblingChildOverridesValue;
|
|
}
|
|
}
|
|
}
|
|
return graph.resolveVertexValue(vertex, defaultValueVertex);
|
|
}
|
|
function mapOperation(graph, vertex, values) {
|
|
const [mapOperationVertex, mapValuesVertex] = values;
|
|
const mapOperationValue = graph.getVertexValue(mapOperationVertex);
|
|
const mapValues3 = graph.resolveVertexValue(vertex, mapValuesVertex);
|
|
if (!Array.isArray(mapValues3))
|
|
return;
|
|
const neighbours = graph.neighboursWithEdgeValue(vertex, PATH_EDGE);
|
|
if (neighbours && neighbours.length > 0) {
|
|
return;
|
|
}
|
|
let index = 0;
|
|
for (const value of mapValues3) {
|
|
graph.graftValue(vertex, `${index}`, mapOperationValue, value);
|
|
index++;
|
|
}
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
function mergeOperation(graph, vertex, values) {
|
|
for (const valueVertex of values) {
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
if (!(0, import_ag_charts_core182.isPlainObject)(value))
|
|
continue;
|
|
graph.graftObject(vertex, value);
|
|
}
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
function omitOperation(graph, vertex, values) {
|
|
const [keysVertex, objectVertex] = values;
|
|
let keys = graph.getVertexValue(keysVertex);
|
|
if (!Array.isArray(keys)) {
|
|
const targetVertex = getOperationTargetVertex(graph, vertex, objectVertex);
|
|
if (!targetVertex)
|
|
return;
|
|
keys = graph.resolveVertexValue(targetVertex, keysVertex);
|
|
}
|
|
const object5 = graph.resolveVertexValue(vertex, objectVertex);
|
|
if (!Array.isArray(keys) || !(0, import_ag_charts_core182.isPlainObject)(object5))
|
|
return;
|
|
return (0, import_ag_charts_core182.without)(object5, keys);
|
|
}
|
|
function sizeOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
if (!(0, import_ag_charts_core182.isObjectLike)(value))
|
|
return 0;
|
|
if ("length" in value)
|
|
return value.length;
|
|
return Object.keys(value).length;
|
|
}
|
|
function shallowSimpleOperation(graph, _vertex, values) {
|
|
const shallowValues = [];
|
|
for (const valueVertex of values) {
|
|
shallowValues.push(graph.getVertexValue(valueVertex));
|
|
}
|
|
return shallowValues;
|
|
}
|
|
function shallowOperation(graph, vertex, values) {
|
|
const pathArray = graph.getPathArray(vertex);
|
|
const hasUserOption = graph.hasUserOption(pathArray);
|
|
if (!hasUserOption && values.length === 1) {
|
|
return graph.resolveVertexValue(vertex, values[0]);
|
|
}
|
|
const shallowValues = [];
|
|
for (const valueVertex of values) {
|
|
shallowValues.push(graph.getVertexValue(valueVertex));
|
|
}
|
|
if (hasUserOption) {
|
|
graph.prune(vertex, [OVERRIDES_EDGE, DEFAULTS_EDGE]);
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
graph.graftObject(vertex, shallowValues);
|
|
return RESOLVED_TO_BRANCH;
|
|
}
|
|
function valueOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.getVertexValue(valueVertex);
|
|
const pathArray = graph.getPathArray(vertex);
|
|
if (value === "$index") {
|
|
return getPathLastIndex(pathArray);
|
|
}
|
|
if (value === "$parentIndex") {
|
|
return getPathLastIndex(pathArray, 1);
|
|
}
|
|
if (value === "$1") {
|
|
return graph.resolveValue$1(pathArray);
|
|
}
|
|
}
|
|
var numericOperations = {
|
|
$isEven: isEvenOperation
|
|
};
|
|
function isEvenOperation(graph, vertex, values) {
|
|
const [valueVertex] = values;
|
|
const value = graph.resolveVertexValue(vertex, valueVertex);
|
|
if (Number.isNaN(Number(value)))
|
|
return false;
|
|
return Number(value) % 2 === 0;
|
|
}
|
|
var operations = {
|
|
...cacheOperations,
|
|
...chartOperations,
|
|
...colorOperations,
|
|
...fontOperations,
|
|
...locationOperations,
|
|
...logicOperations,
|
|
...numericOperations,
|
|
...transformOperations
|
|
};
|
|
var operationTypes = new Set(Object.keys(operations));
|
|
function isOperation(value) {
|
|
return operationTypes.has(value);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/module/optionsGraph.ts
|
|
var debug2 = import_ag_charts_core183.Debug.create("opts", "options-graph");
|
|
var createOptionsGraph = (0, import_ag_charts_core183.simpleMemorize)(createOptionsGraphFn);
|
|
function createOptionsGraphFn(theme, options) {
|
|
return debug2.group("OptionsGraph.constructor()", () => {
|
|
const optionsGraph = new OptionsGraph(
|
|
theme.config,
|
|
options,
|
|
theme.params,
|
|
theme.palette,
|
|
theme.overrides,
|
|
theme.getTemplateParameters()
|
|
);
|
|
return {
|
|
resolve() {
|
|
return optionsGraph.resolve();
|
|
},
|
|
resolveParams() {
|
|
return optionsGraph.resolveParams();
|
|
},
|
|
resolveAnnotationThemes() {
|
|
return optionsGraph.resolveAnnotationThemes();
|
|
},
|
|
resolvePartial(path, partialOptions, resolveOptions) {
|
|
return optionsGraph.resolvePartial(path, partialOptions, resolveOptions);
|
|
},
|
|
clearSafe() {
|
|
return optionsGraph.clearSafe();
|
|
}
|
|
};
|
|
});
|
|
}
|
|
var _OptionsGraph = class _OptionsGraph extends import_ag_charts_core183.AdjacencyListGraph {
|
|
constructor(config = {}, userOptions = {}, params = void 0, palette = {}, overrides = void 0, internalParams = /* @__PURE__ */ new Map()) {
|
|
super(PATH_EDGE, OPERATION_EDGE, /* @__PURE__ */ new Set([USER_PARTIAL_OPTIONS_EDGE, USER_OPTIONS_EDGE]));
|
|
this.config = config;
|
|
this.userOptions = userOptions;
|
|
this.palette = palette;
|
|
this.overrides = overrides;
|
|
this.internalParams = internalParams;
|
|
// The current priority order in which to resolve options values.
|
|
this.edgePriority = [..._OptionsGraph.EDGE_PRIORITY];
|
|
// The edge value to use when grafting new branches onto the graph from operations.
|
|
this.graftEdge = _OptionsGraph.GRAFT_EDGE;
|
|
this.resolvedParams = {};
|
|
this.resolvedAnnotations = {};
|
|
// The current value referenced by operations that use `$1`.
|
|
this.value$1 = /* @__PURE__ */ new Map();
|
|
this.cachedPathVertices = /* @__PURE__ */ new Map();
|
|
this.hasUnsafeClearKeys = false;
|
|
this.rollbackVertices = [];
|
|
this.rollbackEdgesFrom = [];
|
|
this.rollbackEdgesTo = [];
|
|
this.rollbackEdgesValue = [];
|
|
this.isRollingBack = false;
|
|
// Records the already resolved root ancestors, i.e. vertices with a path of a single segment
|
|
this.resolvedRootAncestorsPaths = /* @__PURE__ */ new Set();
|
|
this.EMPTY_PATH_ARRAY_VERTEX = this.addVertex([]);
|
|
this.root = this.addVertex("root");
|
|
this.params = this.addVertex("params");
|
|
this.annotations = this.addVertex("annotations");
|
|
this.paletteType = (0, import_ag_charts_core183.isObject)(userOptions?.theme) ? paletteType(userOptions.theme?.palette) : "inbuilt";
|
|
const seriesType = userOptions.series?.[0]?.type ?? "line";
|
|
debug2("build user");
|
|
this.buildGraphFromObject(this.root, USER_OPTIONS_EDGE, (0, import_ag_charts_core183.without)(userOptions, ["theme"]));
|
|
debug2("build defaults");
|
|
this.buildGraphFromObject(this.root, DEFAULTS_EDGE, (0, import_ag_charts_core183.without)(config[seriesType], _OptionsGraph.COMPLEX_KEYS));
|
|
const seriesOverrides = overrides ? (0, import_ag_charts_core183.without)(overrides[seriesType], _OptionsGraph.COMPLEX_KEYS) : {};
|
|
if (Object.keys(seriesOverrides).length > 0) {
|
|
debug2("build series overrides");
|
|
this.buildGraphFromObject(this.root, OVERRIDES_EDGE, seriesOverrides);
|
|
}
|
|
const commonOverrides = overrides ? (0, import_ag_charts_core183.without)(overrides.common, _OptionsGraph.COMPLEX_KEYS) : {};
|
|
if (Object.keys(commonOverrides).length > 0) {
|
|
debug2("build common overrides");
|
|
this.buildGraphFromObject(
|
|
this.root,
|
|
OVERRIDES_EDGE,
|
|
import_ag_charts_core183.ModuleRegistry.getSeriesModule(seriesType)?.chartType === "cartesian" ? commonOverrides : (0, import_ag_charts_core183.without)(commonOverrides, ["zoom", "navigator"])
|
|
);
|
|
}
|
|
if (params) {
|
|
debug2("build params");
|
|
this.buildGraphFromObject(this.params, DEFAULTS_EDGE, params);
|
|
}
|
|
const axesVertex = this.findNeighbourWithValue(this.root, "axes", PATH_EDGE);
|
|
const seriesVertex = this.findNeighbourWithValue(this.root, "series", PATH_EDGE);
|
|
if (axesVertex) {
|
|
debug2("build axes");
|
|
this.buildGraphFromObject(axesVertex, DEFAULTS_EDGE, {
|
|
$applyTheme: [
|
|
["/$seriesType/axes/$axisType/$position", "/$seriesType/axes/$axisType"],
|
|
{
|
|
seriesType: { $path: ["/series/0/type", "line"] },
|
|
axisType: { $path: ["./type", "category"] },
|
|
position: { $path: ["./position"] }
|
|
},
|
|
["top", "right", "bottom", "left"]
|
|
]
|
|
});
|
|
}
|
|
if (seriesVertex) {
|
|
debug2("build series");
|
|
this.buildGraphFromObject(seriesVertex, DEFAULTS_EDGE, {
|
|
$applyTheme: ["/$seriesType/series", { seriesType: { $path: ["./type", "line"] } }]
|
|
});
|
|
}
|
|
const annotationsTypeConfig = (0, import_ag_charts_core183.without)(
|
|
config[seriesType]?.annotations ?? {},
|
|
_OptionsGraph.ANNOTATIONS_OPTIONS_KEYS
|
|
);
|
|
if (Object.keys(annotationsTypeConfig).length > 0) {
|
|
debug2("build annotations type config");
|
|
this.buildGraphFromObject(this.annotations, DEFAULTS_EDGE, annotationsTypeConfig);
|
|
}
|
|
const annotationsTypeOverrides = (0, import_ag_charts_core183.without)(
|
|
overrides?.common?.annotations ?? {},
|
|
_OptionsGraph.ANNOTATIONS_OPTIONS_KEYS
|
|
);
|
|
if (Object.keys(annotationsTypeOverrides).length > 0) {
|
|
debug2("build annotations type overrides");
|
|
this.buildGraphFromObject(this.annotations, OVERRIDES_EDGE, annotationsTypeOverrides);
|
|
}
|
|
const annotationsConfig = (0, import_ag_charts_core183.pick)(config[seriesType]?.annotations ?? {}, _OptionsGraph.ANNOTATIONS_OPTIONS_KEYS);
|
|
if (Object.keys(annotationsConfig).length > 0) {
|
|
debug2("build annotations config");
|
|
this.buildGraphFromObject(this.root, DEFAULTS_EDGE, { annotations: annotationsConfig });
|
|
}
|
|
const annotationsOverrides = (0, import_ag_charts_core183.pick)(overrides?.common?.annotations ?? {}, _OptionsGraph.ANNOTATIONS_OPTIONS_KEYS);
|
|
if (Object.keys(annotationsOverrides).length > 0) {
|
|
debug2("build annotations overrides");
|
|
this.buildGraphFromObject(this.root, OVERRIDES_EDGE, { annotations: annotationsOverrides });
|
|
}
|
|
this.buildDependencyGraph();
|
|
}
|
|
static clearValueCache() {
|
|
_OptionsGraph.valueCache.clear();
|
|
}
|
|
clear() {
|
|
debug2.group("OptionsGraph.clear()", () => {
|
|
super.clear();
|
|
this.cachedPathVertices.clear();
|
|
this.root = void 0;
|
|
this.params = void 0;
|
|
this.annotations = void 0;
|
|
debug2("cleared");
|
|
});
|
|
}
|
|
clearSafe() {
|
|
if (this.hasUnsafeClearKeys)
|
|
return;
|
|
this.clear();
|
|
}
|
|
resolve() {
|
|
return debug2.group("OptionsGraph.resolve()", () => {
|
|
this.resolved = {};
|
|
this.resolvedParams = {};
|
|
this.resolvedAnnotations = {};
|
|
debug2("resolve params");
|
|
this.resolveVertex(this.params, this.resolvedParams);
|
|
debug2("resolve annotations");
|
|
this.resolveVertex(this.annotations, this.resolvedAnnotations);
|
|
debug2("resolve root");
|
|
this.resolveVertex(this.root);
|
|
debug2("resolved root", this.resolved);
|
|
debug2("vertex count", this.getVertexCount());
|
|
debug2("edge count", this.getEdgeCount());
|
|
return this.resolved;
|
|
});
|
|
}
|
|
resolveParams() {
|
|
return this.resolvedParams;
|
|
}
|
|
resolveAnnotationThemes() {
|
|
return this.resolvedAnnotations;
|
|
}
|
|
addVertex(value) {
|
|
const vertex = super.addVertex(value);
|
|
if (this.isRollingBack) {
|
|
this.rollbackVertices.push(vertex);
|
|
}
|
|
return vertex;
|
|
}
|
|
addEdge(from, to, edge) {
|
|
const hasEdge = (this.neighboursWithEdgeValue(from, edge)?.indexOf(to) ?? -1) !== -1;
|
|
if (this.isRollingBack && !hasEdge) {
|
|
this.rollbackEdgesFrom.push(from);
|
|
this.rollbackEdgesTo.push(to);
|
|
this.rollbackEdgesValue.push(edge);
|
|
}
|
|
super.addEdge(from, to, edge);
|
|
}
|
|
/**
|
|
* Resolve partial options against the existing graph at a given path without overriding the existing user values.
|
|
* Returns an object with only those keys that were also present within `partialOptions`.
|
|
*/
|
|
resolvePartial(path, partialOptions, resolveOptions) {
|
|
if (!partialOptions)
|
|
return;
|
|
if (!this.root)
|
|
return;
|
|
const { permissivePath, proxyPaths } = resolveOptions ?? {};
|
|
const partialKeys = Object.keys(partialOptions);
|
|
if (debug2.check()) {
|
|
console.groupCollapsed(`OptionsGraph.resolvePartial() - ${path.join(".")} [${partialKeys}]`);
|
|
}
|
|
if (partialKeys.length === 0)
|
|
return {};
|
|
const parentVertex = this.findVertexAtPath(path);
|
|
if (!parentVertex) {
|
|
if (permissivePath) {
|
|
return void 0;
|
|
} else {
|
|
throw new Error(`Could not find vertex in OptionsGraph at path [${path.join(".")}].`);
|
|
}
|
|
}
|
|
const pathArrayVertex = this.findNeighbour(parentVertex, PATH_ARRAY_EDGE);
|
|
this.userPartialOptions = {};
|
|
setPathSafe(this.userPartialOptions, path, partialOptions);
|
|
if (proxyPaths) {
|
|
for (const proxyFrom of Object.keys(proxyPaths)) {
|
|
const proxyTo = proxyPaths[proxyFrom];
|
|
const proxyValue = getPathSafe(partialOptions, [proxyFrom]);
|
|
if (proxyValue != null) {
|
|
setPathSafe(partialOptions, proxyTo, proxyValue);
|
|
setPathSafe(this.userPartialOptions, [...path, ...proxyTo], proxyValue);
|
|
delete partialOptions[proxyFrom];
|
|
delete this.userPartialOptions[proxyFrom];
|
|
}
|
|
}
|
|
}
|
|
this.graftEdge = USER_PARTIAL_OPTIONS_EDGE;
|
|
this.edgePriority = [USER_PARTIAL_OPTIONS_EDGE, ..._OptionsGraph.EDGE_PRIORITY];
|
|
this.snapshot();
|
|
this.buildGraphFromObject(parentVertex, USER_PARTIAL_OPTIONS_EDGE, partialOptions, pathArrayVertex);
|
|
for (const key of partialKeys) {
|
|
const childVertex = proxyPaths?.[key] ? this.findVertexAtPath([...path, ...proxyPaths[key]]) : this.findNeighbourWithValue(parentVertex, key, PATH_EDGE);
|
|
if (childVertex) {
|
|
this.refreshPendingProcessingEdges(childVertex);
|
|
}
|
|
}
|
|
this.buildDependencyGraph();
|
|
const resolved = {};
|
|
this.resolveVertex(parentVertex, resolved);
|
|
this.rollback();
|
|
this.graftEdge = _OptionsGraph.GRAFT_EDGE;
|
|
this.edgePriority = _OptionsGraph.EDGE_PRIORITY;
|
|
this.userPartialOptions = void 0;
|
|
if (proxyPaths) {
|
|
for (const proxyFrom of Object.keys(proxyPaths)) {
|
|
const proxyTo = proxyPaths[proxyFrom];
|
|
const proxyValue = getPathSafe(resolved, [...path, ...proxyTo]);
|
|
setPathSafe(resolved, [...path, proxyFrom], proxyValue);
|
|
}
|
|
}
|
|
const pathed = getPathSafe(resolved, path);
|
|
const shouldPick = resolveOptions?.pick ?? true;
|
|
const partial = shouldPick ? (0, import_ag_charts_core183.pick)(getPathSafe(resolved, path), partialKeys) : pathed;
|
|
debug2("vertex count", this.getVertexCount());
|
|
debug2("edge count", this.getEdgeCount());
|
|
debug2("resolved partial", partial);
|
|
if (debug2.check()) {
|
|
console.groupEnd();
|
|
}
|
|
return partial;
|
|
}
|
|
findVertexAtPath(path) {
|
|
const key = path.join(".");
|
|
if (this.cachedPathVertices.has(key)) {
|
|
return this.cachedPathVertices.get(key);
|
|
}
|
|
const vertex = this.findVertexAlongEdge(this.root, path, PATH_EDGE);
|
|
if (!vertex)
|
|
return;
|
|
this.cachedPathVertices.set(key, vertex);
|
|
return vertex;
|
|
}
|
|
hasUserOption(path) {
|
|
const hasUserOptionSimple = hasPathSafe(this.userOptions, path);
|
|
if (hasUserOptionSimple)
|
|
return true;
|
|
const pathVertex = this.findVertexAtPath(path);
|
|
if (pathVertex) {
|
|
if (this.findNeighbour(pathVertex, USER_OPTIONS_EDGE) != null)
|
|
return true;
|
|
if (this.findNeighbour(pathVertex, USER_PARTIAL_OPTIONS_EDGE) != null)
|
|
return true;
|
|
const childrenSource = this.findNeighbourValue(pathVertex, CHILDREN_SOURCE_EDGE);
|
|
return childrenSource === USER_OPTIONS_EDGE || childrenSource === USER_PARTIAL_OPTIONS_EDGE;
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* Get the value from the user options at the given path. This method is dangerous since it does not resolve
|
|
* through the graph, however is useful for operations that operate on their own path where attempting to
|
|
* resolve would cause an infinite loop.
|
|
*/
|
|
dangerouslyGetUserOption(path) {
|
|
if (this.userPartialOptions) {
|
|
const value = getPathSafe(this.userPartialOptions, path);
|
|
if (value != null)
|
|
return value;
|
|
}
|
|
return getPathSafe(this.userOptions, path);
|
|
}
|
|
hasThemeOverride(path) {
|
|
if (this.overrides == null)
|
|
return false;
|
|
if (path[0] === "axes" && path.length > 1) {
|
|
const axisType = this.getResolvedPath(["axes", path[1], "type"]);
|
|
if (hasPathSafe(this.overrides, ["common", "axes", axisType, ...path.slice(2)])) {
|
|
return true;
|
|
}
|
|
const seriesType = this.getResolvedPath(["series", "0", "type"]);
|
|
return hasPathSafe(this.overrides, [seriesType, "axes", axisType, ...path.slice(2)]);
|
|
}
|
|
if (path[0] === "series" && path.length > 1) {
|
|
const seriesType = this.getResolvedPath(["series", path[1], "type"]);
|
|
return hasPathSafe(this.overrides, [seriesType, "series", ...path.slice(2)]);
|
|
}
|
|
return hasPathSafe(this.overrides, path);
|
|
}
|
|
getParamValue(path) {
|
|
if (this.resolvedParams[path] != null) {
|
|
return this.resolvedParams[path];
|
|
}
|
|
const paramVertex = this.findVertexAlongEdge(this.params, [path], PATH_EDGE);
|
|
if (!paramVertex)
|
|
return;
|
|
const defaultValueVertex = this.findNeighbour(paramVertex, DEFAULTS_EDGE);
|
|
if (!defaultValueVertex)
|
|
return;
|
|
const resolved = this.resolveVertexValue(paramVertex, defaultValueVertex);
|
|
this.resolvedParams[path] = resolved;
|
|
return resolved;
|
|
}
|
|
getPathArray(vertex) {
|
|
return this.findNeighbourValue(vertex, PATH_ARRAY_EDGE) ?? [];
|
|
}
|
|
getResolvedPath(path) {
|
|
return getPathSafe(this.resolved, path);
|
|
}
|
|
getCachedValue(path, key) {
|
|
const cacheKey = [...path, key].join(".");
|
|
return _OptionsGraph.valueCache.get(cacheKey);
|
|
}
|
|
setCachedValue(path, key, value) {
|
|
const cacheKey = [...path, key].join(".");
|
|
_OptionsGraph.valueCache.set(cacheKey, value);
|
|
}
|
|
prune(vertex, edges) {
|
|
this.addEdge(vertex, this.addVertex(edges), PRUNE_EDGE);
|
|
}
|
|
resolveVertexValue(vertex, valueVertex) {
|
|
this.resolveVertexDependencies(valueVertex);
|
|
const operation = this.findNeighbourValue(valueVertex, OPERATION_EDGE);
|
|
if (operation && isOperation(operation)) {
|
|
const operationValues = this.neighboursWithEdgeValue(valueVertex, OPERATION_VALUE_EDGE);
|
|
const operator = operations[operation];
|
|
const operatorFn = typeof operator === "function" ? operator : operator.resolve;
|
|
const resolved = operatorFn?.(this, vertex, operationValues ?? []);
|
|
return resolved === RESOLVED_TO_BRANCH ? void 0 : resolved;
|
|
}
|
|
let value = this.getVertexValue(valueVertex);
|
|
if (Array.isArray(value)) {
|
|
const object5 = {};
|
|
this.resolveVertexChildren(valueVertex, object5);
|
|
value = getPathSafe(object5, this.getPathArray(vertex));
|
|
}
|
|
return this.resolveValueOrSymbol(value);
|
|
}
|
|
/**
|
|
* Resolve the value currently referenced by `$1` by the nearest self-or-ancestor that has a defined value.
|
|
*/
|
|
resolveValue$1(pathArray) {
|
|
for (let i = pathArray.length; i >= 0; i--) {
|
|
const key = pathArray.slice(0, i).join(".");
|
|
const resolvedValue = this.value$1.get(key);
|
|
if (resolvedValue != void 0) {
|
|
return resolvedValue;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Graft a branch of the theme config onto the target vertex.
|
|
*/
|
|
graftConfig(target, configPathArray, ignorePaths) {
|
|
const targetConfigObject = getPathSafe(this.config, configPathArray);
|
|
const targetPathArrayVertex = this.findNeighbour(target, PATH_ARRAY_EDGE);
|
|
if ((0, import_ag_charts_core183.isObject)(targetConfigObject)) {
|
|
this.buildGraphFromObject(
|
|
target,
|
|
DEFAULTS_EDGE,
|
|
targetConfigObject,
|
|
targetPathArrayVertex,
|
|
void 0,
|
|
ignorePaths
|
|
);
|
|
}
|
|
if (this.overrides) {
|
|
const targetOverridesObject = getPathSafe(this.overrides, configPathArray);
|
|
if ((0, import_ag_charts_core183.isObject)(targetOverridesObject)) {
|
|
this.buildGraphFromObject(
|
|
target,
|
|
OVERRIDES_EDGE,
|
|
targetOverridesObject,
|
|
targetPathArrayVertex,
|
|
void 0,
|
|
ignorePaths
|
|
);
|
|
}
|
|
const commonOverridesObject = getPathSafe(this.overrides, ["common", ...configPathArray.slice(1)]);
|
|
if ((0, import_ag_charts_core183.isObject)(commonOverridesObject)) {
|
|
this.buildGraphFromObject(
|
|
target,
|
|
OVERRIDES_EDGE,
|
|
commonOverridesObject,
|
|
targetPathArrayVertex,
|
|
void 0,
|
|
ignorePaths
|
|
);
|
|
}
|
|
}
|
|
this.buildDependencyGraph();
|
|
}
|
|
/**
|
|
* Graft a given object onto the target vertex.
|
|
*/
|
|
graftObject(target, object5, overridesPathArrays, edgeValue = this.graftEdge) {
|
|
const pathArrayVertex = this.findNeighbour(target, PATH_ARRAY_EDGE);
|
|
this.buildGraphFromObject(target, edgeValue, object5, pathArrayVertex);
|
|
if (this.overrides && overridesPathArrays) {
|
|
for (const overridePathArray of overridesPathArrays) {
|
|
if (overridePathArray == null)
|
|
continue;
|
|
const overrides = getPathSafe(this.overrides, overridePathArray);
|
|
if (overrides) {
|
|
this.buildGraphFromObject(target, OVERRIDES_EDGE, overrides, pathArrayVertex);
|
|
}
|
|
}
|
|
}
|
|
this.buildDependencyGraph();
|
|
}
|
|
/**
|
|
* Graft a given operation and value onto `path` child of the target vertex. The `ontoObject` value is built onto
|
|
* the graph each time this function is called, at the given path, while `value` is used for value$1 where
|
|
* `ontoObject` is an operation that invokes value$1.
|
|
*/
|
|
graftValue(target, path, ontoObject, value, edgeValue = this.graftEdge) {
|
|
const pathArray = [...this.getPathArray(target), path];
|
|
const pathVertex = this.findVertexAtPath(pathArray) ?? this.addVertex(path);
|
|
this.value$1.set(pathArray.join("."), value);
|
|
this.buildGraphFromValue(target, pathVertex, edgeValue, pathArray, ontoObject);
|
|
this.buildDependencyGraph();
|
|
}
|
|
/**
|
|
* Resolve a branch as if it were a child of the context vertex, but without attaching it to the resolved root.
|
|
*/
|
|
graftAndResolveOrphan(context, branch) {
|
|
const orphan = {};
|
|
const orphanVertex = this.addVertex(orphan);
|
|
const contextPathArray = this.getPathArray(context);
|
|
this.graftAndResolveChildren(branch, orphanVertex, contextPathArray, []);
|
|
this.resolveVertex(orphanVertex, orphan);
|
|
return getPathSafe(orphan, contextPathArray);
|
|
}
|
|
/**
|
|
* Resolve a value as if it were a child of the context vertex, but without attaching it to the resolved root.
|
|
*/
|
|
graftAndResolveOrphanValue(context, path, ontoObject, value, edgeValue = this.graftEdge) {
|
|
const orphan = {};
|
|
const orphanVertex = this.addVertex(orphan);
|
|
const contextPathArray = this.getPathArray(context);
|
|
const pathArray = [...contextPathArray, path];
|
|
const pathVertex = this.findVertexAtPath(pathArray) ?? this.addVertex(path);
|
|
this.value$1.set(pathArray.join("."), value);
|
|
this.buildGraphFromValue(orphanVertex, pathVertex, edgeValue, pathArray, ontoObject);
|
|
this.resolveVertex(orphanVertex, orphan);
|
|
return getPathSafe(orphan, pathArray);
|
|
}
|
|
buildGraphFromObject(parentVertex, edgeValue, object5, pathArrayVertex, shallowPaths = _OptionsGraph.SHALLOW_KEYS, ignorePaths) {
|
|
const keys = Object.keys(object5);
|
|
const operation = getOperation(object5, keys);
|
|
if (operation) {
|
|
const valueVertex = this.addVertex(object5);
|
|
this.addEdge(parentVertex, valueVertex, edgeValue);
|
|
this.buildGraphFromOperation(valueVertex, edgeValue, operation, pathArrayVertex);
|
|
return;
|
|
}
|
|
if (keys.length === 0) {
|
|
this.addEdge(parentVertex, this.addVertex(Array.isArray(object5) ? [] : {}), edgeValue);
|
|
this.buildGraphAutoEnable(parentVertex, edgeValue, object5, void 0);
|
|
return;
|
|
}
|
|
const pathVertices = this.getVertexChildrenByKey(parentVertex);
|
|
const pathArray = pathArrayVertex ? this.getVertexValue(pathArrayVertex) : [];
|
|
let enabledVertex;
|
|
if (Array.isArray(object5)) {
|
|
this.addEdge(parentVertex, this.addVertex(edgeValue), CHILDREN_SOURCE_EDGE);
|
|
}
|
|
const childPathArray = [...pathArray];
|
|
const pathArrayLength = pathArray.length;
|
|
for (const key of keys) {
|
|
if (ignorePaths?.has(key))
|
|
continue;
|
|
const childPathVertex = pathVertices?.get(key) ?? this.addVertex(key);
|
|
childPathArray[pathArrayLength] = key;
|
|
if (shallowPaths?.has(key)) {
|
|
this.buildShallowGraphFromValue(parentVertex, childPathVertex, edgeValue, childPathArray, object5[key]);
|
|
} else {
|
|
this.buildGraphFromValue(
|
|
parentVertex,
|
|
childPathVertex,
|
|
edgeValue,
|
|
childPathArray,
|
|
object5[key],
|
|
shallowPaths
|
|
);
|
|
}
|
|
if (key === "enabled") {
|
|
enabledVertex = childPathVertex;
|
|
}
|
|
}
|
|
this.buildGraphAutoEnable(parentVertex, edgeValue, object5, enabledVertex);
|
|
}
|
|
buildGraphAutoEnable(parentVertex, edgeValue, object5, enabledVertex) {
|
|
if (edgeValue === DEFAULTS_EDGE && !enabledVertex)
|
|
return;
|
|
if (edgeValue === USER_OPTIONS_EDGE && enabledVertex)
|
|
return;
|
|
if (edgeValue !== DEFAULTS_EDGE && edgeValue !== USER_OPTIONS_EDGE && edgeValue !== USER_PARTIAL_OPTIONS_EDGE && edgeValue !== OVERRIDES_EDGE)
|
|
return;
|
|
let autoEnableVertex = this.findNeighbour(parentVertex, AUTO_ENABLE_EDGE);
|
|
if (!autoEnableVertex) {
|
|
autoEnableVertex = this.addVertex(AUTO_ENABLE_EDGE);
|
|
this.addEdge(parentVertex, autoEnableVertex, AUTO_ENABLE_EDGE);
|
|
}
|
|
if (enabledVertex) {
|
|
this.addEdge(enabledVertex, autoEnableVertex, AUTO_ENABLE_VALUE_EDGE);
|
|
}
|
|
const { enabled, _enabledFromTheme } = object5;
|
|
this.addEdge(
|
|
autoEnableVertex,
|
|
this.addVertex({ enabled, _enabledFromTheme, keys: Object.keys(object5).length }),
|
|
edgeValue
|
|
);
|
|
}
|
|
getVertexChildrenByKey(vertex) {
|
|
const pathNeighbours = this.neighboursWithEdgeValue(vertex, PATH_EDGE);
|
|
if (!pathNeighbours)
|
|
return;
|
|
const pathVertices = /* @__PURE__ */ new Map();
|
|
for (const neighbour of pathNeighbours) {
|
|
pathVertices.set(this.getVertexValue(neighbour), neighbour);
|
|
}
|
|
return pathVertices;
|
|
}
|
|
buildGraphFromValue(parentVertex, pathVertex, edgeValue, pathArray, value, shallowPaths) {
|
|
this.addEdge(parentVertex, pathVertex, PATH_EDGE);
|
|
let pathArrayVertex = this.findNeighbour(pathVertex, PATH_ARRAY_EDGE);
|
|
if (!pathArrayVertex) {
|
|
pathArrayVertex = this.addVertex([...pathArray]);
|
|
this.addEdge(pathVertex, pathArrayVertex, PATH_ARRAY_EDGE);
|
|
}
|
|
const operation = getOperation(value);
|
|
if (operation) {
|
|
const valueVertex = this.addVertex(value);
|
|
this.addEdge(pathVertex, valueVertex, edgeValue);
|
|
this.addEdge(valueVertex, pathArrayVertex, PATH_ARRAY_EDGE);
|
|
this.buildGraphFromOperation(valueVertex, edgeValue, operation, pathArrayVertex);
|
|
} else if ((0, import_ag_charts_core183.isObjectLike)(value)) {
|
|
this.buildGraphFromObject(pathVertex, edgeValue, value, pathArrayVertex, shallowPaths);
|
|
} else {
|
|
const neighbour = this.findNeighbour(pathVertex, edgeValue);
|
|
if (neighbour && this.getVertexValue(neighbour) === value) {
|
|
return;
|
|
}
|
|
const valueVertex = this.addVertex(value);
|
|
this.addEdge(pathVertex, valueVertex, edgeValue);
|
|
}
|
|
}
|
|
buildShallowGraphFromValue(parentVertex, pathVertex, edgeValue, pathArray, value) {
|
|
this.addEdge(parentVertex, pathVertex, PATH_EDGE);
|
|
let pathArrayVertex = this.findNeighbour(pathVertex, PATH_ARRAY_EDGE);
|
|
if (!pathArrayVertex) {
|
|
pathArrayVertex = this.addVertex([...pathArray]);
|
|
this.addEdge(pathVertex, pathArrayVertex, PATH_ARRAY_EDGE);
|
|
}
|
|
const valueVertex = this.addVertex(value);
|
|
this.addEdge(pathVertex, valueVertex, edgeValue);
|
|
}
|
|
buildGraphFromOperation(valueVertex, edgeValue, operation, pathArrayVertex) {
|
|
const operationVertex = this.addVertex(operation.operation);
|
|
this.addEdge(valueVertex, operationVertex, OPERATION_EDGE);
|
|
for (const operationValue of operation.values) {
|
|
this.buildGraphFromOperationValue(valueVertex, operationValue, edgeValue, pathArrayVertex);
|
|
}
|
|
}
|
|
buildGraphFromOperationValue(valueVertex, operationValue, edgeValue, pathArrayVertex = this.EMPTY_PATH_ARRAY_VERTEX) {
|
|
const operationValueVertex = this.addVertex(operationValue);
|
|
this.addEdge(valueVertex, pathArrayVertex, PATH_ARRAY_EDGE);
|
|
this.addEdge(valueVertex, operationValueVertex, OPERATION_VALUE_EDGE);
|
|
const innerOperation = getOperation(operationValue);
|
|
if (innerOperation) {
|
|
this.buildGraphFromOperation(operationValueVertex, edgeValue, innerOperation, pathArrayVertex);
|
|
} else if ((0, import_ag_charts_core183.isObjectLike)(operationValue)) {
|
|
this.buildGraphFromObject(operationValueVertex, edgeValue, operationValue, pathArrayVertex);
|
|
}
|
|
}
|
|
/**
|
|
* Add dependency edges on operations that require other vertices to be resolved before the operation can be
|
|
* resolved. Then clear the list of pending edges.
|
|
*/
|
|
buildDependencyGraph() {
|
|
for (let i = 0; i < this.pendingProcessingEdgesFrom.length; i++) {
|
|
const valueVertex = this.pendingProcessingEdgesFrom[i];
|
|
const operationKeyVertex = this.pendingProcessingEdgesTo[i];
|
|
const operation = this.getVertexValue(operationKeyVertex);
|
|
if (!isOperation(operation))
|
|
continue;
|
|
const operationValues = this.neighboursWithEdgeValue(valueVertex, OPERATION_VALUE_EDGE);
|
|
const operator = operations[operation];
|
|
const dependenciesFn = typeof operator === "function" ? void 0 : operator.dependencies;
|
|
dependenciesFn?.(this, valueVertex, operationValues ?? []);
|
|
}
|
|
this.pendingProcessingEdgesFrom = [];
|
|
this.pendingProcessingEdgesTo = [];
|
|
}
|
|
/**
|
|
* Within the branch starting at the given vertex, reassign any value vertices and their operation key vertices to
|
|
* the pending processing edges. These can then be built with `this.buildDependencyGraph()`.
|
|
*/
|
|
refreshPendingProcessingEdges(vertex) {
|
|
const defaultValueVertex = this.findNeighbour(vertex, DEFAULTS_EDGE);
|
|
const valueVertex = defaultValueVertex ?? vertex;
|
|
const operationVertex = this.findNeighbour(valueVertex, OPERATION_EDGE);
|
|
if (operationVertex) {
|
|
this.pendingProcessingEdgesFrom.push(valueVertex);
|
|
this.pendingProcessingEdgesTo.push(operationVertex);
|
|
const neighbours2 = this.neighboursWithEdgeValue(valueVertex, OPERATION_VALUE_EDGE);
|
|
if (neighbours2) {
|
|
for (const neighbour of neighbours2) {
|
|
this.refreshPendingProcessingEdges(neighbour);
|
|
}
|
|
}
|
|
}
|
|
const neighbours = this.neighboursWithEdgeValue(vertex, PATH_EDGE);
|
|
if (neighbours) {
|
|
for (const neighbour of neighbours) {
|
|
this.refreshPendingProcessingEdges(neighbour);
|
|
}
|
|
}
|
|
}
|
|
resolveVertex(vertex, object5 = this.resolved, prune) {
|
|
const pathArray = this.getPathArray(vertex);
|
|
const rootAncestorPath = pathArray[0];
|
|
if (pathArray.length === 1) {
|
|
this.resolvedRootAncestorsPaths.add(rootAncestorPath);
|
|
}
|
|
if (pathArray.length > 1 && !this.resolvedRootAncestorsPaths.has(rootAncestorPath)) {
|
|
const rootAncestorVertex = this.findVertexAtPath([rootAncestorPath]);
|
|
if (rootAncestorVertex) {
|
|
this.resolveVertex(rootAncestorVertex, object5, prune);
|
|
return;
|
|
}
|
|
}
|
|
if (this.userPartialOptions == null && object5 === this.resolved && pathArray.length > 0) {
|
|
const resolvedVertexValue = getPathSafe(object5, pathArray);
|
|
if (resolvedVertexValue != null && !(0, import_ag_charts_core183.isPlainObject)(resolvedVertexValue)) {
|
|
return;
|
|
}
|
|
}
|
|
this.resolveVertexInEdgePriority(vertex, object5, pathArray, prune);
|
|
this.resolveVertexAutoEnable(vertex, object5, pathArray);
|
|
this.resolveVertexChildren(vertex, object5, prune);
|
|
}
|
|
resolveVertexInEdgePriority(vertex, object5, pathArray, prune) {
|
|
const children = this.neighboursWithEdgeValue(vertex, PATH_EDGE);
|
|
const [highestPriority] = this.edgePriority;
|
|
for (const edgeValue of this.edgePriority) {
|
|
const valueVertex = this.findNeighbour(vertex, edgeValue);
|
|
if (valueVertex == null)
|
|
continue;
|
|
const value = this.resolveVertexValueInternal(vertex, valueVertex);
|
|
if (value == null && edgeValue !== highestPriority)
|
|
continue;
|
|
if (children && children.length > 0 && edgeValue !== highestPriority)
|
|
continue;
|
|
if (Array.isArray(prune) && prune.includes(edgeValue))
|
|
continue;
|
|
this.hasUnsafeClearKeys || (this.hasUnsafeClearKeys = value != null && _OptionsGraph.UNSAFE_CLEAR_KEYS.has(pathArray.at(-1)));
|
|
if (pathArray.length === 0) {
|
|
if (value == null)
|
|
continue;
|
|
this.resolved = value;
|
|
} else {
|
|
setPathSafe(object5, pathArray, value);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
resolveVertexValueInternal(vertex, valueVertex) {
|
|
this.resolveVertexDependencies(valueVertex);
|
|
const operation = this.findNeighbourValue(valueVertex, OPERATION_EDGE);
|
|
if (operation && isOperation(operation)) {
|
|
const operationValues = this.neighboursWithEdgeValue(valueVertex, OPERATION_VALUE_EDGE);
|
|
const operator = operations[operation];
|
|
const operatorFn = typeof operator === "function" ? operator : operator.resolve;
|
|
const resolved = operatorFn?.(this, vertex, operationValues ?? []);
|
|
return resolved === RESOLVED_TO_BRANCH ? void 0 : resolved;
|
|
}
|
|
return this.resolveValueOrSymbol(this.getVertexValue(valueVertex));
|
|
}
|
|
resolveVertexAutoEnable(vertex, object5, pathArray) {
|
|
const autoEnableValueVertex = this.neighboursWithEdgeValue(vertex, AUTO_ENABLE_VALUE_EDGE)?.[0];
|
|
if (!autoEnableValueVertex)
|
|
return;
|
|
const pathVertex = this.findVertexAtPath(pathArray);
|
|
const defaultsEnabled = this.findNeighbourValue(autoEnableValueVertex, DEFAULTS_EDGE);
|
|
const overridesEnabled = this.findNeighbourValue(autoEnableValueVertex, OVERRIDES_EDGE);
|
|
const userOptionsEnabled = this.findNeighbourValue(autoEnableValueVertex, USER_OPTIONS_EDGE);
|
|
const hasUserOptionEnabled = pathVertex && this.findNeighbour(pathVertex, USER_OPTIONS_EDGE) != null;
|
|
const userPartialOptionsEnabled = hasUserOptionEnabled ? void 0 : this.findNeighbourValue(autoEnableValueVertex, USER_PARTIAL_OPTIONS_EDGE);
|
|
const isUserEnabled = userOptionsEnabled != null && userOptionsEnabled.enabled == null || userPartialOptionsEnabled != null && userPartialOptionsEnabled.enabled == null;
|
|
if (isUserEnabled && !defaultsEnabled?._enabledFromTheme && !overridesEnabled?._enabledFromTheme) {
|
|
setPathSafe(object5, pathArray, true);
|
|
}
|
|
}
|
|
resolveVertexChildren(vertex, object5, prune) {
|
|
const children = this.neighboursWithEdgeValue(vertex, PATH_EDGE);
|
|
if (!children)
|
|
return;
|
|
prune ?? (prune = this.findNeighbourValue(vertex, PRUNE_EDGE));
|
|
for (const child of children) {
|
|
const path = this.getVertexValue(child);
|
|
if (children.length > 1 && isOperation(path))
|
|
continue;
|
|
if (path === "_enabledFromTheme")
|
|
continue;
|
|
this.resolveVertex(child, object5, prune);
|
|
}
|
|
}
|
|
resolveVertexDependencies(vertex) {
|
|
const dependencies = this.neighboursWithEdgeValue(vertex, DEPENDENCY_EDGE);
|
|
if (!dependencies)
|
|
return;
|
|
for (const dependency of dependencies) {
|
|
this.resolveVertex(dependency);
|
|
}
|
|
}
|
|
graftAndResolveChildren(remoteBranch, orphanBranch, contextPathArray, orphanPathArray) {
|
|
const remoteChildren = this.neighboursWithEdgeValue(remoteBranch, PATH_EDGE);
|
|
if (!remoteChildren)
|
|
return;
|
|
for (const remoteChild of remoteChildren) {
|
|
const remoteChildPath = this.getVertexValue(remoteChild);
|
|
const childContextPathArray = [...contextPathArray, remoteChildPath];
|
|
const childOrphanPathArray = [...orphanPathArray, remoteChildPath];
|
|
const orphanChildPathVertex = this.addVertex(remoteChildPath);
|
|
const defaultValue = this.findNeighbourValue(remoteChild, DEFAULTS_EDGE);
|
|
this.addEdge(orphanBranch, orphanChildPathVertex, PATH_EDGE);
|
|
const orphanChildPathArrayVertex = this.addVertex(childContextPathArray);
|
|
this.addEdge(orphanChildPathVertex, orphanChildPathArrayVertex, PATH_ARRAY_EDGE);
|
|
if ((0, import_ag_charts_core183.isObject)(defaultValue)) {
|
|
this.buildGraphFromObject(
|
|
orphanChildPathVertex,
|
|
DEFAULTS_EDGE,
|
|
defaultValue,
|
|
orphanChildPathArrayVertex
|
|
);
|
|
const orphanChildValueVertex = this.findNeighbour(orphanChildPathVertex, DEFAULTS_EDGE);
|
|
this.addEdge(orphanChildValueVertex, this.addVertex(childContextPathArray), PATH_ARRAY_EDGE);
|
|
const operation = this.findNeighbourValue(orphanChildValueVertex, OPERATION_EDGE);
|
|
if (isOperation(operation)) {
|
|
const operationValues = this.neighboursWithEdgeValue(orphanChildValueVertex, OPERATION_VALUE_EDGE);
|
|
const operator = operations[operation];
|
|
const dependenciesFn = typeof operator === "function" ? void 0 : operator.dependencies;
|
|
dependenciesFn?.(this, orphanChildValueVertex, operationValues ?? []);
|
|
}
|
|
}
|
|
this.graftAndResolveChildren(
|
|
remoteChild,
|
|
orphanChildPathVertex,
|
|
childContextPathArray,
|
|
childOrphanPathArray
|
|
);
|
|
}
|
|
}
|
|
resolveValueOrSymbol(value) {
|
|
return typeof value === "symbol" && this.internalParams?.has(value) ? this.internalParams.get(value) : value;
|
|
}
|
|
snapshot() {
|
|
debug2(`snapshot`);
|
|
this.isRollingBack = true;
|
|
}
|
|
rollback() {
|
|
debug2(`rollback ${this.rollbackEdgesFrom.length} edges and ${this.rollbackVertices.length} vertices`);
|
|
for (let i = 0; i < this.rollbackEdgesFrom.length; i++) {
|
|
const from = this.rollbackEdgesFrom[i];
|
|
const to = this.rollbackEdgesTo[i];
|
|
const edgeValue = this.rollbackEdgesValue[i];
|
|
this.removeEdge(from, to, edgeValue);
|
|
}
|
|
for (const vertex of this.rollbackVertices) {
|
|
this.removeVertex(vertex);
|
|
}
|
|
this.cachedPathVertices.clear();
|
|
this.rollbackVertices = [];
|
|
this.rollbackEdgesFrom = [];
|
|
this.rollbackEdgesTo = [];
|
|
this.rollbackEdgesValue = [];
|
|
this.isRollingBack = false;
|
|
}
|
|
/**
|
|
* Console log a flowchart diagram of the graph at the given path.
|
|
*/
|
|
diagram(pathArray, maxDepth = 2) {
|
|
this.diagramKeys = /* @__PURE__ */ new Map();
|
|
this.diagramEdges = /* @__PURE__ */ new Map();
|
|
const vertex = this.findVertexAtPath(pathArray);
|
|
const diagram = [
|
|
"---",
|
|
"config:",
|
|
" layout: elk",
|
|
" look: neo",
|
|
" theme: redux",
|
|
"---",
|
|
"flowchart TB"
|
|
];
|
|
if (vertex) {
|
|
this.diagramVertex(diagram, vertex, 1, maxDepth);
|
|
}
|
|
diagram.push("classDef UO fill: #e8f5e8, stroke: #4caf50");
|
|
diagram.push("classDef DE fill: #e3f2fd, stroke: #2196f3");
|
|
diagram.push("classDef DEP fill: #ffe0fd, stroke: #ff00f2");
|
|
diagram.push("classDef OP fill: #fff3e0, stroke: #ff9800");
|
|
diagram.push("classDef OPV fill: #fff3e0, stroke: #ff9800, stroke-width: 1px");
|
|
diagram.push("classDef OV fill: #e8f5ee, stroke: #4caf87");
|
|
console.log(diagram.join("\n"));
|
|
}
|
|
diagramKey(path) {
|
|
let diagramKey = this.diagramKeys.get(path);
|
|
if (!diagramKey) {
|
|
diagramKey = `${this.diagramKeys.size}`;
|
|
this.diagramKeys.set(path, diagramKey);
|
|
}
|
|
return diagramKey;
|
|
}
|
|
diagramLabel(path, vertex, edge) {
|
|
let diagramKey = this.diagramKeys.get(path);
|
|
if (diagramKey)
|
|
return diagramKey;
|
|
diagramKey = this.diagramKey(path);
|
|
const classNames = {
|
|
[USER_OPTIONS_EDGE]: "UO",
|
|
[DEFAULTS_EDGE]: "DE",
|
|
[DEPENDENCY_EDGE]: "DEP",
|
|
[OPERATION_EDGE]: "OP",
|
|
[OPERATION_VALUE_EDGE]: "OPV",
|
|
[OVERRIDES_EDGE]: "OV"
|
|
};
|
|
let className = edge ? classNames[edge] ?? void 0 : void 0;
|
|
className = className ? `:::${className}` : "";
|
|
if (typeof vertex.value === "symbol") {
|
|
return `${diagramKey}[/"[symbol]"\\]${className}`;
|
|
} else if (Array.isArray(vertex.value)) {
|
|
return `${diagramKey}[/"[array]"\\]${className}`;
|
|
} else if (typeof vertex.value === "object") {
|
|
return `${diagramKey}[/"[object]"\\]${className}`;
|
|
} else if (edge === DEFAULTS_EDGE || edge === USER_OPTIONS_EDGE || edge === OVERRIDES_EDGE) {
|
|
return `${diagramKey}("${vertex.value}")${className}`;
|
|
} else {
|
|
return `${diagramKey}["${vertex.value}"]${className}`;
|
|
}
|
|
}
|
|
diagramVertex(diagram, vertex, depth, maxDepth) {
|
|
const pathArray = this.getPathArray(vertex);
|
|
const path = pathArray.length > 0 ? pathArray.join(".") : "root";
|
|
this.diagramNeighbours(diagram, path, vertex, depth + 1, maxDepth);
|
|
let diagramKey = this.diagramKeys.get(path);
|
|
if (!diagramKey) {
|
|
diagramKey = this.diagramKey(path);
|
|
diagram.push(` ${diagramKey}["${vertex.value}"]`);
|
|
}
|
|
}
|
|
diagramNeighbours(diagram, path, vertex, depth, maxDepth) {
|
|
for (const neighbour of this.neighboursWithEdgeValue(vertex, PATH_EDGE) ?? []) {
|
|
const neighbourPathArray = this.getPathArray(neighbour);
|
|
const neighbourPath = neighbourPathArray.length > 0 ? neighbourPathArray.join(".") : "root";
|
|
if (depth < maxDepth) {
|
|
this.diagramVertex(diagram, neighbour, depth + 1, maxDepth);
|
|
}
|
|
this.diagramChild(diagram, PATH_EDGE, path, vertex, neighbourPath, vertex);
|
|
}
|
|
const userValues = this.neighboursWithEdgeValue(vertex, USER_OPTIONS_EDGE) ?? [];
|
|
let index = 0;
|
|
for (const userValue of userValues) {
|
|
this.diagramChild(
|
|
diagram,
|
|
USER_OPTIONS_EDGE,
|
|
path,
|
|
vertex,
|
|
`${path}.${USER_OPTIONS_EDGE}.${index}`,
|
|
userValue
|
|
);
|
|
index++;
|
|
}
|
|
const defaultValues = this.neighboursWithEdgeValue(vertex, DEFAULTS_EDGE) ?? [];
|
|
index = 0;
|
|
for (const defaultValue of defaultValues) {
|
|
this.diagramChildWithNeighbours(
|
|
diagram,
|
|
DEFAULTS_EDGE,
|
|
path,
|
|
vertex,
|
|
`${path}.${DEFAULTS_EDGE}.${index}`,
|
|
defaultValue,
|
|
depth + 1,
|
|
maxDepth
|
|
);
|
|
index++;
|
|
}
|
|
const operationVertices = this.neighboursWithEdgeValue(vertex, OPERATION_EDGE) ?? [];
|
|
index = 0;
|
|
const [operation] = operationVertices;
|
|
if (operation) {
|
|
this.diagramChildWithNeighbours(
|
|
diagram,
|
|
OPERATION_EDGE,
|
|
path,
|
|
vertex,
|
|
`${path}.${OPERATION_EDGE}.${index}`,
|
|
operation,
|
|
depth + 1,
|
|
maxDepth
|
|
);
|
|
index++;
|
|
}
|
|
const operationValueVertices = this.neighboursWithEdgeValue(vertex, OPERATION_VALUE_EDGE) ?? [];
|
|
index = 0;
|
|
for (const operationValue of operationValueVertices) {
|
|
this.diagramChildWithNeighbours(
|
|
diagram,
|
|
OPERATION_VALUE_EDGE,
|
|
path,
|
|
vertex,
|
|
`${path}.${OPERATION_VALUE_EDGE}.${index}`,
|
|
operationValue,
|
|
depth + 1,
|
|
maxDepth
|
|
);
|
|
index++;
|
|
}
|
|
const dependencyVertices = this.neighboursWithEdgeValue(vertex, DEPENDENCY_EDGE) ?? [];
|
|
index = 0;
|
|
for (const dependency of dependencyVertices) {
|
|
this.diagramChildWithNeighbours(
|
|
diagram,
|
|
DEPENDENCY_EDGE,
|
|
path,
|
|
vertex,
|
|
this.getPathArray(dependency).join("."),
|
|
dependency,
|
|
depth + 1,
|
|
maxDepth
|
|
);
|
|
index++;
|
|
}
|
|
}
|
|
diagramChild(diagram, edge, parentPath, parentVertex, childPath, childVertex) {
|
|
let edges = this.diagramEdges.get(parentPath);
|
|
if (edges?.has(childPath))
|
|
return;
|
|
if (!edges) {
|
|
edges = /* @__PURE__ */ new Set();
|
|
this.diagramEdges.set(parentPath, edges);
|
|
}
|
|
edges.add(childPath);
|
|
const edgeString = edge === PATH_EDGE ? "" : `|${edge}|`;
|
|
diagram.push(
|
|
` ${this.diagramLabel(parentPath, parentVertex)} -->${edgeString} ${this.diagramLabel(childPath, childVertex, edge)}`
|
|
);
|
|
}
|
|
diagramChildWithNeighbours(diagram, edge, parentPath, parentVertex, childPath, childVertex, depth, maxDepth) {
|
|
this.diagramChild(diagram, edge, parentPath, parentVertex, childPath, childVertex);
|
|
this.diagramNeighbours(diagram, childPath, childVertex, depth + 1, maxDepth);
|
|
}
|
|
};
|
|
// The default priority order in which to resolve options values.
|
|
_OptionsGraph.EDGE_PRIORITY = [USER_OPTIONS_EDGE, OVERRIDES_EDGE, DEFAULTS_EDGE];
|
|
_OptionsGraph.GRAFT_EDGE = DEFAULTS_EDGE;
|
|
// These keys must be stored as shallow objects in the graph and not manipulated.
|
|
_OptionsGraph.SHALLOW_KEYS = /* @__PURE__ */ new Set(["context", "data", "topology"]);
|
|
// These keys must be excluded when building the graph, they are instead resolved separately since they are objects
|
|
// that must be applied to arrays.
|
|
_OptionsGraph.COMPLEX_KEYS = ["annotations", "axes", "series"];
|
|
_OptionsGraph.ANNOTATIONS_OPTIONS_KEYS = [
|
|
"axesButtons",
|
|
"data",
|
|
"enabled",
|
|
"optionsToolbar",
|
|
"snap",
|
|
"toolbar",
|
|
"xKey",
|
|
"volumeKey"
|
|
];
|
|
// If any of these keys are present in the resolved object then calling `clearSafe()` will not clear the graph.
|
|
_OptionsGraph.UNSAFE_CLEAR_KEYS = /* @__PURE__ */ new Set(["itemStyler", "styler"]);
|
|
// A cache of values that persists between chart updates, use sparingly.
|
|
_OptionsGraph.valueCache = /* @__PURE__ */ new Map();
|
|
var OptionsGraph = _OptionsGraph;
|
|
|
|
// packages/ag-charts-community/src/module/optionsModule.ts
|
|
var stringFormat = (value) => `'${value}'`;
|
|
var AXIS_ID_PREFIX = "__AXIS_ID_";
|
|
var POSITION_DIRECTIONS = {
|
|
top: import_ag_charts_core184.ChartAxisDirection.X,
|
|
bottom: import_ag_charts_core184.ChartAxisDirection.X,
|
|
left: import_ag_charts_core184.ChartAxisDirection.Y,
|
|
right: import_ag_charts_core184.ChartAxisDirection.Y
|
|
};
|
|
var _ChartOptions = class _ChartOptions {
|
|
constructor(currentUserOptions, newUserOptions, processedOverrides, specialOverrides, metadata, deltaOptions, stripSymbols = false, apiStartTime) {
|
|
this.themeParameters = {};
|
|
this.optionMetadata = metadata ?? {};
|
|
this.processedOverrides = processedOverrides ?? {};
|
|
let baseChartOptions = null;
|
|
if (currentUserOptions instanceof _ChartOptions) {
|
|
baseChartOptions = currentUserOptions;
|
|
this.specialOverrides = baseChartOptions.specialOverrides;
|
|
if (deltaOptions) {
|
|
this.userDeltaKeys = new Set(Object.keys(deltaOptions));
|
|
}
|
|
deltaOptions ?? (deltaOptions = (0, import_ag_charts_core184.jsonDiff)(
|
|
baseChartOptions.userOptions,
|
|
newUserOptions,
|
|
_ChartOptions.JSON_DIFF_OPTS
|
|
));
|
|
this.userOptions = (0, import_ag_charts_core184.deepClone)((0, import_ag_charts_core184.merge)(deltaOptions, baseChartOptions.userOptions), {
|
|
..._ChartOptions.OPTIONS_CLONE_OPTS_SLOW,
|
|
seen: []
|
|
});
|
|
} else {
|
|
this.userOptions = (0, import_ag_charts_core184.deepClone)(currentUserOptions ?? newUserOptions, {
|
|
..._ChartOptions.OPTIONS_CLONE_OPTS_SLOW,
|
|
seen: []
|
|
});
|
|
this.specialOverrides = this.specialOverridesDefaults({ ...specialOverrides });
|
|
}
|
|
this.findSeriesWithUserVisiblity(newUserOptions, deltaOptions);
|
|
if (stripSymbols) {
|
|
this.removeLeftoverSymbols(this.userOptions);
|
|
}
|
|
const dataChangedLength = currentUserOptions instanceof _ChartOptions && deltaOptions?.data !== void 0 && deltaOptions?.data?.length !== currentUserOptions.userOptions.data?.length;
|
|
let activeTheme, processedOptions, fastDelta, themeParameters, annotationThemes, googleFonts, optionsGraph;
|
|
if (!stripSymbols && this.seriesWithUserVisibility == void 0 && deltaOptions !== void 0 && _ChartOptions.isFastPathDelta(deltaOptions) && baseChartOptions != null && !dataChangedLength) {
|
|
({ activeTheme, processedOptions, fastDelta } = this.fastSetup(deltaOptions, baseChartOptions));
|
|
themeParameters = baseChartOptions.themeParameters;
|
|
annotationThemes = baseChartOptions.annotationThemes;
|
|
} else {
|
|
_ChartOptions.perfDebug(`ChartOptions.slowSetup()`);
|
|
({ activeTheme, processedOptions, themeParameters, annotationThemes, googleFonts, optionsGraph } = this.slowSetup(processedOverrides, deltaOptions, stripSymbols));
|
|
}
|
|
this.activeTheme = activeTheme;
|
|
this.processedOptions = processedOptions;
|
|
this.fastDelta = fastDelta ?? void 0;
|
|
this.themeParameters = themeParameters;
|
|
this.annotationThemes = annotationThemes;
|
|
this.googleFonts = googleFonts;
|
|
this.optionsGraph = optionsGraph;
|
|
if (apiStartTime !== void 0 && typeof apiStartTime === "number" && !Number.isNaN(apiStartTime)) {
|
|
const endTime = performance.now();
|
|
this.optionsProcessingTime = endTime - apiStartTime;
|
|
}
|
|
import_ag_charts_core184.Debug.inDevelopmentMode(() => (0, import_ag_charts_core184.deepFreeze)(this));
|
|
}
|
|
static isFastPathDelta(deltaOptions) {
|
|
for (const key of Object.keys(deltaOptions ?? {})) {
|
|
if (!this.FAST_PATH_OPTIONS.has(key)) {
|
|
_ChartOptions.perfDebug("ChartOptions.isFastPathDelta() - slow path required due to presence of: ", key);
|
|
return false;
|
|
}
|
|
}
|
|
_ChartOptions.perfDebug(`ChartOptions.isFastPathDelta() - fast path possible.`);
|
|
return true;
|
|
}
|
|
findSeriesWithUserVisiblity(newUserOptions, deltaOptions) {
|
|
for (const o of [newUserOptions, deltaOptions]) {
|
|
const series = o?.series;
|
|
if (!Array.isArray(series))
|
|
continue;
|
|
for (let index = 0; index < series.length; index++) {
|
|
const s = series[index];
|
|
if (!("visible" in s))
|
|
continue;
|
|
this.seriesWithUserVisibility ?? (this.seriesWithUserVisibility = {
|
|
identifiers: /* @__PURE__ */ new Set(),
|
|
indices: /* @__PURE__ */ new Set()
|
|
});
|
|
if (s.id) {
|
|
this.seriesWithUserVisibility.identifiers.add(s.id);
|
|
} else {
|
|
this.seriesWithUserVisibility.indices.add(index);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fastSetup(deltaOptions, baseChartOptions) {
|
|
const { activeTheme, processedOptions: baseOptions } = baseChartOptions;
|
|
const { presetType } = this.optionMetadata;
|
|
if (presetType != null && deltaOptions?.data != null) {
|
|
const presetDef = import_ag_charts_core184.ModuleRegistry.getPresetModule(presetType);
|
|
if (presetDef?.processData) {
|
|
const { series, data } = presetDef.processData(deltaOptions.data);
|
|
deltaOptions = (0, import_ag_charts_core184.mergeDefaults)({ series, data }, deltaOptions);
|
|
}
|
|
}
|
|
this.fastSeriesSetup(deltaOptions, baseOptions);
|
|
const processedOptions = (0, import_ag_charts_core184.mergeDefaults)(deltaOptions, baseOptions);
|
|
_ChartOptions.debug("ChartOptions.fastSetup() - processed options", processedOptions);
|
|
return { activeTheme, processedOptions, fastDelta: deltaOptions };
|
|
}
|
|
fastSeriesSetup(deltaOptions, baseOptions) {
|
|
if (!deltaOptions?.series)
|
|
return;
|
|
if (deltaOptions.series?.every((s, i) => (0, import_ag_charts_core184.jsonPropertyCompare)(s, baseOptions.series?.[i] ?? {}))) {
|
|
delete deltaOptions["series"];
|
|
} else {
|
|
deltaOptions.series = deltaOptions.series.map((s, i) => {
|
|
return (0, import_ag_charts_core184.merge)(s, baseOptions.series?.[i] ?? {});
|
|
});
|
|
}
|
|
}
|
|
slowSetup(processedOverrides, deltaOptions, stripSymbols = false) {
|
|
let options = (0, import_ag_charts_core184.deepClone)(this.userOptions, _ChartOptions.OPTIONS_CLONE_OPTS_FAST);
|
|
if (deltaOptions) {
|
|
options = (0, import_ag_charts_core184.mergeDefaults)(deltaOptions, options);
|
|
if (stripSymbols) {
|
|
this.removeLeftoverSymbols(options);
|
|
}
|
|
}
|
|
let activeTheme = sanitizeThemeModules(getChartTheme(options.theme));
|
|
const { presetType } = this.optionMetadata;
|
|
if (presetType != null) {
|
|
const presetDef = import_ag_charts_core184.ModuleRegistry.getPresetModule(presetType);
|
|
if (presetDef) {
|
|
const { validate: validatePreset = import_ag_charts_core184.validate } = presetDef;
|
|
const presetParams = options;
|
|
const presetSubType = options.type;
|
|
const presetTheme = presetSubType == null ? void 0 : activeTheme.presets[presetSubType];
|
|
const { cleared, invalid } = validatePreset(presetParams, presetDef.options, "");
|
|
for (const error of invalid) {
|
|
import_ag_charts_core184.Logger.warn(error);
|
|
}
|
|
if ((0, import_ag_charts_core184.hasRequiredInPath)(invalid, "")) {
|
|
options = {};
|
|
} else {
|
|
_ChartOptions.debug(">>> AgCharts.createOrUpdate() - applying preset", cleared);
|
|
options = presetDef.create(cleared, presetTheme, () => this.activeTheme);
|
|
activeTheme = sanitizeThemeModules(getChartTheme(options.theme));
|
|
}
|
|
}
|
|
}
|
|
this.soloSeriesIntegrity(options);
|
|
if (presetType != null) {
|
|
activeTheme.templateTheme(options, false);
|
|
}
|
|
removeIncompatibleModuleOptions(void 0, options);
|
|
const missingSeriesModules = this.validateSeriesOptions(options);
|
|
const chartType = detectChartType(options);
|
|
this.chartDef = import_ag_charts_core184.ModuleRegistry.getChartModule(chartType);
|
|
if (!this.chartDef.placeholder) {
|
|
const { validate: validateChart = import_ag_charts_core184.validate } = this.chartDef;
|
|
const { cleared, invalid } = validateChart(options, this.chartDef.options, "");
|
|
for (const error of invalid) {
|
|
import_ag_charts_core184.Logger.warn(error);
|
|
}
|
|
options = cleared;
|
|
}
|
|
this.validateAxesOptions(options);
|
|
this.removeDisabledOptions(options);
|
|
let googleFonts = this.processFonts(activeTheme.params);
|
|
googleFonts = this.processFonts(options, googleFonts);
|
|
this.processSeriesOptions(options);
|
|
const unmappedAxisKeys = this.processAxesOptions(options, chartType);
|
|
const optionsGraph = createOptionsGraph(activeTheme, options);
|
|
const resolvedOptions = optionsGraph.resolve();
|
|
const themeParameters = optionsGraph.resolveParams();
|
|
const annotationThemes = optionsGraph.resolveAnnotationThemes();
|
|
optionsGraph.clearSafe();
|
|
const processedOptions = (0, import_ag_charts_core184.mergeDefaults)(processedOverrides, resolvedOptions);
|
|
removeIncompatibleModuleOptions(this.chartDef.name, processedOptions);
|
|
processModuleOptions(this.chartDef.name, processedOptions, missingSeriesModules);
|
|
this.validateSeriesOptions(processedOptions);
|
|
this.validateAxesOptions(processedOptions, unmappedAxisKeys);
|
|
this.validatePluginOptions(processedOptions);
|
|
this.processMiniChartSeriesOptions(processedOptions);
|
|
if (!processedOptions.loadGoogleFonts) {
|
|
googleFonts.clear();
|
|
}
|
|
_ChartOptions.debug(() => ["ChartOptions.slowSetup() - processed options", (0, import_ag_charts_core184.deepClone)(processedOptions)]);
|
|
return { activeTheme, processedOptions, themeParameters, annotationThemes, googleFonts, optionsGraph };
|
|
}
|
|
validatePluginOptions(options) {
|
|
for (const pluginDef of import_ag_charts_core184.ModuleRegistry.listModulesByType(import_ag_charts_core184.ModuleType.Plugin)) {
|
|
const pluginKey = pluginDef.name;
|
|
if (pluginKey in options && pluginDef.options != null && (!pluginDef.chartType || pluginDef.chartType === this.chartDef?.name)) {
|
|
const { cleared, invalid } = (0, import_ag_charts_core184.validate)(options[pluginKey], pluginDef.options, pluginDef.name);
|
|
for (const error of invalid) {
|
|
import_ag_charts_core184.Logger.warn(error);
|
|
}
|
|
options[pluginKey] = cleared;
|
|
}
|
|
}
|
|
}
|
|
validateSeriesOptions(options) {
|
|
const chartType = this.chartDef?.name;
|
|
const validatedSeriesOptions = [];
|
|
const seriesCount = options.series?.length ?? 0;
|
|
const missingModules = [];
|
|
let validSeriesTypes;
|
|
for (let index = 0; index < seriesCount; index++) {
|
|
const keyPath = `series[${index}]`;
|
|
const seriesOptions = options.series[index];
|
|
const seriesDef = import_ag_charts_core184.ModuleRegistry.getSeriesModule(seriesOptions.type);
|
|
if (seriesDef == null) {
|
|
const isEnterprise = import_ag_charts_core184.ModuleRegistry.isEnterprise();
|
|
validSeriesTypes ?? (validSeriesTypes = (0, import_ag_charts_core184.joinFormatted)(
|
|
Array.from(ExpectedModules.values()).filter(
|
|
(def) => def.type === import_ag_charts_core184.ModuleType.Series && (isEnterprise || !def.enterprise) && (!chartType || def.chartType === chartType)
|
|
).map((def) => def.name),
|
|
"or",
|
|
stringFormat
|
|
));
|
|
const modulePlaceholder = ExpectedModules.get(seriesOptions.type);
|
|
if (seriesOptions.type != null && modulePlaceholder?.type === import_ag_charts_core184.ModuleType.Series) {
|
|
missingModules.push(modulePlaceholder);
|
|
continue;
|
|
}
|
|
import_ag_charts_core184.Logger.warn(
|
|
seriesOptions.type == null ? `Option \`${keyPath}.type\` is required and has not been provided; expecting ${validSeriesTypes}, ignoring.` : `Unknown type \`${seriesOptions.type}\` at \`${keyPath}.type\`; expecting ${validSeriesTypes}, ignoring.`
|
|
);
|
|
continue;
|
|
} else if (chartType && seriesDef.chartType !== chartType) {
|
|
import_ag_charts_core184.Logger.warn(
|
|
`Series type \`${seriesDef.name}\` at \`${keyPath}.type\` is not supported by chart type \`${chartType}\`, ignoring.`
|
|
);
|
|
continue;
|
|
}
|
|
if (seriesDef.options == null) {
|
|
validatedSeriesOptions.push(seriesOptions);
|
|
continue;
|
|
}
|
|
const { validate: validateSeries = import_ag_charts_core184.validate } = seriesDef;
|
|
const { cleared, invalid } = validateSeries(seriesOptions, seriesDef.options, keyPath);
|
|
for (const error of invalid) {
|
|
import_ag_charts_core184.Logger.warn(error);
|
|
}
|
|
if (!(0, import_ag_charts_core184.hasRequiredInPath)(invalid, keyPath)) {
|
|
validatedSeriesOptions.push(cleared);
|
|
}
|
|
}
|
|
options.series = validatedSeriesOptions;
|
|
return missingModules;
|
|
}
|
|
validateAxesOptions(options, unmappedAxisKeys) {
|
|
if (!("axes" in options) || !options.axes)
|
|
return;
|
|
const chartType = this.chartDef?.name;
|
|
const validatedAxesOptions = {};
|
|
let validAxesTypes;
|
|
for (const [key, axisOptions] of (0, import_ag_charts_core184.entries)(options.axes)) {
|
|
if (!axisOptions)
|
|
continue;
|
|
if (axisOptions.type == null) {
|
|
validatedAxesOptions[key] = axisOptions;
|
|
continue;
|
|
}
|
|
const keyPath = `axes.${unmappedAxisKeys?.get(key) ?? key}`;
|
|
const axisDef = import_ag_charts_core184.ModuleRegistry.getAxisModule(axisOptions.type);
|
|
if (axisDef == null) {
|
|
const isEnterprise = import_ag_charts_core184.ModuleRegistry.isEnterprise();
|
|
validAxesTypes ?? (validAxesTypes = (0, import_ag_charts_core184.joinFormatted)(
|
|
Array.from(ExpectedModules.values()).filter(
|
|
(def) => def.type === import_ag_charts_core184.ModuleType.Axis && (isEnterprise || !def.enterprise) && def.chartType === chartType
|
|
).map((def) => def.name),
|
|
"or",
|
|
stringFormat
|
|
));
|
|
const modulePlaceholder = ExpectedModules.get(axisOptions.type);
|
|
if (modulePlaceholder?.type !== import_ag_charts_core184.ModuleType.Axis) {
|
|
import_ag_charts_core184.Logger.warn(
|
|
`Unknown type \`${axisOptions.type}\` at \`${keyPath}.type\`; expecting one of ${validAxesTypes}, ignoring.`
|
|
);
|
|
}
|
|
continue;
|
|
} else if (axisDef.chartType !== chartType) {
|
|
import_ag_charts_core184.Logger.warn(
|
|
`Axis type \`${axisDef.name}\` at \`${keyPath}.type\` is not supported by chart type \`${chartType}\`, ignoring.`
|
|
);
|
|
break;
|
|
}
|
|
const { validate: validateAxis = import_ag_charts_core184.validate } = axisDef;
|
|
const { cleared, invalid } = validateAxis(axisOptions, axisDef.options, keyPath);
|
|
for (const error of invalid) {
|
|
import_ag_charts_core184.Logger.warn(error);
|
|
}
|
|
if (!(0, import_ag_charts_core184.hasRequiredInPath)(invalid, keyPath)) {
|
|
validatedAxesOptions[key] = cleared;
|
|
}
|
|
}
|
|
options.axes = validatedAxesOptions;
|
|
}
|
|
diffOptions(other) {
|
|
if (this === other)
|
|
return {};
|
|
if (other == null)
|
|
return this.processedOptions;
|
|
return this.fastDelta ?? (0, import_ag_charts_core184.jsonDiff)(other.processedOptions, this.processedOptions, _ChartOptions.JSON_DIFF_OPTS);
|
|
}
|
|
optionsType(options) {
|
|
return options.series?.[0]?.type ?? "line";
|
|
}
|
|
processSeriesOptions(options) {
|
|
const displayNullData = options.displayNullData;
|
|
const processedSeries = options.series?.map((series) => {
|
|
const seriesDef = import_ag_charts_core184.ModuleRegistry.getSeriesModule(series.type);
|
|
const visibleDefined = Boolean(seriesDef?.options?.visible);
|
|
const seriesDefaults = {};
|
|
if (visibleDefined) {
|
|
seriesDefaults.visible = true;
|
|
}
|
|
if (displayNullData !== void 0 && series.allowNullKeys === void 0) {
|
|
seriesDefaults.allowNullKeys = displayNullData;
|
|
}
|
|
return (0, import_ag_charts_core184.mergeDefaults)(this.getSeriesGroupingOptions(series), series, seriesDefaults);
|
|
});
|
|
options.series = this.setSeriesGroupingOptions(processedSeries ?? []);
|
|
}
|
|
/**
|
|
* Collates axis keys from the axis and series options to determine the full set of axis keys, defaults series to
|
|
* the primary axes and renames the primary axes to the internal direction-based names.
|
|
*/
|
|
processAxesOptions(options, chartType) {
|
|
const directions2 = chartType === "polar" ? [import_ag_charts_core184.ChartAxisDirection.Angle, import_ag_charts_core184.ChartAxisDirection.Radius] : [import_ag_charts_core184.ChartAxisDirection.X, import_ag_charts_core184.ChartAxisDirection.Y];
|
|
const hasAxes = "axes" in options && Object.keys(options.axes ?? {}).length > 0;
|
|
const nonDefaultSeriesAxisKeysCount = this.countNonDefaultSeriesAxisKeys(options, directions2);
|
|
const hasNonDefaultSeriesAxisKeys = nonDefaultSeriesAxisKeysCount > 0;
|
|
const hasExtraImplicitDefaultSeriesAxisKeys = hasNonDefaultSeriesAxisKeys && nonDefaultSeriesAxisKeysCount < (options?.series?.length ?? 0);
|
|
const primarySeriesOptions = options.series?.[0];
|
|
const seriesType = this.optionsType(options);
|
|
const defaultAxes = this.predictAxes(seriesType, directions2, primarySeriesOptions, options.data) ?? this.cloneDefaultAxes(seriesType);
|
|
const isPrimarySeriesFlipped = (0, import_ag_charts_core184.isObject)(primarySeriesOptions) && "direction" in primarySeriesOptions && primarySeriesOptions.direction === "horizontal" && import_ag_charts_core184.ModuleRegistry.getSeriesModule(primarySeriesOptions.type)?.axisKeysFlipped != null;
|
|
if (!hasAxes && !hasNonDefaultSeriesAxisKeys && !isPrimarySeriesFlipped) {
|
|
options.axes = defaultAxes;
|
|
return;
|
|
}
|
|
const axisKeys = "axes" in options ? new Set(Object.keys(options.axes ?? {})) : /* @__PURE__ */ new Set();
|
|
const primaryAxisKeys = this.getPrimaryAxisKeys(options, directions2, axisKeys, hasNonDefaultSeriesAxisKeys);
|
|
const remappedAxisKeys = this.getRemappedAxisKeys(
|
|
axisKeys,
|
|
primaryAxisKeys,
|
|
directions2,
|
|
hasExtraImplicitDefaultSeriesAxisKeys
|
|
);
|
|
const newAxes = {};
|
|
const unmappedAxisKeys = /* @__PURE__ */ new Map();
|
|
for (const [fromAxisKey, toAxisKey] of remappedAxisKeys) {
|
|
newAxes[toAxisKey] = "axes" in options ? (0, import_ag_charts_core184.shallowClone)(options.axes?.[fromAxisKey]) : void 0;
|
|
unmappedAxisKeys.set(toAxisKey, fromAxisKey);
|
|
}
|
|
this.remapSeriesAxisKeys(
|
|
options,
|
|
directions2,
|
|
newAxes,
|
|
remappedAxisKeys,
|
|
defaultAxes,
|
|
hasExtraImplicitDefaultSeriesAxisKeys
|
|
);
|
|
this.predictAxesMissingTypesAndPositions(options, directions2, newAxes, defaultAxes);
|
|
this.alternateSecondaryAxisPositions(options, newAxes, unmappedAxisKeys);
|
|
options.axes = newAxes;
|
|
return unmappedAxisKeys;
|
|
}
|
|
/**
|
|
* These keys are used to map a series to an axis for each direction. They are retrieved per-series to allow a
|
|
* mixture of flipped and non-flipped series within the same chart.
|
|
*/
|
|
getSeriesDirectionAxisKey(seriesOptions, direction) {
|
|
const seriesModule = import_ag_charts_core184.ModuleRegistry.getSeriesModule(seriesOptions.type);
|
|
if (!seriesModule)
|
|
return;
|
|
const isFlipped = "direction" in seriesOptions && seriesOptions.direction === "horizontal";
|
|
return isFlipped && seriesModule.axisKeysFlipped ? seriesModule.axisKeysFlipped[direction] : seriesModule.axisKeys?.[direction];
|
|
}
|
|
/**
|
|
* Check if any of the series' axis keys have values that do not match the expected value, i.e. the direction.
|
|
*/
|
|
countNonDefaultSeriesAxisKeys(options, directions2) {
|
|
let count = 0;
|
|
for (const seriesOptions of options.series ?? []) {
|
|
for (const direction of directions2) {
|
|
const directionAxisKey = this.getSeriesDirectionAxisKey(seriesOptions, direction);
|
|
if (!directionAxisKey || !(0, import_ag_charts_core184.isKeyOf)(directionAxisKey, seriesOptions))
|
|
continue;
|
|
if (seriesOptions[directionAxisKey] === direction)
|
|
continue;
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
/**
|
|
* The primary axes are defined, for each direction, as those first in the `axes` object or referenced by a series.
|
|
* This is irregardless of the specific key of the axis, e.g. an axis with the key `y` may have the position `top`,
|
|
* and would therefore be classified as the primary `x` axis.
|
|
*/
|
|
getPrimaryAxisKeys(options, directions2, axisKeys, hasNonDefaultSeriesAxisKeys) {
|
|
const primaryAxisKeys = /* @__PURE__ */ new Map();
|
|
for (const direction of directions2) {
|
|
let foundPrimaryAxisKey = false;
|
|
if (
|
|
// has axes
|
|
"axes" in options && options.axes && // does not have standard-name primary axis without position
|
|
!(direction in options.axes && (0, import_ag_charts_core184.isObject)(options.axes[direction]) && !("position" in options.axes[direction]))
|
|
) {
|
|
for (const [axisKey, axisOptions] of (0, import_ag_charts_core184.entries)(options.axes)) {
|
|
if ("position" in axisOptions && axisOptions.position && direction === POSITION_DIRECTIONS[axisOptions.position]) {
|
|
primaryAxisKeys.set(direction, axisKey);
|
|
foundPrimaryAxisKey = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (foundPrimaryAxisKey)
|
|
continue;
|
|
if (!hasNonDefaultSeriesAxisKeys)
|
|
continue;
|
|
for (const seriesOptions of options.series ?? []) {
|
|
const directionAxisKey = this.getSeriesDirectionAxisKey(seriesOptions, direction);
|
|
if (!directionAxisKey)
|
|
continue;
|
|
const seriesAxisKey = seriesOptions[directionAxisKey];
|
|
if (axisKeys.has(seriesAxisKey))
|
|
continue;
|
|
if (!seriesAxisKey) {
|
|
primaryAxisKeys.set(direction, direction);
|
|
break;
|
|
}
|
|
primaryAxisKeys.set(direction, seriesAxisKey);
|
|
break;
|
|
}
|
|
}
|
|
if (axisKeys.size === 0 || !("axes" in options) || !options.axes)
|
|
return primaryAxisKeys;
|
|
if (primaryAxisKeys.size === 0) {
|
|
for (const direction of directions2) {
|
|
if (direction in options.axes) {
|
|
primaryAxisKeys.set(direction, direction);
|
|
}
|
|
}
|
|
}
|
|
if (primaryAxisKeys.size === 0) {
|
|
for (const direction of directions2) {
|
|
for (const [axisKey, axisOptions] of (0, import_ag_charts_core184.entries)(options.axes)) {
|
|
if (axisOptions.type?.startsWith(direction)) {
|
|
primaryAxisKeys.set(direction, axisKey);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (primaryAxisKeys.size === 0 && (options.series?.length ?? 0) > 0) {
|
|
for (const direction of directions2) {
|
|
for (const seriesOptions of options.series) {
|
|
const directionAxisKey = this.getSeriesDirectionAxisKey(seriesOptions, direction);
|
|
if (!directionAxisKey)
|
|
continue;
|
|
const seriesAxisKey = seriesOptions[directionAxisKey];
|
|
if (!axisKeys.has(seriesAxisKey))
|
|
continue;
|
|
primaryAxisKeys.set(direction, seriesAxisKey);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (primaryAxisKeys.size < 2) {
|
|
const primaryAxisIdsFound = new Set(primaryAxisKeys.values());
|
|
for (const [axisKey, axisOptions] of (0, import_ag_charts_core184.entries)(options.axes)) {
|
|
if (primaryAxisIdsFound.has(axisKey) || "position" in axisOptions)
|
|
continue;
|
|
for (const direction of directions2) {
|
|
if (primaryAxisKeys.has(direction))
|
|
continue;
|
|
primaryAxisKeys.set(direction, axisKey);
|
|
primaryAxisIdsFound.add(axisKey);
|
|
break;
|
|
}
|
|
if (primaryAxisKeys.size === 2)
|
|
break;
|
|
}
|
|
}
|
|
return primaryAxisKeys;
|
|
}
|
|
getRemappedAxisKeys(axisKeys, primaryAxisKeys, directions2, hasExtraImplicitDefaultSeriesAxisKeys) {
|
|
const remappedAxisKeys = /* @__PURE__ */ new Map();
|
|
for (const [direction, axisKey] of primaryAxisKeys) {
|
|
remappedAxisKeys.set(axisKey, direction);
|
|
}
|
|
for (const axisKey of axisKeys) {
|
|
if (remappedAxisKeys.has(axisKey))
|
|
continue;
|
|
remappedAxisKeys.set(axisKey, `${AXIS_ID_PREFIX}${remappedAxisKeys.size}`);
|
|
}
|
|
if (hasExtraImplicitDefaultSeriesAxisKeys) {
|
|
for (const direction of directions2) {
|
|
if (!remappedAxisKeys.has(direction)) {
|
|
remappedAxisKeys.set(direction, `${AXIS_ID_PREFIX}${remappedAxisKeys.size}`);
|
|
}
|
|
}
|
|
}
|
|
return remappedAxisKeys;
|
|
}
|
|
/**
|
|
* Update each series' axis keys to match the name used internally, such as the direction or a constant suffixed by
|
|
* the index for secondary axes.
|
|
*/
|
|
remapSeriesAxisKeys(options, directions2, newAxes, remappedAxisKeys, defaultAxes, hasExtraImplicitDefaultSeriesAxisKeys) {
|
|
for (const seriesOptions of options.series ?? []) {
|
|
for (const direction of directions2) {
|
|
const directionAxisKey = this.getSeriesDirectionAxisKey(seriesOptions, direction);
|
|
if (!directionAxisKey)
|
|
continue;
|
|
newAxes[direction] ?? (newAxes[direction] = (0, import_ag_charts_core184.shallowClone)(defaultAxes[direction]));
|
|
let remappedSeriesAxisKey = direction;
|
|
if (directionAxisKey in seriesOptions) {
|
|
const seriesAxisKey = seriesOptions[directionAxisKey];
|
|
if (remappedAxisKeys.has(seriesAxisKey)) {
|
|
remappedSeriesAxisKey = remappedAxisKeys.get(seriesAxisKey);
|
|
} else {
|
|
remappedSeriesAxisKey = `${AXIS_ID_PREFIX}${remappedAxisKeys.size}`;
|
|
remappedAxisKeys.set(seriesAxisKey, remappedSeriesAxisKey);
|
|
newAxes[remappedSeriesAxisKey] = (0, import_ag_charts_core184.shallowClone)(defaultAxes[direction]);
|
|
}
|
|
} else if (remappedAxisKeys.has(direction) && hasExtraImplicitDefaultSeriesAxisKeys) {
|
|
remappedSeriesAxisKey = remappedAxisKeys.get(direction);
|
|
newAxes[remappedSeriesAxisKey] ?? (newAxes[remappedSeriesAxisKey] = (0, import_ag_charts_core184.shallowClone)(defaultAxes[direction]));
|
|
}
|
|
seriesOptions[directionAxisKey] = remappedSeriesAxisKey;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Attempt to predict the axes for each direction based on a subset of the data. Each series has its own prediction
|
|
* algorithm.
|
|
*/
|
|
predictAxes(seriesType, directions2, userSeriesOptions, data) {
|
|
if (!userSeriesOptions)
|
|
return;
|
|
const seriesData = userSeriesOptions?.data ?? data;
|
|
if (!seriesData?.length)
|
|
return;
|
|
const predictAxis = import_ag_charts_core184.ModuleRegistry.getSeriesModule(seriesType)?.predictAxis;
|
|
if (!predictAxis)
|
|
return;
|
|
const axes = /* @__PURE__ */ new Map();
|
|
const indices = (0, import_ag_charts_core184.distribute)(0, seriesData.length - 1, 5);
|
|
for (const index of indices) {
|
|
const datum = seriesData[index];
|
|
for (const direction of directions2) {
|
|
const axis = predictAxis(direction, datum, userSeriesOptions);
|
|
if (!axes.has(direction)) {
|
|
axes.set(direction, axis);
|
|
continue;
|
|
}
|
|
const prevAxis = axes.get(direction);
|
|
if (!axis && !prevAxis)
|
|
continue;
|
|
if (!axis || !prevAxis)
|
|
return;
|
|
for (const key of Object.keys(prevAxis)) {
|
|
if (prevAxis[key] !== axis[key])
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
for (const [direction, axis] of axes) {
|
|
if (!axis)
|
|
axes.delete(direction);
|
|
}
|
|
if (axes.size === 0)
|
|
return;
|
|
if (axes.size === 1) {
|
|
const [predictedAxis] = axes.values();
|
|
const defaultAxes = this.cloneDefaultAxes(seriesType);
|
|
if (!("position" in predictedAxis))
|
|
return;
|
|
return (0, import_ag_charts_core184.mapValues)(defaultAxes, (axis) => {
|
|
if (!("position" in axis))
|
|
return axis;
|
|
return axis.position === predictedAxis.position ? predictedAxis : axis;
|
|
});
|
|
}
|
|
return Object.fromEntries(axes);
|
|
}
|
|
cloneDefaultAxes(seriesType) {
|
|
const seriesModule = import_ag_charts_core184.ModuleRegistry.getSeriesModule(seriesType);
|
|
return seriesModule?.defaultAxes ? (0, import_ag_charts_core184.deepClone)(seriesModule.defaultAxes) : {};
|
|
}
|
|
predictAxesMissingTypesAndPositions(options, directions2, newAxes, defaultAxes) {
|
|
for (const [key, axis] of (0, import_ag_charts_core184.entries)(newAxes)) {
|
|
if (!(0, import_ag_charts_core184.isPlainObject)(axis))
|
|
continue;
|
|
if ("type" in axis && "position" in axis)
|
|
continue;
|
|
if (key in defaultAxes) {
|
|
axis.type ?? (axis.type = defaultAxes[key].type);
|
|
axis.position ?? (axis.position = defaultAxes[key].position);
|
|
continue;
|
|
}
|
|
const predictedType = this.predictAxisMissingTypeFromPosition(axis, defaultAxes);
|
|
if (predictedType)
|
|
continue;
|
|
this.predictAxisMissingTypeAndPositionFromSeries(options, directions2, key, axis, defaultAxes);
|
|
if (!("type" in axis)) {
|
|
delete newAxes[key];
|
|
}
|
|
}
|
|
}
|
|
predictAxisMissingTypeFromPosition(axis, defaultAxes) {
|
|
if (!("position" in axis) || !(0, import_ag_charts_core184.isKeyOf)(axis.position, POSITION_DIRECTIONS)) {
|
|
return false;
|
|
}
|
|
for (const defaultAxis of Object.values(defaultAxes)) {
|
|
if ((0, import_ag_charts_core184.isKeyOf)(defaultAxis.position, POSITION_DIRECTIONS) && POSITION_DIRECTIONS[axis.position] === POSITION_DIRECTIONS[defaultAxis.position]) {
|
|
axis.type = defaultAxis.type;
|
|
return true;
|
|
}
|
|
}
|
|
for (const [position, positionDirection] of (0, import_ag_charts_core184.entries)(POSITION_DIRECTIONS)) {
|
|
if (axis.position !== position && positionDirection === POSITION_DIRECTIONS[axis.position]) {
|
|
axis.type = defaultAxes[positionDirection].type;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
predictAxisMissingTypeAndPositionFromSeries(options, directions2, axisKey, axis, defaultAxes) {
|
|
for (const seriesOptions of options.series ?? []) {
|
|
for (const direction of directions2) {
|
|
const directionAxisKey = this.getSeriesDirectionAxisKey(seriesOptions, direction);
|
|
if (!directionAxisKey || !(0, import_ag_charts_core184.isKeyOf)(directionAxisKey, seriesOptions))
|
|
continue;
|
|
if (seriesOptions[directionAxisKey] !== axisKey)
|
|
continue;
|
|
axis.type ?? (axis.type = defaultAxes[direction].type);
|
|
axis.position ?? (axis.position = defaultAxes[direction].position);
|
|
return direction === import_ag_charts_core184.ChartAxisDirection.Y;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* If the first secondary axis in either direction does not have a specified position, it will be placed in the
|
|
* alternate position to the primary axis (i.e. right or top).
|
|
*/
|
|
alternateSecondaryAxisPositions(options, newAxes, unmappedAxisKeys) {
|
|
let xAxisCount = 0;
|
|
let yAxisCount = 0;
|
|
for (const [axisKey, axis] of (0, import_ag_charts_core184.entries)(newAxes)) {
|
|
if (!(0, import_ag_charts_core184.isPlainObject)(axis) || !("position" in axis))
|
|
continue;
|
|
const unmappedAxisKey = unmappedAxisKeys.get(axisKey);
|
|
const unmappedAxis = "axes" in options && options.axes && unmappedAxisKey && unmappedAxisKey in options.axes ? options.axes[unmappedAxisKey] : void 0;
|
|
const unmappedAxisPosition = unmappedAxis && "position" in unmappedAxis ? unmappedAxis.position : void 0;
|
|
if (axis.position === "top" || axis.position === "bottom") {
|
|
xAxisCount += 1;
|
|
if (xAxisCount === 2 && unmappedAxisPosition == null) {
|
|
axis.position = "top";
|
|
}
|
|
} else if (axis.position === "left" || axis.position === "right") {
|
|
yAxisCount += 1;
|
|
if (yAxisCount === 2 && unmappedAxisPosition == null) {
|
|
axis.position = "right";
|
|
}
|
|
}
|
|
if (xAxisCount > 1 && yAxisCount > 1)
|
|
break;
|
|
}
|
|
}
|
|
processMiniChartSeriesOptions(options) {
|
|
const miniChartSeries = options.navigator?.miniChart?.series;
|
|
if (miniChartSeries == null)
|
|
return;
|
|
options.navigator.miniChart.series = this.setSeriesGroupingOptions(
|
|
miniChartSeries
|
|
);
|
|
}
|
|
getSeriesGroupingOptions(series) {
|
|
const { groupable, stackable, stackedByDefault = false } = import_ag_charts_core184.ModuleRegistry.getSeriesModule(series.type);
|
|
if (series.grouped && !groupable) {
|
|
import_ag_charts_core184.Logger.warnOnce(`unsupported grouping of series type "${series.type}".`);
|
|
}
|
|
if ((series.stacked || series.stackGroup) && !stackable) {
|
|
import_ag_charts_core184.Logger.warnOnce(`unsupported stacking of series type "${series.type}".`);
|
|
}
|
|
let { grouped, stacked } = series;
|
|
stacked ?? (stacked = (stackedByDefault || series.stackGroup != null) && !(groupable && grouped));
|
|
grouped ?? (grouped = true);
|
|
return {
|
|
stacked: stackable && stacked,
|
|
grouped: groupable && grouped && !(stackable && stacked)
|
|
};
|
|
}
|
|
setSeriesGroupingOptions(allSeries) {
|
|
const seriesGroups = this.getSeriesGrouping(allSeries);
|
|
_ChartOptions.debug("ChartOptions.setSeriesGroupingOptions() - series grouping: ", seriesGroups);
|
|
const groupIdx = {};
|
|
const groupCount2 = seriesGroups.reduce((countMap, seriesGroup) => {
|
|
var _a;
|
|
if (seriesGroup.groupType === "default" /* DEFAULT */) {
|
|
return countMap;
|
|
}
|
|
countMap[_a = seriesGroup.seriesType] ?? (countMap[_a] = 0);
|
|
countMap[seriesGroup.seriesType] += seriesGroup.groupType === "stack" /* STACK */ ? 1 : seriesGroup.series.length;
|
|
return countMap;
|
|
}, {});
|
|
return seriesGroups.flatMap((seriesGroup) => {
|
|
var _a;
|
|
groupIdx[_a = seriesGroup.seriesType] ?? (groupIdx[_a] = 0);
|
|
switch (seriesGroup.groupType) {
|
|
case "stack" /* STACK */: {
|
|
const groupIndex = groupIdx[seriesGroup.seriesType]++;
|
|
return seriesGroup.series.map(
|
|
(series, stackIndex) => Object.assign(series, {
|
|
seriesGrouping: {
|
|
groupId: seriesGroup.groupId,
|
|
groupIndex,
|
|
groupCount: groupCount2[seriesGroup.seriesType],
|
|
stackIndex,
|
|
stackCount: seriesGroup.series.length
|
|
}
|
|
})
|
|
);
|
|
}
|
|
case "group" /* GROUP */:
|
|
return seriesGroup.series.map(
|
|
(series) => Object.assign(series, {
|
|
seriesGrouping: {
|
|
groupId: seriesGroup.groupId,
|
|
groupIndex: groupIdx[seriesGroup.seriesType]++,
|
|
groupCount: groupCount2[seriesGroup.seriesType],
|
|
stackIndex: 0,
|
|
stackCount: 0
|
|
}
|
|
})
|
|
);
|
|
}
|
|
return seriesGroup.series;
|
|
}).map(({ stacked: _, grouped: __, ...seriesOptions }) => seriesOptions);
|
|
}
|
|
getSeriesGroupId(series) {
|
|
return [series.type, series.xKey, series.stacked ? series.stackGroup ?? "stacked" : "grouped"].filter(Boolean).join("-");
|
|
}
|
|
getSeriesGrouping(allSeries) {
|
|
const groupMap = /* @__PURE__ */ new Map();
|
|
return allSeries.reduce((result, series) => {
|
|
const seriesType = series.type;
|
|
if (!series.stacked && !series.grouped) {
|
|
result.push({ groupType: "default" /* DEFAULT */, seriesType, series: [series], groupId: "__default__" });
|
|
} else {
|
|
const groupId = this.getSeriesGroupId(series);
|
|
if (!groupMap.has(groupId)) {
|
|
const groupType = series.stacked ? "stack" /* STACK */ : "group" /* GROUP */;
|
|
const record = { groupType, seriesType, series: [], groupId };
|
|
groupMap.set(groupId, record);
|
|
result.push(record);
|
|
}
|
|
groupMap.get(groupId).series.push(series);
|
|
}
|
|
return result;
|
|
}, []);
|
|
}
|
|
soloSeriesIntegrity(options) {
|
|
if (!(0, import_ag_charts_core184.isArray)(options.series))
|
|
return;
|
|
const isSolo = (seriesType) => import_ag_charts_core184.ModuleRegistry.getSeriesModule(seriesType)?.solo ?? false;
|
|
const allSeries = options.series;
|
|
if (allSeries && allSeries.length > 1 && allSeries.some((series) => isSolo(series.type))) {
|
|
const mainSeriesType = this.optionsType(options);
|
|
if (isSolo(mainSeriesType)) {
|
|
import_ag_charts_core184.Logger.warn(
|
|
`series[0] of type '${mainSeriesType}' is incompatible with other series types. Only processing series[0]`
|
|
);
|
|
options.series = allSeries.slice(0, 1);
|
|
} else {
|
|
const { solo, nonSolo } = (0, import_ag_charts_core184.groupBy)(allSeries, (s) => isSolo(s.type) ? "solo" : "nonSolo");
|
|
const rejects = (0, import_ag_charts_core184.unique)(solo.map((s) => s.type)).join(", ");
|
|
import_ag_charts_core184.Logger.warn(`Unable to mix these series types with the lead series type: ${rejects}`);
|
|
options.series = nonSolo;
|
|
}
|
|
}
|
|
}
|
|
static processFontOptions(node, _, __, googleFonts = /* @__PURE__ */ new Set()) {
|
|
if (typeof node === "object" && "fontFamily" in node) {
|
|
if (Array.isArray(node.fontFamily)) {
|
|
const fontFamily = [];
|
|
for (const font of node.fontFamily) {
|
|
if (typeof font === "object" && "googleFont" in font) {
|
|
fontFamily.push(font.googleFont);
|
|
googleFonts?.add(font.googleFont);
|
|
} else {
|
|
fontFamily.push(font);
|
|
}
|
|
}
|
|
node.fontFamily = fontFamily.join(", ");
|
|
} else if (typeof node.fontFamily === "object" && "googleFont" in node.fontFamily) {
|
|
node.fontFamily = node.fontFamily.googleFont;
|
|
googleFonts?.add(node.fontFamily);
|
|
}
|
|
}
|
|
return googleFonts;
|
|
}
|
|
processFonts(options, googleFonts = /* @__PURE__ */ new Set()) {
|
|
return (0, import_ag_charts_core184.jsonWalk)(
|
|
options,
|
|
_ChartOptions.processFontOptions,
|
|
/* @__PURE__ */ new Set(["data", "theme"]),
|
|
void 0,
|
|
void 0,
|
|
googleFonts
|
|
);
|
|
}
|
|
static removeDisabledOptionJson(optionsNode) {
|
|
if ("enabled" in optionsNode && optionsNode.enabled === false) {
|
|
for (const key of Object.keys(optionsNode)) {
|
|
if (key === "enabled")
|
|
continue;
|
|
delete optionsNode[key];
|
|
}
|
|
}
|
|
}
|
|
removeDisabledOptions(options) {
|
|
(0, import_ag_charts_core184.jsonWalk)(options, _ChartOptions.removeDisabledOptionJson, /* @__PURE__ */ new Set(["data", "theme", "contextMenu"]));
|
|
}
|
|
static removeLeftoverSymbolsJson(optionsNode) {
|
|
if (!optionsNode || !(0, import_ag_charts_core184.isObject)(optionsNode))
|
|
return;
|
|
for (const key of Object.keys(optionsNode)) {
|
|
const value = optionsNode[key];
|
|
if ((0, import_ag_charts_core184.isSymbol)(value)) {
|
|
delete optionsNode[key];
|
|
}
|
|
}
|
|
}
|
|
removeLeftoverSymbols(options) {
|
|
(0, import_ag_charts_core184.jsonWalk)(options, _ChartOptions.removeLeftoverSymbolsJson, /* @__PURE__ */ new Set(["data"]));
|
|
}
|
|
specialOverridesDefaults(options) {
|
|
if (options.window == null) {
|
|
options.window = (0, import_ag_charts_core184.getWindow)();
|
|
} else {
|
|
(0, import_ag_charts_core184.setWindow)(options.window);
|
|
}
|
|
if (options.document == null) {
|
|
options.document = (0, import_ag_charts_core184.getDocument)();
|
|
} else {
|
|
(0, import_ag_charts_core184.setDocument)(options.document);
|
|
}
|
|
if (options.window == null) {
|
|
throw new Error("AG Charts - unable to resolve global window");
|
|
}
|
|
if (options.document == null) {
|
|
throw new Error("AG Charts - unable to resolve global document");
|
|
}
|
|
return options;
|
|
}
|
|
};
|
|
_ChartOptions.OPTIONS_CLONE_OPTS_SLOW = {
|
|
shallow: /* @__PURE__ */ new Set(["data", "container"]),
|
|
assign: /* @__PURE__ */ new Set(["context", "theme"])
|
|
};
|
|
_ChartOptions.OPTIONS_CLONE_OPTS_FAST = {
|
|
shallow: /* @__PURE__ */ new Set(["container"]),
|
|
assign: /* @__PURE__ */ new Set(["data", "context", "theme"])
|
|
};
|
|
_ChartOptions.JSON_DIFF_OPTS = /* @__PURE__ */ new Set(["data", "localeText"]);
|
|
_ChartOptions.perfDebug = import_ag_charts_core184.Debug.create(true, "perf");
|
|
_ChartOptions.FAST_PATH_OPTIONS = /* @__PURE__ */ new Set(["data", "width", "height", "container"]);
|
|
// AG-16389: Track keys the user passed in deltaOptions
|
|
_ChartOptions.debug = import_ag_charts_core184.Debug.create(true, "opts");
|
|
var ChartOptions = _ChartOptions;
|
|
|
|
// packages/ag-charts-community/src/chart/chartProxy.ts
|
|
var debug3 = import_ag_charts_core185.Debug.create(true, "opts");
|
|
var DESTROYED_ERROR = "AG Charts - Chart was destroyed, cannot perform request.";
|
|
var _AgChartInstanceProxy = class _AgChartInstanceProxy {
|
|
constructor(chart, factoryApi, licenseManager) {
|
|
this.factoryApi = factoryApi;
|
|
this.licenseManager = licenseManager;
|
|
this.chart = chart;
|
|
}
|
|
async update(options) {
|
|
if (!this.chart)
|
|
throw new Error(DESTROYED_ERROR);
|
|
return debug3.group("AgChartInstance.update()", async () => {
|
|
const apiStartTime = import_ag_charts_core185.Debug.check("scene:stats", "scene:stats:verbose") ? performance.now() : void 0;
|
|
this.factoryApi.update(options, this, void 0, apiStartTime);
|
|
await this.chart?.waitForUpdate();
|
|
});
|
|
}
|
|
async updateDelta(deltaOptions) {
|
|
if (!this.chart)
|
|
throw new Error(DESTROYED_ERROR);
|
|
return debug3.group("AgChartInstance.updateDelta()", async () => {
|
|
const apiStartTime = import_ag_charts_core185.Debug.check("scene:stats", "scene:stats:verbose") ? performance.now() : void 0;
|
|
this.factoryApi.updateUserDelta(this, deltaOptions, apiStartTime);
|
|
await this.chart?.waitForUpdate();
|
|
});
|
|
}
|
|
getOptions() {
|
|
if (!this.chart)
|
|
throw new Error(DESTROYED_ERROR);
|
|
const options = (0, import_ag_charts_core185.deepClone)(this.chart.getOptions(), ChartOptions.OPTIONS_CLONE_OPTS_FAST);
|
|
for (const key of Object.keys(options)) {
|
|
if (key.startsWith("_")) {
|
|
delete options[key];
|
|
}
|
|
}
|
|
return options;
|
|
}
|
|
waitForUpdate() {
|
|
if (!this.chart)
|
|
throw new Error(DESTROYED_ERROR);
|
|
return this.chart.waitForUpdate();
|
|
}
|
|
applyTransaction(transaction) {
|
|
const { chart } = this;
|
|
if (!chart)
|
|
throw new Error(DESTROYED_ERROR);
|
|
if (transaction == null || typeof transaction !== "object") {
|
|
throw new Error("AG Charts - applyTransaction expects a transaction object.");
|
|
}
|
|
const { add, addIndex, remove, update } = transaction;
|
|
if (add != null && !Array.isArray(add)) {
|
|
throw new Error('AG Charts - transaction "add" must be an array.');
|
|
}
|
|
if (addIndex != null) {
|
|
if (typeof addIndex !== "number" || !Number.isSafeInteger(addIndex) || addIndex < 0) {
|
|
throw new Error(
|
|
'AG Charts - transaction "addIndex" must be a safe non-negative integer (0 to 9007199254740991).'
|
|
);
|
|
}
|
|
if (add == null || add.length === 0) {
|
|
throw new Error('AG Charts - transaction "addIndex" requires a non-empty "add" array.');
|
|
}
|
|
}
|
|
if (remove != null && !Array.isArray(remove)) {
|
|
throw new Error('AG Charts - transaction "remove" must be an array.');
|
|
}
|
|
if (update != null && !Array.isArray(update)) {
|
|
throw new Error('AG Charts - transaction "update" must be an array.');
|
|
}
|
|
return debug3.group("AgChartInstance.applyTransaction()", async () => {
|
|
if (!chart.isDataTransactionSupported()) {
|
|
const dataSet = chart.data.deepClone();
|
|
dataSet.addTransaction(transaction);
|
|
dataSet.commitPendingTransactions();
|
|
return this.updateDelta({ data: dataSet.data });
|
|
}
|
|
debug3("transaction", transaction);
|
|
return await this.chart?.applyTransaction(transaction);
|
|
});
|
|
}
|
|
async download(opts) {
|
|
if (!this.chart)
|
|
throw new Error(DESTROYED_ERROR);
|
|
const clone = await this.prepareResizedChart(this, this.chart, opts);
|
|
try {
|
|
clone.chart?.download(opts?.fileName, opts?.fileFormat);
|
|
} finally {
|
|
clone.destroy();
|
|
}
|
|
}
|
|
async __toSVG(opts) {
|
|
if (!this.chart)
|
|
throw new Error(DESTROYED_ERROR);
|
|
const clone = await this.prepareResizedChart(this, this.chart, { width: 600, height: 300, ...opts });
|
|
try {
|
|
return clone?.chart?.toSVG();
|
|
} finally {
|
|
clone?.destroy();
|
|
}
|
|
}
|
|
async getImageDataURL(opts) {
|
|
if (!this.chart)
|
|
throw new Error(DESTROYED_ERROR);
|
|
const clone = await this.prepareResizedChart(this, this.chart, opts);
|
|
try {
|
|
return clone.chart.getCanvasDataURL(opts?.fileFormat);
|
|
} finally {
|
|
clone.destroy();
|
|
}
|
|
}
|
|
getState() {
|
|
return this.factoryApi.caretaker.save(...this.getEnabledOriginators());
|
|
}
|
|
async setState(state) {
|
|
const { chart } = this;
|
|
if (!chart)
|
|
return;
|
|
const originators = this.getEnabledOriginators();
|
|
if (!originators.includes(chart.ctx.legendManager)) {
|
|
await this.setStateOriginators(state, originators);
|
|
return;
|
|
}
|
|
await this.setStateOriginators(
|
|
state,
|
|
originators.filter((originator) => originator !== chart.ctx.zoomManager)
|
|
);
|
|
await this.setStateOriginators(state, [chart.ctx.zoomManager]);
|
|
}
|
|
resetAnimations() {
|
|
this.chart?.resetAnimations();
|
|
}
|
|
skipAnimations() {
|
|
this.chart?.skipAnimations();
|
|
}
|
|
destroy() {
|
|
if (this.releaseChart) {
|
|
this.releaseChart();
|
|
this.releaseChart = void 0;
|
|
} else if (this.chart) {
|
|
this.chart.publicApi = void 0;
|
|
this.chart.destroy();
|
|
}
|
|
this.chart = void 0;
|
|
}
|
|
async prepareResizedChart(proxy, chart, opts = {}) {
|
|
const width = opts.width ?? chart.width ?? chart.ctx.scene.canvas.width;
|
|
const height = opts.height ?? chart.height ?? chart.ctx.scene.canvas.height;
|
|
const state = proxy.getState();
|
|
const processedOverrides = {
|
|
...chart.chartOptions.processedOverrides,
|
|
container: (0, import_ag_charts_core185.getDocument)().createElement("div"),
|
|
width,
|
|
height
|
|
};
|
|
if (opts.width != null && opts.height != null) {
|
|
processedOverrides.overrideDevicePixelRatio = 1;
|
|
}
|
|
const userOptions = chart.getOptions();
|
|
if (import_ag_charts_core185.ModuleRegistry.isEnterprise()) {
|
|
processedOverrides.animation = { enabled: false };
|
|
const foreground = this.licenseManager?.getWatermarkForegroundConfigForBrowser();
|
|
if (foreground) {
|
|
processedOverrides.foreground = foreground;
|
|
}
|
|
}
|
|
const specialOverrides = { ...chart.chartOptions.specialOverrides };
|
|
const optionsMetadata = { ...chart.chartOptions.optionMetadata };
|
|
const data = await this.chart?.ctx.dataService.getData();
|
|
const cloneProxy = this.factoryApi.create(
|
|
userOptions,
|
|
processedOverrides,
|
|
specialOverrides,
|
|
optionsMetadata,
|
|
data
|
|
);
|
|
if (state.legend) {
|
|
this.syncLegend(chart, cloneProxy, state);
|
|
}
|
|
cloneProxy.chart?.update(import_ag_charts_core185.ChartUpdateType.FULL, { forceNodeDataRefresh: true });
|
|
await cloneProxy.waitForUpdate();
|
|
await cloneProxy.setState(state);
|
|
const sourcing = { source: "chart-update", sourceDetail: "internal-prepareResizedChart" };
|
|
cloneProxy.chart?.ctx.zoomManager.updateZoom(sourcing, chart.ctx.zoomManager.getZoom());
|
|
cloneProxy.chart?.update(import_ag_charts_core185.ChartUpdateType.FULL, { forceNodeDataRefresh: true });
|
|
await cloneProxy.waitForUpdate();
|
|
const legendPages = [];
|
|
for (const legend of chart.modulesManager.legends()) {
|
|
legendPages.push(legend.legend.pagination?.currentPage ?? 0);
|
|
}
|
|
for (const legend of cloneProxy.chart.modulesManager.legends()) {
|
|
const page = legendPages.shift() ?? 0;
|
|
if (!legend.legend.pagination)
|
|
continue;
|
|
legend.legend.pagination.setPage(page);
|
|
}
|
|
cloneProxy.chart?.update(import_ag_charts_core185.ChartUpdateType.FULL, { forceNodeDataRefresh: true });
|
|
await cloneProxy.waitForUpdate();
|
|
return cloneProxy;
|
|
}
|
|
syncLegend(chart, cloneProxy, state) {
|
|
const seriesIdMap = /* @__PURE__ */ new Map();
|
|
for (const [index, series] of chart.series.entries()) {
|
|
const cloneSeries = cloneProxy.chart?.series[index];
|
|
if (!cloneSeries)
|
|
continue;
|
|
seriesIdMap.set(series.id, cloneSeries.id);
|
|
}
|
|
state.legend = state.legend?.map((legend) => {
|
|
return {
|
|
...legend,
|
|
seriesId: seriesIdMap.get(legend.seriesId ?? "") ?? legend.seriesId
|
|
};
|
|
});
|
|
}
|
|
getEnabledOriginators() {
|
|
if (!this.chart)
|
|
return [];
|
|
const {
|
|
chartOptions: { processedOptions, optionMetadata },
|
|
ctx: { annotationManager, chartTypeOriginator, zoomManager, legendManager },
|
|
modulesManager
|
|
} = this.chart;
|
|
const originators = [];
|
|
if ("annotations" in processedOptions && processedOptions.annotations?.enabled) {
|
|
originators.push(annotationManager);
|
|
}
|
|
const isFinancialChart = optionMetadata.presetType === "price-volume";
|
|
if (isFinancialChart) {
|
|
originators.push(chartTypeOriginator);
|
|
}
|
|
if (processedOptions.navigator?.enabled || processedOptions.zoom?.enabled) {
|
|
originators.push(zoomManager);
|
|
}
|
|
const legendEnabled = modulesManager.isEnabled("legend") && processedOptions.legend?.enabled !== false;
|
|
if (legendEnabled) {
|
|
originators.push(legendManager);
|
|
}
|
|
originators.push(this.chart.ctx.activeManager);
|
|
return originators;
|
|
}
|
|
async setStateOriginators(state, originators) {
|
|
this.factoryApi.caretaker.restore(state, ...originators);
|
|
this.chart?.ctx.updateService.update(import_ag_charts_core185.ChartUpdateType.PROCESS_DATA, { forceNodeDataRefresh: true });
|
|
await this.chart?.waitForUpdate();
|
|
}
|
|
};
|
|
_AgChartInstanceProxy.chartInstances = /* @__PURE__ */ new WeakMap();
|
|
__decorateClass([
|
|
(0, import_ag_charts_core185.ActionOnSet)({
|
|
oldValue(chart) {
|
|
if (!chart.destroyed) {
|
|
chart.publicApi = void 0;
|
|
}
|
|
_AgChartInstanceProxy.chartInstances.delete(chart);
|
|
},
|
|
newValue(chart) {
|
|
if (!chart)
|
|
return;
|
|
chart.publicApi = this;
|
|
_AgChartInstanceProxy.chartInstances.set(chart, this);
|
|
}
|
|
})
|
|
], _AgChartInstanceProxy.prototype, "chart", 2);
|
|
var AgChartInstanceProxy = _AgChartInstanceProxy;
|
|
|
|
// packages/ag-charts-community/src/util/pool.ts
|
|
var import_ag_charts_core186 = require("ag-charts-core");
|
|
var CLEANUP_TIMEOUT_MS = 1e3;
|
|
var _Pool = class _Pool {
|
|
constructor(name, buildItem, releaseItem, destroyItem, maxPoolSize, cleanupTimeMs = CLEANUP_TIMEOUT_MS) {
|
|
this.name = name;
|
|
this.buildItem = buildItem;
|
|
this.releaseItem = releaseItem;
|
|
this.destroyItem = destroyItem;
|
|
this.maxPoolSize = maxPoolSize;
|
|
this.cleanupTimeMs = cleanupTimeMs;
|
|
this.freePool = [];
|
|
this.busyPool = /* @__PURE__ */ new Set();
|
|
}
|
|
static getPool(name, buildItem, releaseItem, destroyItem, maxPoolSize) {
|
|
if (!this.pools.has(name)) {
|
|
this.pools.set(name, new _Pool(name, buildItem, releaseItem, destroyItem, maxPoolSize));
|
|
}
|
|
return this.pools.get(name);
|
|
}
|
|
isFull() {
|
|
return this.freePool.length + this.busyPool.size >= this.maxPoolSize;
|
|
}
|
|
hasFree() {
|
|
return this.freePool.length > 0;
|
|
}
|
|
obtain(params) {
|
|
if (!this.hasFree() && this.isFull()) {
|
|
throw new Error("AG Charts - pool exhausted");
|
|
}
|
|
let nextFree = this.freePool.pop();
|
|
if (nextFree == null) {
|
|
nextFree = this.buildItem(params);
|
|
_Pool.debug(() => [
|
|
`Pool[name=${this.name}]: Created instance (${this.freePool.length} / ${this.busyPool.size + 1} / ${this.maxPoolSize})`,
|
|
nextFree
|
|
]);
|
|
} else {
|
|
_Pool.debug(() => [
|
|
`Pool[name=${this.name}]: Re-used instance (${this.freePool.length} / ${this.busyPool.size + 1} / ${this.maxPoolSize})`,
|
|
nextFree
|
|
]);
|
|
}
|
|
this.busyPool.add(nextFree);
|
|
return { item: nextFree, release: () => this.release(nextFree) };
|
|
}
|
|
obtainFree() {
|
|
const nextFree = this.freePool.pop();
|
|
if (nextFree == null) {
|
|
throw new Error("AG Charts - pool has no free instances");
|
|
}
|
|
_Pool.debug(() => [
|
|
`Pool[name=${this.name}]: Re-used instance (${this.freePool.length} / ${this.busyPool.size + 1} / ${this.maxPoolSize})`,
|
|
nextFree
|
|
]);
|
|
this.busyPool.add(nextFree);
|
|
return { item: nextFree, release: () => this.release(nextFree) };
|
|
}
|
|
release(item) {
|
|
if (!this.busyPool.has(item)) {
|
|
throw new Error("AG Charts - cannot free item from pool which is not tracked as busy.");
|
|
}
|
|
_Pool.debug(() => [
|
|
`Pool[name=${this.name}]: Releasing instance (${this.freePool.length} / ${this.busyPool.size} / ${this.maxPoolSize})`,
|
|
item
|
|
]);
|
|
this.releaseItem(item);
|
|
this.busyPool.delete(item);
|
|
this.freePool.push(item);
|
|
_Pool.debug(() => [
|
|
`Pool[name=${this.name}]: Returned instance to free pool (${this.freePool.length} / ${this.busyPool.size} / ${this.maxPoolSize})`,
|
|
item
|
|
]);
|
|
const now = Date.now();
|
|
const earliestClean = now + this.cleanupTimeMs * 0.5;
|
|
if (this.cleanPoolTimer && (this.cleanPoolDue ?? Infinity) < earliestClean) {
|
|
clearTimeout(this.cleanPoolTimer);
|
|
this.cleanPoolTimer = void 0;
|
|
}
|
|
if (!this.cleanPoolTimer) {
|
|
this.cleanPoolDue = now + this.cleanupTimeMs;
|
|
this.cleanPoolTimer = setTimeout(this.cleanPool.bind(this), this.cleanupTimeMs);
|
|
}
|
|
}
|
|
cleanPool() {
|
|
const itemsToFree = this.freePool.splice(0);
|
|
for (const item of itemsToFree) {
|
|
this.destroyItem(item);
|
|
}
|
|
_Pool.debug(() => [
|
|
`Pool[name=${this.name}]: Cleaned pool of ${itemsToFree.length} items (${this.freePool.length} / ${this.busyPool.size} / ${this.maxPoolSize})`
|
|
]);
|
|
}
|
|
destroy() {
|
|
this.cleanPool();
|
|
for (const item of this.busyPool.values()) {
|
|
this.destroyItem(item);
|
|
}
|
|
this.busyPool.clear();
|
|
}
|
|
};
|
|
_Pool.pools = /* @__PURE__ */ new Map();
|
|
_Pool.debug = import_ag_charts_core186.Debug.create(true, "pool");
|
|
var Pool = _Pool;
|
|
|
|
// packages/ag-charts-community/src/api/agCharts.ts
|
|
var debug4 = import_ag_charts_core187.Debug.create(true, "opts");
|
|
var AgCharts = class {
|
|
static licenseCheck(options) {
|
|
if (this.licenseChecked)
|
|
return;
|
|
this.licenseManager = import_ag_charts_core187.enterpriseRegistry.licenseManager?.(options);
|
|
this.licenseManager?.validateLicense();
|
|
this.licenseChecked = true;
|
|
}
|
|
static getLicenseDetails(licenseKey) {
|
|
return import_ag_charts_core187.enterpriseRegistry.licenseManager?.({}).getLicenseDetails(licenseKey);
|
|
}
|
|
/**
|
|
* Returns the `AgChartInstance` for a DOM node, if there is one.
|
|
*/
|
|
static getInstance(element2) {
|
|
return AgChartsInternal.getInstance(element2);
|
|
}
|
|
/**
|
|
* Create a new `AgChartInstance` based upon the given configuration options.
|
|
*/
|
|
static create(userOptions, optionsMetadata) {
|
|
const apiStartTime = import_ag_charts_core187.Debug.check("scene:stats", "scene:stats:verbose") ? performance.now() : void 0;
|
|
return debug4.group("AgCharts.create()", () => {
|
|
userOptions = import_ag_charts_core187.Debug.inDevelopmentMode(() => (0, import_ag_charts_core187.deepFreeze)((0, import_ag_charts_core187.deepClone)(userOptions))) ?? userOptions;
|
|
this.licenseCheck(userOptions);
|
|
const chart = AgChartsInternal.createOrUpdate({
|
|
userOptions,
|
|
licenseManager: this.licenseManager,
|
|
optionsMetadata,
|
|
apiStartTime
|
|
});
|
|
if (this.licenseManager?.isDisplayWatermark()) {
|
|
import_ag_charts_core187.enterpriseRegistry.injectWatermark?.(
|
|
chart.chart.ctx.domManager,
|
|
this.licenseManager.getWatermarkMessage()
|
|
);
|
|
}
|
|
return chart;
|
|
});
|
|
}
|
|
static createFinancialChart(options) {
|
|
return debug4.group("AgCharts.createFinancialChart()", () => {
|
|
return this.create(options, { presetType: "price-volume" });
|
|
});
|
|
}
|
|
static createGauge(options) {
|
|
return debug4.group("AgCharts.createGauge()", () => {
|
|
return this.create(options, { presetType: "gauge-preset" });
|
|
});
|
|
}
|
|
static __createSparkline(options) {
|
|
return debug4.group("AgCharts.__createSparkline()", () => {
|
|
const { pool, ...normalOptions } = options;
|
|
return this.create(normalOptions, {
|
|
presetType: "sparkline",
|
|
pool: pool ?? true,
|
|
domMode: "minimal",
|
|
withDragInterpretation: false
|
|
});
|
|
});
|
|
}
|
|
};
|
|
AgCharts.licenseChecked = false;
|
|
var _AgChartsInternal = class _AgChartsInternal {
|
|
static getInstance(element2) {
|
|
const chart = Chart.getInstance(element2);
|
|
return chart ? AgChartInstanceProxy.chartInstances.get(chart) : void 0;
|
|
}
|
|
static createOrUpdate(opts) {
|
|
let { proxy } = opts;
|
|
const {
|
|
userOptions,
|
|
licenseManager,
|
|
processedOverrides = proxy?.chart?.chartOptions.processedOverrides ?? {},
|
|
specialOverrides = proxy?.chart?.chartOptions.specialOverrides ?? {},
|
|
optionsMetadata = proxy?.chart?.chartOptions.optionMetadata ?? {},
|
|
deltaOptions,
|
|
data,
|
|
stripSymbols = false,
|
|
apiStartTime
|
|
} = opts;
|
|
const styles = import_ag_charts_core187.enterpriseRegistry.styles == null ? [] : [["ag-charts-enterprise", import_ag_charts_core187.enterpriseRegistry.styles]];
|
|
if (import_ag_charts_core187.ModuleRegistry.listModules().next().done) {
|
|
throw new Error(
|
|
[
|
|
"AG Charts - No modules have been registered.",
|
|
"",
|
|
"Call ModuleRegistry.registerModules(...) with the modules you need before using AgCharts.create().",
|
|
"",
|
|
"See https://www.ag-grid.com/charts/r/module-registry/ for more details."
|
|
].join("\n")
|
|
);
|
|
}
|
|
debug4(() => [">>> AgCharts.createOrUpdate() user options", (0, import_ag_charts_core187.deepClone)(userOptions)]);
|
|
const { presetType } = optionsMetadata;
|
|
let mutableOptions = userOptions;
|
|
if (AgCharts.optionsMutationFn && mutableOptions) {
|
|
mutableOptions = AgCharts.optionsMutationFn(
|
|
(0, import_ag_charts_core187.deepClone)(mutableOptions, ChartOptions.OPTIONS_CLONE_OPTS_FAST),
|
|
presetType
|
|
);
|
|
debug4(() => [">>> AgCharts.createOrUpdate() MUTATED user options", (0, import_ag_charts_core187.deepClone)(mutableOptions)]);
|
|
}
|
|
const pool = this.getPool(optionsMetadata);
|
|
let create = false;
|
|
let poolResult;
|
|
let chart = proxy?.chart;
|
|
if (chart == null && pool?.hasFree()) {
|
|
poolResult = pool.obtainFree();
|
|
chart = poolResult.item;
|
|
}
|
|
const { document, window: userWindow, styleContainer, skipCss, ...options } = mutableOptions ?? {};
|
|
const baseOptions = chart?.getChartOptions();
|
|
const chartOptions = new ChartOptions(
|
|
baseOptions,
|
|
options,
|
|
processedOverrides,
|
|
{
|
|
...specialOverrides,
|
|
document,
|
|
window: userWindow,
|
|
styleContainer,
|
|
skipCss
|
|
},
|
|
optionsMetadata,
|
|
deltaOptions,
|
|
stripSymbols,
|
|
apiStartTime
|
|
);
|
|
if (chart == null || detectChartType(chartOptions.processedOptions) !== detectChartType(chart.chartOptions.processedOptions)) {
|
|
poolResult?.release();
|
|
poolResult = this.getPool(chartOptions.optionMetadata)?.obtain(chartOptions);
|
|
if (poolResult) {
|
|
chart = poolResult.item;
|
|
} else {
|
|
create = true;
|
|
chart = _AgChartsInternal.createChartInstance(chartOptions, chart);
|
|
}
|
|
}
|
|
if (chartOptions.optionsGraph) {
|
|
chart.ctx.optionsGraphService.updateCallback((path, partialOptions, resolveOptions) => {
|
|
return chartOptions.optionsGraph?.resolvePartial(path, partialOptions, resolveOptions);
|
|
});
|
|
}
|
|
for (const [id, css] of styles) {
|
|
chart.ctx.domManager.addStyles(id, css);
|
|
}
|
|
chart.ctx.fontManager.updateFonts(chartOptions.googleFonts);
|
|
if (data != null) {
|
|
chart.ctx.dataService.restoreData(data);
|
|
}
|
|
if (proxy == null) {
|
|
proxy = new AgChartInstanceProxy(chart, _AgChartsInternal.callbackApi, licenseManager);
|
|
proxy.releaseChart = poolResult?.release;
|
|
} else if (poolResult || create) {
|
|
proxy.releaseChart?.();
|
|
proxy.chart = chart;
|
|
proxy.releaseChart = poolResult?.release;
|
|
}
|
|
if (debug4.check() && typeof globalThis.window !== "undefined") {
|
|
globalThis.agChartInstances ?? (globalThis.agChartInstances = {});
|
|
globalThis.agChartInstances[chart.id] = chart;
|
|
}
|
|
chart.queuedUserOptions.push(chartOptions.userOptions);
|
|
chart.queuedChartOptions.push(chartOptions);
|
|
chart.requestFactoryUpdate((chartRef) => {
|
|
debug4.group(">>>> Chart.applyOptions()", () => {
|
|
chartRef.applyOptions(chartOptions);
|
|
const queueIdx = chartRef.queuedUserOptions.indexOf(chartOptions.userOptions) + 1;
|
|
chartRef.queuedUserOptions.splice(0, queueIdx);
|
|
chartRef.queuedChartOptions.splice(0, queueIdx);
|
|
});
|
|
});
|
|
return proxy;
|
|
}
|
|
static updateUserDelta(proxy, deltaOptions, apiStartTime) {
|
|
deltaOptions = (0, import_ag_charts_core187.deepClone)(deltaOptions, ChartOptions.OPTIONS_CLONE_OPTS_FAST);
|
|
const stripSymbols = (0, import_ag_charts_core187.jsonWalk)(
|
|
deltaOptions,
|
|
_AgChartsInternal.markRemovedProperties,
|
|
/* @__PURE__ */ new Set(["data"]),
|
|
void 0,
|
|
void 0,
|
|
false
|
|
);
|
|
debug4(() => [">>> AgCharts.updateUserDelta() user delta", (0, import_ag_charts_core187.deepClone)(deltaOptions)]);
|
|
_AgChartsInternal.createOrUpdate({
|
|
proxy,
|
|
deltaOptions,
|
|
stripSymbols,
|
|
apiStartTime
|
|
});
|
|
}
|
|
static createChartInstance(options, oldChart) {
|
|
const transferableResource = oldChart?.destroy({ keepTransferableResources: true });
|
|
const chartType = detectChartType(options.processedOptions);
|
|
const chartDef = import_ag_charts_core187.ModuleRegistry.getChartModule(chartType);
|
|
return chartDef.create(options, transferableResource);
|
|
}
|
|
static getPool(optionMetadata) {
|
|
if (optionMetadata.pool !== true)
|
|
return;
|
|
return Pool.getPool(
|
|
optionMetadata.presetType ?? "default",
|
|
this.createChartInstance,
|
|
this.detachAndClear,
|
|
this.destroy,
|
|
Infinity
|
|
// AG-13480 - Prevent Grid exhausting pool during sorting.
|
|
);
|
|
}
|
|
};
|
|
_AgChartsInternal.caretaker = new import_ag_charts_core187.MementoCaretaker(VERSION);
|
|
_AgChartsInternal.callbackApi = {
|
|
caretaker: _AgChartsInternal.caretaker,
|
|
create(userOptions, processedOverrides, specialOverrides, optionsMetadata, data) {
|
|
return _AgChartsInternal.createOrUpdate({
|
|
userOptions,
|
|
processedOverrides,
|
|
specialOverrides,
|
|
optionsMetadata,
|
|
data
|
|
});
|
|
},
|
|
update(opts, chart, specialOverrides, apiStartTime) {
|
|
return _AgChartsInternal.createOrUpdate({
|
|
userOptions: opts,
|
|
proxy: chart,
|
|
specialOverrides,
|
|
apiStartTime
|
|
});
|
|
},
|
|
updateUserDelta(chart, deltaOptions, apiStartTime) {
|
|
return _AgChartsInternal.updateUserDelta(chart, deltaOptions, apiStartTime);
|
|
}
|
|
};
|
|
// CRT-1018 Use `Parameters` and `unknown` to strictly enforce type-safety
|
|
_AgChartsInternal.markRemovedProperties = (node, _parallelNode, _ctx, previousModified) => {
|
|
let modified = previousModified ?? false;
|
|
if (typeof node !== "object" || node == null)
|
|
return modified;
|
|
for (const key of (0, import_ag_charts_core187.strictObjectKeys)(node)) {
|
|
const value = node[key];
|
|
if (value === void 0) {
|
|
Object.assign(node, { [key]: Symbol("UNSET") });
|
|
modified || (modified = true);
|
|
}
|
|
}
|
|
return modified;
|
|
};
|
|
_AgChartsInternal.detachAndClear = (chart) => chart.detachAndClear();
|
|
_AgChartsInternal.destroy = (chart) => chart.destroy();
|
|
var AgChartsInternal = _AgChartsInternal;
|
|
|
|
// packages/ag-charts-community/src/main.ts
|
|
var import_ag_charts_core286 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/module-support.ts
|
|
var module_support_exports = {};
|
|
__export(module_support_exports, {
|
|
APPROXIMATE_THRESHOLD: () => APPROXIMATE_THRESHOLD,
|
|
AbstractBarSeries: () => AbstractBarSeries,
|
|
AbstractBarSeriesProperties: () => AbstractBarSeriesProperties,
|
|
AggregationManager: () => AggregationManager,
|
|
AnchoredPopover: () => AnchoredPopover,
|
|
ApproximateOrdinalTimeScale: () => ApproximateOrdinalTimeScale,
|
|
Arc: () => Arc,
|
|
Axis: () => Axis,
|
|
AxisGroupZIndexMap: () => AxisGroupZIndexMap,
|
|
AxisInterval: () => AxisInterval,
|
|
AxisLabel: () => AxisLabel,
|
|
AxisTick: () => AxisTick,
|
|
BBox: () => BBox,
|
|
Background: () => Background,
|
|
BandScale: () => BandScale,
|
|
BaseToolbar: () => BaseToolbar,
|
|
Caption: () => Caption,
|
|
CartesianAxis: () => CartesianAxis,
|
|
CartesianCrossLine: () => CartesianCrossLine,
|
|
CartesianSeries: () => CartesianSeries,
|
|
CartesianSeriesNodeEvent: () => CartesianSeriesNodeEvent,
|
|
CartesianSeriesProperties: () => CartesianSeriesProperties,
|
|
CategoryAxis: () => CategoryAxis,
|
|
CategoryScale: () => CategoryScale,
|
|
Chart: () => Chart,
|
|
ChartAxes: () => ChartAxes,
|
|
ChartOptions: () => ChartOptions,
|
|
CollapseMode: () => CollapseMode,
|
|
ColorScale: () => ColorScale,
|
|
ContextMenuRegistry: () => ContextMenuRegistry,
|
|
ContinuousScale: () => ContinuousScale,
|
|
DEFAULT_CARTESIAN_DIRECTION_KEYS: () => DEFAULT_CARTESIAN_DIRECTION_KEYS,
|
|
DEFAULT_CARTESIAN_DIRECTION_NAMES: () => DEFAULT_CARTESIAN_DIRECTION_NAMES,
|
|
DEFAULT_POLAR_DIRECTION_KEYS: () => DEFAULT_POLAR_DIRECTION_KEYS,
|
|
DEFAULT_POLAR_DIRECTION_NAMES: () => DEFAULT_POLAR_DIRECTION_NAMES,
|
|
DOMManager: () => DOMManager,
|
|
DataController: () => DataController,
|
|
DataModel: () => DataModel,
|
|
DataModelSeries: () => DataModelSeries,
|
|
DataSet: () => DataSet,
|
|
DiscreteTimeAxis: () => DiscreteTimeAxis,
|
|
DraggablePopover: () => DraggablePopover,
|
|
DropShadow: () => DropShadow,
|
|
ExtendedPath2D: () => ExtendedPath2D,
|
|
FillGradientDefaults: () => FillGradientDefaults,
|
|
FillImageDefaults: () => FillImageDefaults,
|
|
FillPatternDefaults: () => FillPatternDefaults,
|
|
FloatingToolbar: () => FloatingToolbar,
|
|
FormatManager: () => FormatManager,
|
|
Group: () => Group,
|
|
GroupWidget: () => GroupWidget,
|
|
HierarchyHighlightState: () => HierarchyHighlightState,
|
|
HierarchyNode: () => HierarchyNode,
|
|
HierarchySeries: () => HierarchySeries,
|
|
HierarchySeriesProperties: () => HierarchySeriesProperties,
|
|
HighlightManager: () => HighlightManager,
|
|
HighlightProperties: () => HighlightProperties,
|
|
HighlightState: () => HighlightState,
|
|
Image: () => Image2,
|
|
InteractionManager: () => InteractionManager,
|
|
InteractionState: () => InteractionState,
|
|
LARGEST_KEY_INTERVAL: () => LARGEST_KEY_INTERVAL,
|
|
Label: () => Label,
|
|
LabelStyle: () => LabelStyle,
|
|
LayoutElement: () => LayoutElement,
|
|
Line: () => Line,
|
|
LinearScale: () => LinearScale,
|
|
LogScale: () => LogScale,
|
|
Marker: () => Marker,
|
|
Menu: () => Menu,
|
|
MercatorScale: () => MercatorScale,
|
|
NODE_UPDATE_STATE_TO_PHASE_MAPPING: () => NODE_UPDATE_STATE_TO_PHASE_MAPPING,
|
|
NativeWidget: () => NativeWidget,
|
|
NiceMode: () => NiceMode,
|
|
Node: () => Node,
|
|
OrdinalTimeScale: () => OrdinalTimeScale,
|
|
Path: () => Path,
|
|
PointerEvents: () => PointerEvents,
|
|
PolarAxis: () => PolarAxis,
|
|
PolarSeries: () => PolarSeries,
|
|
QuadtreeNearest: () => QuadtreeNearest,
|
|
RadialColumnShape: () => RadialColumnShape,
|
|
Range: () => Range,
|
|
Rect: () => Rect,
|
|
Rotatable: () => Rotatable,
|
|
RotatableText: () => RotatableText,
|
|
SMALLEST_KEY_INTERVAL: () => SMALLEST_KEY_INTERVAL,
|
|
Scalable: () => Scalable,
|
|
ScalableGroup: () => ScalableGroup,
|
|
Scene: () => Scene,
|
|
Sector: () => Sector,
|
|
SectorBox: () => SectorBox,
|
|
SegmentedPath: () => SegmentedPath,
|
|
Selection: () => Selection,
|
|
Series: () => Series,
|
|
SeriesItemHighlightStyle: () => SeriesItemHighlightStyle,
|
|
SeriesMarker: () => SeriesMarker,
|
|
SeriesNodeEvent: () => SeriesNodeEvent,
|
|
SeriesNodePickMode: () => SeriesNodePickMode,
|
|
SeriesProperties: () => SeriesProperties,
|
|
SeriesTooltip: () => SeriesTooltip,
|
|
Shape: () => Shape,
|
|
SliderWidget: () => SliderWidget,
|
|
StopProperties: () => StopProperties,
|
|
SvgPath: () => SvgPath,
|
|
Text: () => Text,
|
|
TimeAxisParentLevel: () => TimeAxisParentLevel,
|
|
TimeScale: () => TimeScale,
|
|
Toolbar: () => Toolbar,
|
|
ToolbarButtonWidget: () => ToolbarButtonWidget,
|
|
ToolbarWidget: () => ToolbarWidget,
|
|
TooltipManager: () => TooltipManager,
|
|
Transformable: () => Transformable,
|
|
TransformableGroup: () => TransformableGroup,
|
|
TransformableText: () => TransformableText,
|
|
Translatable: () => Translatable,
|
|
TranslatableGroup: () => TranslatableGroup,
|
|
TranslatableSvgPath: () => TranslatableSvgPath,
|
|
UnitTimeScale: () => UnitTimeScale,
|
|
ZoomManager: () => ZoomManager,
|
|
accumulativeValueProperty: () => accumulativeValueProperty,
|
|
addHitTestersToQuadtree: () => addHitTestersToQuadtree,
|
|
adjustLabelPlacement: () => adjustLabelPlacement,
|
|
angleCategoryAxisOptionsDefs: () => angleCategoryAxisOptionsDefs,
|
|
angleNumberAxisOptionsDefs: () => angleNumberAxisOptionsDefs,
|
|
animationValidation: () => animationValidation,
|
|
annotationCalloutStylesDefs: () => annotationCalloutStylesDefs,
|
|
annotationChannelTextDefs: () => annotationChannelTextDefs,
|
|
annotationCommentStylesDefs: () => annotationCommentStylesDefs,
|
|
annotationCrossLineStyleDefs: () => annotationCrossLineStyleDefs,
|
|
annotationDisjointChannelStyleDefs: () => annotationDisjointChannelStyleDefs,
|
|
annotationFibonacciStylesDefs: () => annotationFibonacciStylesDefs,
|
|
annotationLineStyleDefs: () => annotationLineStyleDefs,
|
|
annotationLineTextDefs: () => annotationLineTextDefs,
|
|
annotationMeasurerStylesDefs: () => annotationMeasurerStylesDefs,
|
|
annotationNoteStylesDefs: () => annotationNoteStylesDefs,
|
|
annotationOptionsDef: () => annotationOptionsDef,
|
|
annotationParallelChannelStyleDefs: () => annotationParallelChannelStyleDefs,
|
|
annotationQuickMeasurerStylesDefs: () => annotationQuickMeasurerStylesDefs,
|
|
annotationShapeStylesDefs: () => annotationShapeStylesDefs,
|
|
annotationTextStylesDef: () => annotationTextStylesDef,
|
|
boxPlotSeriesThemeableOptionsDef: () => boxPlotSeriesThemeableOptionsDef,
|
|
buildResetPathFn: () => buildResetPathFn,
|
|
calculateDataDiff: () => calculateDataDiff,
|
|
calculateLabelTranslation: () => calculateLabelTranslation,
|
|
calculateSegments: () => calculateSegments,
|
|
candlestickSeriesThemeableOptionsDef: () => candlestickSeriesThemeableOptionsDef,
|
|
checkCrisp: () => checkCrisp,
|
|
chordSeriesThemeableOptionsDef: () => chordSeriesThemeableOptionsDef,
|
|
clippedRoundRect: () => clippedRoundRect,
|
|
collapsedStartingBarPosition: () => collapsedStartingBarPosition,
|
|
computeBarFocusBounds: () => computeBarFocusBounds,
|
|
computeMarkerFocusBounds: () => computeMarkerFocusBounds,
|
|
coneFunnelSeriesThemeableOptionsDef: () => coneFunnelSeriesThemeableOptionsDef,
|
|
createDatumId: () => createDatumId,
|
|
diff: () => diff,
|
|
drawCorner: () => drawCorner,
|
|
drawMarkerUnitPolygon: () => drawMarkerUnitPolygon,
|
|
findNodeDatumInArray: () => findNodeDatumInArray,
|
|
findQuadtreeMatch: () => findQuadtreeMatch,
|
|
fixNumericExtent: () => fixNumericExtent,
|
|
fromToMotion: () => fromToMotion,
|
|
funnelSeriesThemeableOptionsDef: () => funnelSeriesThemeableOptionsDef,
|
|
generateTicks: () => generateTicks,
|
|
getColorStops: () => getColorStops,
|
|
getCrossLineValue: () => getCrossLineValue,
|
|
getItemStyles: () => getItemStyles,
|
|
getItemStylesPerItemId: () => getItemStylesPerItemId,
|
|
getLabelStyles: () => getLabelStyles,
|
|
getMarkerStyles: () => getMarkerStyles,
|
|
getMissCount: () => getMissCount,
|
|
getRadialColumnWidth: () => getRadialColumnWidth,
|
|
getShapeFill: () => getShapeFill,
|
|
getShapeStyle: () => getShapeStyle,
|
|
groupAccumulativeValueProperty: () => groupAccumulativeValueProperty,
|
|
hasDimmedOpacity: () => hasDimmedOpacity,
|
|
heatmapSeriesThemeableOptionsDef: () => heatmapSeriesThemeableOptionsDef,
|
|
initialStatePickedOptionsDef: () => initialStatePickedOptionsDef,
|
|
interpolatePoints: () => interpolatePoints,
|
|
isTooltipValueMissing: () => isTooltipValueMissing,
|
|
keyProperty: () => keyProperty,
|
|
makeSeriesTooltip: () => makeSeriesTooltip,
|
|
mapLineBackgroundSeriesThemeableOptionsDef: () => mapLineBackgroundSeriesThemeableOptionsDef,
|
|
mapLineSeriesThemeableOptionsDef: () => mapLineSeriesThemeableOptionsDef,
|
|
mapMarkerSeriesThemeableOptionsDef: () => mapMarkerSeriesThemeableOptionsDef,
|
|
mapShapeBackgroundSeriesThemeableOptionsDef: () => mapShapeBackgroundSeriesThemeableOptionsDef,
|
|
mapShapeSeriesThemeableOptionsDef: () => mapShapeSeriesThemeableOptionsDef,
|
|
markerEnabled: () => markerEnabled,
|
|
markerFadeInAnimation: () => markerFadeInAnimation,
|
|
markerSwipeScaleInAnimation: () => markerSwipeScaleInAnimation,
|
|
midpointStartingBarPosition: () => midpointStartingBarPosition,
|
|
minimumTimeAxisDatumGranularity: () => minimumTimeAxisDatumGranularity,
|
|
motion: () => motion,
|
|
nightingaleSeriesThemeableOptionsDef: () => nightingaleSeriesThemeableOptionsDef,
|
|
normaliseGroupTo: () => normaliseGroupTo,
|
|
ohlcSeriesThemeableOptionsDef: () => ohlcSeriesThemeableOptionsDef,
|
|
ordinalTimeAxisOptionsDefs: () => ordinalTimeAxisOptionsDefs,
|
|
pairUpSpans: () => pairUpSpans,
|
|
pathFadeInAnimation: () => pathFadeInAnimation,
|
|
pathMotion: () => pathMotion,
|
|
pathSwipeInAnimation: () => pathSwipeInAnimation,
|
|
plotAreaPathFill: () => plotAreaPathFill,
|
|
plotInterpolatedLinePathStroke: () => plotInterpolatedLinePathStroke,
|
|
plotLinePathStroke: () => plotLinePathStroke,
|
|
predictCartesianFinancialAxis: () => predictCartesianFinancialAxis,
|
|
predictCartesianNonPrimitiveAxis: () => predictCartesianNonPrimitiveAxis,
|
|
prepareAreaFillAnimationFns: () => prepareAreaFillAnimationFns,
|
|
prepareBarAnimationFunctions: () => prepareBarAnimationFunctions,
|
|
prepareLinePathPropertyAnimation: () => prepareLinePathPropertyAnimation,
|
|
processedDataIsAnimatable: () => processedDataIsAnimatable,
|
|
pyramidSeriesThemeableOptionsDef: () => pyramidSeriesThemeableOptionsDef,
|
|
radarAreaSeriesThemeableOptionsDef: () => radarAreaSeriesThemeableOptionsDef,
|
|
radarLineSeriesThemeableOptionsDef: () => radarLineSeriesThemeableOptionsDef,
|
|
radialBarSeriesThemeableOptionsDef: () => radialBarSeriesThemeableOptionsDef,
|
|
radialColumnSeriesThemeableOptionsDef: () => radialColumnSeriesThemeableOptionsDef,
|
|
radiusCategoryAxisOptionsDefs: () => radiusCategoryAxisOptionsDefs,
|
|
radiusNumberAxisOptionsDefs: () => radiusNumberAxisOptionsDefs,
|
|
rangeAreaSeriesThemeableOptionsDef: () => rangeAreaSeriesThemeableOptionsDef,
|
|
rangeBarSeriesThemeableOptionsDef: () => rangeBarSeriesThemeableOptionsDef,
|
|
resetAxisLabelSelectionFn: () => resetAxisLabelSelectionFn,
|
|
resetBarSelectionsDirect: () => resetBarSelectionsDirect,
|
|
resetBarSelectionsFn: () => resetBarSelectionsFn,
|
|
resetLabelFn: () => resetLabelFn,
|
|
resetMarkerFn: () => resetMarkerFn,
|
|
resetMarkerPositionFn: () => resetMarkerPositionFn,
|
|
resetMarkerSelectionsDirect: () => resetMarkerSelectionsDirect,
|
|
resetMotion: () => resetMotion,
|
|
sankeySeriesThemeableOptionsDef: () => sankeySeriesThemeableOptionsDef,
|
|
sectorBox: () => sectorBox,
|
|
seriesLabelFadeInAnimation: () => seriesLabelFadeInAnimation,
|
|
seriesLabelFadeOutAnimation: () => seriesLabelFadeOutAnimation,
|
|
stackCartesianSeries: () => stackCartesianSeries,
|
|
standaloneChartOptionsDefs: () => standaloneChartOptionsDefs,
|
|
sunburstSeriesThemeableOptionsDef: () => sunburstSeriesThemeableOptionsDef,
|
|
toHierarchyHighlightString: () => toHierarchyHighlightString,
|
|
toHighlightString: () => toHighlightString,
|
|
topologyChartOptionsDefs: () => topologyChartOptionsDefs,
|
|
trailingAccumulatedValueProperty: () => trailingAccumulatedValueProperty,
|
|
treemapSeriesThemeableOptionsDef: () => treemapSeriesThemeableOptionsDef,
|
|
updateClipPath: () => updateClipPath,
|
|
updateLabelNode: () => updateLabelNode,
|
|
upsertNodeDatum: () => upsertNodeDatum,
|
|
userInteraction: () => userInteraction,
|
|
validateCrossLineValue: () => validateCrossLineValue,
|
|
valueProperty: () => valueProperty,
|
|
visibleRangeIndices: () => visibleRangeIndices,
|
|
waterfallSeriesThemeableOptionsDef: () => waterfallSeriesThemeableOptionsDef
|
|
});
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/util.ts
|
|
var import_ag_charts_core188 = require("ag-charts-core");
|
|
function isAxisReversed(axis) {
|
|
return axis.isReversed() !== axis.range[1] < axis.range[0];
|
|
}
|
|
function calculateSegments(segmentation, xAxis, yAxis, seriesRect, chartSize, applyOffset = true) {
|
|
if (xAxis.scale.domain.length === 0 || yAxis.scale.domain.length === 0) {
|
|
return;
|
|
}
|
|
const axis = segmentation.key === import_ag_charts_core188.ChartAxisDirection.X ? xAxis : yAxis;
|
|
const { scale: scale2, direction } = axis;
|
|
const isXDirection = direction === import_ag_charts_core188.ChartAxisDirection.X;
|
|
const bandwidth = scale2.bandwidth ?? 0;
|
|
const offset = applyOffset ? ((scale2.step ?? 0) - bandwidth) / 2 : 0;
|
|
const horizontalMargin = Math.max(seriesRect.x, chartSize.width - (seriesRect.x + seriesRect.width));
|
|
const verticalMargin = Math.max(seriesRect.y, chartSize.height - (seriesRect.y + seriesRect.height));
|
|
const getDefaultStart = () => {
|
|
if (isAxisReversed(isXDirection ? xAxis : yAxis)) {
|
|
return isXDirection ? seriesRect.width + horizontalMargin : seriesRect.height + verticalMargin;
|
|
}
|
|
return isXDirection ? -horizontalMargin : -verticalMargin;
|
|
};
|
|
const getDefaultStop = () => {
|
|
if (isAxisReversed(isXDirection ? xAxis : yAxis)) {
|
|
return isXDirection ? -horizontalMargin : -verticalMargin;
|
|
}
|
|
return isXDirection ? seriesRect.width + horizontalMargin : seriesRect.height + verticalMargin;
|
|
};
|
|
const getSegments = (segments) => {
|
|
const result = [];
|
|
let previousDefinedStopIndex = -1;
|
|
for (let i = 0; i < segments.length; i++) {
|
|
const segment = segments[i];
|
|
if ((0, import_ag_charts_core188.isEmptyObject)(segment)) {
|
|
continue;
|
|
}
|
|
const { start, stop, ...styles } = segments[i];
|
|
const startFallback = segments[previousDefinedStopIndex]?.stop;
|
|
const stopFallback = segments.slice(i + 1).find((s) => s.start != null)?.start;
|
|
let startPosition = scale2.convert(start ?? startFallback) - offset;
|
|
let stopPosition = scale2.convert(stop ?? stopFallback) + 2 * offset;
|
|
const invalidStart = start != null && Number.isNaN(startPosition);
|
|
const invalidStop = stop != null && Number.isNaN(stopPosition);
|
|
if (invalidStart || invalidStop) {
|
|
continue;
|
|
}
|
|
if (Number.isNaN(startPosition))
|
|
startPosition = getDefaultStart();
|
|
if (Number.isNaN(stopPosition))
|
|
stopPosition = getDefaultStop();
|
|
if (stop != null) {
|
|
previousDefinedStopIndex = i;
|
|
}
|
|
result.push({ start: startPosition, stop: stopPosition, ...styles });
|
|
}
|
|
return result;
|
|
};
|
|
return getSegments(segmentation.segments).map(({ stop, start, ...style }) => {
|
|
const x0 = isXDirection ? start : -horizontalMargin;
|
|
const y0 = isXDirection ? -verticalMargin : start;
|
|
const x1 = isXDirection ? stop + bandwidth : seriesRect.width + horizontalMargin;
|
|
const y1 = isXDirection ? seriesRect.height + verticalMargin : stop + bandwidth;
|
|
return { clipRect: { x0, y0, x1, y1 }, ...style };
|
|
});
|
|
}
|
|
var TIME_AXIS_KEYS = /* @__PURE__ */ new Set(["time", "timestamp", "date", "datetime"]);
|
|
function predictCartesianAxis(direction, datum, seriesOptions, { allowPrimitiveTypes = true } = {}) {
|
|
if (direction !== import_ag_charts_core188.ChartAxisDirection.X && direction !== import_ag_charts_core188.ChartAxisDirection.Y)
|
|
return;
|
|
if (!(0, import_ag_charts_core188.isObject)(datum))
|
|
return;
|
|
const key = getSeriesOptionsKey(direction, seriesOptions);
|
|
if (key == null || !(key in datum))
|
|
return;
|
|
const value = datum[key];
|
|
const position = getAxisPosition(direction, seriesOptions);
|
|
const groupedCategory = predictGroupedCategoryAxisType(value);
|
|
if (groupedCategory) {
|
|
return { type: groupedCategory, position };
|
|
}
|
|
const timeAxis = predictTimeAxisType(key, value);
|
|
if (timeAxis) {
|
|
return { type: timeAxis, position };
|
|
}
|
|
if (!allowPrimitiveTypes)
|
|
return;
|
|
if (typeof value === "number") {
|
|
return {
|
|
type: import_ag_charts_core188.CARTESIAN_AXIS_TYPE.NUMBER,
|
|
position
|
|
};
|
|
}
|
|
return {
|
|
type: import_ag_charts_core188.CARTESIAN_AXIS_TYPE.CATEGORY,
|
|
position
|
|
};
|
|
}
|
|
function predictCartesianNonPrimitiveAxis(direction, datum, seriesOptions) {
|
|
return predictCartesianAxis(direction, datum, seriesOptions, { allowPrimitiveTypes: false });
|
|
}
|
|
function predictCartesianFinancialAxis(direction, datum, seriesOptions) {
|
|
if (direction !== import_ag_charts_core188.ChartAxisDirection.X)
|
|
return;
|
|
if (!(0, import_ag_charts_core188.isObject)(datum))
|
|
return;
|
|
const key = getSeriesOptionsKey(direction, seriesOptions);
|
|
if (key == null || !(key in datum))
|
|
return;
|
|
const value = datum[key];
|
|
const position = getAxisPosition(direction, seriesOptions);
|
|
const ordinalTimeAxis = predictOrdinalTimeAxisType(key, value);
|
|
if (ordinalTimeAxis) {
|
|
return { type: ordinalTimeAxis, position };
|
|
}
|
|
if ((0, import_ag_charts_core188.isString)(value)) {
|
|
return { type: "category", position };
|
|
}
|
|
}
|
|
function predictGroupedCategoryAxisType(value) {
|
|
if ((0, import_ag_charts_core188.isArray)(value) && value.every((v) => (0, import_ag_charts_core188.isString)(v) || v === null)) {
|
|
return import_ag_charts_core188.CARTESIAN_AXIS_TYPE.GROUPED_CATEGORY;
|
|
}
|
|
}
|
|
function predictTimeAxisType(key, value) {
|
|
if ((0, import_ag_charts_core188.isDate)(value) || TIME_AXIS_KEYS.has(key) && (0, import_ag_charts_core188.isNumber)(value)) {
|
|
return import_ag_charts_core188.CARTESIAN_AXIS_TYPE.TIME;
|
|
}
|
|
}
|
|
function predictOrdinalTimeAxisType(key, value) {
|
|
if ((0, import_ag_charts_core188.isDate)(value) || TIME_AXIS_KEYS.has(key) && (0, import_ag_charts_core188.isNumber)(value)) {
|
|
return import_ag_charts_core188.CARTESIAN_AXIS_TYPE.ORDINAL_TIME;
|
|
}
|
|
}
|
|
function getSeriesOptionsKey(direction, seriesOptions) {
|
|
if (direction === import_ag_charts_core188.ChartAxisDirection.X && "xKey" in seriesOptions) {
|
|
return seriesOptions.xKey;
|
|
} else if (direction === import_ag_charts_core188.ChartAxisDirection.Y && "yKey" in seriesOptions) {
|
|
return seriesOptions.yKey;
|
|
}
|
|
}
|
|
function getAxisPosition(direction, seriesOptions) {
|
|
if ("direction" in seriesOptions && seriesOptions.direction === "horizontal") {
|
|
return direction === import_ag_charts_core188.ChartAxisDirection.X ? import_ag_charts_core188.CARTESIAN_POSITION.LEFT : import_ag_charts_core188.CARTESIAN_POSITION.BOTTOM;
|
|
}
|
|
return direction === import_ag_charts_core188.ChartAxisDirection.X ? import_ag_charts_core188.CARTESIAN_POSITION.BOTTOM : import_ag_charts_core188.CARTESIAN_POSITION.LEFT;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/cartesianSeries.ts
|
|
var import_ag_charts_core197 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scale/logScale.ts
|
|
var import_ag_charts_core189 = require("ag-charts-core");
|
|
var logFunctions = {
|
|
2: (_base, x) => Math.log2(x),
|
|
[Math.E]: (_base, x) => Math.log(x),
|
|
10: (_base, x) => Math.log10(x)
|
|
};
|
|
var DEFAULT_LOG = (base, x) => Math.log(x) / Math.log(base);
|
|
function log(base, domain, x) {
|
|
const start = Math.min(...domain);
|
|
const fn = logFunctions[base] ?? DEFAULT_LOG;
|
|
return start >= 0 ? fn(base, x) : -fn(base, -x);
|
|
}
|
|
var powFunctions = {
|
|
[Math.E]: (_base, x) => Math.exp(x),
|
|
10: (_base, x) => x >= 0 ? 10 ** x : 1 / 10 ** -x
|
|
};
|
|
var DEFAULT_POW = (base, x) => base ** x;
|
|
function pow(base, domain, x) {
|
|
const start = Math.min(...domain);
|
|
const fn = powFunctions[base] ?? DEFAULT_POW;
|
|
return start >= 0 ? fn(base, x) : -fn(base, -x);
|
|
}
|
|
var LogScale = class _LogScale extends ContinuousScale {
|
|
constructor(d = [1, 10], r = [0, 1]) {
|
|
super(d, r);
|
|
this.type = "log";
|
|
// Handling <1 and crossing 0 cases is tricky, easiest solution is to default to clamping.
|
|
this.defaultClamp = true;
|
|
this.base = 10;
|
|
this.log = (x) => log(this.base, this.domain, x);
|
|
this.pow = (x) => pow(this.base, this.domain, x);
|
|
}
|
|
static is(value) {
|
|
return value instanceof _LogScale;
|
|
}
|
|
transform(x) {
|
|
const [min, max] = (0, import_ag_charts_core189.findMinMax)(this.domain);
|
|
if (min >= 0 !== max >= 0)
|
|
return Number.NaN;
|
|
return min >= 0 ? Math.log(x) : -Math.log(-x);
|
|
}
|
|
transformInvert(x) {
|
|
const [min, max] = (0, import_ag_charts_core189.findMinMax)(this.domain);
|
|
if (min >= 0 !== max >= 0)
|
|
return Number.NaN;
|
|
return min >= 0 ? Math.exp(x) : -Math.exp(-x);
|
|
}
|
|
toDomain(d) {
|
|
return d;
|
|
}
|
|
niceDomain(ticks, domain = this.domain) {
|
|
if (domain.length < 2)
|
|
return [];
|
|
const { base } = this;
|
|
const [d0, d1] = domain;
|
|
const roundStart = d0 > d1 ? Math.ceil : Math.floor;
|
|
const roundStop = d0 > d1 ? Math.floor : Math.ceil;
|
|
const n0 = pow(base, domain, roundStart(log(base, domain, d0)));
|
|
const n1 = pow(base, domain, roundStop(log(base, domain, d1)));
|
|
return [ticks.nice[0] ? n0 : domain[0], ticks.nice[1] ? n1 : domain[1]];
|
|
}
|
|
ticks({ interval, tickCount = ContinuousScale.defaultTickCount }, domain = this.domain, visibleRange) {
|
|
if (!domain || domain.length < 2 || tickCount < 1) {
|
|
return;
|
|
}
|
|
const base = this.base;
|
|
const [d0, d1] = domain;
|
|
const start = Math.min(d0, d1);
|
|
const stop = Math.max(d0, d1);
|
|
let p0 = this.log(start);
|
|
let p1 = this.log(stop);
|
|
if (interval) {
|
|
const inBounds = (tick) => tick >= start && tick <= stop;
|
|
const step = Math.min(Math.abs(interval), Math.abs(p1 - p0));
|
|
const { ticks: rangeTicks, count, firstTickIndex } = (0, import_ag_charts_core189.range)(p0, p1, step, visibleRange);
|
|
const ticks2 = rangeTicks.map(this.pow).filter(inBounds);
|
|
if (!(0, import_ag_charts_core189.isDenseInterval)(ticks2.length, this.getPixelRange())) {
|
|
return { ticks: ticks2, count, firstTickIndex };
|
|
}
|
|
}
|
|
if (!(0, import_ag_charts_core189.isInteger)(base) || p1 - p0 >= tickCount) {
|
|
const step = Math.min(p1 - p0, tickCount);
|
|
const { ticks: ticks2, count, firstTickIndex } = (0, import_ag_charts_core189.createTicks)(p0, p1, step, void 0, void 0, visibleRange);
|
|
return {
|
|
ticks: ticks2.map(this.pow),
|
|
count,
|
|
firstTickIndex
|
|
};
|
|
}
|
|
const ticks = [];
|
|
const isPositive = start > 0;
|
|
p0 = Math.floor(p0) - 1;
|
|
p1 = Math.round(p1) + 1;
|
|
const availableSpacing = (0, import_ag_charts_core189.findRangeExtent)(this.range) / tickCount;
|
|
let lastTickPosition = Infinity;
|
|
for (let p = p0; p <= p1; p++) {
|
|
const nextMagnitudeTickPosition = this.convert(this.pow(p + 1));
|
|
for (let k = 1; k < base; k++) {
|
|
const q = isPositive ? k : base - k + 1;
|
|
const t = this.pow(p) * q;
|
|
const tickPosition = this.convert(t);
|
|
const prevSpacing = Math.abs(lastTickPosition - tickPosition);
|
|
const nextSpacing = Math.abs(tickPosition - nextMagnitudeTickPosition);
|
|
const fits = prevSpacing >= availableSpacing && nextSpacing >= availableSpacing;
|
|
if (t >= start && t <= stop && (k === 1 || fits || ticks.length === 0)) {
|
|
ticks.push(t);
|
|
lastTickPosition = tickPosition;
|
|
}
|
|
}
|
|
}
|
|
return filterVisibleTicks(ticks, isPositive, visibleRange);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/segmentedGroup.ts
|
|
var import_ag_charts_core191 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/shape/segmentedPath.ts
|
|
var import_ag_charts_core190 = require("ag-charts-core");
|
|
var SegmentedPath = class extends Path {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.segmentPath = new Path();
|
|
}
|
|
drawPath(ctx) {
|
|
if (!this.segments || this.segments.length === 0) {
|
|
super.drawPath(ctx);
|
|
return;
|
|
}
|
|
ctx.save();
|
|
const Path2DCtor = (0, import_ag_charts_core190.getPath2D)();
|
|
const inverse = new Path2DCtor();
|
|
rect(inverse, { x0: 0, y0: 0, x1: ctx.canvas.width, y1: ctx.canvas.height }, false);
|
|
for (const s of this.segments) {
|
|
rect(inverse, s.clipRect);
|
|
}
|
|
ctx.clip(inverse);
|
|
super.drawPath(ctx);
|
|
ctx.restore();
|
|
const { segmentPath } = this;
|
|
segmentPath.setProperties({
|
|
opacity: this.opacity,
|
|
visible: this.visible,
|
|
lineCap: this.lineCap,
|
|
lineJoin: this.lineJoin,
|
|
pointerEvents: this.pointerEvents
|
|
});
|
|
for (const { clipRect, fill, stroke, ...styles } of this.segments) {
|
|
ctx.save();
|
|
segmentPath.path = this.path;
|
|
segmentPath.setProperties(styles);
|
|
segmentPath.fill = this.fill == null ? "none" : fill;
|
|
segmentPath.stroke = this.stroke == null ? "none" : stroke;
|
|
const clipPath = new Path2DCtor();
|
|
rect(clipPath, clipRect);
|
|
ctx.clip(clipPath);
|
|
segmentPath.drawPath(ctx);
|
|
ctx.restore();
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core190.SceneRefChangeDetection)()
|
|
], SegmentedPath.prototype, "segments", 2);
|
|
function rect(path, { x0, y0, x1, y1 }, clockwise = true) {
|
|
const minX = Math.min(x0, x1);
|
|
const minY = Math.min(y0, y1);
|
|
const maxX = Math.max(x0, x1);
|
|
const maxY = Math.max(y0, y1);
|
|
path.moveTo(minX, minY);
|
|
if (clockwise) {
|
|
path.lineTo(maxX, minY);
|
|
path.lineTo(maxX, maxY);
|
|
path.lineTo(minX, maxY);
|
|
} else {
|
|
path.lineTo(minX, maxY);
|
|
path.lineTo(maxX, maxY);
|
|
path.lineTo(maxX, minY);
|
|
}
|
|
path.closePath();
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/segmentedGroup.ts
|
|
var SegmentedGroup = class extends TranslatableGroup {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.segments = [];
|
|
this.scalablePath = new (Scalable(Path))();
|
|
}
|
|
renderInContext(childRenderCtx) {
|
|
if (!this.visible)
|
|
return;
|
|
const { ctx } = childRenderCtx;
|
|
if (!this.segments || this.segments?.length === 0) {
|
|
return super.renderInContext(childRenderCtx);
|
|
}
|
|
ctx.save();
|
|
const Path2DCtor = (0, import_ag_charts_core191.getPath2D)();
|
|
const inverse = new Path2DCtor();
|
|
rect(inverse, { x0: 0, y0: 0, x1: ctx.canvas.width, y1: ctx.canvas.height }, false);
|
|
for (const s of this.segments) {
|
|
rect(inverse, s.clipRect);
|
|
}
|
|
ctx.clip(inverse);
|
|
for (const child of this.children()) {
|
|
if (!child.visible)
|
|
continue;
|
|
child.render(childRenderCtx);
|
|
}
|
|
ctx.restore();
|
|
const { scalablePath } = this;
|
|
for (const { clipRect, ...styles } of this.segments) {
|
|
ctx.save();
|
|
const clipPath = new Path2DCtor();
|
|
rect(clipPath, clipRect);
|
|
ctx.clip(clipPath);
|
|
scalablePath.setProperties(styles);
|
|
for (const child of this.children()) {
|
|
if (!child.visible || !(child instanceof Path))
|
|
continue;
|
|
scalablePath.path = child.path;
|
|
scalablePath.setProperties({
|
|
opacity: child.opacity,
|
|
lineCap: child.lineCap,
|
|
lineJoin: child.lineJoin,
|
|
...isScalable(child) && {
|
|
scalingX: child.scalingX,
|
|
scalingY: child.scalingY,
|
|
scalingCenterX: child.scalingCenterX,
|
|
scalingCenterY: child.scalingCenterY
|
|
}
|
|
});
|
|
scalablePath.render(childRenderCtx);
|
|
}
|
|
ctx.restore();
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core191.SceneRefChangeDetection)()
|
|
], SegmentedGroup.prototype, "segments", 2);
|
|
|
|
// packages/ag-charts-community/src/scene/util/quadtree.ts
|
|
var import_ag_charts_core192 = require("ag-charts-core");
|
|
var QuadtreeNearest = class {
|
|
constructor(capacity, maxdepth, boundary) {
|
|
this.root = new QuadtreeNodeNearest(capacity, maxdepth, boundary);
|
|
}
|
|
clear(boundary) {
|
|
this.root.clear(boundary);
|
|
}
|
|
addValue(hitTester, value) {
|
|
const elem = {
|
|
hitTester,
|
|
value,
|
|
distanceSquared: (x, y) => {
|
|
return hitTester.distanceSquared(x, y);
|
|
}
|
|
};
|
|
this.root.addElem(elem);
|
|
}
|
|
find(x, y) {
|
|
const arg = { best: { nearest: void 0, distanceSquared: Infinity } };
|
|
this.root.find(x, y, arg);
|
|
return arg.best;
|
|
}
|
|
};
|
|
var QuadtreeSubdivisions = class {
|
|
constructor(nw, ne, sw, se) {
|
|
this.nw = nw;
|
|
this.ne = ne;
|
|
this.sw = sw;
|
|
this.se = se;
|
|
}
|
|
addElem(elem) {
|
|
this.nw.addElem(elem);
|
|
this.ne.addElem(elem);
|
|
this.sw.addElem(elem);
|
|
this.se.addElem(elem);
|
|
}
|
|
find(x, y, arg) {
|
|
this.nw.find(x, y, arg);
|
|
this.ne.find(x, y, arg);
|
|
this.sw.find(x, y, arg);
|
|
this.se.find(x, y, arg);
|
|
}
|
|
};
|
|
var QuadtreeNode = class {
|
|
constructor(capacity, maxdepth, boundary) {
|
|
this.capacity = capacity;
|
|
this.maxdepth = maxdepth;
|
|
this.boundary = boundary ?? BBox.NaN;
|
|
this.elems = [];
|
|
this.subdivisions = void 0;
|
|
}
|
|
clear(boundary) {
|
|
this.elems.length = 0;
|
|
this.boundary = boundary;
|
|
this.subdivisions = void 0;
|
|
}
|
|
addElem(e) {
|
|
if (this.addCondition(e)) {
|
|
if (this.subdivisions === void 0) {
|
|
if (this.maxdepth === 0 || this.elems.length < this.capacity) {
|
|
this.elems.push(e);
|
|
} else {
|
|
this.subdivide(e);
|
|
}
|
|
} else {
|
|
this.subdivisions.addElem(e);
|
|
}
|
|
}
|
|
}
|
|
find(x, y, arg) {
|
|
if (this.findCondition(x, y, arg)) {
|
|
if (this.subdivisions === void 0) {
|
|
this.findAction(x, y, arg);
|
|
} else {
|
|
this.subdivisions.find(x, y, arg);
|
|
}
|
|
}
|
|
}
|
|
subdivide(newElem) {
|
|
this.subdivisions = this.makeSubdivisions();
|
|
for (const e of this.elems) {
|
|
this.subdivisions.addElem(e);
|
|
}
|
|
this.subdivisions.addElem(newElem);
|
|
this.elems.length = 0;
|
|
}
|
|
makeSubdivisions() {
|
|
const { x, y, width, height } = this.boundary;
|
|
const { capacity } = this;
|
|
const depth = this.maxdepth - 1;
|
|
const halfWidth = width / 2;
|
|
const halfHeight = height / 2;
|
|
const nwBoundary = new BBox(x, y, halfWidth, halfHeight);
|
|
const neBoundary = new BBox(x + halfWidth, y, halfWidth, halfHeight);
|
|
const swBoundary = new BBox(x, y + halfHeight, halfWidth, halfHeight);
|
|
const seBoundary = new BBox(x + halfWidth, y + halfHeight, halfWidth, halfHeight);
|
|
return new QuadtreeSubdivisions(
|
|
this.child(capacity, depth, nwBoundary),
|
|
this.child(capacity, depth, neBoundary),
|
|
this.child(capacity, depth, swBoundary),
|
|
this.child(capacity, depth, seBoundary)
|
|
);
|
|
}
|
|
};
|
|
var QuadtreeNodeNearest = class _QuadtreeNodeNearest extends QuadtreeNode {
|
|
addCondition(e) {
|
|
const { x, y } = e.hitTester.midPoint;
|
|
return this.boundary.containsPoint(x, y);
|
|
}
|
|
findCondition(x, y, arg) {
|
|
const { best } = arg;
|
|
return best.distanceSquared !== 0 && this.boundary.distanceSquared(x, y) < best.distanceSquared;
|
|
}
|
|
findAction(x, y, arg) {
|
|
const other = (0, import_ag_charts_core192.nearestSquared)(x, y, this.elems, arg.best.distanceSquared);
|
|
if (other.nearest !== void 0 && other.distanceSquared < arg.best.distanceSquared) {
|
|
arg.best = other;
|
|
}
|
|
}
|
|
child(capacity, depth, boundary) {
|
|
return new _QuadtreeNodeNearest(capacity, depth, boundary);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/axis/numberAxis.ts
|
|
var import_ag_charts_core194 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scale/linearScale.ts
|
|
var import_ag_charts_core193 = require("ag-charts-core");
|
|
var LinearScale = class _LinearScale extends ContinuousScale {
|
|
constructor() {
|
|
super([0, 1], [0, 1]);
|
|
this.type = "number";
|
|
}
|
|
static is(value) {
|
|
return value instanceof _LinearScale;
|
|
}
|
|
static getTickStep(start, stop, ticks) {
|
|
const { interval, tickCount = ContinuousScale.defaultTickCount, minTickCount, maxTickCount } = ticks;
|
|
return interval ?? (0, import_ag_charts_core193.tickStep)(start, stop, tickCount, minTickCount, maxTickCount);
|
|
}
|
|
toDomain(d) {
|
|
return d;
|
|
}
|
|
ticks({ interval, tickCount = ContinuousScale.defaultTickCount, minTickCount, maxTickCount }, domain = this.domain, visibleRange) {
|
|
if (!domain || domain.length < 2 || tickCount < 1 || !domain.every(Number.isFinite)) {
|
|
return { ticks: [], count: 0, firstTickIndex: 0 };
|
|
}
|
|
const [d0, d1] = domain;
|
|
if (interval) {
|
|
const step = Math.abs(interval);
|
|
if (!(0, import_ag_charts_core193.isDenseInterval)((d1 - d0) / step, this.getPixelRange())) {
|
|
return (0, import_ag_charts_core193.range)(d0, d1, step, visibleRange);
|
|
}
|
|
}
|
|
return (0, import_ag_charts_core193.createTicks)(d0, d1, tickCount, minTickCount, maxTickCount, visibleRange);
|
|
}
|
|
niceDomain(ticks, domain = this.domain) {
|
|
if (domain.length < 2)
|
|
return [];
|
|
const { tickCount = ContinuousScale.defaultTickCount } = ticks;
|
|
let [start, stop] = domain;
|
|
if (tickCount === 1) {
|
|
[start, stop] = (0, import_ag_charts_core193.niceTicksDomain)(start, stop);
|
|
} else if (tickCount > 1) {
|
|
const roundStart = start > stop ? Math.ceil : Math.floor;
|
|
const roundStop = start > stop ? Math.floor : Math.ceil;
|
|
const maxAttempts = 4;
|
|
for (let i = 0; i < maxAttempts; i++) {
|
|
const prev0 = start;
|
|
const prev1 = stop;
|
|
const step = _LinearScale.getTickStep(start, stop, ticks);
|
|
const [d0, d1] = domain;
|
|
start = roundStart(d0 / step) * step;
|
|
stop = roundStop(d1 / step) * step;
|
|
if (start === prev0 && stop === prev1)
|
|
break;
|
|
}
|
|
}
|
|
return [ticks.nice[0] ? start : domain[0], ticks.nice[1] ? stop : domain[1]];
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/axis/numberAxis.ts
|
|
var NumberAxis = class extends CartesianAxis {
|
|
constructor(moduleCtx, scale2 = new LinearScale()) {
|
|
super(moduleCtx, scale2);
|
|
}
|
|
hasDefinedDomain() {
|
|
const { min, max } = this;
|
|
return min != null && max != null && min < max;
|
|
}
|
|
normaliseDataDomain(d) {
|
|
const { min, max, preferredMin, preferredMax } = this;
|
|
const { extent: extent6, clipped } = (0, import_ag_charts_core194.normalisedExtentWithMetadata)(
|
|
d.domain,
|
|
min,
|
|
max,
|
|
preferredMin,
|
|
preferredMax,
|
|
void 0,
|
|
d.sortMetadata?.sortOrder
|
|
);
|
|
return { domain: extent6, clipped };
|
|
}
|
|
getDomainExtentsNice() {
|
|
return [this.min == null && this.nice, this.max == null && this.nice];
|
|
}
|
|
getVisibleDomain(domain) {
|
|
const [d0, d1] = domain;
|
|
const [r0, r1] = this.visibleRange;
|
|
const length = d1 - d0;
|
|
return [d0 + r0 * length, d1 - (1 - r1) * length];
|
|
}
|
|
tickFormatParams(domain, _ticks, fractionDigits) {
|
|
return { type: "number", visibleDomain: this.getVisibleDomain(domain), fractionDigits };
|
|
}
|
|
datumFormatParams(value, params, fractionDigits) {
|
|
const { datum, seriesId, legendItemName, key, source, property, domain, boundSeries } = params;
|
|
const visibleDomain = this.getVisibleDomain(domain);
|
|
return {
|
|
type: "number",
|
|
value,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key,
|
|
source,
|
|
property,
|
|
domain,
|
|
visibleDomain,
|
|
boundSeries,
|
|
fractionDigits
|
|
};
|
|
}
|
|
};
|
|
NumberAxis.className = "NumberAxis";
|
|
NumberAxis.type = "number";
|
|
__decorateClass([
|
|
import_ag_charts_core194.Property
|
|
], NumberAxis.prototype, "min", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core194.Property
|
|
], NumberAxis.prototype, "max", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core194.Property
|
|
], NumberAxis.prototype, "preferredMin", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core194.Property
|
|
], NumberAxis.prototype, "preferredMax", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/timeAxis.ts
|
|
var import_ag_charts_core195 = require("ag-charts-core");
|
|
var TimeAxisParentLevel = class extends import_ag_charts_core195.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = false;
|
|
this.label = new AxisLabel();
|
|
this.tick = new AxisTick();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core195.Property
|
|
], TimeAxisParentLevel.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core195.Property
|
|
], TimeAxisParentLevel.prototype, "label", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core195.Property
|
|
], TimeAxisParentLevel.prototype, "tick", 2);
|
|
var TimeAxis = class extends CartesianAxis {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, new TimeScale());
|
|
this.parentLevel = new TimeAxisParentLevel();
|
|
this.min = void 0;
|
|
this.max = void 0;
|
|
this.preferredMin = void 0;
|
|
this.preferredMax = void 0;
|
|
}
|
|
// eslint-disable-next-line sonarjs/use-type-alias
|
|
get _unit() {
|
|
return void 0;
|
|
}
|
|
set _unit(_unit) {
|
|
import_ag_charts_core195.Logger.warnOnce(`To use 'unit', use an axis with type 'unit-time' instead of 'time'.`);
|
|
}
|
|
hasDefinedDomain() {
|
|
const { min, max } = this;
|
|
return min != null && max != null && min < max;
|
|
}
|
|
isCategoryLike() {
|
|
return false;
|
|
}
|
|
get primaryLabel() {
|
|
return this.parentLevel.enabled ? this.parentLevel.label : void 0;
|
|
}
|
|
get primaryTick() {
|
|
return this.parentLevel.enabled ? this.parentLevel.tick : void 0;
|
|
}
|
|
normaliseDataDomain(d) {
|
|
const { extent: extent6, clipped } = (0, import_ag_charts_core195.normalisedTimeExtentWithMetadata)(
|
|
d,
|
|
this.min,
|
|
this.max,
|
|
this.preferredMin,
|
|
this.preferredMax
|
|
);
|
|
return { domain: extent6, clipped };
|
|
}
|
|
processData() {
|
|
super.processData();
|
|
const { boundSeries, direction, min, max } = this;
|
|
this.minimumTimeGranularity = minimumTimeAxisDatumGranularity(boundSeries, direction, min, max);
|
|
}
|
|
tickFormatParams(domain, ticks, _fractionDigits, timeInterval2) {
|
|
timeInterval2 ?? (timeInterval2 = (0, import_ag_charts_core195.lowestGranularityUnitForTicks)(ticks));
|
|
const truncateDate = (0, import_ag_charts_core195.dateTruncationForDomain)(domain);
|
|
const unit = (0, import_ag_charts_core195.intervalUnit)(timeInterval2);
|
|
const step = (0, import_ag_charts_core195.intervalStep)(timeInterval2);
|
|
const epoch = (0, import_ag_charts_core195.intervalEpoch)(timeInterval2);
|
|
return { type: "date", unit, step, epoch, truncateDate };
|
|
}
|
|
datumFormatParams(value, params, _fractionDigits, timeInterval2, style) {
|
|
if (typeof value === "number") {
|
|
value = new Date(value);
|
|
}
|
|
if (timeInterval2 == null) {
|
|
const { minimumTimeGranularity } = this;
|
|
const datumGranularity = (0, import_ag_charts_core195.lowestGranularityUnitForValue)(value);
|
|
if (minimumTimeGranularity != null && (0, import_ag_charts_core195.intervalMilliseconds)(minimumTimeGranularity) < (0, import_ag_charts_core195.intervalMilliseconds)(datumGranularity)) {
|
|
timeInterval2 = minimumTimeGranularity;
|
|
} else {
|
|
timeInterval2 = datumGranularity;
|
|
}
|
|
}
|
|
const { datum, seriesId, legendItemName, key, source, property, domain, boundSeries } = params;
|
|
const unit = (0, import_ag_charts_core195.intervalUnit)(timeInterval2);
|
|
const step = (0, import_ag_charts_core195.intervalStep)(timeInterval2);
|
|
const epoch = (0, import_ag_charts_core195.intervalEpoch)(timeInterval2);
|
|
return {
|
|
type: "date",
|
|
value,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key,
|
|
source,
|
|
property,
|
|
domain,
|
|
boundSeries,
|
|
unit,
|
|
step,
|
|
epoch,
|
|
style
|
|
};
|
|
}
|
|
};
|
|
TimeAxis.className = "TimeAxis";
|
|
TimeAxis.type = "time";
|
|
__decorateClass([
|
|
import_ag_charts_core195.Property
|
|
], TimeAxis.prototype, "parentLevel", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core195.Property
|
|
], TimeAxis.prototype, "min", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core195.Property
|
|
], TimeAxis.prototype, "max", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core195.Property
|
|
], TimeAxis.prototype, "preferredMin", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core195.Property
|
|
], TimeAxis.prototype, "preferredMax", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core195.Property,
|
|
(0, import_ag_charts_core195.ProxyPropertyOnWrite)("_unit")
|
|
], TimeAxis.prototype, "unit", 2);
|
|
function minimumTimeAxisDatumGranularity(boundSeries, direction, min, max) {
|
|
const minTimeInterval = boundSeries.reduce((t, series) => {
|
|
return Math.min(series.minTimeInterval() ?? Infinity, t);
|
|
}, Infinity);
|
|
if (Number.isFinite(minTimeInterval)) {
|
|
return (0, import_ag_charts_core195.lowestGranularityForInterval)(minTimeInterval);
|
|
} else {
|
|
return calculateDefaultUnit(boundSeries, direction, min, max)?.unit;
|
|
}
|
|
}
|
|
function calculateDefaultUnit(boundSeries, direction, min, max) {
|
|
let start = Infinity;
|
|
let end2 = -Infinity;
|
|
let interval;
|
|
let maxDataCount = 0;
|
|
const domainValues = [];
|
|
for (const series of boundSeries) {
|
|
if (!series.visible)
|
|
continue;
|
|
const { extent: domain } = (0, import_ag_charts_core195.normalisedTimeExtentWithMetadata)(series.getDomain(direction));
|
|
if (domain.length === 0)
|
|
continue;
|
|
const d0 = domain[0].valueOf();
|
|
const d1 = domain.at(-1).valueOf();
|
|
domainValues.push(d0, d1);
|
|
start = Math.min(start ?? Infinity, d0, d1);
|
|
end2 = Math.max(end2 ?? -Infinity, d0, d1);
|
|
const domainExtent = Math.abs(d1 - d0);
|
|
if (domainExtent === 0)
|
|
continue;
|
|
const dataCount = series.dataCount();
|
|
maxDataCount = Math.max(maxDataCount, dataCount);
|
|
if (dataCount <= 1)
|
|
continue;
|
|
const i = domainExtent / (dataCount - 1);
|
|
interval = Math.min(interval ?? Infinity, i);
|
|
}
|
|
start = Math.min(start, min?.valueOf() ?? Infinity, max?.valueOf() ?? Infinity);
|
|
end2 = Math.max(end2, min?.valueOf() ?? -Infinity, max?.valueOf() ?? -Infinity);
|
|
if (!Number.isFinite(start) || !Number.isFinite(end2))
|
|
return;
|
|
interval ?? (interval = Math.abs(end2 - start));
|
|
interval = Math.min(interval, minNonZeroDifference(domainValues));
|
|
const unit = (0, import_ag_charts_core195.lowestGranularityForInterval)(interval);
|
|
let step = interval / (0, import_ag_charts_core195.intervalMilliseconds)(unit);
|
|
if (maxDataCount <= 2) {
|
|
step = Math.floor(step);
|
|
} else {
|
|
step = Math.round(step);
|
|
}
|
|
step = Math.max(step, 1);
|
|
const epoch = step === 1 ? void 0 : (0, import_ag_charts_core195.intervalFloor)(unit, start);
|
|
return { unit, step, epoch };
|
|
}
|
|
function minNonZeroDifference(values) {
|
|
values.sort((a, b) => a - b);
|
|
let minDiff = Infinity;
|
|
for (let i = 1; i < values.length; i++) {
|
|
const d0 = values[i - 1];
|
|
const d1 = values[i];
|
|
const delta3 = d1 - d0;
|
|
if (delta3 > 0) {
|
|
minDiff = Math.min(minDiff, Math.abs(d1 - d0));
|
|
}
|
|
}
|
|
return minDiff;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/dataModelSeries.ts
|
|
var import_ag_charts_core196 = require("ag-charts-core");
|
|
var DataModelSeries = class extends Series {
|
|
constructor({ clipFocusBox, categoryKey, ...seriesOpts }) {
|
|
super(seriesOpts);
|
|
this.categoryKey = categoryKey;
|
|
this.clipFocusBox = clipFocusBox ?? true;
|
|
}
|
|
dataCount() {
|
|
return this.processedData?.dataSources?.get(this.id)?.data?.length ?? 0;
|
|
}
|
|
invalidDataCount() {
|
|
return this.processedData?.invalidDataCount?.get(this.id) ?? 0;
|
|
}
|
|
missingDataCount() {
|
|
return this.dataModel?.resolveMissingDataCount(this) ?? 0;
|
|
}
|
|
get hasData() {
|
|
return Math.max(0, this.dataCount() - this.invalidDataCount() - this.missingDataCount()) > 0;
|
|
}
|
|
getScaleInformation({
|
|
xScale,
|
|
yScale
|
|
}) {
|
|
const isContinuousX = ContinuousScale.is(xScale);
|
|
const isContinuousY = ContinuousScale.is(yScale);
|
|
return { isContinuousX, isContinuousY, xScaleType: xScale?.type, yScaleType: yScale?.type };
|
|
}
|
|
getModulePropertyDefinitions() {
|
|
const xScale = this.axes[import_ag_charts_core196.ChartAxisDirection.X]?.scale;
|
|
const yScale = this.axes[import_ag_charts_core196.ChartAxisDirection.Y]?.scale;
|
|
return this.moduleMap.mapModules((m) => m.getPropertyDefinitions(this.getScaleInformation({ xScale, yScale }))).flat();
|
|
}
|
|
// Request data, but with message dispatching to series-options (modules).
|
|
async requestDataModel(dataController, dataSet, opts) {
|
|
opts.props.push(...this.getModulePropertyDefinitions());
|
|
const { dataModel, processedData } = await dataController.request(
|
|
this.id,
|
|
dataSet ?? DataSet.empty(),
|
|
opts
|
|
);
|
|
this.dataModel = dataModel;
|
|
this.processedData = processedData;
|
|
this.events.emit("data-processed", { dataModel, processedData });
|
|
return { dataModel, processedData };
|
|
}
|
|
isProcessedDataAnimatable() {
|
|
const { processedData, ctx } = this;
|
|
if (!processedData)
|
|
return false;
|
|
const nodeData = this.getNodeData();
|
|
if (nodeData != null && nodeData.length > ctx.animationManager.maxAnimatableItems)
|
|
return false;
|
|
const validationResults = processedData.reduced?.animationValidation;
|
|
if (!validationResults)
|
|
return true;
|
|
const { orderedKeys, uniqueKeys } = validationResults;
|
|
return orderedKeys && uniqueKeys;
|
|
}
|
|
checkProcessedDataAnimatable() {
|
|
if (!this.isProcessedDataAnimatable()) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
}
|
|
}
|
|
findNodeDatum(itemId) {
|
|
return findNodeDatumInArray(itemId, this.getNodeData());
|
|
}
|
|
pickFocus(opts) {
|
|
const nodeData = this.getNodeData();
|
|
if (nodeData === void 0 || nodeData.length === 0) {
|
|
return;
|
|
}
|
|
const datumIndex = this.computeFocusDatumIndex(opts, nodeData);
|
|
if (datumIndex === void 0) {
|
|
return;
|
|
}
|
|
const { clipFocusBox } = this;
|
|
const datum = nodeData[datumIndex];
|
|
const derivedOpts = { ...opts, datumIndex };
|
|
const bounds = this.computeFocusBounds(derivedOpts);
|
|
if (bounds !== void 0) {
|
|
return { bounds, clipFocusBox, datum, datumIndex };
|
|
}
|
|
}
|
|
pickNodesExactShape(point) {
|
|
const datums = super.pickNodesExactShape(point);
|
|
datums.sort((a, b) => a.datumIndex - b.datumIndex);
|
|
return datums;
|
|
}
|
|
isDatumEnabled(nodeData, datumIndex) {
|
|
const { missing = false, enabled = true, focusable = true } = nodeData[datumIndex];
|
|
return !missing && enabled && focusable;
|
|
}
|
|
computeFocusDatumIndex(opts, nodeData) {
|
|
const searchBackward = (datumIndex2, delta3) => {
|
|
while (datumIndex2 >= 0 && !this.isDatumEnabled(nodeData, datumIndex2)) {
|
|
datumIndex2 += delta3;
|
|
}
|
|
return datumIndex2 === -1 ? void 0 : datumIndex2;
|
|
};
|
|
const searchForward = (datumIndex2, delta3) => {
|
|
while (datumIndex2 < nodeData.length && !this.isDatumEnabled(nodeData, datumIndex2)) {
|
|
datumIndex2 += delta3;
|
|
}
|
|
return datumIndex2 === nodeData.length ? void 0 : datumIndex2;
|
|
};
|
|
let datumIndex;
|
|
const clampedIndex = (0, import_ag_charts_core196.clamp)(0, opts.datumIndex, nodeData.length - 1);
|
|
if (opts.datumIndexDelta < 0) {
|
|
datumIndex = searchBackward(clampedIndex, opts.datumIndexDelta);
|
|
} else if (opts.datumIndexDelta > 0) {
|
|
datumIndex = searchForward(clampedIndex, opts.datumIndexDelta);
|
|
} else {
|
|
datumIndex = searchForward(clampedIndex, 1) ?? searchBackward(clampedIndex, -1);
|
|
}
|
|
if (datumIndex === void 0) {
|
|
if (opts.datumIndexDelta === 0) {
|
|
return;
|
|
} else {
|
|
return opts.datumIndex - opts.datumIndexDelta;
|
|
}
|
|
} else {
|
|
return datumIndex;
|
|
}
|
|
}
|
|
// Workaround - it would be nice if this difference didn't exist
|
|
dataModelPropertyIsKey(key) {
|
|
const { processedData } = this;
|
|
if (!processedData)
|
|
return false;
|
|
return processedData.defs.keys.some((def) => def.id === key && def.idsMap?.get(this.id)?.has(key) === true);
|
|
}
|
|
keysOrValues(xKey) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return [];
|
|
return this.dataModelPropertyIsKey(xKey) ? dataModel.resolveKeysById(this, xKey, processedData) : dataModel.resolveColumnById(this, xKey, processedData);
|
|
}
|
|
sortOrder(xKey) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return;
|
|
return this.dataModelPropertyIsKey(xKey) ? dataModel.getKeySortOrder(this, xKey, processedData) : dataModel.getColumnSortOrder(this, xKey, processedData);
|
|
}
|
|
getCategoryKey() {
|
|
return this.categoryKey;
|
|
}
|
|
getCategoryValue(datumIndex) {
|
|
const { processedData, dataModel } = this;
|
|
const categoryKey = this.getCategoryKey();
|
|
if (!processedData || !dataModel || !categoryKey)
|
|
return;
|
|
const invalid = processedData.invalidData?.get(this.id)?.[datumIndex] ?? false;
|
|
return invalid ? void 0 : this.keysOrValues(categoryKey)[datumIndex];
|
|
}
|
|
datumIndexForCategoryValue(categoryValue) {
|
|
const { processedData, dataModel } = this;
|
|
const categoryKey = this.getCategoryKey();
|
|
if (!processedData || !dataModel || !categoryKey)
|
|
return;
|
|
categoryValue = categoryValue.valueOf();
|
|
const invalidValues = processedData.invalidData?.get(this.id);
|
|
const xValues = this.keysOrValues(categoryKey);
|
|
for (let datumIndex = 0; datumIndex < xValues.length; datumIndex += 1) {
|
|
if (invalidValues?.[datumIndex] === true)
|
|
continue;
|
|
const xValue = xValues[datumIndex]?.valueOf();
|
|
if ((0, import_ag_charts_core196.objectsEqual)(categoryValue, xValue))
|
|
return datumIndex;
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/cartesianSeries.ts
|
|
var DEFAULT_CARTESIAN_DIRECTION_KEYS = {
|
|
[import_ag_charts_core197.ChartAxisDirection.X]: ["xKey"],
|
|
[import_ag_charts_core197.ChartAxisDirection.Y]: ["yKey"]
|
|
};
|
|
var DEFAULT_CARTESIAN_DIRECTION_NAMES = {
|
|
[import_ag_charts_core197.ChartAxisDirection.X]: ["xName"],
|
|
[import_ag_charts_core197.ChartAxisDirection.Y]: ["yName"]
|
|
};
|
|
var CartesianSeriesNodeEvent = class extends SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.xKey = series.properties.xKey;
|
|
this.yKey = series.properties.yKey;
|
|
}
|
|
};
|
|
var CartesianSeriesProperties = class extends SeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.xKeyAxis = "x";
|
|
this.yKeyAxis = "y";
|
|
this.pickOutsideVisibleMinorAxis = false;
|
|
this.segmentation = new Segmentation();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core197.Property
|
|
], CartesianSeriesProperties.prototype, "xKeyAxis", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core197.Property
|
|
], CartesianSeriesProperties.prototype, "yKeyAxis", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core197.Property
|
|
], CartesianSeriesProperties.prototype, "legendItemName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core197.Property
|
|
], CartesianSeriesProperties.prototype, "pickOutsideVisibleMinorAxis", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core197.Property
|
|
], CartesianSeriesProperties.prototype, "segmentation", 2);
|
|
var RENDER_TO_OFFSCREEN_CANVAS_THRESHOLD = 100;
|
|
var CartesianSeries = class extends DataModelSeries {
|
|
constructor({
|
|
pathsPerSeries = ["path"],
|
|
pathsZIndexSubOrderOffset = [],
|
|
datumSelectionGarbageCollection = true,
|
|
animationAlwaysUpdateSelections = false,
|
|
animationAlwaysPopulateNodeData = false,
|
|
segmentedDataNodes = true,
|
|
animationResetFns,
|
|
propertyKeys,
|
|
propertyNames,
|
|
...otherOpts
|
|
}) {
|
|
super({
|
|
propertyKeys,
|
|
propertyNames,
|
|
canHaveAxes: true,
|
|
...otherOpts
|
|
});
|
|
this.NodeEvent = CartesianSeriesNodeEvent;
|
|
this.dataNodeGroup = this.contentGroup.appendChild(
|
|
new SegmentedGroup({ name: `${this.id}-series-dataNodes`, zIndex: 1 })
|
|
);
|
|
this.labelGroup = this.contentGroup.appendChild(
|
|
new TranslatableGroup({ name: `${this.id}-series-labels` })
|
|
);
|
|
this.labelSelection = Selection.select(this.labelGroup, Text);
|
|
this.highlightSelection = Selection.select(this.highlightNodeGroup, () => this.nodeFactory());
|
|
this.highlightLabelSelection = Selection.select(
|
|
this.highlightLabelGroup,
|
|
Text
|
|
);
|
|
this.annotationSelections = /* @__PURE__ */ new Set();
|
|
this.seriesBelowStackContext = void 0;
|
|
this.debug = import_ag_charts_core197.Debug.create();
|
|
if (!propertyKeys || !propertyNames)
|
|
throw new Error(`Unable to initialise series type ${this.type}`);
|
|
this.opts = {
|
|
pathsPerSeries,
|
|
pathsZIndexSubOrderOffset,
|
|
propertyKeys,
|
|
propertyNames,
|
|
animationResetFns,
|
|
animationAlwaysUpdateSelections,
|
|
animationAlwaysPopulateNodeData,
|
|
datumSelectionGarbageCollection,
|
|
segmentedDataNodes
|
|
};
|
|
this.paths = pathsPerSeries.map((path) => {
|
|
return new SegmentedPath({ name: `${this.id}-${path}` });
|
|
});
|
|
this.datumSelection = Selection.select(
|
|
this.dataNodeGroup,
|
|
() => this.nodeFactory(),
|
|
datumSelectionGarbageCollection
|
|
);
|
|
this.animationState = new import_ag_charts_core197.StateMachine(
|
|
"empty",
|
|
{
|
|
empty: {
|
|
update: {
|
|
target: "ready",
|
|
action: (data) => this.animateEmptyUpdateReady(data)
|
|
},
|
|
reset: "empty",
|
|
skip: "ready",
|
|
disable: "disabled"
|
|
},
|
|
ready: {
|
|
updateData: "waiting",
|
|
clear: "clearing",
|
|
highlight: (data) => this.animateReadyHighlight(data),
|
|
resize: (data) => this.animateReadyResize(data),
|
|
reset: "empty",
|
|
skip: "ready",
|
|
disable: "disabled"
|
|
},
|
|
waiting: {
|
|
update: {
|
|
target: "ready",
|
|
action: (data) => {
|
|
if (this.ctx.animationManager.isSkipped()) {
|
|
this.resetAllAnimation(data);
|
|
} else {
|
|
this.animateWaitingUpdateReady(data);
|
|
}
|
|
}
|
|
},
|
|
reset: "empty",
|
|
skip: "ready",
|
|
disable: "disabled"
|
|
},
|
|
disabled: {
|
|
update: (data) => this.resetAllAnimation(data),
|
|
reset: "empty"
|
|
},
|
|
clearing: {
|
|
update: {
|
|
target: "empty",
|
|
action: (data) => this.animateClearingUpdateEmpty(data)
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
}
|
|
},
|
|
this.checkProcessedDataAnimatable.bind(this)
|
|
);
|
|
this.cleanup.register(
|
|
this.ctx.eventsHub.on("legend:item-click", (event) => this.onLegendItemClick(event)),
|
|
this.ctx.eventsHub.on("legend:item-double-click", (event) => this.onLegendItemDoubleClick(event))
|
|
);
|
|
}
|
|
get contextNodeData() {
|
|
return this._contextNodeData;
|
|
}
|
|
getNodeData() {
|
|
return this.contextNodeData?.nodeData;
|
|
}
|
|
getKeyAxis(direction) {
|
|
if (this.shouldFlipXY()) {
|
|
if (direction === import_ag_charts_core197.ChartAxisDirection.X)
|
|
return this.properties.yKeyAxis;
|
|
if (direction === import_ag_charts_core197.ChartAxisDirection.Y)
|
|
return this.properties.xKeyAxis;
|
|
}
|
|
if (direction === import_ag_charts_core197.ChartAxisDirection.X)
|
|
return this.properties.xKeyAxis;
|
|
if (direction === import_ag_charts_core197.ChartAxisDirection.Y)
|
|
return this.properties.yKeyAxis;
|
|
}
|
|
attachSeries(seriesContentNode, seriesNode, annotationNode) {
|
|
super.attachSeries(seriesContentNode, seriesNode, annotationNode);
|
|
this.attachPaths(this.paths);
|
|
}
|
|
detachSeries(seriesContentNode, seriesNode, annotationNode) {
|
|
super.detachSeries(seriesContentNode, seriesNode, annotationNode);
|
|
this.detachPaths(this.paths);
|
|
}
|
|
updatedDomains() {
|
|
this.animationState.transition("updateData");
|
|
}
|
|
attachPaths(paths) {
|
|
for (const path of paths) {
|
|
this.contentGroup.appendChild(path);
|
|
}
|
|
}
|
|
detachPaths(paths) {
|
|
for (const path of paths) {
|
|
path.remove();
|
|
}
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
const nodeData = this.getNodeData();
|
|
return nodeData != null && nodeData.length > RENDER_TO_OFFSCREEN_CANVAS_THRESHOLD;
|
|
}
|
|
resetAnimation(phase) {
|
|
if (phase === "initial") {
|
|
this.animationState.transition("reset");
|
|
} else if (phase === "ready") {
|
|
this.animationState.transition("skip");
|
|
} else if (phase === "disabled") {
|
|
this.animationState.transition("disable");
|
|
}
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this._contextNodeData = void 0;
|
|
}
|
|
isSeriesHighlighted(highlightedDatum) {
|
|
if (!this.properties.highlight.enabled) {
|
|
return false;
|
|
}
|
|
const { series, legendItemName: activeLegendItemName } = highlightedDatum ?? {};
|
|
const { legendItemName } = this.properties;
|
|
return series === this || legendItemName != null && legendItemName === activeLegendItemName;
|
|
}
|
|
strokewidthChange() {
|
|
const unhighlightedStrokeWidth = ("strokeWidth" in this.properties && this.properties.strokeWidth) ?? 0;
|
|
const highlightedSeriesStrokeWidth = this.properties.highlight.highlightedSeries.strokeWidth ?? unhighlightedStrokeWidth;
|
|
const highlightedItemStrokeWidth = this.properties.highlight.highlightedItem?.strokeWidth ?? unhighlightedStrokeWidth;
|
|
return unhighlightedStrokeWidth > highlightedItemStrokeWidth || highlightedSeriesStrokeWidth > highlightedItemStrokeWidth;
|
|
}
|
|
update({ seriesRect }) {
|
|
const { _contextNodeData: previousContextData } = this;
|
|
const resize = this.checkResize(seriesRect);
|
|
const itemHighlighted = this.updateHighlightSelection();
|
|
const series = this;
|
|
this.contentGroup.batchedUpdate(function updateSelections() {
|
|
const dataChanged = series.updateSelections();
|
|
const segments = series.contextNodeData?.segments;
|
|
if (series.opts.segmentedDataNodes) {
|
|
series.dataNodeGroup.segments = segments ?? series.dataNodeGroup.segments;
|
|
} else {
|
|
series.dataNodeGroup.segments = void 0;
|
|
}
|
|
series.updateNodes(itemHighlighted, resize || dataChanged);
|
|
});
|
|
const animationData = this.getAnimationData(seriesRect, previousContextData);
|
|
if (!animationData)
|
|
return;
|
|
if (resize) {
|
|
this.animationState.transition("resize", animationData);
|
|
}
|
|
this.animationState.transition("update", animationData);
|
|
this.processedDataUpdated = false;
|
|
}
|
|
createStackContext() {
|
|
return void 0;
|
|
}
|
|
// ============================================================================
|
|
// createNodeData() Pattern Helpers
|
|
// ============================================================================
|
|
// These methods support the optimized createNodeData() pattern with incremental updates.
|
|
// See series-performance-optimization.md for detailed documentation.
|
|
/**
|
|
* Determines if incremental node updates are possible based on common criteria.
|
|
*
|
|
* Returns true if existing nodeData exists AND either:
|
|
* - processedData has a changeDescription (partial update), OR
|
|
* - animation is disabled (large dataset)
|
|
*
|
|
* Series may extend with additional conditions by OR'ing additional checks:
|
|
* ```
|
|
* const canIncrementallyUpdate =
|
|
* this.canIncrementallyUpdateNodes() || (existingNodeData && seriesSpecificCondition);
|
|
* ```
|
|
*
|
|
* @param additionalCondition - Optional series-specific condition to OR with base conditions
|
|
*/
|
|
canIncrementallyUpdateNodes(additionalCondition = false) {
|
|
const existingNodeData = this.contextNodeData?.nodeData;
|
|
if (existingNodeData == null)
|
|
return false;
|
|
const { processedData } = this;
|
|
if (!processedData)
|
|
return false;
|
|
return processedData.changeDescription != null || !processedDataIsAnimatable(processedData) || additionalCondition;
|
|
}
|
|
/**
|
|
* Trims the node array after incremental updates.
|
|
*
|
|
* Call at the end of createNodeData() when using incremental updates:
|
|
* ```
|
|
* if (ctx.canIncrementallyUpdate) {
|
|
* this.trimIncrementalNodeArray(ctx.nodes, ctx.nodeIndex);
|
|
* }
|
|
* ```
|
|
*
|
|
* @param nodes - The node array to trim
|
|
* @param nodeIndex - The final write position (new array length)
|
|
*/
|
|
trimIncrementalNodeArray(nodes, nodeIndex) {
|
|
if (nodeIndex < nodes.length) {
|
|
nodes.length = nodeIndex;
|
|
}
|
|
}
|
|
// ============================================================================
|
|
// createNodeData() Template Method Pattern
|
|
// ============================================================================
|
|
// The template method pattern pulls the common createNodeData() flow into the
|
|
// base class. Subclasses implement hooks to customize behaviour.
|
|
//
|
|
// Subclasses that have been migrated implement:
|
|
// - createNodeDatumContext() - cache expensive lookups
|
|
// - populateNodeData() - iterate and create/update datums
|
|
// - initializeResult() - create result object shell
|
|
//
|
|
// And optionally override:
|
|
// - validateCreateNodeDataPreconditions() - custom axis validation
|
|
// - finalizeNodeData() - custom cleanup (multiple arrays, sorting)
|
|
// - assembleResult() - add computed fields (segments)
|
|
/**
|
|
* Template method for creating node data.
|
|
*
|
|
* This implementation provides the common algorithm skeleton:
|
|
* 1. Validate preconditions (axes, dataModel, processedData)
|
|
* 2. Create context with cached values
|
|
* 3. Initialise result object
|
|
* 4. Populate node data (strategy selection inside)
|
|
* 5. Finalize (trim arrays, post-processing)
|
|
* 6. Assemble and return result
|
|
*
|
|
* Subclasses that have been migrated to the template pattern should NOT
|
|
* override this method. Instead, implement the abstract hooks.
|
|
*
|
|
* Subclasses that haven't been migrated yet can override this method entirely.
|
|
*/
|
|
createNodeData() {
|
|
const validation = this.validateCreateNodeDataPreconditions();
|
|
if (!validation)
|
|
return void 0;
|
|
const { xAxis, yAxis } = validation;
|
|
const ctx = this.createNodeDatumContext(xAxis, yAxis);
|
|
if (!ctx)
|
|
return this.getEmptyResult();
|
|
const result = this.initializeResult(ctx);
|
|
if (!this.visible && (this.seriesGrouping == null && !this.opts.animationAlwaysPopulateNodeData || !ctx.animationEnabled))
|
|
return result;
|
|
this.populateNodeData(ctx);
|
|
this.finalizeNodeData(ctx);
|
|
return this.assembleResult(ctx, result);
|
|
}
|
|
// ============================================================================
|
|
// Template Method Hooks (Subclasses MUST implement when NOT overriding createNodeData)
|
|
// ============================================================================
|
|
// Series that override createNodeData() entirely don't need these hooks.
|
|
// Series using the template method MUST implement createNodeDatumContext,
|
|
// populateNodeData, and initializeResult.
|
|
/**
|
|
* Creates the shared context for datum creation/update operations.
|
|
* Called once per createNodeData() invocation.
|
|
*
|
|
* MUST return an object extending CartesianCreateNodeDataContext with:
|
|
* - Cached data arrays (resolved from dataModel)
|
|
* - Cached scales (from axes)
|
|
* - Pre-computed positioning values
|
|
* - Property key lookups
|
|
* - Incremental update state (canIncrementallyUpdate, nodes, nodeIndex)
|
|
*
|
|
* @returns Context object or undefined if context cannot be created
|
|
*/
|
|
createNodeDatumContext(_xAxis, _yAxis) {
|
|
throw new Error(
|
|
`${this.constructor.name}: createNodeDatumContext() must be implemented when using the template method pattern`
|
|
);
|
|
}
|
|
/**
|
|
* Populates the node data array by iterating over data.
|
|
*
|
|
* Strategy selection happens inside this method:
|
|
* - Simple iteration for ungrouped data
|
|
* - Grouped iteration for grouped data
|
|
* - Aggregation iteration for large datasets
|
|
*
|
|
* Implementations should use the upsert pattern:
|
|
* - prepareNodeDatumState() → validate and compute state
|
|
* - upsertNodeDatum() → create or update node in place
|
|
*/
|
|
populateNodeData(_ctx) {
|
|
throw new Error(
|
|
`${this.constructor.name}: populateNodeData() must be implemented when using the template method pattern`
|
|
);
|
|
}
|
|
/**
|
|
* Initializes the result context object that will be returned.
|
|
* Called before populate phase to allow early return for invisible series.
|
|
*
|
|
* Should create the context with:
|
|
* - itemId
|
|
* - nodeData (reference to ctx.nodes)
|
|
* - labelData (reference or separate array)
|
|
* - scales
|
|
* - visible
|
|
* - styles
|
|
*/
|
|
initializeResult(_ctx) {
|
|
throw new Error(
|
|
`${this.constructor.name}: initializeResult() must be implemented when using the template method pattern`
|
|
);
|
|
}
|
|
// ============================================================================
|
|
// Virtual Hooks (Subclasses MAY Override)
|
|
// ============================================================================
|
|
/**
|
|
* Validates preconditions for createNodeData.
|
|
* Default: checks axes, dataModel, and processedData exist.
|
|
*
|
|
* Override for specialized axis requirements (e.g., category vs value axis in bar series).
|
|
*/
|
|
validateCreateNodeDataPreconditions() {
|
|
const xAxis = this.axes[import_ag_charts_core197.ChartAxisDirection.X];
|
|
const yAxis = this.axes[import_ag_charts_core197.ChartAxisDirection.Y];
|
|
if (!xAxis || !yAxis || !this.dataModel || !this.processedData) {
|
|
return void 0;
|
|
}
|
|
return { xAxis, yAxis };
|
|
}
|
|
/**
|
|
* Returns empty result when context creation fails.
|
|
* Default: returns undefined.
|
|
*/
|
|
getEmptyResult() {
|
|
return void 0;
|
|
}
|
|
/**
|
|
* Finalizes node data after population phase.
|
|
* Default: trims incremental node arrays.
|
|
*
|
|
* Override to add post-processing (sorting, additional cleanup, multiple arrays).
|
|
*/
|
|
finalizeNodeData(ctx) {
|
|
if (ctx.canIncrementallyUpdate) {
|
|
this.trimIncrementalNodeArray(ctx.nodes, ctx.nodeIndex);
|
|
}
|
|
}
|
|
/**
|
|
* Assembles final result from context and initialized result.
|
|
* Default: returns the initialized result unchanged.
|
|
*
|
|
* Override to add computed fields (segments, groupScale).
|
|
*/
|
|
assembleResult(_ctx, result) {
|
|
return result;
|
|
}
|
|
updateSelections() {
|
|
var _a;
|
|
const animationSkipUpdate = !this.opts.animationAlwaysUpdateSelections && this.ctx.animationManager.isSkipped();
|
|
if (!this.visible && animationSkipUpdate) {
|
|
return false;
|
|
}
|
|
const { nodeDataRefresh } = this;
|
|
if (!nodeDataRefresh && !this.isPathOrSelectionDirty()) {
|
|
return false;
|
|
}
|
|
if (nodeDataRefresh) {
|
|
this.nodeDataRefresh = false;
|
|
this.debug(`CartesianSeries.updateSelections() - calling createNodeData() for`, this.id);
|
|
this.markQuadtreeDirty();
|
|
this._contextNodeData = this.createNodeData();
|
|
const animationValid = this.isProcessedDataAnimatable();
|
|
if (this._contextNodeData) {
|
|
(_a = this._contextNodeData).animationValid ?? (_a.animationValid = animationValid);
|
|
const nodeDataSize = this._contextNodeData.nodeData?.length;
|
|
if (nodeDataSize != null) {
|
|
import_ag_charts_core197.DebugMetrics.record(`${this.type}:nodeData`, nodeDataSize);
|
|
}
|
|
}
|
|
const { dataModel, processedData } = this;
|
|
if (dataModel !== void 0 && processedData !== void 0) {
|
|
this.events.emit("data-update", { dataModel, processedData });
|
|
}
|
|
this.updateSeriesSelections();
|
|
}
|
|
return nodeDataRefresh;
|
|
}
|
|
updateSeriesSelections() {
|
|
const { datumSelection, labelSelection, paths } = this;
|
|
const contextData = this._contextNodeData;
|
|
if (!contextData)
|
|
return;
|
|
const { nodeData, labelData, itemId } = contextData;
|
|
this.updatePaths({ itemId, contextData, paths });
|
|
this.datumSelection = this.updateDatumSelection({ nodeData, datumSelection });
|
|
this.labelGroup.batchedUpdate(() => {
|
|
this.labelSelection = this.updateLabelSelection({ labelData, labelSelection }) ?? labelSelection;
|
|
});
|
|
}
|
|
getShapeFillBBox() {
|
|
const { axes } = this;
|
|
const xAxis = axes[import_ag_charts_core197.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core197.ChartAxisDirection.Y];
|
|
const [axisX1, axisX2] = (0, import_ag_charts_core197.findMinMax)(xAxis?.range ?? [0, 1]);
|
|
const [axisY1, axisY2] = (0, import_ag_charts_core197.findMinMax)(yAxis?.range ?? [0, 1]);
|
|
const xSeriesDomain = (0, import_ag_charts_core197.extractDomain)(this.getSeriesDomain(import_ag_charts_core197.ChartAxisDirection.X));
|
|
const xSeriesRange = [xAxis?.scale.convert(xSeriesDomain.at(0)), xAxis?.scale.convert(xSeriesDomain.at(-1))];
|
|
const ySeriesDomain = (0, import_ag_charts_core197.extractDomain)(this.getSeriesDomain(import_ag_charts_core197.ChartAxisDirection.Y));
|
|
const ySeriesRange = [yAxis?.scale.convert(ySeriesDomain.at(0)), yAxis?.scale.convert(ySeriesDomain.at(-1))];
|
|
const [seriesX1, seriesX2] = (0, import_ag_charts_core197.findMinMax)(xSeriesRange);
|
|
const [seriesY1, seriesY2] = (0, import_ag_charts_core197.findMinMax)(ySeriesRange);
|
|
return {
|
|
axis: new BBox(axisX1, axisY1, axisX2 - axisX1, axisY2 - axisY1),
|
|
series: new BBox(seriesX1, seriesY1, seriesX2 - seriesX1, seriesY2 - seriesY1)
|
|
};
|
|
}
|
|
updateNodes(itemHighlighted, nodeRefresh) {
|
|
const { highlightSelection, datumSelection } = this;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const visible = this.visible && this._contextNodeData != null;
|
|
this.contentGroup.visible = animationEnabled || visible;
|
|
this.highlightGroup.visible = (animationEnabled || visible) && itemHighlighted;
|
|
this.updateDatumStyles({ datumSelection: highlightSelection, isHighlight: true });
|
|
const drawingMode = this.ctx.chartService.highlight?.drawingMode ?? "overlay";
|
|
this.updateDatumNodes({
|
|
datumSelection: highlightSelection,
|
|
isHighlight: true,
|
|
drawingMode
|
|
});
|
|
this.highlightLabelGroup.batchedUpdate(() => {
|
|
this.updateLabelNodes({ labelSelection: this.highlightLabelSelection, isHighlight: true });
|
|
});
|
|
this.animationState.transition("highlight", highlightSelection);
|
|
const { dataNodeGroup, labelSelection, paths, labelGroup } = this;
|
|
const { itemId } = this.contextNodeData ?? {};
|
|
this.updatePathNodes({ itemId, paths, visible, animationEnabled });
|
|
dataNodeGroup.visible = animationEnabled || visible;
|
|
labelGroup.visible = visible;
|
|
if (!dataNodeGroup.visible) {
|
|
return;
|
|
}
|
|
if (this.hasItemStylers()) {
|
|
this.updateDatumStyles({ datumSelection, isHighlight: false });
|
|
}
|
|
const redrawAll = this.strokewidthChange() || this.hasChangesOnHighlight;
|
|
if (nodeRefresh || redrawAll) {
|
|
this.updateDatumNodes({ datumSelection, isHighlight: false, drawingMode: "overlay" });
|
|
if (!this.usesPlacedLabels) {
|
|
this.labelGroup.batchedUpdate(() => {
|
|
this.updateLabelNodes({ labelSelection, isHighlight: false });
|
|
});
|
|
}
|
|
}
|
|
}
|
|
getHighlightData(_nodeData, highlightedItem) {
|
|
return highlightedItem ? [{ ...highlightedItem }] : void 0;
|
|
}
|
|
getHighlightLabelData(labelData, highlightedItem) {
|
|
const labelItems = labelData.filter(
|
|
(ld) => ld.datum === highlightedItem.datum && ld.itemId === highlightedItem.itemId
|
|
);
|
|
return labelItems.length === 0 ? void 0 : labelItems;
|
|
}
|
|
updateHighlightSelection() {
|
|
const { highlightSelection, highlightLabelSelection, _contextNodeData: contextNodeData } = this;
|
|
if (!contextNodeData)
|
|
return false;
|
|
const highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
const seriesHighlighted = this.isSeriesHighlighted(highlightedDatum);
|
|
const item = seriesHighlighted && highlightedDatum?.datum ? highlightedDatum : void 0;
|
|
if (item == null)
|
|
return false;
|
|
const { nodeData, labelData } = contextNodeData;
|
|
const highlightItems = this.getHighlightData(nodeData, item);
|
|
this.highlightSelection = this.updateHighlightSelectionItem({
|
|
items: highlightItems,
|
|
highlightSelection
|
|
});
|
|
const highlightLabelItems = this.getHighlightLabelData(labelData, item) ?? [];
|
|
this.highlightLabelSelection = this.updateLabelSelection({
|
|
labelData: highlightLabelItems,
|
|
labelSelection: highlightLabelSelection
|
|
}) ?? highlightLabelSelection;
|
|
return true;
|
|
}
|
|
markQuadtreeDirty() {
|
|
this.quadtree = void 0;
|
|
}
|
|
*datumNodesIter() {
|
|
for (const { node } of this.datumSelection) {
|
|
if (node.datum.missing === true)
|
|
continue;
|
|
yield node;
|
|
}
|
|
}
|
|
getQuadTree() {
|
|
if (this.quadtree === void 0) {
|
|
const canvas = this.ctx.scene?.canvas ?? { width: 0, height: 0 };
|
|
const canvasRect = new BBox(0, 0, canvas.width, canvas.height);
|
|
this.quadtree = new QuadtreeNearest(100, 10, canvasRect);
|
|
this.initQuadTree(this.quadtree);
|
|
}
|
|
return this.quadtree;
|
|
}
|
|
initQuadTree(_quadtree) {
|
|
}
|
|
pickNodeDataExactShape(point) {
|
|
const { x, y } = point;
|
|
const { dataNodeGroup } = this;
|
|
const matches = dataNodeGroup.pickNodes(x, y).filter((match) => match.datum.missing !== true);
|
|
if (matches.length !== 0) {
|
|
const datums = matches.map((match) => match.datum);
|
|
return datums;
|
|
}
|
|
}
|
|
pickModulesExactShape(point) {
|
|
for (const mod of this.moduleMap.modules()) {
|
|
const { datum } = mod.pickNodeExact(point) ?? {};
|
|
if (datum == null)
|
|
continue;
|
|
if (datum?.missing === true)
|
|
continue;
|
|
return [datum];
|
|
}
|
|
}
|
|
pickNodesExactShape(point) {
|
|
const result = super.pickNodesExactShape(point);
|
|
if (result.length !== 0) {
|
|
return result;
|
|
}
|
|
return this.pickNodeDataExactShape(point) ?? this.pickModulesExactShape(point) ?? [];
|
|
}
|
|
pickNodeDataClosestDatum(point) {
|
|
const { x, y } = point;
|
|
const { axes, _contextNodeData: contextNodeData } = this;
|
|
if (!contextNodeData)
|
|
return;
|
|
const xAxis = axes[import_ag_charts_core197.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core197.ChartAxisDirection.Y];
|
|
const hitPoint = { x, y };
|
|
let minDistanceSquared = Infinity;
|
|
let closestDatum;
|
|
for (const datum of contextNodeData.nodeData) {
|
|
const { point: { x: datumX = Number.NaN, y: datumY = Number.NaN } = {} } = datum;
|
|
if (Number.isNaN(datumX) || Number.isNaN(datumY)) {
|
|
continue;
|
|
}
|
|
const isInRange = xAxis?.inRange(datumX) && yAxis?.inRange(datumY);
|
|
if (!isInRange) {
|
|
continue;
|
|
}
|
|
const distanceSquared = Math.max((hitPoint.x - datumX) ** 2 + (hitPoint.y - datumY) ** 2, 0);
|
|
if (distanceSquared < minDistanceSquared) {
|
|
minDistanceSquared = distanceSquared;
|
|
closestDatum = datum;
|
|
}
|
|
}
|
|
if (minDistanceSquared != null) {
|
|
return { datum: closestDatum, distance: Math.sqrt(minDistanceSquared) };
|
|
}
|
|
}
|
|
pickModulesClosestDatum(point) {
|
|
let minDistanceSquared = Infinity;
|
|
let closestDatum;
|
|
for (const mod of this.moduleMap.modules()) {
|
|
const modPick = mod.pickNodeNearest(point);
|
|
if (modPick !== void 0 && modPick.distanceSquared < minDistanceSquared) {
|
|
minDistanceSquared = modPick.distanceSquared;
|
|
closestDatum = modPick.datum;
|
|
}
|
|
}
|
|
if (minDistanceSquared != null) {
|
|
return { datum: closestDatum, distance: Math.sqrt(minDistanceSquared) };
|
|
}
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
let minDistance = Infinity;
|
|
let closestDatum;
|
|
const pick2 = this.pickNodeDataClosestDatum(point);
|
|
if (pick2 != null && pick2.distance < minDistance) {
|
|
minDistance = pick2.distance;
|
|
closestDatum = pick2.datum;
|
|
}
|
|
const modPick = this.pickModulesClosestDatum(point);
|
|
if (modPick != null && modPick.distance < minDistance) {
|
|
minDistance = modPick.distance;
|
|
closestDatum = modPick.datum;
|
|
}
|
|
if (closestDatum) {
|
|
const distance = Math.max(minDistance - (closestDatum.point?.size ?? 0) / 2, 0);
|
|
return { datum: closestDatum, distance };
|
|
}
|
|
}
|
|
pickNodeMainAxisFirst(point, requireCategoryAxis) {
|
|
const { x, y } = point;
|
|
const { axes, _contextNodeData: contextNodeData } = this;
|
|
const { pickOutsideVisibleMinorAxis } = this.properties;
|
|
if (!contextNodeData)
|
|
return;
|
|
const xAxis = axes[import_ag_charts_core197.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core197.ChartAxisDirection.Y];
|
|
if (xAxis == null || yAxis == null)
|
|
return;
|
|
const directions2 = [xAxis, yAxis].filter((axis) => axis.isCategoryLike()).map((a) => a.direction);
|
|
if (requireCategoryAxis && directions2.length === 0)
|
|
return;
|
|
const [majorDirection = import_ag_charts_core197.ChartAxisDirection.X] = directions2;
|
|
const hitPointCoords = [x, y];
|
|
if (majorDirection !== import_ag_charts_core197.ChartAxisDirection.X)
|
|
hitPointCoords.reverse();
|
|
const minDistance = [Infinity, Infinity];
|
|
let closestDatum;
|
|
for (const datum of contextNodeData.nodeData) {
|
|
const { x: datumX = Number.NaN, y: datumY = Number.NaN } = datum.point ?? datum.midPoint ?? {};
|
|
if (Number.isNaN(datumX) || Number.isNaN(datumY) || datum.missing === true)
|
|
continue;
|
|
const visible = [xAxis?.inRange(datumX, 1), yAxis?.inRange(datumY, 1)];
|
|
if (majorDirection !== import_ag_charts_core197.ChartAxisDirection.X) {
|
|
visible.reverse();
|
|
}
|
|
if (!visible[0] || !pickOutsideVisibleMinorAxis && !visible[1])
|
|
continue;
|
|
const datumPoint = [datumX, datumY];
|
|
if (majorDirection !== import_ag_charts_core197.ChartAxisDirection.X) {
|
|
datumPoint.reverse();
|
|
}
|
|
let newMinDistance = true;
|
|
for (let i = 0; i < datumPoint.length; i++) {
|
|
const dist = Math.abs(datumPoint[i] - hitPointCoords[i]);
|
|
if (dist > minDistance[i]) {
|
|
newMinDistance = false;
|
|
break;
|
|
} else if (dist < minDistance[i]) {
|
|
minDistance[i] = dist;
|
|
minDistance.fill(Infinity, i + 1, minDistance.length);
|
|
}
|
|
}
|
|
if (newMinDistance) {
|
|
closestDatum = datum;
|
|
}
|
|
}
|
|
if (closestDatum) {
|
|
let closestDistanceSquared = Math.max(
|
|
minDistance[0] ** 2 + minDistance[1] ** 2 - (closestDatum.point?.size ?? 0),
|
|
0
|
|
);
|
|
for (const mod of this.moduleMap.modules()) {
|
|
const modPick = mod.pickNodeMainAxisFirst(point, majorDirection);
|
|
if (modPick != null && modPick.distanceSquared < closestDistanceSquared) {
|
|
closestDatum = modPick.datum;
|
|
closestDistanceSquared = modPick.distanceSquared;
|
|
break;
|
|
}
|
|
}
|
|
return {
|
|
datum: closestDatum,
|
|
distance: Math.sqrt(closestDistanceSquared)
|
|
};
|
|
}
|
|
}
|
|
isPathOrSelectionDirty() {
|
|
return false;
|
|
}
|
|
shouldFlipXY() {
|
|
return false;
|
|
}
|
|
visibleRangeIndices(axisKey, visibleRange, indices, sortOrderParams) {
|
|
let sortOrder;
|
|
if (sortOrderParams == null) {
|
|
const { processedData, dataModel } = this;
|
|
sortOrder = dataModel.getColumnSortOrder(this, axisKey, processedData) ?? 1;
|
|
} else {
|
|
sortOrder = sortOrderParams.sortOrder;
|
|
}
|
|
const xValues = this.keysOrValues(axisKey);
|
|
const pixelSize = 0;
|
|
const [start, end2] = visibleRangeIndices(
|
|
sortOrder,
|
|
indices?.length ?? xValues.length,
|
|
visibleRange,
|
|
(topIndex) => {
|
|
const datumIndex = indices?.[topIndex] ?? topIndex;
|
|
return this.xCoordinateRange(xValues[datumIndex], pixelSize, datumIndex);
|
|
}
|
|
);
|
|
return start < end2 ? [start, end2] : [end2, start];
|
|
}
|
|
domainForVisibleRange(_direction, axisKeys, crossAxisKey, visibleRange, indices) {
|
|
const { processedData, dataModel } = this;
|
|
const [r0, r1] = visibleRange;
|
|
const crossAxisValues = this.keysOrValues(crossAxisKey);
|
|
const sortOrder = this.sortOrder(crossAxisKey);
|
|
if (sortOrder != null) {
|
|
const crossAxisRange = this.visibleRangeIndices(crossAxisKey, visibleRange, indices, { sortOrder });
|
|
return dataModel.getDomainBetweenRange(this, axisKeys, crossAxisRange, processedData);
|
|
}
|
|
const allAxisValues = axisKeys.map((axisKey) => this.keysOrValues(axisKey));
|
|
let axisMin = Infinity;
|
|
let axisMax = -Infinity;
|
|
for (const [i, crossAxisValue] of crossAxisValues.entries()) {
|
|
const [x0, x1] = this.xCoordinateRange(crossAxisValue, 0, i);
|
|
if (x1 < r0 || x0 > r1)
|
|
continue;
|
|
for (let j = 0; j < axisKeys.length; j++) {
|
|
const axisValue = allAxisValues[j][i];
|
|
axisMin = Math.min(axisMin, axisValue);
|
|
axisMax = Math.max(axisMax, axisValue);
|
|
}
|
|
}
|
|
return axisMin > axisMax ? [Number.NaN, Number.NaN] : [axisMin, axisMax];
|
|
}
|
|
domainForClippedRange(direction, axisKeys, crossAxisKey) {
|
|
const { processedData, dataModel, axes } = this;
|
|
const crossDirection = direction === import_ag_charts_core197.ChartAxisDirection.X ? import_ag_charts_core197.ChartAxisDirection.Y : import_ag_charts_core197.ChartAxisDirection.X;
|
|
const crossAxisRange = axisExtent(axes[crossDirection]);
|
|
if (!crossAxisRange) {
|
|
return axisKeys.flatMap((axisKey) => dataModel.getDomain(this, axisKey, "value", processedData).domain);
|
|
}
|
|
const crossAxisValues = this.keysOrValues(crossAxisKey);
|
|
const sortOrder = dataModel.getColumnSortOrder(this, crossAxisKey, processedData);
|
|
if (sortOrder != null) {
|
|
const crossRange = clippedRangeIndices(
|
|
sortOrder,
|
|
crossAxisValues.length,
|
|
crossAxisRange,
|
|
(index) => crossAxisValues[index]
|
|
);
|
|
return dataModel.getDomainBetweenRange(this, axisKeys, crossRange, processedData);
|
|
}
|
|
const allAxisValues = axisKeys.map((axisKey) => this.keysOrValues(axisKey));
|
|
const range0 = crossAxisRange[0].valueOf();
|
|
const range1 = crossAxisRange[1].valueOf();
|
|
const axisValues = [];
|
|
for (const [i, crossAxisValue] of crossAxisValues.entries()) {
|
|
const c = crossAxisValue.valueOf();
|
|
if (c < range0 || c > range1)
|
|
continue;
|
|
const values = allAxisValues.map((v) => v[i]);
|
|
if (c >= range0) {
|
|
axisValues.push(...values);
|
|
}
|
|
if (c <= range1) {
|
|
axisValues.push(...values);
|
|
}
|
|
}
|
|
return axisValues;
|
|
}
|
|
zoomFittingVisibleItems(crossAxisKey, _axisKeys, xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return;
|
|
const crossAxis = this.axes[import_ag_charts_core197.ChartAxisDirection.X];
|
|
if (yVisibleRange != null)
|
|
return;
|
|
const sortOrder = this.sortOrder(crossAxisKey);
|
|
if (sortOrder == null)
|
|
return;
|
|
const xValues = this.keysOrValues(crossAxisKey);
|
|
if (minVisibleItems > xValues.length) {
|
|
return { x: [0, 1], y: void 0 };
|
|
}
|
|
const crossScale = crossAxis.scale;
|
|
const crossScaleRange = crossScale.range;
|
|
crossScale.range = [0, 1];
|
|
let [r0, r1] = this.visibleRangeIndices(crossAxisKey, xVisibleRange, void 0, { sortOrder });
|
|
r1 -= 1;
|
|
const pixelSize = 0;
|
|
if (this.xCoordinateRange(xValues[r0], pixelSize, r0)[0] < xVisibleRange[0]) {
|
|
r0 += 1;
|
|
}
|
|
if (this.xCoordinateRange(xValues[r1], pixelSize, r1)[1] > xVisibleRange[1]) {
|
|
r1 -= 1;
|
|
}
|
|
let xZoom;
|
|
if (Math.abs(r1 - r0) >= minVisibleItems - 1) {
|
|
xZoom = xVisibleRange;
|
|
} else {
|
|
const midPoint = (xVisibleRange[0] + xVisibleRange[1]) / 2;
|
|
while (Math.abs(r1 - r0) < minVisibleItems - 1 && (r0 > 0 || r1 < xValues.length - 1)) {
|
|
if (r0 === 0) {
|
|
r1 += 1;
|
|
} else if (r1 === xValues.length - 1) {
|
|
r0 -= 1;
|
|
} else {
|
|
const nextR0X = this.xCoordinateRange(xValues[r0 - 1], pixelSize, r0 - 1)[0];
|
|
const nextR1X = this.xCoordinateRange(xValues[r1 + 1], pixelSize, r1 + 1)[1];
|
|
if (Math.abs(nextR0X - midPoint) < Math.abs(nextR1X - midPoint)) {
|
|
r0 -= 1;
|
|
} else {
|
|
r1 += 1;
|
|
}
|
|
}
|
|
}
|
|
const x0 = this.xCoordinateRange(xValues[r0], pixelSize, r0)[0];
|
|
const x1 = this.xCoordinateRange(xValues[r1], pixelSize, r1)[1];
|
|
xZoom = [Math.min(xVisibleRange[0], x0), Math.max(xVisibleRange[1], x1)];
|
|
}
|
|
crossScale.range = crossScaleRange;
|
|
return { x: xZoom, y: void 0 };
|
|
}
|
|
countVisibleItems(crossAxisKey, axisKeys, xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return Infinity;
|
|
const crossValues = this.keysOrValues(crossAxisKey);
|
|
const allAxisValues = axisKeys.map((axisKey) => dataModel.resolveColumnById(this, axisKey, processedData));
|
|
const shouldFlipXY = this.shouldFlipXY();
|
|
const crossAxis = shouldFlipXY ? this.axes[import_ag_charts_core197.ChartAxisDirection.Y] : this.axes[import_ag_charts_core197.ChartAxisDirection.X];
|
|
const axis = shouldFlipXY ? this.axes[import_ag_charts_core197.ChartAxisDirection.X] : this.axes[import_ag_charts_core197.ChartAxisDirection.Y];
|
|
const crossVisibleRange = shouldFlipXY ? yVisibleRange ?? [0, 1] : xVisibleRange;
|
|
const axisVisibleRange = shouldFlipXY ? xVisibleRange : yVisibleRange ?? [0, 1];
|
|
if (yVisibleRange == null) {
|
|
const sortOrder = this.sortOrder(crossAxisKey);
|
|
if (sortOrder != null) {
|
|
const crossScale = crossAxis.scale;
|
|
const crossScaleRange = crossScale.range;
|
|
crossScale.range = [0, 1];
|
|
const xValues = this.keysOrValues(crossAxisKey);
|
|
let [r0, r1] = this.visibleRangeIndices(crossAxisKey, crossVisibleRange, void 0, { sortOrder });
|
|
r1 -= 1;
|
|
if (r1 < r0)
|
|
return 0;
|
|
const pixelSize2 = 0;
|
|
if (this.xCoordinateRange(xValues[r0], pixelSize2, r0)[0] < crossVisibleRange[0]) {
|
|
r0 += 1;
|
|
}
|
|
if (this.xCoordinateRange(xValues[r1], pixelSize2, r1)[1] > crossVisibleRange[1]) {
|
|
r1 -= 1;
|
|
}
|
|
const xItemsVisible = Math.abs(r1 - r0) + 1;
|
|
crossScale.range = crossScaleRange;
|
|
return xItemsVisible;
|
|
}
|
|
}
|
|
const convert = (d, r, v) => {
|
|
return d[0] + (v - r[0]) / (r[1] - r[0]) * (d[1] - d[0]);
|
|
};
|
|
const crossAxisRange = crossAxis.range.toSorted();
|
|
const axisRange = axis.range.toSorted();
|
|
const crossMin = convert(crossAxisRange, crossAxis.visibleRange, crossVisibleRange[0]);
|
|
const crossMax = convert(crossAxisRange, crossAxis.visibleRange, crossVisibleRange[1]);
|
|
const axisMin = convert(axisRange, axis.visibleRange, Math.min(...axisVisibleRange));
|
|
const axisMax = convert(axisRange, axis.visibleRange, Math.max(...axisVisibleRange));
|
|
const startIndex = Math.round(
|
|
(crossVisibleRange[0] + (crossVisibleRange[1] - crossVisibleRange[0]) / 2) * crossValues.length
|
|
);
|
|
const pixelSize = 0;
|
|
return countExpandingSearch(0, crossValues.length - 1, startIndex, minVisibleItems, (index) => {
|
|
const [cross0, cross1] = this.xCoordinateRange(crossValues[index], pixelSize, index);
|
|
const [axis0, axis1] = this.yCoordinateRange(
|
|
allAxisValues.map((axisValues) => axisValues[index]),
|
|
pixelSize,
|
|
index
|
|
);
|
|
if (!(0, import_ag_charts_core197.isFiniteNumber)(cross0) || !(0, import_ag_charts_core197.isFiniteNumber)(cross1) || !(0, import_ag_charts_core197.isFiniteNumber)(axis0) || !(0, import_ag_charts_core197.isFiniteNumber)(axis1)) {
|
|
return false;
|
|
}
|
|
return cross0 >= crossMin && cross1 <= crossMax && axis0 >= axisMin && axis1 <= axisMax;
|
|
});
|
|
}
|
|
// @todo(AG-13777) - Remove this function.
|
|
// We need data model updates to know if a data set is sorted & unique - and at the same time
|
|
// it should generate the equivalent of `SMALLEST_KEY_INTERVAL`. We'll use that value here
|
|
minTimeInterval() {
|
|
let xValues;
|
|
try {
|
|
xValues = this.keysOrValues("xValue");
|
|
} catch {
|
|
}
|
|
if (xValues == null || xValues.length > 1e3)
|
|
return;
|
|
let minInterval = Infinity;
|
|
let x0 = xValues[0];
|
|
let sortOrder;
|
|
for (let i = 1; i < xValues.length; i++) {
|
|
const x1 = xValues[i];
|
|
if (x1 != null && x0 != null) {
|
|
const interval = x1.valueOf() - x0.valueOf();
|
|
const sign = Math.sign(interval);
|
|
if (sign === 0)
|
|
continue;
|
|
if (sortOrder !== void 0 && sign !== sortOrder)
|
|
return;
|
|
minInterval = Math.min(minInterval, Math.abs(interval));
|
|
sortOrder = sign;
|
|
}
|
|
x0 = x1;
|
|
}
|
|
if (Number.isFinite(minInterval))
|
|
return minInterval;
|
|
}
|
|
updateHighlightSelectionItem(opts) {
|
|
const { items, highlightSelection } = opts;
|
|
const nodeData = items ?? [];
|
|
return this.updateDatumSelection({
|
|
nodeData,
|
|
datumSelection: highlightSelection
|
|
});
|
|
}
|
|
updateDatumSelection(opts) {
|
|
return opts.datumSelection;
|
|
}
|
|
updateDatumNodes(_opts) {
|
|
}
|
|
updateDatumStyles(_opts) {
|
|
}
|
|
updatePaths(opts) {
|
|
for (const p of opts.paths) {
|
|
p.visible = false;
|
|
}
|
|
}
|
|
updatePathNodes(opts) {
|
|
const { paths, visible } = opts;
|
|
for (const path of paths) {
|
|
path.visible = visible;
|
|
}
|
|
}
|
|
resetPathAnimation(data) {
|
|
const { path } = this.opts?.animationResetFns ?? {};
|
|
if (path) {
|
|
for (const paths of data.paths) {
|
|
resetMotion([paths], path);
|
|
}
|
|
}
|
|
}
|
|
resetDatumAnimation(data) {
|
|
const { datum } = this.opts?.animationResetFns ?? {};
|
|
if (datum) {
|
|
resetMotion([data.datumSelection], datum);
|
|
}
|
|
}
|
|
resetLabelAnimation(data) {
|
|
const { label } = this.opts?.animationResetFns ?? {};
|
|
if (label) {
|
|
resetMotion([data.labelSelection], label);
|
|
}
|
|
}
|
|
resetAllAnimation(data) {
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
this.resetPathAnimation(data);
|
|
this.resetDatumAnimation(data);
|
|
this.resetLabelAnimation(data);
|
|
if (data.contextData?.animationValid === false) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
}
|
|
}
|
|
animateEmptyUpdateReady(data) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.resetAllAnimation(data);
|
|
}
|
|
animateWaitingUpdateReady(data) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.resetAllAnimation(data);
|
|
}
|
|
animateReadyHighlight(data) {
|
|
const { datum } = this.opts?.animationResetFns ?? {};
|
|
if (datum) {
|
|
resetMotion([data], datum);
|
|
}
|
|
}
|
|
animateReadyResize(data) {
|
|
this.resetAllAnimation(data);
|
|
}
|
|
animateClearingUpdateEmpty(data) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.resetAllAnimation(data);
|
|
}
|
|
getAnimationData(seriesRect, previousContextData) {
|
|
const { _contextNodeData: contextData } = this;
|
|
if (!contextData)
|
|
return;
|
|
const animationData = {
|
|
datumSelection: this.datumSelection,
|
|
labelSelection: this.labelSelection,
|
|
annotationSelections: [...this.annotationSelections],
|
|
contextData,
|
|
previousContextData,
|
|
paths: this.paths,
|
|
seriesRect
|
|
};
|
|
return animationData;
|
|
}
|
|
updateLabelSelection(opts) {
|
|
return opts.labelSelection;
|
|
}
|
|
getScaling(scale2) {
|
|
if (scale2 instanceof LogScale) {
|
|
const { range: range4, domain } = scale2;
|
|
return {
|
|
type: "log",
|
|
convert: (d) => scale2.convert(d),
|
|
domain: [domain[0], domain[1]],
|
|
range: [range4[0], range4[1]]
|
|
};
|
|
} else if (scale2 instanceof ContinuousScale) {
|
|
const { range: range4, domain } = scale2;
|
|
return {
|
|
type: "continuous",
|
|
domain: [domain[0], domain[1]],
|
|
range: [range4[0], range4[1]]
|
|
};
|
|
} else if (scale2 instanceof BandScale) {
|
|
if (scale2 instanceof UnitTimeScale) {
|
|
const linearParams = scale2.getLinearParams();
|
|
const bandCount = scale2.getBandCountForUpdate();
|
|
if (linearParams != null && bandCount > 0) {
|
|
return {
|
|
type: "category",
|
|
variant: "unit-time",
|
|
firstBandTime: linearParams.firstBandTime,
|
|
lastBandTime: linearParams.firstBandTime + (bandCount - 1) * linearParams.intervalMs,
|
|
bandCount,
|
|
intervalMs: linearParams.intervalMs,
|
|
inset: scale2.inset,
|
|
step: scale2.step
|
|
};
|
|
}
|
|
}
|
|
return {
|
|
type: "category",
|
|
domain: scale2.domain,
|
|
inset: scale2.inset,
|
|
step: scale2.step
|
|
};
|
|
}
|
|
}
|
|
calculateScaling() {
|
|
const result = {};
|
|
for (const direction of Object.values(import_ag_charts_core197.ChartAxisDirection)) {
|
|
const axis = this.axes[direction];
|
|
if (!axis)
|
|
continue;
|
|
const scalingResult = this.getScaling(axis.scale);
|
|
if (scalingResult != null) {
|
|
result[direction] = scalingResult;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
function axisExtent(axis) {
|
|
let min;
|
|
let max;
|
|
if (axis instanceof NumberAxis || axis instanceof TimeAxis) {
|
|
({ min, max } = axis);
|
|
}
|
|
if (min == null && max == null)
|
|
return;
|
|
min ?? (min = -Infinity);
|
|
max ?? (max = Infinity);
|
|
return [min, max];
|
|
}
|
|
function clippedRangeIndices(sortOrder, length, range4, xValue) {
|
|
const range0 = range4[0].valueOf();
|
|
const range1 = range4[1].valueOf();
|
|
let xMinIndex = (0, import_ag_charts_core197.findMinIndex)(0, length - 1, (i) => {
|
|
const index = sortOrder === 1 ? i : length - i;
|
|
const x = xValue(index)?.valueOf();
|
|
return !Number.isFinite(x) || x >= range0;
|
|
});
|
|
let xMaxIndex = (0, import_ag_charts_core197.findMaxIndex)(0, length - 1, (i) => {
|
|
const index = sortOrder === 1 ? i : length - i;
|
|
const x = xValue(index)?.valueOf();
|
|
return !Number.isFinite(x) || x <= range1;
|
|
});
|
|
if (xMinIndex == null || xMaxIndex == null)
|
|
return [0, 0];
|
|
if (sortOrder === -1) {
|
|
[xMinIndex, xMaxIndex] = [length - xMaxIndex, length - xMinIndex];
|
|
}
|
|
xMinIndex = Math.max(xMinIndex, 0);
|
|
xMaxIndex = Math.min(xMaxIndex + 1, length);
|
|
return [xMinIndex, xMaxIndex];
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/cartesianUtil.ts
|
|
function stackCartesianSeries(series) {
|
|
const seriesGroups = /* @__PURE__ */ new Map();
|
|
for (const s of series) {
|
|
if (!(s instanceof CartesianSeries))
|
|
continue;
|
|
const stackCount = s.seriesGrouping?.stackCount ?? 0;
|
|
const groupIndex = stackCount > 0 ? s.seriesGrouping?.groupIndex : void 0;
|
|
if (groupIndex == null) {
|
|
s.seriesBelowStackContext = void 0;
|
|
s.createStackContext();
|
|
continue;
|
|
}
|
|
const groupKey = `${s.type}-${groupIndex}`;
|
|
let group = seriesGroups.get(groupKey);
|
|
if (group == null) {
|
|
group = [];
|
|
seriesGroups.set(groupKey, group);
|
|
}
|
|
group.push(s);
|
|
}
|
|
for (const group of seriesGroups.values()) {
|
|
group.sort((a, b) => (a.seriesGrouping?.stackIndex ?? 0) - (b.seriesGrouping?.stackIndex ?? 0));
|
|
let seriesBelowStackContext;
|
|
for (const s of group) {
|
|
s.seriesBelowStackContext = seriesBelowStackContext;
|
|
seriesBelowStackContext = s.createStackContext();
|
|
}
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/labelUtil.ts
|
|
var import_ag_charts_core198 = require("ag-charts-core");
|
|
function getLabelStyles(series, nodeDatum, params, label, isHighlight, activeHighlight, labelPath = ["series", `${series.declarationOrder}`, "label"]) {
|
|
if (series.visible && label.itemStyler) {
|
|
const highlightState = series.getHighlightStateString(
|
|
activeHighlight,
|
|
isHighlight || nodeDatum != null && activeHighlight?.series === nodeDatum.series && activeHighlight?.datumIndex === nodeDatum.datumIndex,
|
|
nodeDatum?.datumIndex
|
|
);
|
|
const itemId = typeof nodeDatum?.datumIndex === "number" ? nodeDatum.datumIndex : nodeDatum?.itemId;
|
|
const styleParams = {
|
|
border: label.border,
|
|
color: label.color,
|
|
cornerRadius: label.cornerRadius,
|
|
datum: nodeDatum?.datum,
|
|
enabled: label.enabled,
|
|
fill: label.fill,
|
|
fillOpacity: label.fillOpacity,
|
|
fontFamily: label.fontFamily,
|
|
fontSize: label.fontSize,
|
|
fontStyle: label.fontStyle,
|
|
fontWeight: label.fontWeight,
|
|
itemId,
|
|
itemType: nodeDatum?.itemType,
|
|
seriesId: series.id,
|
|
padding: label.padding,
|
|
highlightState
|
|
};
|
|
const stylerResult = series.ctx.optionsGraphService.resolvePartial(
|
|
labelPath,
|
|
series.cachedCallWithContext(label.itemStyler, { ...params, ...styleParams }),
|
|
{ pick: false }
|
|
) ?? {};
|
|
return (0, import_ag_charts_core198.mergeDefaults)(stylerResult, styleParams);
|
|
}
|
|
return label;
|
|
}
|
|
function updateLabelNode(series, textNode, params, label, labelDatum, isHighlight, activeHighlight) {
|
|
if (series.visible && label.enabled && labelDatum) {
|
|
const style = getLabelStyles(series, textNode.datum, params, label, isHighlight, activeHighlight);
|
|
textNode.visible = true;
|
|
textNode.x = labelDatum.x;
|
|
textNode.y = labelDatum.y;
|
|
textNode.text = labelDatum.text;
|
|
textNode.fill = style.color;
|
|
textNode.setAlign(labelDatum);
|
|
textNode.setFont(style);
|
|
textNode.setBoxing(style);
|
|
} else {
|
|
textNode.visible = false;
|
|
}
|
|
}
|
|
var placements = {
|
|
"inside-start": { inside: true, direction: -1, textAlignment: 1 },
|
|
"inside-end": { inside: true, direction: 1, textAlignment: -1 },
|
|
"outside-start": { inside: false, direction: -1, textAlignment: -1 },
|
|
"outside-end": { inside: false, direction: 1, textAlignment: 1 }
|
|
};
|
|
function adjustLabelPlacement({
|
|
isUpward,
|
|
isVertical,
|
|
placement,
|
|
spacing = 0,
|
|
rect: rect2
|
|
}) {
|
|
let x = rect2.x + rect2.width / 2;
|
|
let y = rect2.y + rect2.height / 2;
|
|
let textAlign = "center";
|
|
let textBaseline = "middle";
|
|
if (placement !== "inside-center") {
|
|
const barDirection = (isUpward ? 1 : -1) * (isVertical ? -1 : 1);
|
|
const { direction, textAlignment } = placements[placement];
|
|
const displacementRatio = (direction + 1) * 0.5;
|
|
if (isVertical) {
|
|
const y0 = isUpward ? rect2.y + rect2.height : rect2.y;
|
|
const height = rect2.height * barDirection;
|
|
y = y0 + height * displacementRatio + spacing * textAlignment * barDirection;
|
|
textBaseline = textAlignment === barDirection ? "top" : "bottom";
|
|
} else {
|
|
const x0 = isUpward ? rect2.x : rect2.x + rect2.width;
|
|
const width = rect2.width * barDirection;
|
|
x = x0 + width * displacementRatio + spacing * textAlignment * barDirection;
|
|
textAlign = textAlignment === barDirection ? "left" : "right";
|
|
}
|
|
}
|
|
return { x, y, textAlign, textBaseline };
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/seriesLabelUtil.ts
|
|
function seriesLabelFadeInAnimation({ id }, subId, animationManager, ...labelSelections) {
|
|
for (const labelSelection of labelSelections) {
|
|
labelSelection.cleanup();
|
|
}
|
|
staticFromToMotion(
|
|
id,
|
|
subId,
|
|
animationManager,
|
|
labelSelections,
|
|
{ opacity: 0 },
|
|
{ opacity: 1 },
|
|
{ phase: "trailing" }
|
|
);
|
|
}
|
|
function seriesLabelFadeOutAnimation({ id }, subId, animationManager, ...labelSelections) {
|
|
staticFromToMotion(
|
|
id,
|
|
subId,
|
|
animationManager,
|
|
labelSelections,
|
|
{ opacity: 1 },
|
|
{ opacity: 0 },
|
|
{ phase: "remove" }
|
|
);
|
|
}
|
|
function resetLabelFn(_node) {
|
|
return { opacity: 1 };
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/seriesMarker.ts
|
|
var import_ag_charts_core199 = require("ag-charts-core");
|
|
var SeriesMarker = class extends import_ag_charts_core199.ChangeDetectableProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.shape = "circle";
|
|
this.size = 0;
|
|
this.fillOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
}
|
|
getStyle() {
|
|
const { size, shape, fill, fillOpacity, stroke, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this;
|
|
return {
|
|
size,
|
|
shape,
|
|
fill,
|
|
fillOpacity,
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset
|
|
};
|
|
}
|
|
getDiameter() {
|
|
return this.size + this.strokeWidth;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property,
|
|
(0, import_ag_charts_core199.SceneChangeDetection)()
|
|
], SeriesMarker.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property,
|
|
(0, import_ag_charts_core199.SceneObjectChangeDetection)({ equals: import_ag_charts_core199.TRIPLE_EQ })
|
|
], SeriesMarker.prototype, "shape", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property,
|
|
(0, import_ag_charts_core199.SceneChangeDetection)()
|
|
], SeriesMarker.prototype, "size", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property,
|
|
(0, import_ag_charts_core199.SceneObjectChangeDetection)({ equals: import_ag_charts_core199.objectsEqual })
|
|
], SeriesMarker.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property,
|
|
(0, import_ag_charts_core199.SceneChangeDetection)()
|
|
], SeriesMarker.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property,
|
|
(0, import_ag_charts_core199.SceneChangeDetection)()
|
|
], SeriesMarker.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property,
|
|
(0, import_ag_charts_core199.SceneChangeDetection)()
|
|
], SeriesMarker.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property,
|
|
(0, import_ag_charts_core199.SceneChangeDetection)()
|
|
], SeriesMarker.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property
|
|
], SeriesMarker.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property
|
|
], SeriesMarker.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core199.Property,
|
|
(0, import_ag_charts_core199.SceneObjectChangeDetection)({ equals: import_ag_charts_core199.TRIPLE_EQ })
|
|
], SeriesMarker.prototype, "itemStyler", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/seriesTooltip.ts
|
|
var import_ag_charts_core200 = require("ag-charts-core");
|
|
function buildLineWithMarkerDefaults(line, marker) {
|
|
if (line == null)
|
|
return void 0;
|
|
return {
|
|
enabled: line.enabled ?? true,
|
|
stroke: line.stroke ?? marker?.stroke ?? "transparent",
|
|
strokeWidth: line.strokeWidth ?? marker?.strokeWidth ?? 1,
|
|
strokeOpacity: line.strokeOpacity ?? marker?.strokeOpacity ?? 1,
|
|
lineDash: line.lineDash ?? marker?.lineDash ?? []
|
|
};
|
|
}
|
|
var SeriesTooltipInteraction = class extends import_ag_charts_core200.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core200.Property
|
|
], SeriesTooltipInteraction.prototype, "enabled", 2);
|
|
var SeriesTooltip = class extends import_ag_charts_core200.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.interaction = new SeriesTooltipInteraction();
|
|
this.position = new TooltipPosition();
|
|
this.range = void 0;
|
|
this.class = void 0;
|
|
}
|
|
formatTooltip(callers, content, params) {
|
|
const overrides = this.renderer == null ? void 0 : (0, import_ag_charts_core200.callWithContext)(callers, this.renderer, params);
|
|
if ((0, import_ag_charts_core200.isString)(overrides) || (0, import_ag_charts_core200.isNumber)(overrides) || (0, import_ag_charts_core200.isDate)(overrides)) {
|
|
return { type: "raw", rawHtmlString: (0, import_ag_charts_core200.toTextString)(overrides) };
|
|
}
|
|
if (overrides != null) {
|
|
const mergedMarker = (0, import_ag_charts_core200.mergeDefaults)(overrides.symbol?.marker, content.symbol?.marker);
|
|
const mergedLineInput = overrides.symbol?.line ?? content.symbol?.line ? (0, import_ag_charts_core200.mergeDefaults)(overrides.symbol?.line, content.symbol?.line) : void 0;
|
|
const symbol = content.symbol || overrides.symbol ? {
|
|
marker: mergedMarker,
|
|
line: buildLineWithMarkerDefaults(mergedLineInput, mergedMarker)
|
|
} : void 0;
|
|
return { type: "structured", ...content, ...overrides, symbol };
|
|
}
|
|
return { type: "structured", ...content };
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core200.Property
|
|
], SeriesTooltip.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core200.Property
|
|
], SeriesTooltip.prototype, "showArrow", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core200.Property
|
|
], SeriesTooltip.prototype, "renderer", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core200.Property
|
|
], SeriesTooltip.prototype, "interaction", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core200.Property
|
|
], SeriesTooltip.prototype, "position", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core200.Property
|
|
], SeriesTooltip.prototype, "range", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core200.Property
|
|
], SeriesTooltip.prototype, "class", 2);
|
|
function makeSeriesTooltip() {
|
|
return new SeriesTooltip();
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/abstractBarSeries.ts
|
|
var import_ag_charts_core204 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/axis/categoryAxis.ts
|
|
var import_ag_charts_core201 = require("ag-charts-core");
|
|
var _CategoryAxis = class _CategoryAxis extends CartesianAxis {
|
|
constructor(moduleCtx, scale2 = new CategoryScale(), includeInvisibleDomains = true) {
|
|
super(moduleCtx, scale2);
|
|
this.groupPaddingInner = 0.1;
|
|
this.includeInvisibleDomains = includeInvisibleDomains;
|
|
this.nice = false;
|
|
}
|
|
static is(value) {
|
|
return value instanceof _CategoryAxis;
|
|
}
|
|
isCategoryLike() {
|
|
return true;
|
|
}
|
|
hasDefinedDomain() {
|
|
return false;
|
|
}
|
|
normaliseDataDomain(d) {
|
|
return { domain: d.domain, clipped: false };
|
|
}
|
|
getUpdateTypeOnResize() {
|
|
if (this.bandAlignment == null || this.bandAlignment === "justify") {
|
|
return super.getUpdateTypeOnResize();
|
|
}
|
|
return import_ag_charts_core201.ChartUpdateType.PROCESS_DOMAIN;
|
|
}
|
|
updateScale() {
|
|
super.updateScale();
|
|
let { paddingInner, paddingOuter } = this;
|
|
if (!(0, import_ag_charts_core201.isFiniteNumber)(paddingInner) || !(0, import_ag_charts_core201.isFiniteNumber)(paddingOuter)) {
|
|
const padding2 = this.reduceBandScalePadding();
|
|
paddingInner ?? (paddingInner = padding2.inner);
|
|
paddingOuter ?? (paddingOuter = padding2.outer);
|
|
}
|
|
this.scale.paddingInner = paddingInner ?? 0;
|
|
this.scale.paddingOuter = paddingOuter ?? 0;
|
|
}
|
|
calculateGridLines(ticks, p1, p2) {
|
|
const gridLines = super.calculateGridLines(ticks, p1, p2);
|
|
if (this.interval.placement === "between" && ticks.length > 0) {
|
|
gridLines.push(
|
|
super.calculateGridLine(
|
|
{
|
|
index: ticks.at(-1).index + 1,
|
|
tickId: `after:${ticks.at(-1).tickId}`,
|
|
translation: this.range[1]
|
|
},
|
|
ticks.length,
|
|
p1,
|
|
p2,
|
|
ticks
|
|
)
|
|
);
|
|
}
|
|
return gridLines;
|
|
}
|
|
calculateGridLine({ index: tickIndex, tickId, translation }, index, p1, p2, ticks) {
|
|
const { gridLine, horizontal, interval, scale: scale2 } = this;
|
|
if (interval.placement !== "between") {
|
|
return super.calculateGridLine({ index: tickIndex, tickId, translation }, index, p1, p2, ticks);
|
|
}
|
|
const halfStep = translation < scale2.step ? Math.floor(scale2.step / 2) : scale2.step / 2;
|
|
const offset = translation - halfStep;
|
|
const [x1, y1, x2, y2] = horizontal ? [offset, Math.max(p1, p2), offset, Math.min(p1, p2)] : [Math.min(p1, p2), offset, Math.max(p1, p2), offset];
|
|
const { style } = gridLine;
|
|
const { stroke, strokeWidth = 0, lineDash } = style[tickIndex % style.length] ?? {};
|
|
return { tickId, offset, x1, y1, x2, y2, stroke, strokeWidth, lineDash };
|
|
}
|
|
calculateGridFills(ticks, p1, p2) {
|
|
const { horizontal, range: range4, scale: scale2 } = this;
|
|
if (this.interval.placement !== "between") {
|
|
return super.calculateGridFills(ticks, p1, p2);
|
|
}
|
|
const gridFills = [];
|
|
if (ticks.length == 0)
|
|
return gridFills;
|
|
const firstTick = ticks[0];
|
|
const firstFillOffCanvas = firstTick.translation > range4[0] + scale2.step / 2;
|
|
const lastTick = ticks.at(-1);
|
|
const lastFillOffCanvas = horizontal && lastTick.translation < range4[1] - scale2.step / 2;
|
|
if (firstFillOffCanvas) {
|
|
const tick = { tickId: `before:${firstTick.tickId}`, translation: firstTick.translation - scale2.step };
|
|
gridFills.push(this.calculateGridFill(tick, -1, firstTick.index - 1, p1, p2, ticks));
|
|
}
|
|
gridFills.push(...ticks.map((tick, index) => this.calculateGridFill(tick, index, tick.index, p1, p2, ticks)));
|
|
if (lastFillOffCanvas) {
|
|
const tick = { tickId: `after:${lastTick.tickId}`, translation: lastTick.translation + scale2.step };
|
|
gridFills.push(this.calculateGridFill(tick, ticks.length, lastTick.index + 1, p1, p2, ticks));
|
|
}
|
|
return gridFills;
|
|
}
|
|
calculateGridFill({ tickId, translation }, index, gridFillIndex, p1, p2, ticks) {
|
|
const { gridLine, horizontal, interval, scale: scale2 } = this;
|
|
if (interval.placement !== "between") {
|
|
return super.calculateGridFill({ tickId, translation }, index, gridFillIndex, p1, p2, ticks);
|
|
}
|
|
const startOffset = translation - scale2.step / 2;
|
|
const endOffset = translation + scale2.step / 2;
|
|
const [x1, y1, x2, y2] = horizontal ? [startOffset, Math.max(p1, p2), endOffset, Math.min(p1, p2)] : [Math.min(p1, p2), startOffset, Math.max(p1, p2), endOffset];
|
|
const { fill, fillOpacity } = gridLine.style[gridFillIndex % gridLine.style.length] ?? {};
|
|
return { tickId, x1, y1, x2, y2, fill, fillOpacity };
|
|
}
|
|
calculateTickLines(ticks, direction, scrollbarThickness = 0) {
|
|
const tickLines = super.calculateTickLines(ticks, direction, scrollbarThickness);
|
|
if (this.interval.placement === "between" && ticks.length > 0) {
|
|
tickLines.push(
|
|
super.calculateTickLine(
|
|
{ isPrimary: false, tickId: `after:${ticks.at(-1)?.tickId}`, translation: this.range[1] },
|
|
ticks.length,
|
|
direction,
|
|
ticks,
|
|
scrollbarThickness
|
|
)
|
|
);
|
|
}
|
|
return tickLines;
|
|
}
|
|
calculateTickLine({ isPrimary, tickId, translation }, index, direction, ticks, scrollbarThickness = 0) {
|
|
const { horizontal, interval, primaryTick, scale: scale2, tick } = this;
|
|
if (interval.placement !== "between") {
|
|
return super.calculateTickLine(
|
|
{ isPrimary, tickId, translation },
|
|
index,
|
|
direction,
|
|
ticks,
|
|
scrollbarThickness
|
|
);
|
|
}
|
|
const datumTick = isPrimary && primaryTick?.enabled ? primaryTick : tick;
|
|
const h = -direction * this.getTickSize(datumTick);
|
|
const halfStep = translation < scale2.step ? Math.floor(scale2.step / 2) : scale2.step / 2;
|
|
const offset = translation - halfStep;
|
|
const tickOffset = -direction * (scrollbarThickness + this.getTickSpacing(datumTick));
|
|
const [x1, y1, x2, y2] = horizontal ? [offset, tickOffset, offset, tickOffset + h] : [tickOffset, offset, tickOffset + h, offset];
|
|
const { stroke, width: strokeWidth } = datumTick;
|
|
const lineDash = void 0;
|
|
return { tickId, offset, x1, y1, x2, y2, stroke, strokeWidth, lineDash };
|
|
}
|
|
reduceBandScalePadding() {
|
|
return this.boundSeries.reduce(
|
|
(result, series) => {
|
|
const padding2 = series.getBandScalePadding?.();
|
|
if (padding2) {
|
|
if (result.inner > padding2.inner) {
|
|
result.inner = padding2.inner;
|
|
}
|
|
if (result.outer < padding2.outer) {
|
|
result.outer = padding2.outer;
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
{ inner: Infinity, outer: -Infinity }
|
|
);
|
|
}
|
|
tickFormatParams(_domain, _ticks, _fractionDigits, _timeInterval) {
|
|
return { type: "category" };
|
|
}
|
|
datumFormatParams(value, params, _fractionDigits, _timeInterval, _style) {
|
|
const { datum, seriesId, legendItemName, key, source, property, domain, boundSeries } = params;
|
|
if (Array.isArray(value) && value.some((v) => typeof v !== "string")) {
|
|
value = value.map(String);
|
|
}
|
|
return { type: "category", value, datum, seriesId, legendItemName, key, source, property, domain, boundSeries };
|
|
}
|
|
};
|
|
_CategoryAxis.className = "CategoryAxis";
|
|
_CategoryAxis.type = "category";
|
|
__decorateClass([
|
|
import_ag_charts_core201.Property
|
|
], _CategoryAxis.prototype, "groupPaddingInner", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core201.Property
|
|
], _CategoryAxis.prototype, "paddingInner", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core201.Property
|
|
], _CategoryAxis.prototype, "paddingOuter", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core201.ProxyPropertyOnWrite)("layoutConstraints", "align")
|
|
], _CategoryAxis.prototype, "bandAlignment", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core201.ActionOnSet)({
|
|
newValue(value) {
|
|
if (value == null || value <= 0) {
|
|
this.layoutConstraints.width = 100;
|
|
this.layoutConstraints.unit = "percent";
|
|
} else {
|
|
this.layoutConstraints.width = value;
|
|
this.layoutConstraints.unit = "px";
|
|
this.animationManager.skipCurrentBatch();
|
|
}
|
|
}
|
|
})
|
|
], _CategoryAxis.prototype, "requiredRange", 2);
|
|
var CategoryAxis = _CategoryAxis;
|
|
|
|
// packages/ag-charts-community/src/chart/axis/groupedCategoryAxis.ts
|
|
var import_ag_charts_core202 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scale/groupedCategoryScale.ts
|
|
var MAX_ANIMATABLE_NODES2 = 1e3;
|
|
var GroupedCategoryScale = class _GroupedCategoryScale extends CategoryScale {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.previousDomainJson = void 0;
|
|
/** Whether the current domain update is animatable (initial load or no domain change). */
|
|
this.animatable = true;
|
|
}
|
|
static is(value) {
|
|
return value instanceof _GroupedCategoryScale;
|
|
}
|
|
set domain(values) {
|
|
if (values.length <= MAX_ANIMATABLE_NODES2) {
|
|
const currentDomainJson = JSON.stringify(values);
|
|
this.animatable = this.previousDomainJson === void 0 || this.previousDomainJson === currentDomainJson;
|
|
this.previousDomainJson = currentDomainJson;
|
|
} else {
|
|
this.animatable = this.previousDomainJson === void 0;
|
|
this.previousDomainJson = "";
|
|
}
|
|
super.domain = values;
|
|
}
|
|
get domain() {
|
|
return super.domain;
|
|
}
|
|
normalizeDomains(...domains) {
|
|
const { domain } = super.normalizeDomains(...domains);
|
|
return { domain, animatable: false };
|
|
}
|
|
findIndex(value) {
|
|
return super.findIndex(value) ?? this.getMatchIndex(value);
|
|
}
|
|
getMatchIndex(value) {
|
|
const key = JSON.stringify(value);
|
|
const match = this._domain.find((d) => JSON.stringify(d) === key);
|
|
if (match != null) {
|
|
return super.findIndex(match);
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/axis/tree.ts
|
|
var Dimensions = class {
|
|
constructor() {
|
|
this.top = Infinity;
|
|
this.right = -Infinity;
|
|
this.bottom = -Infinity;
|
|
this.left = Infinity;
|
|
}
|
|
update(x, y) {
|
|
if (x > this.right) {
|
|
this.right = x;
|
|
}
|
|
if (x < this.left) {
|
|
this.left = x;
|
|
}
|
|
if (y > this.bottom) {
|
|
this.bottom = y;
|
|
}
|
|
if (y < this.top) {
|
|
this.top = y;
|
|
}
|
|
}
|
|
};
|
|
var TreeNode = class _TreeNode {
|
|
constructor(label = "", parent, refId) {
|
|
this.label = label;
|
|
this.parent = parent;
|
|
this.refId = refId;
|
|
this.position = 0;
|
|
this.subtreeLeft = Number.NaN;
|
|
this.subtreeRight = Number.NaN;
|
|
this.children = [];
|
|
this.leafCount = 0;
|
|
this.prelim = 0;
|
|
this.mod = 0;
|
|
this.ancestor = this;
|
|
this.change = 0;
|
|
this.shift = 0;
|
|
this.index = 0;
|
|
// screen is meant to be recomputed from (layout) when the tree is resized (without performing another layout)
|
|
this.screen = 0;
|
|
this.depth = parent ? parent.depth + 1 : 0;
|
|
}
|
|
insertTick(tick, index) {
|
|
let current = this;
|
|
let endNode;
|
|
for (let i = 0; i < tick.length; i++) {
|
|
const pathPart = tick[i];
|
|
const isNotLeaf = i !== tick.length - 1;
|
|
const { children } = current;
|
|
const existingNode = children.find((child) => child.label === pathPart);
|
|
if (existingNode && isNotLeaf) {
|
|
current = existingNode;
|
|
endNode = existingNode;
|
|
} else {
|
|
const node = new _TreeNode(pathPart, current, index);
|
|
node.index = children.length;
|
|
children.push(node);
|
|
if (isNotLeaf) {
|
|
current = node;
|
|
}
|
|
endNode = node;
|
|
}
|
|
}
|
|
return endNode;
|
|
}
|
|
getLeftSibling() {
|
|
return this.index > 0 ? this.parent?.children[this.index - 1] : void 0;
|
|
}
|
|
getLeftmostSibling() {
|
|
return this.index > 0 ? this.parent?.children[0] : void 0;
|
|
}
|
|
// traverse the left contour of a subtree, return the successor of v on this contour
|
|
nextLeft() {
|
|
return this.children[0];
|
|
}
|
|
// traverse the right contour of a subtree, return the successor of v on this contour
|
|
nextRight() {
|
|
return this.children.at(-1);
|
|
}
|
|
getSiblings() {
|
|
return this.parent?.children.filter((_, i) => i !== this.index) ?? [];
|
|
}
|
|
};
|
|
function ticksToTree(ticks) {
|
|
const maxDepth = ticks.reduce((depth, tick) => Math.max(depth, tick.length), 0);
|
|
const root = new TreeNode();
|
|
const tickNodes = /* @__PURE__ */ new Map();
|
|
for (let i = 0; i < ticks.length; i++) {
|
|
const tick = ticks[i];
|
|
while (tick.length < maxDepth) {
|
|
tick.push("");
|
|
}
|
|
const node = root.insertTick(tick, i);
|
|
if (node != null) {
|
|
tickNodes.set(tick, node);
|
|
}
|
|
}
|
|
return { root, tickNodes };
|
|
}
|
|
function moveSubtree(wm, wp, shift) {
|
|
const subtrees = wp.index - wm.index;
|
|
const ratio10 = shift / subtrees;
|
|
wp.change -= ratio10;
|
|
wp.shift += shift;
|
|
wm.change += ratio10;
|
|
wp.prelim += shift;
|
|
wp.mod += shift;
|
|
}
|
|
function ancestor(vim, v, defaultAncestor) {
|
|
return v.getSiblings().includes(vim.ancestor) ? vim.ancestor : defaultAncestor;
|
|
}
|
|
function executeShifts({ children }) {
|
|
let shift = 0;
|
|
let change = 0;
|
|
for (let i = children.length - 1; i >= 0; i--) {
|
|
const w = children[i];
|
|
w.prelim += shift;
|
|
w.mod += shift;
|
|
change += w.change;
|
|
shift += w.shift + change;
|
|
}
|
|
}
|
|
function apportion(v, defaultAncestor) {
|
|
const w = v.getLeftSibling();
|
|
if (w) {
|
|
let vop = v;
|
|
let vip = v;
|
|
let vim = w;
|
|
let vom = vip.getLeftmostSibling();
|
|
let sip = vip.mod;
|
|
let sop = vop.mod;
|
|
let sim = vim.mod;
|
|
let som = vom.mod;
|
|
while (vim.nextRight() && vip.nextLeft()) {
|
|
vim = vim.nextRight();
|
|
vip = vip.nextLeft();
|
|
vom = vom.nextLeft();
|
|
vop = vop.nextRight();
|
|
vop.ancestor = v;
|
|
const shift = vim.prelim + sim - (vip.prelim + sip) + 1;
|
|
if (shift > 0) {
|
|
moveSubtree(ancestor(vim, v, defaultAncestor), v, shift);
|
|
sip += shift;
|
|
sop += shift;
|
|
}
|
|
sim += vim.mod;
|
|
sip += vip.mod;
|
|
som += vom.mod;
|
|
sop += vop.mod;
|
|
}
|
|
if (vim.nextRight() && !vop.nextRight()) {
|
|
vop.mod += sim - sop;
|
|
} else {
|
|
if (vip.nextLeft() && !vom.nextLeft()) {
|
|
vom.mod += sip - som;
|
|
}
|
|
defaultAncestor = v;
|
|
}
|
|
}
|
|
return defaultAncestor;
|
|
}
|
|
function firstWalk(node) {
|
|
const { children } = node;
|
|
if (children.length) {
|
|
let [defaultAncestor] = children;
|
|
for (const child of children) {
|
|
firstWalk(child);
|
|
defaultAncestor = apportion(child, defaultAncestor);
|
|
}
|
|
executeShifts(node);
|
|
const midpoint = (children[0].prelim + children.at(-1).prelim) / 2;
|
|
const leftSibling = node.getLeftSibling();
|
|
if (leftSibling) {
|
|
node.prelim = leftSibling.prelim + 1;
|
|
node.mod = node.prelim - midpoint;
|
|
} else {
|
|
node.prelim = midpoint;
|
|
}
|
|
} else {
|
|
const leftSibling = node.getLeftSibling();
|
|
node.prelim = leftSibling ? leftSibling.prelim + 1 : 0;
|
|
}
|
|
}
|
|
function secondWalk(v, m, layout) {
|
|
v.position = v.prelim + m;
|
|
layout.insertNode(v);
|
|
for (const w of v.children) {
|
|
secondWalk(w, m + v.mod, layout);
|
|
}
|
|
}
|
|
function thirdWalk(v) {
|
|
const { children } = v;
|
|
let leafCount = 0;
|
|
for (const w of children) {
|
|
thirdWalk(w);
|
|
if (w.children.length) {
|
|
leafCount += w.leafCount;
|
|
} else {
|
|
leafCount++;
|
|
}
|
|
}
|
|
v.leafCount = leafCount;
|
|
if (children.length) {
|
|
v.subtreeLeft = children[0].subtreeLeft;
|
|
v.subtreeRight = children.at(-1).subtreeRight;
|
|
v.position = (v.subtreeLeft + v.subtreeRight) / 2;
|
|
} else {
|
|
v.subtreeLeft = v.position;
|
|
v.subtreeRight = v.position;
|
|
}
|
|
}
|
|
function treeLayout(ticks) {
|
|
const layout = new TreeLayout();
|
|
const { root, tickNodes } = ticksToTree(ticks);
|
|
firstWalk(root);
|
|
secondWalk(root, -root.prelim, layout);
|
|
thirdWalk(root);
|
|
return { layout, tickNodes };
|
|
}
|
|
var TreeLayout = class {
|
|
constructor() {
|
|
this.dimensions = new Dimensions();
|
|
this.nodes = [];
|
|
this.depth = 0;
|
|
}
|
|
insertNode(node) {
|
|
if (this.depth < node.depth) {
|
|
this.depth = node.depth;
|
|
}
|
|
this.dimensions.update(node.position, node.depth);
|
|
this.nodes.push(node);
|
|
}
|
|
scaling(extent6, flip) {
|
|
let scaling = 1;
|
|
if (extent6 > 0) {
|
|
const { left, right } = this.dimensions;
|
|
if (right !== left) {
|
|
scaling = extent6 / (right - left);
|
|
}
|
|
}
|
|
if (flip) {
|
|
scaling *= -1;
|
|
}
|
|
return scaling;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/axis/groupedCategoryAxis.ts
|
|
var MIN_CATEGORY_SPACING = 5;
|
|
var DepthLabelProperties = class extends import_ag_charts_core202.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.border = new LabelBorder();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "avoidCollisions", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "border", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "color", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "wrapping", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "truncate", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "fontFamily", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthLabelProperties.prototype, "padding", 2);
|
|
var DepthTickProperties = class extends import_ag_charts_core202.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthTickProperties.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthTickProperties.prototype, "width", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthTickProperties.prototype, "stroke", 2);
|
|
var DepthProperties = class extends import_ag_charts_core202.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.label = new DepthLabelProperties();
|
|
this.tick = new DepthTickProperties();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], DepthProperties.prototype, "tick", 2);
|
|
var GroupedCategoryAxis = class extends CategoryAxis {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, new GroupedCategoryScale());
|
|
// Label scale (labels are positioned between ticks, tick count = label count + 1).
|
|
// We don't call is `labelScale` for consistency with other axes.
|
|
this.tickScale = new GroupedCategoryScale();
|
|
this.computedLayout = void 0;
|
|
this.tickTreeLayout = void 0;
|
|
this.tickNodes = void 0;
|
|
this.depthOptions = new import_ag_charts_core202.PropertiesArray(DepthProperties);
|
|
this.includeInvisibleDomains = true;
|
|
this.tickScale.paddingInner = 1;
|
|
this.tickScale.paddingOuter = 0;
|
|
}
|
|
resizeTickTree() {
|
|
if (!this.tickTreeLayout)
|
|
return;
|
|
const { nodes } = this.tickTreeLayout;
|
|
const { range: range4, step, inset, bandwidth } = this.scale;
|
|
const width = Math.abs(range4[1] - range4[0]) - step;
|
|
const scaling = this.tickTreeLayout.scaling(width, range4[0] > range4[1]);
|
|
const shift = inset + bandwidth / 2;
|
|
let offset = 0;
|
|
for (const node of nodes) {
|
|
const screen = node.position * scaling;
|
|
if (offset > screen) {
|
|
offset = screen;
|
|
}
|
|
node.screen = screen + shift;
|
|
}
|
|
for (const node of nodes) {
|
|
node.screen -= offset;
|
|
}
|
|
}
|
|
getDepthOptionsMap(maxDepth) {
|
|
const optionsMap = [];
|
|
const { depthOptions, label } = this;
|
|
const defaultNonLeafRotation = this.horizontal ? 0 : -90;
|
|
for (let i = 0; i < maxDepth; i++) {
|
|
optionsMap.push(
|
|
depthOptions[i]?.label.enabled ?? label.enabled ? {
|
|
enabled: true,
|
|
spacing: depthOptions[i]?.label.spacing ?? label.spacing,
|
|
wrapping: depthOptions[i]?.label.wrapping ?? label.wrapping,
|
|
truncate: depthOptions[i]?.label.truncate ?? label.truncate,
|
|
rotation: depthOptions[i]?.label.rotation ?? (i ? defaultNonLeafRotation : label.rotation),
|
|
// Default top-level label rotation only applies to label leaves
|
|
avoidCollisions: depthOptions[i]?.label.avoidCollisions ?? label.avoidCollisions
|
|
} : { enabled: false, spacing: 0, rotation: 0, avoidCollisions: false }
|
|
);
|
|
}
|
|
return optionsMap;
|
|
}
|
|
updateCategoryLabels() {
|
|
if (!this.computedLayout)
|
|
return;
|
|
this.tickLabelGroupSelection.update(this.computedLayout.tickLabelLayout).each((node, datum) => {
|
|
node.fill = datum.color;
|
|
node.text = datum.text;
|
|
node.textBaseline = datum.textBaseline;
|
|
node.textAlign = datum.textAlign ?? "center";
|
|
node.pointerEvents = datum.textUntruncated == null ? 1 /* None */ : 0 /* All */;
|
|
node.setFont(datum);
|
|
node.setBoxing(datum);
|
|
});
|
|
}
|
|
updateAxisLine() {
|
|
if (!this.computedLayout)
|
|
return;
|
|
this.lineNode.visible = this.line.enabled;
|
|
this.lineNode.stroke = this.line.stroke;
|
|
this.lineNode.strokeWidth = this.line.width;
|
|
}
|
|
computeLayout() {
|
|
this.updateDirection();
|
|
this.updateScale();
|
|
const { step } = this.scale;
|
|
const { title, label, range: range4, depthOptions, horizontal, line } = this;
|
|
const scrollbar = this.chartLayout?.scrollbars?.[this.id];
|
|
const scrollbarThickness = this.getScrollbarThickness(scrollbar);
|
|
this.lineNode.datum = horizontal ? { x1: range4[0], x2: range4[1], y1: 0, y2: 0 } : { x1: 0, x2: 0, y1: range4[0], y2: range4[1] };
|
|
this.lineNode.setProperties({ stroke: line.stroke, strokeWidth: line.enabled ? line.width : 0 });
|
|
this.resizeTickTree();
|
|
if (!this.tickTreeLayout?.depth) {
|
|
return { bbox: BBox.zero, spacing: 0, depthLabelMaxSize: {}, tickLabelLayout: [] };
|
|
}
|
|
const { depth: maxDepth, nodes: treeLabels } = this.tickTreeLayout;
|
|
const sideFlag = horizontal ? -label.getSideFlag() : label.getSideFlag();
|
|
const tickLabelLayout = [];
|
|
const labelBBoxes = /* @__PURE__ */ new Map();
|
|
const truncatedLabelText = /* @__PURE__ */ new Map();
|
|
const tempText = new TransformableText();
|
|
const optionsMap = this.getDepthOptionsMap(maxDepth);
|
|
const labelSpacing = sideFlag * (optionsMap[0].spacing + this.getTickSpacing() + scrollbarThickness);
|
|
const tickFormatter = this.tickFormatter(this.scale.domain, this.scale.domain, false);
|
|
const setLabelProps = (datum, index) => {
|
|
const depth = maxDepth - datum.depth;
|
|
if (!optionsMap[depth]?.enabled || !(0, import_ag_charts_core202.inRange)(datum.screen, range4))
|
|
return false;
|
|
let maxWidth = (datum.leafCount || 1) * step;
|
|
if (maxWidth < MIN_CATEGORY_SPACING)
|
|
return false;
|
|
const inputText = tickFormatter(datum.label, index - 1);
|
|
let text = inputText;
|
|
const labelStyles = this.getLabelStyles(
|
|
{ value: datum.index, formattedValue: text, depth },
|
|
depthOptions[depth]?.label
|
|
);
|
|
if (label.avoidCollisions) {
|
|
const rotation = optionsMap[depth].rotation;
|
|
let maxHeight = this.thickness;
|
|
if (rotation != null) {
|
|
const innerRect = (0, import_ag_charts_core202.getMaxInnerRectSize)(rotation, maxWidth, maxHeight);
|
|
maxWidth = innerRect.width;
|
|
maxHeight = innerRect.height;
|
|
}
|
|
const wrapOptions = {
|
|
font: labelStyles,
|
|
textWrap: optionsMap[depth].wrapping,
|
|
overflow: optionsMap[depth].truncate ? "ellipsis" : "hide",
|
|
maxWidth,
|
|
maxHeight
|
|
};
|
|
text = (0, import_ag_charts_core202.wrapTextOrSegments)(text, wrapOptions) || text;
|
|
}
|
|
if (text !== inputText && (0, import_ag_charts_core202.isTruncated)(text)) {
|
|
truncatedLabelText.set(index, (0, import_ag_charts_core202.toPlainText)(inputText));
|
|
} else {
|
|
truncatedLabelText.delete(index);
|
|
}
|
|
tempText.x = horizontal ? datum.screen : labelSpacing;
|
|
tempText.y = horizontal ? labelSpacing : datum.screen;
|
|
tempText.rotation = 0;
|
|
tempText.fill = labelStyles.color;
|
|
tempText.text = text;
|
|
tempText.textAlign = "center";
|
|
tempText.textBaseline = label.parallel ? "top" : "bottom";
|
|
tempText.setFont(labelStyles);
|
|
tempText.setBoxing(labelStyles);
|
|
return true;
|
|
};
|
|
const depthLabelMaxSize = {};
|
|
for (const [index, datum] of treeLabels.entries()) {
|
|
const depth = maxDepth - datum.depth;
|
|
depthLabelMaxSize[depth] ?? (depthLabelMaxSize[depth] = 0);
|
|
const isLeaf = !datum.children.length;
|
|
if (isLeaf && step < MIN_CATEGORY_SPACING)
|
|
continue;
|
|
const isVisible = setLabelProps(datum, index);
|
|
if (!isVisible || !tempText.getBBox())
|
|
continue;
|
|
labelBBoxes.set(index, tempText.getBBox());
|
|
tempText.rotation = (0, import_ag_charts_core202.normalizeAngle360FromDegrees)(optionsMap[depth]?.rotation);
|
|
const { width, height } = tempText.getBBox();
|
|
const labelSize = horizontal ? height : width;
|
|
if (depthLabelMaxSize[depth] < labelSize) {
|
|
depthLabelMaxSize[depth] = labelSize;
|
|
}
|
|
}
|
|
const idGenerator = (0, import_ag_charts_core202.createIdsGenerator)();
|
|
const nestedPadding = (d) => {
|
|
if (d === 0)
|
|
return 0;
|
|
let v = depthLabelMaxSize[0];
|
|
for (let i = 1; i <= d; i++) {
|
|
v += optionsMap[i].spacing;
|
|
if (i !== d) {
|
|
v += depthLabelMaxSize[i];
|
|
}
|
|
}
|
|
return v;
|
|
};
|
|
for (const [index, datum] of treeLabels.entries()) {
|
|
if (index === 0)
|
|
continue;
|
|
const visible = setLabelProps(datum, index);
|
|
const isLeaf = !datum.children.length;
|
|
const depth = maxDepth - datum.depth;
|
|
if (isLeaf && step < MIN_CATEGORY_SPACING)
|
|
continue;
|
|
if (!visible)
|
|
continue;
|
|
const labelRotation = (0, import_ag_charts_core202.normalizeAngle360FromDegrees)(optionsMap[depth].rotation);
|
|
const labelBBox = labelBBoxes.get(index);
|
|
if (!labelBBox)
|
|
continue;
|
|
const { width: w, height: h } = labelBBox;
|
|
const depthPadding = nestedPadding(depth);
|
|
tempText.textAlign = "center";
|
|
tempText.textBaseline = "middle";
|
|
tempText.rotation = labelRotation;
|
|
if (horizontal) {
|
|
tempText.y += (depthPadding + (0, import_ag_charts_core202.angularPadding)(w / 2, h / 2, labelRotation)) * sideFlag;
|
|
tempText.rotationCenterX = datum.screen;
|
|
tempText.rotationCenterY = tempText.y;
|
|
} else {
|
|
tempText.x += depthPadding * sideFlag + (0, import_ag_charts_core202.angularPadding)(
|
|
(optionsMap[depth].spacing * sideFlag + w) / 2,
|
|
label.mirrored ? w : 0,
|
|
labelRotation
|
|
) - w / 2;
|
|
tempText.rotationCenterX = tempText.x;
|
|
tempText.rotationCenterY = datum.screen;
|
|
}
|
|
if (optionsMap[depth].avoidCollisions) {
|
|
const { width, height } = tempText.getBBox();
|
|
const labelSize = horizontal ? width : height;
|
|
const availableRange = isLeaf ? step : datum.leafCount * step;
|
|
if (labelSize > availableRange) {
|
|
labelBBoxes.delete(index);
|
|
continue;
|
|
}
|
|
}
|
|
const text = tempText.getPlainText();
|
|
const boxing = tempText.getBoxingProperties();
|
|
tickLabelLayout.push({
|
|
text,
|
|
textUntruncated: truncatedLabelText.get(index),
|
|
visible: true,
|
|
tickId: idGenerator(text),
|
|
range: this.scale.range,
|
|
border: boxing.border,
|
|
color: tempText.fill,
|
|
cornerRadius: boxing.cornerRadius,
|
|
fill: boxing.fill,
|
|
fontFamily: tempText.fontFamily,
|
|
fontSize: tempText.fontSize,
|
|
fontStyle: tempText.fontStyle,
|
|
fontWeight: tempText.fontWeight,
|
|
padding: boxing.padding,
|
|
rotation: tempText.rotation,
|
|
rotationCenterX: tempText.rotationCenterX,
|
|
rotationCenterY: tempText.rotationCenterY,
|
|
textAlign: tempText.textAlign,
|
|
textBaseline: tempText.textBaseline,
|
|
x: tempText.x,
|
|
y: tempText.y
|
|
});
|
|
labelBBoxes.set(index, Transformable.toCanvas(tempText));
|
|
}
|
|
let maxTickSize = depthLabelMaxSize[0];
|
|
for (let i = 0; i < maxDepth; i++) {
|
|
maxTickSize += optionsMap[i].spacing;
|
|
if (i !== 0) {
|
|
maxTickSize += depthLabelMaxSize[i];
|
|
}
|
|
}
|
|
const maxTickSizeWithScrollbar = maxTickSize + scrollbarThickness;
|
|
const bboxes = [
|
|
this.lineNodeBBox(),
|
|
BBox.merge(labelBBoxes.values()),
|
|
new BBox(0, 0, maxTickSizeWithScrollbar * sideFlag, 0)
|
|
];
|
|
const combined = BBox.merge(bboxes);
|
|
const labelThickness = horizontal ? combined.height : combined.width;
|
|
const { spacing, scrollbarLayout } = this.applyScrollbarLayout(bboxes, labelThickness, scrollbar);
|
|
this.layout.labelThickness = labelThickness;
|
|
this.layout.scrollbar = scrollbarLayout;
|
|
if (title.enabled) {
|
|
bboxes.push(this.titleBBox(this.scale.domain, spacing));
|
|
}
|
|
const mergedBBox = BBox.merge(bboxes);
|
|
this.layoutCrossLines();
|
|
return { bbox: mergedBBox, spacing, depthLabelMaxSize, tickLabelLayout };
|
|
}
|
|
/**
|
|
* Creates/removes/updates the scene graph nodes that constitute the axis.
|
|
* Supposed to be called _manually_ after changing _any_ of the axis properties.
|
|
* This allows to bulk set axis properties before updating the nodes.
|
|
* The node changes made by this method are rendered on the next animation frame.
|
|
* We could schedule this method call automatically on the next animation frame
|
|
* when any of the axis properties change (the way we do when properties of scene graph's
|
|
* nodes change), but this will mean that we first wait for the next animation
|
|
* frame to make changes to the nodes of the axis, then wait for another animation
|
|
* frame to render those changes. It's nice to have everything update automatically,
|
|
* but this extra level of async indirection will not just introduce an unwanted delay,
|
|
* it will also make it harder to reason about the program.
|
|
*/
|
|
update() {
|
|
if (!this.computedLayout)
|
|
return;
|
|
if (!this.scale.animatable) {
|
|
this.moduleCtx.animationManager.skipCurrentBatch();
|
|
}
|
|
const { tickScale, tick, gridLine, gridLength, visibleRange, tickTreeLayout } = this;
|
|
if (!tickTreeLayout)
|
|
return;
|
|
const { depthLabelMaxSize, spacing } = this.computedLayout;
|
|
const { depth: maxDepth } = tickTreeLayout;
|
|
const optionsMap = this.getDepthOptionsMap(maxDepth);
|
|
const scrollbar = this.chartLayout?.scrollbars?.[this.id];
|
|
const scrollbarThickness = this.getScrollbarThickness(scrollbar);
|
|
const { position, horizontal, gridPadding } = this;
|
|
const direction = position === "bottom" || position === "right" ? -1 : 1;
|
|
const p1 = gridPadding;
|
|
const p2 = direction * gridLength - gridPadding;
|
|
const tickParams = {
|
|
nice: [false, false],
|
|
interval: void 0,
|
|
tickCount: void 0,
|
|
minTickCount: 0,
|
|
maxTickCount: Infinity
|
|
};
|
|
const { ticks: allTicks } = tickScale.ticks(tickParams, void 0, visibleRange);
|
|
const { tickInfos: allTickInfos, minSpacingByDepth } = buildTickInfos(
|
|
allTicks,
|
|
this.tickNodes,
|
|
tickScale,
|
|
maxDepth
|
|
);
|
|
const minDepthToShow = getMinDepthToShow(minSpacingByDepth);
|
|
const visibleTickInfos = selectVisibleTickInfos(allTickInfos, minDepthToShow, maxDepth, minSpacingByDepth);
|
|
const gridLineData = visibleTickInfos.map(
|
|
({ tickLabel, position: tickPosition }, index) => ({
|
|
index: tickScale.findIndex(tickLabel),
|
|
tickId: createDatumId(index, ...tickLabel),
|
|
translation: Math.round(tickPosition)
|
|
})
|
|
);
|
|
this.gridLineGroupSelection.update(
|
|
gridLine.enabled && gridLength ? this.calculateGridLines(gridLineData, p1, p2) : []
|
|
);
|
|
this.gridFillGroupSelection.update(
|
|
gridLine.enabled && gridLength ? this.calculateGridFills(gridLineData, p1, p2) : []
|
|
);
|
|
this.tickLineGroupSelection.update(
|
|
tick.enabled ? visibleTickInfos.map(({ depth }, index) => {
|
|
const { tickId, translation: offset } = gridLineData[index];
|
|
const tickOptions = this.depthOptions[depth]?.tick;
|
|
let tickSize = depthLabelMaxSize[0];
|
|
for (let i = 0; i <= depth; i++) {
|
|
tickSize += optionsMap[i].spacing;
|
|
if (i !== 0) {
|
|
tickSize += depthLabelMaxSize[i];
|
|
}
|
|
}
|
|
const stroke = tickOptions?.stroke ?? tick.stroke;
|
|
const strokeWidth = tickOptions?.enabled === false ? 0 : tickOptions?.width ?? tick.width;
|
|
const h = -direction * tickSize;
|
|
const tickOffset = -direction * (scrollbarThickness + this.getTickSpacing());
|
|
const [x1, y1, x2, y2] = horizontal ? [offset, tickOffset, offset, tickOffset + h] : [tickOffset, offset, tickOffset + h, offset];
|
|
const lineDash = void 0;
|
|
return { tickId, offset, x1, y1, x2, y2, stroke, strokeWidth, lineDash };
|
|
}) : []
|
|
);
|
|
this.updatePosition();
|
|
this.updateCategoryLabels();
|
|
this.updateAxisLine();
|
|
this.updateGridLines();
|
|
this.updateGridFills();
|
|
this.updateTickLines();
|
|
this.updateTitle(this.scale.domain, spacing);
|
|
this.updateCrossLines();
|
|
this.resetSelectionNodes();
|
|
}
|
|
calculateLayout(_primaryTickCount, chartLayout) {
|
|
this.chartLayout = chartLayout;
|
|
const { depthLabelMaxSize, tickLabelLayout, spacing, bbox } = this.computeLayout();
|
|
this.computedLayout = { depthLabelMaxSize, tickLabelLayout, spacing };
|
|
return { bbox, niceDomain: this.scale.domain };
|
|
}
|
|
/**
|
|
* The length of the grid. The grid is only visible in case of a non-zero value.
|
|
*/
|
|
onGridVisibilityChange() {
|
|
super.onGridVisibilityChange();
|
|
this.tickLabelGroupSelection.clear();
|
|
}
|
|
updateScale() {
|
|
super.updateScale();
|
|
this.tickScale.range = this.scale.range;
|
|
this.scale.paddingOuter = this.scale.paddingInner / 2;
|
|
}
|
|
processData() {
|
|
const { direction } = this;
|
|
const flatDomains = this.boundSeries.filter((s) => s.visible).flatMap((series) => (0, import_ag_charts_core202.extractDomain)(series.getDomain(direction)));
|
|
this.dataDomain = { domain: (0, import_ag_charts_core202.extent)(flatDomains) ?? this.filterDuplicateArrays(flatDomains), clipped: false };
|
|
if (this.isReversed()) {
|
|
this.dataDomain.domain.reverse();
|
|
}
|
|
const domain = this.dataDomain.domain.map(convertIntegratedCategoryValue);
|
|
const { layout, tickNodes } = treeLayout(domain);
|
|
this.tickTreeLayout = layout;
|
|
this.tickNodes = tickNodes;
|
|
const orderedDomain = [];
|
|
for (const node of this.tickTreeLayout.nodes) {
|
|
if (node.leafCount || node.refId == null)
|
|
continue;
|
|
orderedDomain.push(this.dataDomain.domain[node.refId]);
|
|
}
|
|
const sortedDomain = (0, import_ag_charts_core202.sortBasedOnArray)(this.dataDomain.domain, orderedDomain);
|
|
this.scale.domain = sortedDomain;
|
|
const tickScaleDomain = sortedDomain.map(convertIntegratedCategoryValue);
|
|
tickScaleDomain.push([""]);
|
|
this.tickScale.domain = tickScaleDomain;
|
|
}
|
|
filterDuplicateArrays(array4) {
|
|
const seen = /* @__PURE__ */ new Set();
|
|
return array4.filter((item) => {
|
|
const key = (0, import_ag_charts_core202.isArray)(item) ? JSON.stringify(item) : item;
|
|
if (seen.has(key))
|
|
return false;
|
|
seen.add(key);
|
|
return true;
|
|
});
|
|
}
|
|
};
|
|
GroupedCategoryAxis.className = "GroupedCategoryAxis";
|
|
GroupedCategoryAxis.type = "grouped-category";
|
|
__decorateClass([
|
|
import_ag_charts_core202.Property
|
|
], GroupedCategoryAxis.prototype, "depthOptions", 2);
|
|
function separatorDepth2(node) {
|
|
let depth = 0;
|
|
let current = node;
|
|
while (current?.index === 0) {
|
|
depth += 1;
|
|
current = current.parent;
|
|
}
|
|
return depth;
|
|
}
|
|
function buildTickInfos(ticks, tickNodes, tickScale, maxDepth) {
|
|
const tickInfos = new Array(ticks.length);
|
|
const minSpacingByDepth = new Array(maxDepth).fill(Infinity);
|
|
const lastPositionByDepth = new Array(maxDepth).fill(Number.NaN);
|
|
for (let i = 0; i < ticks.length; i++) {
|
|
const tickLabel = ticks[i];
|
|
const node = tickNodes?.get(tickLabel);
|
|
const depth = node == null ? maxDepth - 1 : Math.min(separatorDepth2(node), maxDepth - 1);
|
|
const position = tickScale.convert(tickLabel);
|
|
tickInfos[i] = { tickLabel, depth, position };
|
|
if (!Number.isFinite(position))
|
|
continue;
|
|
for (let d = 0; d <= depth; d++) {
|
|
const lastPosition = lastPositionByDepth[d];
|
|
if (Number.isFinite(lastPosition)) {
|
|
minSpacingByDepth[d] = Math.min(minSpacingByDepth[d], Math.abs(position - lastPosition));
|
|
}
|
|
lastPositionByDepth[d] = position;
|
|
}
|
|
}
|
|
return { tickInfos, minSpacingByDepth };
|
|
}
|
|
function getMinDepthToShow(minSpacingByDepth) {
|
|
for (let depth = 0; depth < minSpacingByDepth.length; depth++) {
|
|
const minSpacing = minSpacingByDepth[depth];
|
|
if (!Number.isFinite(minSpacing) || minSpacing >= MIN_CATEGORY_SPACING) {
|
|
return depth;
|
|
}
|
|
}
|
|
return minSpacingByDepth.length;
|
|
}
|
|
function getTickStepForSpacing(minSpacing) {
|
|
if (!Number.isFinite(minSpacing) || minSpacing <= 0) {
|
|
return 1;
|
|
}
|
|
return Math.max(1, Math.ceil(MIN_CATEGORY_SPACING / minSpacing));
|
|
}
|
|
function selectVisibleTickInfos(allTickInfos, minDepthToShow, maxDepth, minSpacingByDepth) {
|
|
if (minDepthToShow <= 0) {
|
|
return allTickInfos;
|
|
}
|
|
const removedDepth = Math.min(minDepthToShow - 1, maxDepth - 1);
|
|
if (removedDepth < 0) {
|
|
return allTickInfos;
|
|
}
|
|
const tickStep3 = getTickStepForSpacing(minSpacingByDepth[removedDepth]);
|
|
const visibleTickInfos = [];
|
|
let removedIndex = 0;
|
|
for (const info of allTickInfos) {
|
|
if (info.depth >= minDepthToShow) {
|
|
visibleTickInfos.push(info);
|
|
continue;
|
|
}
|
|
if (info.depth !== removedDepth)
|
|
continue;
|
|
if (removedIndex % tickStep3 === 0) {
|
|
visibleTickInfos.push(info);
|
|
}
|
|
removedIndex++;
|
|
}
|
|
return visibleTickInfos;
|
|
}
|
|
function convertIntegratedCategoryValue(datum) {
|
|
return (0, import_ag_charts_core202.toArray)((0, import_ag_charts_core202.isObject)(datum) && "value" in datum ? datum.value : datum);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/quadtreeUtil.ts
|
|
var import_ag_charts_core203 = require("ag-charts-core");
|
|
function addHitTestersToQuadtree(quadtree, hitTesters) {
|
|
for (const node of hitTesters) {
|
|
const datum = node.datum;
|
|
if (datum === void 0) {
|
|
import_ag_charts_core203.Logger.error("undefined datum");
|
|
} else {
|
|
quadtree.addValue(node, datum);
|
|
}
|
|
}
|
|
}
|
|
function findQuadtreeMatch(series, point) {
|
|
const { x, y } = point;
|
|
const { nearest, distanceSquared } = series.getQuadTree().find(x, y);
|
|
if (nearest !== void 0) {
|
|
return { datum: nearest.value, distance: Math.sqrt(distanceSquared) };
|
|
}
|
|
return void 0;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/abstractBarSeries.ts
|
|
var AbstractBarSeriesProperties = class extends CartesianSeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.direction = "vertical";
|
|
this.width = void 0;
|
|
this.widthRatio = void 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core204.Property
|
|
], AbstractBarSeriesProperties.prototype, "direction", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core204.Property
|
|
], AbstractBarSeriesProperties.prototype, "width", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core204.Property
|
|
], AbstractBarSeriesProperties.prototype, "widthRatio", 2);
|
|
var AbstractBarSeries = class extends CartesianSeries {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.smallestDataInterval = void 0;
|
|
this.largestDataInterval = void 0;
|
|
}
|
|
padBandExtent(keys, alignStart) {
|
|
const ratio10 = typeof alignStart === "boolean" ? 1 : 0.5;
|
|
const scalePadding = (0, import_ag_charts_core204.isFiniteNumber)(this.smallestDataInterval) ? this.smallestDataInterval * ratio10 : 0;
|
|
const keysExtent = (0, import_ag_charts_core204.extent)(keys) ?? [Number.NaN, Number.NaN];
|
|
if (typeof alignStart === "boolean") {
|
|
keysExtent[alignStart ? 0 : 1] -= (alignStart ? 1 : -1) * scalePadding;
|
|
} else {
|
|
keysExtent[0] -= scalePadding;
|
|
keysExtent[1] += scalePadding;
|
|
}
|
|
return fixNumericExtent(keysExtent);
|
|
}
|
|
getBandScalePadding() {
|
|
return { inner: 0.3, outer: 0.15 };
|
|
}
|
|
shouldFlipXY() {
|
|
return !this.isVertical();
|
|
}
|
|
isVertical() {
|
|
return this.properties.direction === "vertical";
|
|
}
|
|
getBarDirection() {
|
|
return this.shouldFlipXY() ? import_ag_charts_core204.ChartAxisDirection.X : import_ag_charts_core204.ChartAxisDirection.Y;
|
|
}
|
|
getCategoryDirection() {
|
|
return this.shouldFlipXY() ? import_ag_charts_core204.ChartAxisDirection.Y : import_ag_charts_core204.ChartAxisDirection.X;
|
|
}
|
|
getValueAxis() {
|
|
const direction = this.getBarDirection();
|
|
return this.axes[direction];
|
|
}
|
|
getCategoryAxis() {
|
|
const direction = this.getCategoryDirection();
|
|
return this.axes[direction];
|
|
}
|
|
getMinimumRangeSeries(ranges) {
|
|
const { width } = this.properties;
|
|
if (width == null)
|
|
return;
|
|
const axis = this.getCategoryAxis();
|
|
if (!axis)
|
|
return;
|
|
const { index } = this.ctx.seriesStateManager.getVisiblePeerGroupIndex(this);
|
|
ranges[index] = Math.max(ranges[index] ?? 0, width);
|
|
}
|
|
getMinimumRangeChart(ranges) {
|
|
if (ranges.length === 0)
|
|
return 0;
|
|
const axis = this.getCategoryAxis();
|
|
if (!(axis instanceof GroupedCategoryAxis || axis instanceof CategoryAxis))
|
|
return 0;
|
|
const dataSize = this.data?.netSize() ?? 0;
|
|
if (dataSize === 0)
|
|
return 0;
|
|
const defaultPadding = this.getBandScalePadding();
|
|
const { paddingInner = defaultPadding.inner, paddingOuter = defaultPadding.outer, groupPaddingInner } = axis;
|
|
const width = ranges.reduce((sum, range4) => sum + range4, 0);
|
|
const averageWidth = width / ranges.length;
|
|
const { visibleGroupCount } = this.ctx.seriesStateManager.getVisiblePeerGroupIndex(this);
|
|
const bandWidth = width + groupPaddingInner * averageWidth * (visibleGroupCount - 1);
|
|
const paddingFactor = (dataSize - paddingInner + paddingOuter * 2) / (1 - paddingInner);
|
|
return bandWidth * paddingFactor;
|
|
}
|
|
/**
|
|
* Override to use bar-specific axis resolution (category/value vs X/Y).
|
|
* Bar series can be horizontal or vertical, so we use getCategoryAxis/getValueAxis.
|
|
*/
|
|
validateCreateNodeDataPreconditions() {
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
if (!xAxis || !yAxis || !this.dataModel || !this.processedData) {
|
|
return void 0;
|
|
}
|
|
return { xAxis, yAxis };
|
|
}
|
|
getBandwidth(xAxis, minWidth) {
|
|
return ContinuousScale.is(xAxis.scale) ? xAxis.scale.calcBandwidth(this.smallestDataInterval, minWidth) : xAxis.scale.bandwidth;
|
|
}
|
|
xCoordinateRange(xValue) {
|
|
const xAxis = this.axes[this.getCategoryDirection()];
|
|
const xScale = xAxis.scale;
|
|
const bandWidth = this.getBandwidth(xAxis, 0) ?? 0;
|
|
const barOffset = ContinuousScale.is(xScale) ? bandWidth * -0.5 : 0;
|
|
const x = xScale.convert(xValue) + barOffset;
|
|
return [x, x + bandWidth];
|
|
}
|
|
yCoordinateRange(yValues) {
|
|
const yAxis = this.axes[this.getBarDirection()];
|
|
const yScale = yAxis.scale;
|
|
const ys = yValues.map((yValue) => yScale.convert(yValue));
|
|
if (ys.length === 1) {
|
|
const y0 = yScale.convert(0);
|
|
return [Math.min(ys[0], y0), Math.max(ys[0], y0)];
|
|
}
|
|
return [Math.min(...ys), Math.max(...ys)];
|
|
}
|
|
getBarDimensions() {
|
|
const categoryAxis = this.getCategoryAxis();
|
|
const bandwidth = this.getBandwidth(categoryAxis) ?? 0;
|
|
this.ctx.seriesStateManager.updateGroupScale(this, bandwidth, categoryAxis);
|
|
const groupOffset = this.getGroupOffset();
|
|
const barWidth = this.getBarWidth();
|
|
const barOffset = this.getBarOffset(barWidth);
|
|
return { groupOffset, barOffset, barWidth };
|
|
}
|
|
getGroupOffset() {
|
|
return this.ctx.seriesStateManager.getGroupOffset(this);
|
|
}
|
|
getBarOffset(barWidth) {
|
|
const groupScale = this.ctx.seriesStateManager.getGroupScale(this);
|
|
const xAxis = this.getCategoryAxis();
|
|
let barOffset = 0;
|
|
if (ContinuousScale.is(xAxis.scale)) {
|
|
barOffset = -barWidth / 2;
|
|
} else if (this.seriesGrouping == null && groupScale) {
|
|
const rangeWidth = this.getGroupScaleRangeWidth(groupScale);
|
|
barOffset = (rangeWidth - barWidth) / 2;
|
|
} else if (groupScale && this.properties.widthRatio != null) {
|
|
barOffset = (groupScale.bandwidth - barWidth) / 2;
|
|
}
|
|
const stackOffset = this.ctx.seriesStateManager.getStackOffset(this, barWidth);
|
|
return barOffset + stackOffset;
|
|
}
|
|
getBarWidth() {
|
|
const { seriesGrouping } = this;
|
|
const { width } = this.properties;
|
|
let { widthRatio } = this.properties;
|
|
const groupScale = this.ctx.seriesStateManager.getGroupScale(this);
|
|
const bandwidth = groupScale?.bandwidth ?? 0;
|
|
if (seriesGrouping == null) {
|
|
widthRatio ?? (widthRatio = 1);
|
|
}
|
|
if (widthRatio != null) {
|
|
let relativeWidth = width;
|
|
if (seriesGrouping == null && relativeWidth == null && groupScale) {
|
|
relativeWidth = this.getGroupScaleRangeWidth(groupScale);
|
|
}
|
|
if (relativeWidth == null && bandwidth < 1 && groupScale) {
|
|
return groupScale.rawBandwidth;
|
|
}
|
|
return (relativeWidth ?? bandwidth) * widthRatio;
|
|
}
|
|
if (width != null) {
|
|
return width;
|
|
}
|
|
if (bandwidth < 1 && groupScale) {
|
|
return groupScale.rawBandwidth;
|
|
}
|
|
return bandwidth;
|
|
}
|
|
getGroupScaleRangeWidth(groupScale) {
|
|
let rangeWidth = groupScale.range[1] - groupScale.range[0];
|
|
if (groupScale.round && rangeWidth > 0)
|
|
rangeWidth = Math.floor(rangeWidth);
|
|
return rangeWidth;
|
|
}
|
|
resolveKeyDirection(direction) {
|
|
if (this.getBarDirection() === import_ag_charts_core204.ChartAxisDirection.X) {
|
|
if (direction === import_ag_charts_core204.ChartAxisDirection.X) {
|
|
return import_ag_charts_core204.ChartAxisDirection.Y;
|
|
}
|
|
return import_ag_charts_core204.ChartAxisDirection.X;
|
|
}
|
|
return direction;
|
|
}
|
|
initQuadTree(quadtree) {
|
|
addHitTestersToQuadtree(quadtree, this.datumNodesIter());
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
return findQuadtreeMatch(this, point);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineUtil.ts
|
|
var import_ag_charts_core207 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineInterpolationPlotting.ts
|
|
var import_ag_charts_core205 = require("ag-charts-core");
|
|
function lerp(a, b, ratio10) {
|
|
return (b - a) * ratio10 + a;
|
|
}
|
|
function linearSupertype(span, stepX) {
|
|
const { x0, y0, x1, y1 } = span;
|
|
const m = (y1 - y0) / (x1 - x0);
|
|
const stepY = m * (stepX - x0) + y0;
|
|
return {
|
|
leftCp1x: x0,
|
|
leftCp1y: y0,
|
|
leftCp2x: stepX,
|
|
leftCp2y: stepY,
|
|
stepX,
|
|
stepY0: stepY,
|
|
stepY1: stepY,
|
|
rightCp1x: stepX,
|
|
rightCp1y: stepY,
|
|
rightCp2x: x1,
|
|
rightCp2y: y1
|
|
};
|
|
}
|
|
function bezierSupertype(span, stepX) {
|
|
const { cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y } = span;
|
|
const t = (0, import_ag_charts_core205.solveBezier)(cp0x, cp1x, cp2x, cp3x, stepX);
|
|
const [left, right] = (0, import_ag_charts_core205.splitBezier2D)(cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y, t);
|
|
const stepY = left[3].y;
|
|
return {
|
|
leftCp1x: left[1].x,
|
|
leftCp1y: left[1].y,
|
|
leftCp2x: left[2].x,
|
|
leftCp2y: left[2].y,
|
|
stepX,
|
|
stepY0: stepY,
|
|
stepY1: stepY,
|
|
rightCp1x: right[1].x,
|
|
rightCp1y: right[1].y,
|
|
rightCp2x: right[2].x,
|
|
rightCp2y: right[2].y
|
|
};
|
|
}
|
|
function stepSupertype(span) {
|
|
const { x0, y0, x1, y1, stepX } = span;
|
|
return {
|
|
leftCp1x: (x0 + stepX) / 2,
|
|
leftCp1y: y0,
|
|
leftCp2x: (x0 + stepX) / 2,
|
|
leftCp2y: y0,
|
|
stepX,
|
|
stepY0: y0,
|
|
stepY1: y1,
|
|
rightCp1x: (stepX + x1) / 2,
|
|
rightCp1y: y1,
|
|
rightCp2x: (stepX + x1) / 2,
|
|
rightCp2y: y1
|
|
};
|
|
}
|
|
function spanSupertype(span, stepX) {
|
|
if (span.type === "linear") {
|
|
return linearSupertype(span, stepX);
|
|
} else if (span.type === "cubic") {
|
|
return bezierSupertype(span, stepX);
|
|
} else if (span.type === "step") {
|
|
return stepSupertype(span);
|
|
} else {
|
|
return linearSupertype(span, stepX);
|
|
}
|
|
}
|
|
function plotStart(path, moveTo, x0, y0, x1, y1, reversed) {
|
|
switch (moveTo) {
|
|
case import_ag_charts_core205.SpanJoin.MoveTo:
|
|
if (reversed) {
|
|
path.moveTo(x1, y1);
|
|
} else {
|
|
path.moveTo(x0, y0);
|
|
}
|
|
break;
|
|
case import_ag_charts_core205.SpanJoin.LineTo:
|
|
if (reversed) {
|
|
path.lineTo(x1, y1);
|
|
} else {
|
|
path.lineTo(x0, y0);
|
|
}
|
|
break;
|
|
case import_ag_charts_core205.SpanJoin.Skip:
|
|
break;
|
|
}
|
|
}
|
|
function plotLinear(path, x0, y0, x1, y1, reversed) {
|
|
if (reversed) {
|
|
path.lineTo(x0, y0);
|
|
} else {
|
|
path.lineTo(x1, y1);
|
|
}
|
|
}
|
|
function plotCubic(path, cp0x, cp0y, cp1x, cp1y, cp2x, cp2y, cp3x, cp3y, reversed) {
|
|
if (reversed) {
|
|
path.cubicCurveTo(cp2x, cp2y, cp1x, cp1y, cp0x, cp0y);
|
|
} else {
|
|
path.cubicCurveTo(cp1x, cp1y, cp2x, cp2y, cp3x, cp3y);
|
|
}
|
|
}
|
|
function plotStep(path, x0, y0, x1, y1, stepX, reversed) {
|
|
if (reversed) {
|
|
path.lineTo(stepX, y1);
|
|
path.lineTo(stepX, y0);
|
|
path.lineTo(x0, y0);
|
|
} else {
|
|
path.lineTo(stepX, y0);
|
|
path.lineTo(stepX, y1);
|
|
path.lineTo(x1, y1);
|
|
}
|
|
}
|
|
function plotMultiLine(path, x0, y0, x1, y1, midPoints, reversed) {
|
|
if (reversed) {
|
|
for (let i = midPoints.length - 1; i >= 0; i--) {
|
|
const { x, y } = midPoints[i];
|
|
path.lineTo(x, y);
|
|
}
|
|
path.lineTo(x0, y0);
|
|
} else {
|
|
for (const { x, y } of midPoints) {
|
|
path.lineTo(x, y);
|
|
}
|
|
path.lineTo(x1, y1);
|
|
}
|
|
}
|
|
function plotSpan(path, span, moveTo, reversed) {
|
|
const [start, end2] = (0, import_ag_charts_core205.spanRange)(span);
|
|
plotStart(path, moveTo, start.x, start.y, end2.x, end2.y, reversed);
|
|
switch (span.type) {
|
|
case "linear":
|
|
plotLinear(path, span.x0, span.y0, span.x1, span.y1, reversed);
|
|
break;
|
|
case "cubic":
|
|
plotCubic(
|
|
path,
|
|
span.cp0x,
|
|
span.cp0y,
|
|
span.cp1x,
|
|
span.cp1y,
|
|
span.cp2x,
|
|
span.cp2y,
|
|
span.cp3x,
|
|
span.cp3y,
|
|
reversed
|
|
);
|
|
break;
|
|
case "step":
|
|
plotStep(path, span.x0, span.y0, span.x1, span.y1, span.stepX, reversed);
|
|
break;
|
|
case "multi-line":
|
|
plotMultiLine(path, span.x0, span.y0, span.x1, span.y1, span.midPoints, reversed);
|
|
break;
|
|
}
|
|
}
|
|
function interpolatedSpanRange(a, b, ratio10) {
|
|
const [aStart, aEnd] = (0, import_ag_charts_core205.spanRange)(a);
|
|
const [bStart, bEnd] = (0, import_ag_charts_core205.spanRange)(b);
|
|
const x0 = lerp(aStart.x, bStart.x, ratio10);
|
|
const y0 = lerp(aStart.y, bStart.y, ratio10);
|
|
const x1 = lerp(aEnd.x, bEnd.x, ratio10);
|
|
const y1 = lerp(aEnd.y, bEnd.y, ratio10);
|
|
return [
|
|
{ x: x0, y: y0 },
|
|
{ x: x1, y: y1 }
|
|
];
|
|
}
|
|
function plotInterpolatedSpans(path, a, b, ratio10, moveTo, reversed) {
|
|
const [{ x: x0, y: y0 }, { x: x1, y: y1 }] = interpolatedSpanRange(a, b, ratio10);
|
|
plotStart(path, moveTo, x0, y0, x1, y1, reversed);
|
|
if (a.type === "cubic" && b.type === "cubic") {
|
|
const cp1x = lerp(a.cp1x, b.cp1x, ratio10);
|
|
const cp1y = lerp(a.cp1y, b.cp1y, ratio10);
|
|
const cp2x = lerp(a.cp2x, b.cp2x, ratio10);
|
|
const cp2y = lerp(a.cp2y, b.cp2y, ratio10);
|
|
plotCubic(path, x0, y0, cp1x, cp1y, cp2x, cp2y, x1, y1, reversed);
|
|
} else if (a.type === "step" && b.type === "step") {
|
|
const stepX = lerp(a.stepX, b.stepX, ratio10);
|
|
plotStep(path, x0, y0, x1, y1, stepX, reversed);
|
|
} else if (a.type === "linear" && b.type === "linear") {
|
|
plotLinear(path, x0, y0, x1, y1, reversed);
|
|
} else {
|
|
let defaultStepX;
|
|
if (a.type === "step") {
|
|
defaultStepX = a.stepX;
|
|
} else if (b.type === "step") {
|
|
defaultStepX = b.stepX;
|
|
} else {
|
|
defaultStepX = (x0 + x1) / 2;
|
|
}
|
|
const as = spanSupertype(a, defaultStepX);
|
|
const bs = spanSupertype(b, defaultStepX);
|
|
const leftCp1x = lerp(as.leftCp1x, bs.leftCp1x, ratio10);
|
|
const leftCp1y = lerp(as.leftCp1y, bs.leftCp1y, ratio10);
|
|
const leftCp2x = lerp(as.leftCp2x, bs.leftCp2x, ratio10);
|
|
const leftCp2y = lerp(as.leftCp2y, bs.leftCp2y, ratio10);
|
|
const stepX = lerp(as.stepX, bs.stepX, ratio10);
|
|
const stepY0 = lerp(as.stepY0, bs.stepY0, ratio10);
|
|
const stepY1 = lerp(as.stepY1, bs.stepY1, ratio10);
|
|
const rightCp1x = lerp(as.rightCp1x, bs.rightCp1x, ratio10);
|
|
const rightCp1y = lerp(as.rightCp1y, bs.rightCp1y, ratio10);
|
|
const rightCp2x = lerp(as.rightCp2x, bs.rightCp2x, ratio10);
|
|
const rightCp2y = lerp(as.rightCp2y, bs.rightCp2y, ratio10);
|
|
if (reversed) {
|
|
path.cubicCurveTo(rightCp2x, rightCp2y, rightCp1x, rightCp1y, stepX, stepY1);
|
|
path.lineTo(stepX, stepY0);
|
|
path.cubicCurveTo(leftCp2x, leftCp2y, leftCp1x, leftCp1y, x0, y0);
|
|
} else {
|
|
path.cubicCurveTo(leftCp1x, leftCp1y, leftCp2x, leftCp2y, stepX, stepY0);
|
|
path.lineTo(stepX, stepY1);
|
|
path.cubicCurveTo(rightCp1x, rightCp1y, rightCp2x, rightCp2y, x1, y1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineInterpolationUtil.ts
|
|
var import_ag_charts_core206 = require("ag-charts-core");
|
|
var MAX_CATEGORIES = 1e3;
|
|
var CollapseMode = /* @__PURE__ */ ((CollapseMode2) => {
|
|
CollapseMode2[CollapseMode2["Zero"] = 0] = "Zero";
|
|
CollapseMode2[CollapseMode2["Split"] = 1] = "Split";
|
|
return CollapseMode2;
|
|
})(CollapseMode || {});
|
|
function integratedCategoryMatch(a, b) {
|
|
if (a == null || b == null)
|
|
return false;
|
|
if (typeof a !== "object" || typeof b !== "object")
|
|
return false;
|
|
if ("id" in a && "id" in b) {
|
|
return a.id === b.id;
|
|
}
|
|
return a.toString() === b.toString();
|
|
}
|
|
function toAxisValue(value) {
|
|
return (0, import_ag_charts_core206.transformIntegratedCategoryValue)(value).valueOf();
|
|
}
|
|
function scale(val, scaling) {
|
|
if (!scaling)
|
|
return Number.NaN;
|
|
if (val instanceof Date) {
|
|
val = val.getTime();
|
|
}
|
|
if (scaling.type === "continuous" && typeof val === "number") {
|
|
const domainRatio = (val - scaling.domain[0]) / (scaling.domain[1] - scaling.domain[0]);
|
|
return domainRatio * (scaling.range[1] - scaling.range[0]) + scaling.range[0];
|
|
}
|
|
if (scaling.type === "log" && typeof val === "number") {
|
|
return scaling.convert(val);
|
|
}
|
|
if (scaling.type !== "category")
|
|
return Number.NaN;
|
|
if ((0, import_ag_charts_core206.isUnitTimeCategoryScaling)(scaling)) {
|
|
if (typeof val === "number") {
|
|
const { firstBandTime, intervalMs, bandCount, inset, step } = scaling;
|
|
const matchingIndex2 = Math.round((val - firstBandTime) / intervalMs);
|
|
if (matchingIndex2 >= 0 && matchingIndex2 < bandCount) {
|
|
return inset + step * matchingIndex2;
|
|
}
|
|
}
|
|
return Number.NaN;
|
|
}
|
|
const axisValue = toAxisValue(val);
|
|
let matchingIndex = scaling.domain.findIndex((d) => toAxisValue(d) === axisValue);
|
|
if (matchingIndex === -1) {
|
|
matchingIndex = scaling.domain.findIndex((d) => integratedCategoryMatch(val, d));
|
|
}
|
|
if (matchingIndex >= 0) {
|
|
return scaling.inset + scaling.step * matchingIndex;
|
|
}
|
|
return Number.NaN;
|
|
}
|
|
function getAxisIndices({ data }, values) {
|
|
return data.map((datum, datumIndex) => ({
|
|
xValue0Index: values.indexOf(toAxisValue(datum.xValue0)),
|
|
xValue1Index: values.indexOf(toAxisValue(datum.xValue1)),
|
|
datumIndex
|
|
}));
|
|
}
|
|
function isValidScaling(data) {
|
|
return Object.values(data.scales).every((s) => {
|
|
if (s.type === "category") {
|
|
if ((0, import_ag_charts_core206.isUnitTimeCategoryScaling)(s)) {
|
|
return s.bandCount < MAX_CATEGORIES;
|
|
}
|
|
return s.domain.length < MAX_CATEGORIES;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
function validateCategorySorting(newData, oldData) {
|
|
const oldScale = oldData.scales.x;
|
|
const newScale = newData.scales.x;
|
|
if (oldScale?.type !== "category" || newScale?.type !== "category")
|
|
return true;
|
|
if ((0, import_ag_charts_core206.isUnitTimeCategoryScaling)(oldScale) || (0, import_ag_charts_core206.isUnitTimeCategoryScaling)(newScale)) {
|
|
return true;
|
|
}
|
|
let x0 = -Infinity;
|
|
for (const oldValue of oldScale.domain) {
|
|
const x = scale(oldValue, newScale);
|
|
if (!Number.isFinite(x))
|
|
continue;
|
|
if (x < x0) {
|
|
return false;
|
|
} else {
|
|
x0 = x;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function validateAxisEntriesOrder(axisValues, data) {
|
|
let x0 = -Infinity;
|
|
for (const axisValue of axisValues) {
|
|
const x = scale(axisValue.value, data.scales.x);
|
|
if (!Number.isFinite(x))
|
|
continue;
|
|
if (x < x0) {
|
|
return false;
|
|
} else {
|
|
x0 = x;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function spanAxisContext(newData, oldData) {
|
|
const allAxisEntries = /* @__PURE__ */ new Map();
|
|
for (const { xValue0, xValue1 } of newData.data) {
|
|
const xValue0Value = toAxisValue(xValue0);
|
|
const xValue1Value = toAxisValue(xValue1);
|
|
allAxisEntries.set(xValue0Value, xValue0).set(xValue1Value, xValue1);
|
|
}
|
|
const newAxisEntries = Array.from(allAxisEntries, ([axisValue, value]) => ({ axisValue, value }));
|
|
newAxisEntries.sort((a, b) => {
|
|
return scale(a.value, newData.scales.x) - scale(b.value, newData.scales.x);
|
|
});
|
|
const exclusivelyOldAxisEntries = [];
|
|
for (const { xValue0, xValue1 } of oldData.data) {
|
|
const xValue0Value = toAxisValue(xValue0);
|
|
const xValue1Value = toAxisValue(xValue1);
|
|
if (!allAxisEntries.has(xValue0Value)) {
|
|
allAxisEntries.set(xValue0Value, xValue0);
|
|
exclusivelyOldAxisEntries.push({ axisValue: xValue0Value, value: xValue0 });
|
|
}
|
|
if (!allAxisEntries.has(xValue1Value)) {
|
|
allAxisEntries.set(xValue1Value, xValue1);
|
|
exclusivelyOldAxisEntries.push({ axisValue: xValue1Value, value: xValue1 });
|
|
}
|
|
}
|
|
exclusivelyOldAxisEntries.sort((a, b) => {
|
|
return scale(a.value, oldData.scales.x) - scale(b.value, oldData.scales.x);
|
|
});
|
|
const axisEntries = newAxisEntries;
|
|
let insertionIndex = 0;
|
|
for (const oldAxisEntry of exclusivelyOldAxisEntries) {
|
|
for (let i = axisEntries.length - 1; i >= insertionIndex; i -= 1) {
|
|
const oldValueX = scale(oldAxisEntry.value, oldData.scales.x);
|
|
const newValueX = scale(axisEntries[i].value, oldData.scales.x);
|
|
if (oldValueX > newValueX) {
|
|
insertionIndex = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
axisEntries.splice(insertionIndex, 0, oldAxisEntry);
|
|
insertionIndex += 1;
|
|
}
|
|
if (!validateAxisEntriesOrder(axisEntries, oldData))
|
|
return;
|
|
const axisValues = axisEntries.map((axisEntry) => axisEntry.axisValue);
|
|
const oldDataAxisIndices = getAxisIndices(oldData, axisValues);
|
|
const newDataAxisIndices = getAxisIndices(newData, axisValues);
|
|
return { axisValues, oldDataAxisIndices, newDataAxisIndices };
|
|
}
|
|
function clipSpan(span, data, axisValues, xValue0Index, xIndices) {
|
|
if (xIndices.xValue1Index === xIndices.xValue0Index + 1)
|
|
return span;
|
|
const range4 = (0, import_ag_charts_core206.spanRange)(span);
|
|
let start;
|
|
let end2;
|
|
if (data.scales.x?.type === "category") {
|
|
const step = (range4[1].x - range4[0].x) / (xIndices.xValue1Index - xIndices.xValue0Index);
|
|
start = range4[0].x + (xValue0Index - xIndices.xValue0Index) * step;
|
|
end2 = start + step;
|
|
} else {
|
|
const xValue0 = axisValues[xValue0Index];
|
|
const xValue1 = axisValues[xValue0Index + 1];
|
|
start = scale(xValue0, data.scales.x);
|
|
end2 = scale(xValue1, data.scales.x);
|
|
}
|
|
return (0, import_ag_charts_core206.clipSpanX)(span, start, end2);
|
|
}
|
|
function axisZeroSpan(span, data) {
|
|
const [r0, r1] = (0, import_ag_charts_core206.spanRange)(span);
|
|
const y0 = scale(0, data.scales.y);
|
|
return (0, import_ag_charts_core206.rescaleSpan)(span, { x: r0.x, y: y0 }, { x: r1.x, y: y0 });
|
|
}
|
|
function collapseSpanToMidpoint(span) {
|
|
const [r0, r1] = (0, import_ag_charts_core206.spanRange)(span);
|
|
return (0, import_ag_charts_core206.collapseSpanToPoint)(span, {
|
|
x: (r0.x + r1.x) / 2,
|
|
y: (r0.y + r1.y) / 2
|
|
});
|
|
}
|
|
function collapseSpan(span, collapseMode, data, axisIndices, indices, range4) {
|
|
let xValue;
|
|
let yValue;
|
|
if (indices.xValue0Index >= range4.xValue1Index) {
|
|
const datumIndex = axisIndices.findLast((i) => i.xValue1Index <= range4.xValue1Index)?.datumIndex;
|
|
const datum = datumIndex == null ? void 0 : data.data[datumIndex];
|
|
xValue = datum?.xValue1;
|
|
yValue = datum?.yValue1;
|
|
} else if (indices.xValue0Index <= range4.xValue0Index) {
|
|
const datumIndex = axisIndices.find((i) => i.xValue0Index >= range4.xValue0Index)?.datumIndex;
|
|
const datum = datumIndex == null ? void 0 : data.data[datumIndex];
|
|
xValue = datum?.xValue0;
|
|
yValue = datum?.yValue0;
|
|
}
|
|
if (xValue == null || yValue == null) {
|
|
switch (collapseMode) {
|
|
case 0 /* Zero */:
|
|
return axisZeroSpan(span, data);
|
|
case 1 /* Split */:
|
|
return collapseSpanToMidpoint(span);
|
|
}
|
|
}
|
|
const x = scale(xValue, data.scales.x);
|
|
const y = scale(yValue, data.scales.y);
|
|
const point = { x, y };
|
|
return (0, import_ag_charts_core206.rescaleSpan)(span, point, point);
|
|
}
|
|
function zeroDataSpan(spanDatum, zeroData) {
|
|
if (zeroData == null)
|
|
return;
|
|
const newSpanXValue0 = toAxisValue(spanDatum.xValue0);
|
|
const newSpanXValue1 = toAxisValue(spanDatum.xValue1);
|
|
return zeroData.find(
|
|
(zeroSpanDatum) => toAxisValue(zeroSpanDatum.xValue0) === newSpanXValue0 && toAxisValue(zeroSpanDatum.xValue1) === newSpanXValue1
|
|
)?.span;
|
|
}
|
|
function addSpan(newData, collapseMode, newAxisIndices, newIndices, oldZeroData, range4, out) {
|
|
const newSpanDatum = newData.data[newIndices.datumIndex];
|
|
const newSpan = newSpanDatum.span;
|
|
const zeroSpan = zeroDataSpan(newSpanDatum, oldZeroData);
|
|
if (zeroSpan == null) {
|
|
const oldSpan = collapseSpan(newSpan, collapseMode, newData, newAxisIndices, newIndices, range4);
|
|
out.added.push({ from: oldSpan, to: newSpan });
|
|
} else {
|
|
out.removed.push({ from: zeroSpan, to: zeroSpan });
|
|
out.moved.push({ from: zeroSpan, to: newSpan });
|
|
out.added.push({ from: newSpan, to: newSpan });
|
|
}
|
|
}
|
|
function removeSpan(oldData, collapseMode, oldAxisIndices, oldIndices, newZeroData, range4, out) {
|
|
const oldSpanDatum = oldData.data[oldIndices.datumIndex];
|
|
const oldSpan = oldSpanDatum.span;
|
|
const zeroSpan = zeroDataSpan(oldSpanDatum, newZeroData);
|
|
if (zeroSpan == null) {
|
|
const newSpan = collapseSpan(oldSpan, collapseMode, oldData, oldAxisIndices, oldIndices, range4);
|
|
out.removed.push({ from: oldSpan, to: newSpan });
|
|
} else {
|
|
out.removed.push({ from: oldSpan, to: oldSpan });
|
|
out.moved.push({ from: oldSpan, to: zeroSpan });
|
|
out.added.push({ from: zeroSpan, to: zeroSpan });
|
|
}
|
|
}
|
|
function alignSpanToContainingSpan(span, axisValues, preData, postData, postSpanIndices) {
|
|
const xScale = postData.scales.x;
|
|
const startXValue0 = axisValues[postSpanIndices.xValue0Index];
|
|
const endXValue1 = axisValues[postSpanIndices.xValue1Index];
|
|
let startDatum;
|
|
let endDatum;
|
|
if (xScale?.type === "continuous" || xScale?.type === "log") {
|
|
startDatum = preData.data.findLast((spanDatum) => toAxisValue(spanDatum.xValue0) <= startXValue0);
|
|
endDatum = preData.data.find((spanDatum) => toAxisValue(spanDatum.xValue1) >= endXValue1);
|
|
} else {
|
|
startDatum = preData.data.find((spanDatum) => toAxisValue(spanDatum.xValue0) === startXValue0);
|
|
endDatum = preData.data.find((spanDatum) => toAxisValue(spanDatum.xValue1) === endXValue1);
|
|
}
|
|
if (startDatum == null || endDatum == null)
|
|
return;
|
|
const [{ x: x0 }, { x: x1 }] = (0, import_ag_charts_core206.spanRange)(span);
|
|
const startX = scale(startDatum.xValue0, preData.scales.x);
|
|
const startY = scale(startDatum.yValue0, preData.scales.y);
|
|
const endX = scale(endDatum.xValue1, preData.scales.x);
|
|
const endY = scale(endDatum.yValue1, preData.scales.y);
|
|
let altSpan = postData.data[postSpanIndices.datumIndex].span;
|
|
altSpan = (0, import_ag_charts_core206.rescaleSpan)(altSpan, { x: startX, y: startY }, { x: endX, y: endY });
|
|
altSpan = (0, import_ag_charts_core206.clipSpanX)(altSpan, x0, x1);
|
|
return altSpan;
|
|
}
|
|
function appendSpanPhases(newData, oldData, collapseMode, axisValues, xValue0Index, newAxisIndices, oldAxisIndices, range4, out) {
|
|
const xValue1Index = xValue0Index + 1;
|
|
const oldIndices = oldAxisIndices.find((i) => i.xValue0Index <= xValue0Index && i.xValue1Index >= xValue1Index);
|
|
const newIndices = newAxisIndices.find((i) => i.xValue0Index <= xValue0Index && i.xValue1Index >= xValue1Index);
|
|
const oldZeroData = oldData.zeroData;
|
|
const newZeroData = newData.zeroData;
|
|
if (oldIndices == null && newIndices != null) {
|
|
addSpan(newData, collapseMode, newAxisIndices, newIndices, oldZeroData, range4, out);
|
|
return;
|
|
} else if (oldIndices != null && newIndices == null) {
|
|
removeSpan(oldData, collapseMode, oldAxisIndices, oldIndices, newZeroData, range4, out);
|
|
return;
|
|
} else if (oldIndices == null || newIndices == null) {
|
|
return;
|
|
}
|
|
let ordering;
|
|
if (oldIndices.xValue0Index === newIndices.xValue0Index && oldIndices.xValue1Index === newIndices.xValue1Index) {
|
|
ordering = 0;
|
|
} else if (oldIndices.xValue0Index <= newIndices.xValue0Index && oldIndices.xValue1Index >= newIndices.xValue1Index) {
|
|
ordering = -1;
|
|
} else if (oldIndices.xValue0Index >= newIndices.xValue0Index && oldIndices.xValue1Index <= newIndices.xValue1Index) {
|
|
ordering = 1;
|
|
} else {
|
|
ordering = 0;
|
|
}
|
|
const oldSpanDatum = oldData.data[oldIndices.datumIndex];
|
|
const clippedOldSpanOldScale = clipSpan(oldSpanDatum.span, oldData, axisValues, xValue0Index, oldIndices);
|
|
const newSpanDatum = newData.data[newIndices.datumIndex];
|
|
const clippedNewSpanNewScale = clipSpan(newSpanDatum.span, newData, axisValues, xValue0Index, newIndices);
|
|
if (ordering === 1) {
|
|
const clippedPostRemoveOldSpanOldScale = alignSpanToContainingSpan(
|
|
clippedOldSpanOldScale,
|
|
axisValues,
|
|
oldData,
|
|
newData,
|
|
newIndices
|
|
);
|
|
if (clippedPostRemoveOldSpanOldScale == null) {
|
|
removeSpan(oldData, collapseMode, oldAxisIndices, oldIndices, newZeroData, range4, out);
|
|
} else {
|
|
out.removed.push({ from: clippedOldSpanOldScale, to: clippedPostRemoveOldSpanOldScale });
|
|
out.moved.push({ from: clippedPostRemoveOldSpanOldScale, to: clippedNewSpanNewScale });
|
|
out.added.push({ from: clippedNewSpanNewScale, to: clippedNewSpanNewScale });
|
|
}
|
|
} else if (ordering === -1) {
|
|
const clippedPreAddedNewSpanNewScale = alignSpanToContainingSpan(
|
|
clippedNewSpanNewScale,
|
|
axisValues,
|
|
newData,
|
|
oldData,
|
|
oldIndices
|
|
);
|
|
if (clippedPreAddedNewSpanNewScale == null) {
|
|
addSpan(newData, collapseMode, newAxisIndices, newIndices, oldZeroData, range4, out);
|
|
} else {
|
|
out.removed.push({ from: clippedOldSpanOldScale, to: clippedOldSpanOldScale });
|
|
out.moved.push({ from: clippedOldSpanOldScale, to: clippedPreAddedNewSpanNewScale });
|
|
out.added.push({ from: clippedPreAddedNewSpanNewScale, to: clippedNewSpanNewScale });
|
|
}
|
|
} else {
|
|
out.removed.push({ from: clippedOldSpanOldScale, to: clippedOldSpanOldScale });
|
|
out.moved.push({ from: clippedOldSpanOldScale, to: clippedNewSpanNewScale });
|
|
out.added.push({ from: clippedNewSpanNewScale, to: clippedNewSpanNewScale });
|
|
}
|
|
}
|
|
function phaseAnimation(axisContext, newData, oldData, collapseMode) {
|
|
const out = {
|
|
removed: [],
|
|
moved: [],
|
|
added: []
|
|
};
|
|
const { axisValues, oldDataAxisIndices, newDataAxisIndices } = axisContext;
|
|
const range4 = {
|
|
xValue0Index: Math.max(
|
|
oldDataAxisIndices.at(0)?.xValue0Index ?? -Infinity,
|
|
newDataAxisIndices.at(0)?.xValue0Index ?? -Infinity
|
|
),
|
|
xValue1Index: Math.min(
|
|
oldDataAxisIndices.at(-1)?.xValue1Index ?? Infinity,
|
|
newDataAxisIndices.at(-1)?.xValue1Index ?? Infinity
|
|
)
|
|
};
|
|
for (let xValue0Index = 0; xValue0Index < axisValues.length - 1; xValue0Index += 1) {
|
|
appendSpanPhases(
|
|
newData,
|
|
oldData,
|
|
collapseMode,
|
|
axisValues,
|
|
xValue0Index,
|
|
newDataAxisIndices,
|
|
oldDataAxisIndices,
|
|
range4,
|
|
out
|
|
);
|
|
}
|
|
return out;
|
|
}
|
|
function replotXAnimation(newData, oldData) {
|
|
const removed = [];
|
|
const moved = [];
|
|
const added = [];
|
|
for (let i = 0; i < oldData.data.length; i += 1) {
|
|
const oldSpan = oldData.data[i].span;
|
|
const newSpan = newData.data[i].span;
|
|
removed.push({ from: oldSpan, to: oldSpan });
|
|
moved.push({ from: oldSpan, to: newSpan });
|
|
added.push({ from: newSpan, to: newSpan });
|
|
}
|
|
return {
|
|
removed,
|
|
moved,
|
|
added
|
|
};
|
|
}
|
|
function resetSpan(data, spanDatum, collapseMode) {
|
|
const { span } = spanDatum;
|
|
switch (collapseMode) {
|
|
case 0 /* Zero */:
|
|
return zeroDataSpan(spanDatum, data.zeroData) ?? axisZeroSpan(span, data);
|
|
case 1 /* Split */:
|
|
return collapseSpanToMidpoint(span);
|
|
}
|
|
}
|
|
function resetAnimation(newData, oldData, collapseMode) {
|
|
const added = [];
|
|
const removed = [];
|
|
for (const oldSpanDatum of oldData.data) {
|
|
const oldSpan = oldSpanDatum.span;
|
|
const collapsedSpan = resetSpan(oldData, oldSpanDatum, collapseMode);
|
|
removed.push({ from: oldSpan, to: collapsedSpan });
|
|
}
|
|
for (const newSpanDatum of newData.data) {
|
|
const newSpan = newSpanDatum.span;
|
|
const collapsedSpan = resetSpan(newData, newSpanDatum, collapseMode);
|
|
added.push({ from: collapsedSpan, to: newSpan });
|
|
}
|
|
return {
|
|
removed,
|
|
moved: [],
|
|
added
|
|
};
|
|
}
|
|
function pairUpSpans(newData, oldData, collapseMode) {
|
|
if (!isValidScaling(newData) || !isValidScaling(oldData))
|
|
return;
|
|
if (!validateCategorySorting(newData, oldData))
|
|
return;
|
|
const axisContext = spanAxisContext(newData, oldData);
|
|
if (axisContext == null) {
|
|
return resetAnimation(newData, oldData, collapseMode);
|
|
} else if (axisContext.axisValues.length === axisContext.oldDataAxisIndices.length + axisContext.newDataAxisIndices.length + 2) {
|
|
return replotXAnimation(newData, oldData);
|
|
} else {
|
|
return phaseAnimation(axisContext, newData, oldData, collapseMode);
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineUtil.ts
|
|
function interpolatePoints(points, interpolation) {
|
|
const pointsIter = points.map((point) => point.point);
|
|
let spans = (0, import_ag_charts_core207.linearPoints)(pointsIter);
|
|
switch (interpolation.type) {
|
|
case "linear":
|
|
break;
|
|
case "smooth":
|
|
spans = (0, import_ag_charts_core207.smoothPoints)(pointsIter, interpolation.tension);
|
|
break;
|
|
case "step":
|
|
spans = (0, import_ag_charts_core207.stepPoints)(pointsIter, interpolation.position);
|
|
break;
|
|
}
|
|
return spans.map(function spanToLinePathSpan(span, i) {
|
|
return {
|
|
span,
|
|
xValue0: points[i].xDatum,
|
|
yValue0: points[i].yDatum,
|
|
xValue1: points[i + 1].xDatum,
|
|
yValue1: points[i + 1].yDatum
|
|
};
|
|
});
|
|
}
|
|
function pointsEq(a, b, delta3 = 1e-3) {
|
|
return Math.abs(a.x - b.x) < delta3 && Math.abs(a.y - b.y) < delta3;
|
|
}
|
|
function plotLinePathStroke({ path }, spans) {
|
|
let lastPoint;
|
|
for (const { span } of spans) {
|
|
const [start, end2] = (0, import_ag_charts_core207.spanRange)(span);
|
|
const join = lastPoint != null && pointsEq(lastPoint, start) ? import_ag_charts_core207.SpanJoin.Skip : import_ag_charts_core207.SpanJoin.MoveTo;
|
|
plotSpan(path, span, join, false);
|
|
lastPoint = end2;
|
|
}
|
|
}
|
|
function plotInterpolatedLinePathStroke(ratio10, path, spans) {
|
|
let lastPoint;
|
|
for (const span of spans) {
|
|
const [start, end2] = interpolatedSpanRange(span.from, span.to, ratio10);
|
|
const join = lastPoint != null && pointsEq(lastPoint, start) ? import_ag_charts_core207.SpanJoin.Skip : import_ag_charts_core207.SpanJoin.MoveTo;
|
|
plotInterpolatedSpans(path.path, span.from, span.to, ratio10, join, false);
|
|
lastPoint = end2;
|
|
}
|
|
}
|
|
function prepareLinePathStrokeAnimationFns(status, spans, visibleToggleMode, targetOpacity = 1) {
|
|
const removePhaseFn = (ratio10, path) => plotInterpolatedLinePathStroke(ratio10, path, spans.removed);
|
|
const updatePhaseFn = (ratio10, path) => plotInterpolatedLinePathStroke(ratio10, path, spans.moved);
|
|
const addPhaseFn = (ratio10, path) => plotInterpolatedLinePathStroke(ratio10, path, spans.added);
|
|
const pathProperties = prepareLinePathPropertyAnimation(status, visibleToggleMode, targetOpacity);
|
|
return { status, path: { addPhaseFn, updatePhaseFn, removePhaseFn }, pathProperties };
|
|
}
|
|
function prepareLinePathPropertyAnimation(status, visibleToggleMode, targetOpacity = 1) {
|
|
const phase = visibleToggleMode === "none" ? "updated" : status;
|
|
const result = {
|
|
fromFn(path, datum) {
|
|
const out = { phase: NODE_UPDATE_STATE_TO_PHASE_MAPPING[phase] };
|
|
const segments = path.previousDatum ?? datum;
|
|
if (segments != null) {
|
|
out.segments = segments;
|
|
}
|
|
if (status === "removed") {
|
|
out.finish = { visible: false };
|
|
} else if (status === "added") {
|
|
out.start = { visible: true };
|
|
}
|
|
return out;
|
|
},
|
|
toFn(_path, datum) {
|
|
const out = { phase: NODE_UPDATE_STATE_TO_PHASE_MAPPING[phase] };
|
|
const segments = datum;
|
|
if (segments != null) {
|
|
out.segments = segments;
|
|
}
|
|
return out;
|
|
}
|
|
};
|
|
if (visibleToggleMode === "fade") {
|
|
return {
|
|
fromFn(path, datum) {
|
|
const opacity = status === "added" ? 0 : targetOpacity;
|
|
const segments = status === "removed" ? path.previousDatum ?? datum : datum;
|
|
return { ...result.fromFn(path, datum), opacity, segments };
|
|
},
|
|
toFn(path, datum) {
|
|
const opacity = status === "removed" ? 0 : targetOpacity;
|
|
const segments = status === "removed" ? path.previousDatum ?? datum : datum;
|
|
return { ...result.toFn(path, datum), opacity, segments };
|
|
}
|
|
};
|
|
}
|
|
return result;
|
|
}
|
|
function prepareLinePathAnimation(newData, oldData, diff2, targetOpacity = 1) {
|
|
const isCategoryBased = newData.scales.x?.type === "category";
|
|
const wasCategoryBased = oldData.scales.x?.type === "category";
|
|
if (isCategoryBased !== wasCategoryBased || !(0, import_ag_charts_core207.isScaleValid)(newData.scales.x) || !(0, import_ag_charts_core207.isScaleValid)(oldData.scales.x)) {
|
|
return;
|
|
}
|
|
if (newData.strokeData == null || oldData.strokeData == null) {
|
|
return;
|
|
}
|
|
let status = "updated";
|
|
if (oldData.visible && !newData.visible) {
|
|
status = "removed";
|
|
} else if (!oldData.visible && newData.visible) {
|
|
status = "added";
|
|
}
|
|
const strokeSpans = pairUpSpans(
|
|
{ scales: newData.scales, data: newData.strokeData.spans },
|
|
{ scales: oldData.scales, data: oldData.strokeData.spans },
|
|
1 /* Split */
|
|
);
|
|
if (strokeSpans == null)
|
|
return;
|
|
const stroke = prepareLinePathStrokeAnimationFns(status, strokeSpans, "fade", targetOpacity);
|
|
const hasMotion = (diff2?.changed ?? true) || !(0, import_ag_charts_core207.areScalingEqual)(newData.scales.x, oldData.scales.x) || !(0, import_ag_charts_core207.areScalingEqual)(newData.scales.y, oldData.scales.y) || status !== "updated";
|
|
return { status, stroke, hasMotion };
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/barUtil.ts
|
|
var import_ag_charts_core208 = require("ag-charts-core");
|
|
function checkCrisp(scale2, visibleRange, smallestDataInterval, largestDataInterval) {
|
|
if (visibleRange != null) {
|
|
const [visibleMin, visibleMax] = visibleRange;
|
|
const isZoomed = visibleMin !== 0 || visibleMax !== 1;
|
|
if (isZoomed)
|
|
return false;
|
|
}
|
|
if (ContinuousScale.is(scale2)) {
|
|
const spacing = scale2.calcBandwidth(largestDataInterval) - scale2.calcBandwidth(smallestDataInterval);
|
|
if (spacing > 0 && spacing < 1)
|
|
return false;
|
|
}
|
|
if (BandScale.is(scale2)) {
|
|
const { bandwidth, step } = scale2;
|
|
if (bandwidth > 0 && bandwidth < 1)
|
|
return false;
|
|
const spacing = step - bandwidth;
|
|
if (spacing > 0 && spacing < 1)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
var isDatumNegative = (datum) => {
|
|
return (0, import_ag_charts_core208.isNegative)(datum.yValue ?? 0);
|
|
};
|
|
function collapsedStartingBarPosition(isVertical, axes, mode) {
|
|
const { startingX, startingY } = getStartingValues(isVertical, axes);
|
|
const calculate = (datum, prevDatum) => {
|
|
let x = isVertical ? datum.x : startingX;
|
|
let y = isVertical ? startingY : datum.y;
|
|
let width = isVertical ? datum.width : 0;
|
|
let height = isVertical ? 0 : datum.height;
|
|
const { opacity = 1 } = datum;
|
|
if (prevDatum && (Number.isNaN(x) || Number.isNaN(y))) {
|
|
({ x, y } = prevDatum);
|
|
width = isVertical ? prevDatum.width : 0;
|
|
height = isVertical ? 0 : prevDatum.height;
|
|
if (isVertical && !isDatumNegative(prevDatum)) {
|
|
y += prevDatum.height;
|
|
} else if (!isVertical && isDatumNegative(prevDatum)) {
|
|
x += prevDatum.width;
|
|
}
|
|
}
|
|
let clipBBox;
|
|
if (datum.clipBBox == null) {
|
|
clipBBox = void 0;
|
|
} else if (isDatumNegative(datum)) {
|
|
clipBBox = isVertical ? new BBox(x, y - height, width, height) : new BBox(x - width, y, width, height);
|
|
} else {
|
|
clipBBox = new BBox(x, y, width, height);
|
|
}
|
|
return { x, y, width, height, clipBBox, opacity };
|
|
};
|
|
return { isVertical, calculate, mode };
|
|
}
|
|
function midpointStartingBarPosition(isVertical, mode) {
|
|
return {
|
|
isVertical,
|
|
calculate: (datum) => {
|
|
return {
|
|
x: isVertical ? datum.x : datum.x + datum.width / 2,
|
|
y: isVertical ? datum.y + datum.height / 2 : datum.y,
|
|
width: isVertical ? datum.width : 0,
|
|
height: isVertical ? 0 : datum.height,
|
|
clipBBox: datum.clipBBox,
|
|
opacity: datum.opacity ?? 1
|
|
};
|
|
},
|
|
mode
|
|
};
|
|
}
|
|
function prepareBarAnimationFunctions(initPos, unknownStatus) {
|
|
const isRemoved = (datum) => datum == null || Number.isNaN(datum.x) || Number.isNaN(datum.y);
|
|
const fromFn = (rect2, datum, status) => {
|
|
if (status === "updated" && isRemoved(datum)) {
|
|
status = "removed";
|
|
} else if (status === "updated" && isRemoved(rect2.previousDatum)) {
|
|
status = "added";
|
|
}
|
|
let source;
|
|
if (status === "unknown" || status === "added") {
|
|
if (rect2.previousDatum == null && initPos.mode === "fade") {
|
|
source = {
|
|
...resetBarSelectionsFn(rect2, datum),
|
|
opacity: 0
|
|
};
|
|
} else {
|
|
source = initPos.calculate(datum, rect2.previousDatum);
|
|
}
|
|
if (status === "unknown") {
|
|
status = unknownStatus;
|
|
}
|
|
} else {
|
|
source = {
|
|
x: rect2.x,
|
|
y: rect2.y,
|
|
width: rect2.width,
|
|
height: rect2.height,
|
|
clipBBox: rect2.clipBBox,
|
|
opacity: rect2.opacity ?? 1
|
|
};
|
|
}
|
|
const phase = NODE_UPDATE_STATE_TO_PHASE_MAPPING[status];
|
|
return { ...source, phase };
|
|
};
|
|
const toFn = (rect2, datum, status) => {
|
|
if (status === "removed" && rect2.datum == null && initPos.mode === "fade") {
|
|
return { ...resetBarSelectionsFn(rect2, datum), opacity: 0 };
|
|
} else if (status === "removed" || isRemoved(datum)) {
|
|
return initPos.calculate(datum, rect2.previousDatum);
|
|
} else {
|
|
return {
|
|
x: datum.x,
|
|
y: datum.y,
|
|
width: datum.width,
|
|
height: datum.height,
|
|
clipBBox: datum.clipBBox,
|
|
opacity: datum.opacity ?? 1
|
|
};
|
|
}
|
|
};
|
|
const applyFn = (rect2, datum, status) => {
|
|
rect2.resetAnimationProperties(datum.x, datum.y, datum.width, datum.height, datum.opacity ?? 1, datum.clipBBox);
|
|
rect2.crisp = status === "end" && (rect2.datum?.crisp ?? false);
|
|
};
|
|
return { toFn, fromFn, applyFn };
|
|
}
|
|
function getStartingValues(isVertical, axes) {
|
|
const axis = axes[isVertical ? import_ag_charts_core208.ChartAxisDirection.Y : import_ag_charts_core208.ChartAxisDirection.X];
|
|
let startingX = Infinity;
|
|
let startingY = 0;
|
|
if (!axis) {
|
|
return { startingX, startingY };
|
|
}
|
|
if (isVertical) {
|
|
startingY = axis.scale.convert(ContinuousScale.is(axis.scale) ? 0 : Math.max(...axis.range));
|
|
} else {
|
|
startingX = axis.scale.convert(ContinuousScale.is(axis.scale) ? 0 : Math.min(...axis.range));
|
|
}
|
|
return { startingX, startingY };
|
|
}
|
|
function resetBarSelectionsFn(rect2, { x, y, width, height, clipBBox, opacity = 1 }) {
|
|
return { x, y, width, height, clipBBox, opacity, crisp: rect2.datum?.crisp ?? false };
|
|
}
|
|
function resetBarSelectionsDirect(selections) {
|
|
for (const selection of selections) {
|
|
const nodes = selection.nodes();
|
|
selection.batchedUpdate(function resetBarNodes() {
|
|
for (const node of nodes) {
|
|
const datum = node.datum;
|
|
if (datum == null)
|
|
continue;
|
|
node.resetAnimationProperties(
|
|
datum.x,
|
|
datum.y,
|
|
datum.width,
|
|
datum.height,
|
|
datum.opacity ?? 1,
|
|
datum.clipBBox
|
|
);
|
|
node.crisp = datum.crisp ?? false;
|
|
}
|
|
selection.cleanup();
|
|
});
|
|
}
|
|
}
|
|
function computeBarFocusBounds(series, datum) {
|
|
if (datum === void 0)
|
|
return void 0;
|
|
const { x, y, width, height } = datum;
|
|
return Transformable.toCanvas(series.contentGroup, new BBox(x, y, width, height));
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/cartesianSeriesUtil.ts
|
|
function upsertNodeDatum(ctx, params, createNode, updateNode) {
|
|
const canReuseNode = ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodes.length;
|
|
let node;
|
|
if (canReuseNode) {
|
|
node = ctx.nodes[ctx.nodeIndex];
|
|
updateNode(ctx, node, params);
|
|
} else {
|
|
node = createNode(ctx, params);
|
|
if (node != null) {
|
|
ctx.nodes.push(node);
|
|
}
|
|
}
|
|
ctx.nodeIndex++;
|
|
return node;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/areaUtil.ts
|
|
var import_ag_charts_core209 = require("ag-charts-core");
|
|
function plotAreaPathFill({ path }, { spans, phantomSpans }) {
|
|
let phantomSpanIndex = 0;
|
|
let sp = { x: Number.NaN, y: Number.NaN };
|
|
let pp = { x: Number.NaN, y: Number.NaN };
|
|
for (let i = 0; i < spans.length; i += 1) {
|
|
const { span } = spans[i];
|
|
const { span: phantomSpan } = phantomSpans[i];
|
|
const { 0: sp0, 1: sp1 } = (0, import_ag_charts_core209.spanRange)(span);
|
|
const { 0: pp0, 1: pp1 } = (0, import_ag_charts_core209.spanRange)(phantomSpan);
|
|
if (pointsEq(sp, sp0) && pointsEq(pp, pp0)) {
|
|
plotSpan(path, span, import_ag_charts_core209.SpanJoin.Skip, false);
|
|
} else {
|
|
for (let j = i - 1; j >= phantomSpanIndex; j -= 1) {
|
|
plotSpan(path, phantomSpans[j].span, import_ag_charts_core209.SpanJoin.LineTo, true);
|
|
}
|
|
path.closePath();
|
|
plotSpan(path, span, import_ag_charts_core209.SpanJoin.MoveTo, false);
|
|
phantomSpanIndex = i;
|
|
}
|
|
sp = sp1;
|
|
pp = pp1;
|
|
}
|
|
for (let j = spans.length - 1; j >= phantomSpanIndex; j -= 1) {
|
|
plotSpan(path, phantomSpans[j].span, import_ag_charts_core209.SpanJoin.LineTo, true);
|
|
}
|
|
path.closePath();
|
|
}
|
|
function plotInterpolatedAreaSeriesFillSpans(ratio10, { path }, spans, fillPhantomSpans) {
|
|
for (let i = 0; i < spans.length; i += 1) {
|
|
const span = spans[i];
|
|
const reversedPhantomSpan = fillPhantomSpans[i];
|
|
plotInterpolatedSpans(path, span.from, span.to, ratio10, import_ag_charts_core209.SpanJoin.MoveTo, false);
|
|
plotInterpolatedSpans(path, reversedPhantomSpan.from, reversedPhantomSpan.to, ratio10, import_ag_charts_core209.SpanJoin.LineTo, true);
|
|
path.closePath();
|
|
}
|
|
}
|
|
function prepareAreaFillAnimationFns(status, spans, fillPhantomSpans, visibleToggleMode) {
|
|
const removePhaseFn = (ratio10, path) => plotInterpolatedAreaSeriesFillSpans(ratio10, path, spans.removed, fillPhantomSpans.removed);
|
|
const updatePhaseFn = (ratio10, path) => plotInterpolatedAreaSeriesFillSpans(ratio10, path, spans.moved, fillPhantomSpans.moved);
|
|
const addPhaseFn = (ratio10, path) => plotInterpolatedAreaSeriesFillSpans(ratio10, path, spans.added, fillPhantomSpans.added);
|
|
const pathProperties = prepareLinePathPropertyAnimation(status, visibleToggleMode);
|
|
return { status, path: { addPhaseFn, updatePhaseFn, removePhaseFn }, pathProperties };
|
|
}
|
|
function prepareAreaPathAnimation(newData, oldData) {
|
|
const isCategoryBased = newData.scales.x?.type === "category";
|
|
const wasCategoryBased = oldData.scales.x?.type === "category";
|
|
if (isCategoryBased !== wasCategoryBased || !(0, import_ag_charts_core209.isScaleValid)(newData.scales.x) || !(0, import_ag_charts_core209.isScaleValid)(oldData.scales.x)) {
|
|
return;
|
|
}
|
|
let status = "updated";
|
|
if (oldData.visible && !newData.visible) {
|
|
status = "removed";
|
|
} else if (!oldData.visible && newData.visible) {
|
|
status = "added";
|
|
}
|
|
const fillSpans = pairUpSpans(
|
|
{ scales: newData.scales, data: newData.fillData.spans },
|
|
{ scales: oldData.scales, data: oldData.fillData.spans },
|
|
0 /* Zero */
|
|
);
|
|
if (fillSpans == null)
|
|
return;
|
|
const fillPhantomSpans = pairUpSpans(
|
|
{ scales: newData.scales, data: newData.fillData.phantomSpans },
|
|
{ scales: oldData.scales, data: oldData.fillData.phantomSpans },
|
|
0 /* Zero */
|
|
);
|
|
if (fillPhantomSpans == null)
|
|
return;
|
|
const strokeSpans = pairUpSpans(
|
|
{
|
|
scales: newData.scales,
|
|
data: newData.strokeData.spans,
|
|
zeroData: newData.fillData.phantomSpans
|
|
},
|
|
{
|
|
scales: oldData.scales,
|
|
data: oldData.strokeData.spans,
|
|
zeroData: oldData.fillData.phantomSpans
|
|
},
|
|
0 /* Zero */
|
|
);
|
|
if (strokeSpans == null)
|
|
return;
|
|
const fadeMode = "none";
|
|
const fill = prepareAreaFillAnimationFns(status, fillSpans, fillPhantomSpans, fadeMode);
|
|
const stroke = prepareLinePathStrokeAnimationFns(status, strokeSpans, fadeMode);
|
|
return { status, fill, stroke };
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/diffUtil.ts
|
|
var import_ag_charts_core210 = require("ag-charts-core");
|
|
function calculateDataDiff(seriesId, datumSelection, getDatumId, contextNodeData, previousContextNodeData, processedData, processedDataUpdated) {
|
|
let dataDiff = processedData?.reduced?.diff?.[seriesId];
|
|
if (dataDiff?.changed) {
|
|
return dataDiff;
|
|
}
|
|
if (!processedDataUpdated) {
|
|
return {
|
|
changed: false,
|
|
added: /* @__PURE__ */ new Set(),
|
|
updated: /* @__PURE__ */ new Set(),
|
|
removed: /* @__PURE__ */ new Set(),
|
|
moved: /* @__PURE__ */ new Set()
|
|
};
|
|
}
|
|
const scalingChanged = hasScalingChanged(contextNodeData, previousContextNodeData);
|
|
if (dataDiff == null && processedData?.reduced?.diff != null) {
|
|
dataDiff = {
|
|
changed: true,
|
|
added: /* @__PURE__ */ new Set(),
|
|
updated: /* @__PURE__ */ new Set(),
|
|
removed: /* @__PURE__ */ new Set(),
|
|
moved: /* @__PURE__ */ new Set()
|
|
};
|
|
if (scalingChanged) {
|
|
dataDiff.updated = new Set(Array.from(datumSelection, ({ datum }) => getDatumId(datum)));
|
|
} else {
|
|
dataDiff.added = new Set(Array.from(datumSelection, ({ datum }) => getDatumId(datum)));
|
|
}
|
|
} else if (scalingChanged) {
|
|
dataDiff = {
|
|
changed: true,
|
|
added: /* @__PURE__ */ new Set(),
|
|
updated: new Set(Array.from(datumSelection, ({ datum }) => getDatumId(datum))),
|
|
removed: /* @__PURE__ */ new Set(),
|
|
moved: /* @__PURE__ */ new Set()
|
|
};
|
|
}
|
|
return dataDiff;
|
|
}
|
|
function isGroupScaleContext(ctx) {
|
|
return typeof ctx === "object" && ctx !== null && "groupScale" in ctx;
|
|
}
|
|
function hasScalingChanged(contextNodeData, previousContextNodeData) {
|
|
if (!previousContextNodeData)
|
|
return false;
|
|
const scales = contextNodeData.scales;
|
|
const prevScales = previousContextNodeData.scales;
|
|
if (!(0, import_ag_charts_core210.areScalingEqual)(scales.x, prevScales.x))
|
|
return true;
|
|
if (!(0, import_ag_charts_core210.areScalingEqual)(scales.y, prevScales.y))
|
|
return true;
|
|
if (!isGroupScaleContext(contextNodeData) || !isGroupScaleContext(previousContextNodeData))
|
|
return false;
|
|
const groupScale = contextNodeData.groupScale;
|
|
const prevGroupScale = previousContextNodeData.groupScale;
|
|
return !(0, import_ag_charts_core210.areScalingEqual)(groupScale, prevGroupScale);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/markerUtil.ts
|
|
var import_ag_charts_core211 = require("ag-charts-core");
|
|
function markerFadeInAnimation({ id }, animationManager, status, options, ...markerSelections) {
|
|
const params = {
|
|
...options,
|
|
phase: options?.phase ?? (status ? NODE_UPDATE_STATE_TO_PHASE_MAPPING[status] : "trailing")
|
|
};
|
|
staticFromToMotion(id, "markers", animationManager, markerSelections, { opacity: 0 }, { opacity: 1 }, params);
|
|
for (const s of markerSelections) {
|
|
s.cleanup();
|
|
}
|
|
}
|
|
function markerScaleInAnimation({ id }, animationManager, ...markerSelections) {
|
|
staticFromToMotion(
|
|
id,
|
|
"markers",
|
|
animationManager,
|
|
markerSelections,
|
|
{ scalingX: 0, scalingY: 0 },
|
|
{ scalingX: 1, scalingY: 1 },
|
|
{ phase: "initial" }
|
|
);
|
|
for (const s of markerSelections) {
|
|
s.cleanup();
|
|
}
|
|
}
|
|
function markerSwipeScaleInAnimation({ id, nodeDataDependencies }, animationManager, options, ...markerSelections) {
|
|
const seriesWidth = nodeDataDependencies.seriesRectWidth;
|
|
const fromFn = (_, datum) => {
|
|
const x = datum.midPoint?.x ?? seriesWidth;
|
|
let delay = (0, import_ag_charts_core211.clamp)(0, (0, import_ag_charts_core211.inverseEaseOut)(x / seriesWidth), 1);
|
|
if (Number.isNaN(delay)) {
|
|
delay = 0;
|
|
}
|
|
return {
|
|
scalingX: 0,
|
|
scalingY: 0,
|
|
delay: options?.delay ?? delay,
|
|
duration: options?.duration ?? QUICK_TRANSITION,
|
|
phase: options?.phase ?? "initial",
|
|
start: options?.start,
|
|
finish: options?.finish
|
|
};
|
|
};
|
|
const toFn = () => {
|
|
return { scalingX: 1, scalingY: 1 };
|
|
};
|
|
fromToMotion(id, "markers", animationManager, markerSelections, { fromFn, toFn });
|
|
}
|
|
function resetMarkerFn(_node) {
|
|
return { opacity: 1, scalingX: 1, scalingY: 1 };
|
|
}
|
|
function resetMarkerSelectionsDirect(selections) {
|
|
for (const selection of selections) {
|
|
const nodes = selection.nodes();
|
|
selection.batchedUpdate(function resetMarkerNodes() {
|
|
for (const node of nodes) {
|
|
const datum = node.datum;
|
|
if (datum?.point == null)
|
|
continue;
|
|
const { x, y } = datum.point;
|
|
if (!Number.isFinite(x) || !Number.isFinite(y))
|
|
continue;
|
|
node.resetAnimationProperties(x, y, node.size, 1, 1, 1);
|
|
}
|
|
selection.cleanup();
|
|
});
|
|
}
|
|
}
|
|
function resetMarkerPositionFn(_node, datum) {
|
|
return {
|
|
x: datum.point?.x ?? Number.NaN,
|
|
y: datum.point?.y ?? Number.NaN,
|
|
scalingCenterX: datum.point?.x ?? Number.NaN,
|
|
scalingCenterY: datum.point?.y ?? Number.NaN
|
|
};
|
|
}
|
|
function computeMarkerFocusBounds(series, { datumIndex }) {
|
|
const nodeData = series.getNodeData();
|
|
if (nodeData === void 0)
|
|
return void 0;
|
|
const datum = nodeData[datumIndex];
|
|
const { point } = datum ?? {};
|
|
if (datum == null || point == null)
|
|
return void 0;
|
|
const style = series.getFormattedMarkerStyle(datum);
|
|
const anchor = Marker.anchor(style.shape);
|
|
const size = point.focusSize ?? style.size;
|
|
const paddedSize = 4 + size;
|
|
const paddedRadius = paddedSize / 2;
|
|
const anchorX = (anchor.x - 0.5) * size;
|
|
const anchorY = (anchor.y - 0.5) * size;
|
|
const x = datum.point.x - paddedRadius - anchorX;
|
|
const y = datum.point.y - paddedRadius - anchorY;
|
|
return Transformable.toCanvas(series.contentGroup, new BBox(x, y, paddedSize, paddedSize));
|
|
}
|
|
function markerEnabled(dataCount, scale2, marker, markerStyle = marker) {
|
|
const enabled = markerStyle.enabled ?? marker.enabled;
|
|
if (!enabled)
|
|
return false;
|
|
const minSpacing = 1;
|
|
const step = scale2.step ?? (0, import_ag_charts_core211.findRangeExtent)(scale2.range) / Math.max(1, dataCount);
|
|
return step > minSpacing;
|
|
}
|
|
function getMarkerStyles(series, line, marker, inheritedStyle) {
|
|
inheritedStyle ?? (inheritedStyle = {
|
|
stroke: line.stroke,
|
|
strokeOpacity: line.strokeOpacity,
|
|
strokeWidth: line.strokeWidth
|
|
});
|
|
return highlightStates.reduce(
|
|
(styles, state) => {
|
|
styles[state] = series.getMarkerStyle(
|
|
marker,
|
|
{},
|
|
void 0,
|
|
{ highlightState: state },
|
|
void 0,
|
|
inheritedStyle
|
|
);
|
|
return styles;
|
|
},
|
|
{}
|
|
);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/pathUtil.ts
|
|
function pathSwipeInAnimation({ id, visible, nodeDataDependencies }, animationManager, ...paths) {
|
|
const { seriesRectWidth: width, seriesRectHeight: height } = nodeDataDependencies;
|
|
staticFromToMotion(
|
|
id,
|
|
"path_properties",
|
|
animationManager,
|
|
paths,
|
|
{ clipX: 0 },
|
|
{ clipX: width },
|
|
{
|
|
phase: "initial",
|
|
start: { clip: true, clipY: height, visible },
|
|
finish: { clip: false, visible }
|
|
}
|
|
);
|
|
}
|
|
function pathFadeInAnimation({ id }, subId, animationManager, phase = "add", ...selection) {
|
|
staticFromToMotion(id, subId, animationManager, selection, { opacity: 0 }, { opacity: 1 }, { phase });
|
|
}
|
|
function buildResetPathFn(opts) {
|
|
return (_node) => ({
|
|
visible: opts.getVisible(),
|
|
opacity: opts.getOpacity(),
|
|
clipScalingX: 1,
|
|
clip: false
|
|
});
|
|
}
|
|
function updateClipPath({ nodeDataDependencies }, path) {
|
|
const toFinite = (value) => Number.isFinite(value) ? value : 0;
|
|
path.clipX = toFinite(nodeDataDependencies.seriesRectWidth);
|
|
path.clipY = toFinite(nodeDataDependencies.seriesRectHeight);
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/polarSeries.ts
|
|
var import_ag_charts_core212 = require("ag-charts-core");
|
|
var DEFAULT_POLAR_DIRECTION_KEYS = {
|
|
[import_ag_charts_core212.ChartAxisDirection.Angle]: ["angleKey"],
|
|
[import_ag_charts_core212.ChartAxisDirection.Radius]: ["radiusKey"]
|
|
};
|
|
var DEFAULT_POLAR_DIRECTION_NAMES = {
|
|
[import_ag_charts_core212.ChartAxisDirection.Angle]: ["angleName"],
|
|
[import_ag_charts_core212.ChartAxisDirection.Radius]: ["radiusName"]
|
|
};
|
|
var PolarSeries = class extends DataModelSeries {
|
|
constructor({
|
|
categoryKey,
|
|
pickModes = [1 /* NEAREST_NODE */, 0 /* EXACT_SHAPE_MATCH */],
|
|
canHaveAxes = false,
|
|
animationResetFns,
|
|
...opts
|
|
}) {
|
|
super({
|
|
...opts,
|
|
categoryKey,
|
|
pickModes,
|
|
canHaveAxes
|
|
});
|
|
this.directions = [import_ag_charts_core212.ChartAxisDirection.Angle, import_ag_charts_core212.ChartAxisDirection.Radius];
|
|
this.itemGroup = this.contentGroup.appendChild(new Group({ name: "items" }));
|
|
this.nodeData = [];
|
|
this.itemSelection = Selection.select(
|
|
this.itemGroup,
|
|
() => this.nodeFactory(),
|
|
false
|
|
);
|
|
this.labelSelection = Selection.select(
|
|
this.labelGroup,
|
|
() => this.labelFactory(),
|
|
false
|
|
);
|
|
this.highlightSelection = Selection.select(
|
|
this.highlightNodeGroup,
|
|
() => this.nodeFactory()
|
|
);
|
|
this.highlightLabelSelection = Selection.select(
|
|
this.highlightLabelGroup,
|
|
() => this.labelFactory()
|
|
);
|
|
/**
|
|
* The center of the polar series (for example, the center of a pie).
|
|
* If the polar chart has multiple series, all of them will have their
|
|
* center set to the same value as a result of the polar chart layout.
|
|
* The center coordinates are not supposed to be set by the user.
|
|
*/
|
|
this.centerX = 0;
|
|
this.centerY = 0;
|
|
/**
|
|
* The maximum radius the series can use.
|
|
* This value is set automatically as a result of the polar chart layout
|
|
* and is not supposed to be set by the user.
|
|
*/
|
|
this.radius = 0;
|
|
/**
|
|
* The largest marker size of any series in the same chart. Used to determine the extent of pointer interaction
|
|
* with the series.
|
|
*/
|
|
this.maxChartMarkerSize = 0;
|
|
this.animationResetFns = animationResetFns;
|
|
this.animationState = new import_ag_charts_core212.StateMachine(
|
|
"empty",
|
|
{
|
|
empty: {
|
|
update: {
|
|
target: "ready",
|
|
action: (data) => this.animateEmptyUpdateReady(data)
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
ready: {
|
|
updateData: "waiting",
|
|
clear: "clearing",
|
|
highlight: (data) => this.animateReadyHighlight(data),
|
|
highlightMarkers: (data) => this.animateReadyHighlightMarkers(data),
|
|
resize: (data) => this.animateReadyResize(data),
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
waiting: {
|
|
update: {
|
|
target: "ready",
|
|
action: (data) => this.animateWaitingUpdateReady(data)
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
clearing: {
|
|
update: {
|
|
target: "empty",
|
|
action: (data) => this.animateClearingUpdateEmpty(data)
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
}
|
|
},
|
|
() => this.checkProcessedDataAnimatable()
|
|
);
|
|
this.cleanup.register(
|
|
this.ctx.eventsHub.on("legend:item-click", (event) => this.onLegendItemClick(event)),
|
|
this.ctx.eventsHub.on("legend:item-double-click", (event) => this.onLegendItemDoubleClick(event))
|
|
);
|
|
}
|
|
getItemNodes() {
|
|
return [...this.itemGroup.children()];
|
|
}
|
|
getNodeData() {
|
|
return this.nodeData;
|
|
}
|
|
getKeyAxis(direction) {
|
|
if (direction === import_ag_charts_core212.ChartAxisDirection.Angle)
|
|
return this.properties.angleKeyAxis;
|
|
if (direction === import_ag_charts_core212.ChartAxisDirection.Radius)
|
|
return this.properties.radiusKeyAxis;
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
this.contentGroup.zIndex = [zIndex, import_ag_charts_core212.PolarZIndexMap.FOREGROUND];
|
|
this.highlightGroup.zIndex = [zIndex, import_ag_charts_core212.PolarZIndexMap.HIGHLIGHT];
|
|
this.labelGroup.zIndex = [zIndex, import_ag_charts_core212.PolarZIndexMap.LABEL];
|
|
}
|
|
resetAnimation(phase) {
|
|
if (phase === "initial") {
|
|
this.animationState.transition("reset");
|
|
} else if (phase === "ready") {
|
|
this.animationState.transition("skip");
|
|
}
|
|
}
|
|
labelFactory() {
|
|
const text = new Text();
|
|
text.pointerEvents = 1 /* None */;
|
|
return text;
|
|
}
|
|
getInnerRadius() {
|
|
return 0;
|
|
}
|
|
computeLabelsBBox(_options, _seriesRect) {
|
|
return null;
|
|
}
|
|
getShapeFillBBox() {
|
|
const outerRadius = this.radius;
|
|
return {
|
|
series: new BBox(-outerRadius, -outerRadius, outerRadius * 2, outerRadius * 2),
|
|
axis: new BBox(-outerRadius, -outerRadius, outerRadius * 2, outerRadius * 2)
|
|
};
|
|
}
|
|
resetAllAnimation() {
|
|
const { item, label } = this.animationResetFns ?? {};
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
if (item) {
|
|
resetMotion([this.itemSelection, this.highlightSelection], item);
|
|
}
|
|
if (label) {
|
|
resetMotion([this.labelSelection, this.highlightLabelSelection], label);
|
|
}
|
|
this.itemSelection.cleanup();
|
|
this.labelSelection.cleanup();
|
|
this.highlightSelection.cleanup();
|
|
this.highlightLabelSelection.cleanup();
|
|
}
|
|
animateEmptyUpdateReady(_data) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.resetAllAnimation();
|
|
}
|
|
animateWaitingUpdateReady(_data) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.resetAllAnimation();
|
|
}
|
|
animateReadyHighlight(_data) {
|
|
const { item, label } = this.animationResetFns ?? {};
|
|
if (item) {
|
|
resetMotion([this.highlightSelection], item);
|
|
}
|
|
if (label) {
|
|
resetMotion([this.highlightLabelSelection], label);
|
|
}
|
|
}
|
|
animateReadyHighlightMarkers(_data) {
|
|
}
|
|
animateReadyResize(_data) {
|
|
this.resetAllAnimation();
|
|
}
|
|
animateClearingUpdateEmpty(_data) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.resetAllAnimation();
|
|
}
|
|
computeFocusBounds(opts) {
|
|
const datum = this.getNodeData()?.[opts.datumIndex];
|
|
if (datum !== void 0) {
|
|
return this.itemSelection.select((node) => node instanceof Path && node.datum === datum)[0];
|
|
}
|
|
return void 0;
|
|
}
|
|
getSeriesRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
isSeriesHighlighted(highlightedDatum, legendItemValues) {
|
|
if (!this.properties.highlight.enabled) {
|
|
return false;
|
|
}
|
|
const { series, legendItemName: activeLegendItemName, datumIndex } = highlightedDatum ?? {};
|
|
const legendItemName = typeof datumIndex === "number" ? legendItemValues?.[datumIndex] : void 0;
|
|
return series === this || legendItemName != null && legendItemName === activeLegendItemName;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/hierarchy/hierarchySeries.ts
|
|
var import_ag_charts_core214 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/hierarchy/hierarchySeriesProperties.ts
|
|
var import_ag_charts_core213 = require("ag-charts-core");
|
|
var HierarchyHighlightState = /* @__PURE__ */ ((HierarchyHighlightState2) => {
|
|
HierarchyHighlightState2[HierarchyHighlightState2["None"] = 0] = "None";
|
|
HierarchyHighlightState2[HierarchyHighlightState2["Item"] = 1] = "Item";
|
|
HierarchyHighlightState2[HierarchyHighlightState2["OtherItem"] = 2] = "OtherItem";
|
|
HierarchyHighlightState2[HierarchyHighlightState2["Branch"] = 3] = "Branch";
|
|
HierarchyHighlightState2[HierarchyHighlightState2["OtherBranch"] = 4] = "OtherBranch";
|
|
return HierarchyHighlightState2;
|
|
})(HierarchyHighlightState || {});
|
|
function toHierarchyHighlightString(state) {
|
|
const unreachable = (a) => a;
|
|
switch (state) {
|
|
case 1 /* Item */:
|
|
return "highlighted-item";
|
|
case 2 /* OtherItem */:
|
|
return "unhighlighted-item";
|
|
case 3 /* Branch */:
|
|
return "highlighted-branch";
|
|
case 4 /* OtherBranch */:
|
|
return "unhighlighted-branch";
|
|
case 0 /* None */:
|
|
return "none";
|
|
default:
|
|
return unreachable(state);
|
|
}
|
|
}
|
|
var HierarchySeriesProperties = class extends SeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.childrenKey = "children";
|
|
this.fills = Object.values(DEFAULT_FILLS);
|
|
this.strokes = Object.values(DEFAULT_STROKES);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core213.Property
|
|
], HierarchySeriesProperties.prototype, "childrenKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core213.Property
|
|
], HierarchySeriesProperties.prototype, "sizeKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core213.Property
|
|
], HierarchySeriesProperties.prototype, "colorKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core213.Property
|
|
], HierarchySeriesProperties.prototype, "colorName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core213.Property
|
|
], HierarchySeriesProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core213.Property
|
|
], HierarchySeriesProperties.prototype, "strokes", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core213.Property
|
|
], HierarchySeriesProperties.prototype, "colorRange", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/hierarchy/hierarchySeries.ts
|
|
var _HierarchyNode = class _HierarchyNode {
|
|
constructor(series, itemId, datumIndex, datum, sizeValue, colorValue, sumSize, depth, parent, children, style) {
|
|
this.series = series;
|
|
this.itemId = itemId;
|
|
this.datumIndex = datumIndex;
|
|
this.datum = datum;
|
|
this.sizeValue = sizeValue;
|
|
this.colorValue = colorValue;
|
|
this.sumSize = sumSize;
|
|
this.depth = depth;
|
|
this.parent = parent;
|
|
this.children = children;
|
|
this.style = style;
|
|
this.midPoint = { x: 0, y: 0 };
|
|
}
|
|
get hasChildren() {
|
|
return this.children.length > 0;
|
|
}
|
|
walk(callback4, order = _HierarchyNode.Walk.PreOrder) {
|
|
if (order === _HierarchyNode.Walk.PreOrder) {
|
|
callback4(this);
|
|
}
|
|
for (const child of this.children) {
|
|
child.walk(callback4, order);
|
|
}
|
|
if (order === _HierarchyNode.Walk.PostOrder) {
|
|
callback4(this);
|
|
}
|
|
}
|
|
find(predicate) {
|
|
if (predicate(this)) {
|
|
return this;
|
|
}
|
|
for (const child of this.children) {
|
|
const childResult = child.find(predicate);
|
|
if (childResult != void 0) {
|
|
return childResult;
|
|
}
|
|
}
|
|
return void 0;
|
|
}
|
|
*[Symbol.iterator]() {
|
|
yield this;
|
|
for (const child of this.children) {
|
|
yield* child;
|
|
}
|
|
}
|
|
};
|
|
_HierarchyNode.Walk = {
|
|
PreOrder: 0,
|
|
PostOrder: 1
|
|
};
|
|
var HierarchyNode = _HierarchyNode;
|
|
var HierarchySeries = class extends Series {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
pickModes: [1 /* NEAREST_NODE */, 0 /* EXACT_SHAPE_MATCH */]
|
|
});
|
|
this.colorDomain = [0, 0];
|
|
this.maxDepth = 0;
|
|
this.colorScale = new ColorScale();
|
|
this.animationState = new import_ag_charts_core214.StateMachine(
|
|
"empty",
|
|
{
|
|
empty: {
|
|
update: {
|
|
target: "ready",
|
|
action: (data) => this.animateEmptyUpdateReady(data)
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
ready: {
|
|
updateData: "waiting",
|
|
clear: "clearing",
|
|
highlight: (data) => this.animateReadyHighlight(data),
|
|
resize: (data) => this.animateReadyResize(data),
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
waiting: {
|
|
update: {
|
|
target: "ready",
|
|
action: (data) => this.animateWaitingUpdateReady(data)
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
},
|
|
clearing: {
|
|
update: {
|
|
target: "empty",
|
|
action: (data) => this.animateClearingUpdateEmpty(data)
|
|
},
|
|
reset: "empty",
|
|
skip: "ready"
|
|
}
|
|
},
|
|
() => this.checkProcessedDataAnimatable()
|
|
);
|
|
}
|
|
resetAnimation(phase) {
|
|
if (phase === "initial") {
|
|
this.animationState.transition("reset");
|
|
} else if (phase === "ready") {
|
|
this.animationState.transition("skip");
|
|
}
|
|
}
|
|
processData() {
|
|
const { NodeClass } = this;
|
|
const { childrenKey, sizeKey, colorKey, colorRange } = this.properties;
|
|
let maxDepth = 0;
|
|
let minColor = Infinity;
|
|
let maxColor = -Infinity;
|
|
const createNode = (datum, indexPath, parent) => {
|
|
const depth = parent.depth == null ? 0 : parent.depth + 1;
|
|
const children = childrenKey == null ? void 0 : datum[childrenKey];
|
|
const isLeaf = children == null || children.length === 0;
|
|
let sizeValue = sizeKey == null ? void 0 : datum[sizeKey];
|
|
if (Number.isFinite(sizeValue)) {
|
|
sizeValue = Math.max(sizeValue, 0);
|
|
} else {
|
|
sizeValue = isLeaf ? 1 : 0;
|
|
}
|
|
const sumSize = sizeValue;
|
|
maxDepth = Math.max(maxDepth, depth);
|
|
const colorValue = colorKey == null ? void 0 : datum[colorKey];
|
|
if (typeof colorValue === "number") {
|
|
minColor = Math.min(minColor, colorValue);
|
|
maxColor = Math.max(maxColor, colorValue);
|
|
}
|
|
const style = this.getItemStyle({ datumIndex: indexPath, datum, depth, colorValue }, isLeaf, false);
|
|
return appendChildren(
|
|
new NodeClass(
|
|
this,
|
|
createDatumId(indexPath.join(";")),
|
|
indexPath,
|
|
datum,
|
|
sizeValue,
|
|
colorValue,
|
|
sumSize,
|
|
depth,
|
|
parent,
|
|
[],
|
|
style
|
|
),
|
|
children
|
|
);
|
|
};
|
|
const appendChildren = (node, data) => {
|
|
const { datumIndex } = node;
|
|
if (data) {
|
|
for (const [childIndex, datum] of data.entries()) {
|
|
const child = createNode(datum, datumIndex.concat(childIndex), node);
|
|
node.children.push(child);
|
|
node.sumSize += child.sumSize;
|
|
}
|
|
}
|
|
return node;
|
|
};
|
|
const rootNode = appendChildren(
|
|
new NodeClass(this, "root", [], void 0, 0, void 0, 0, void 0, void 0, [], {}),
|
|
this.data?.data
|
|
);
|
|
const colorDomain = [minColor, maxColor];
|
|
this.colorScale.domain = minColor < maxColor ? [minColor, maxColor] : [0, 1];
|
|
this.colorScale.range = colorRange ?? ["black"];
|
|
this.colorScale.update();
|
|
this.rootNode = rootNode;
|
|
this.maxDepth = maxDepth;
|
|
this.colorDomain = colorDomain;
|
|
}
|
|
update({ seriesRect }) {
|
|
this.updateSelections();
|
|
this.updateNodes();
|
|
const animationData = this.getAnimationData();
|
|
const resize = this.checkResize(seriesRect);
|
|
if (resize) {
|
|
this.animationState.transition("resize", animationData);
|
|
}
|
|
this.animationState.transition("update", animationData);
|
|
}
|
|
resetAllAnimation(_data) {
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
}
|
|
animateEmptyUpdateReady(data) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.resetAllAnimation(data);
|
|
}
|
|
animateWaitingUpdateReady(data) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.resetAllAnimation(data);
|
|
}
|
|
animateReadyHighlight(_data) {
|
|
}
|
|
animateReadyResize(data) {
|
|
this.resetAllAnimation(data);
|
|
}
|
|
animateClearingUpdateEmpty(data) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
this.resetAllAnimation(data);
|
|
}
|
|
getAnimationData() {
|
|
return {};
|
|
}
|
|
isProcessedDataAnimatable() {
|
|
return true;
|
|
}
|
|
checkProcessedDataAnimatable() {
|
|
if (!this.isProcessedDataAnimatable()) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
}
|
|
}
|
|
findNodeDatum(itemId) {
|
|
return this.rootNode?.find((n) => n.itemId === itemId);
|
|
}
|
|
dataCount() {
|
|
return Number.NaN;
|
|
}
|
|
getSeriesDomain() {
|
|
return { domain: [Number.NaN, Number.NaN] };
|
|
}
|
|
getSeriesRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
getLegendData(legendType) {
|
|
const { colorKey, colorRange } = this.properties;
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
return legendType === "gradient" && colorKey != null && colorRange != null ? [
|
|
{
|
|
legendType: "gradient",
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId }),
|
|
seriesId,
|
|
series: this.getFormatterContext("color"),
|
|
colorRange,
|
|
colorDomain: this.colorDomain
|
|
}
|
|
] : [];
|
|
}
|
|
getDatumIdFromData(node) {
|
|
return node.datumIndex.join(":");
|
|
}
|
|
getDatumId(node) {
|
|
return this.getDatumIdFromData(node);
|
|
}
|
|
removeMeIndexPathForIndex(index) {
|
|
return this.datumSelection.at(index + 1)?.datum.datumIndex ?? [];
|
|
}
|
|
removeMeIndexForIndexPath(indexPath) {
|
|
for (const { index, datum } of this.datumSelection) {
|
|
if ((0, import_ag_charts_core214.arraysEqual)(datum.datumIndex, indexPath)) {
|
|
return index - 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
pickFocus(opts) {
|
|
if (!this.rootNode?.children.length)
|
|
return void 0;
|
|
const index = (0, import_ag_charts_core214.clamp)(0, opts.datumIndex - opts.datumIndexDelta, this.datumSelection.length - 1);
|
|
const { datumIndexDelta: childDelta, otherIndexDelta: depthDelta } = opts;
|
|
let path = this.removeMeIndexPathForIndex(index);
|
|
const currentNode = path.reduce((n, childIndex) => n.children[childIndex], this.rootNode);
|
|
if (depthDelta > 0 && currentNode.hasChildren) {
|
|
path = [...path, 0];
|
|
} else if (depthDelta < 0 && path.length > 1) {
|
|
path = path.slice(0, -1);
|
|
} else if (depthDelta === 0 && childDelta !== 0) {
|
|
const maxIndex = currentNode.parent.children.length - 1;
|
|
path = path.slice();
|
|
path[path.length - 1] = (0, import_ag_charts_core214.clamp)(0, path.at(-1) + childDelta, maxIndex);
|
|
}
|
|
const nextNode = path.reduce((n, childIndex) => n.children[childIndex], this.rootNode);
|
|
const bounds = this.computeFocusBounds(this.datumSelection.at(index + 1));
|
|
if (bounds == null)
|
|
return;
|
|
return {
|
|
datum: nextNode,
|
|
datumIndex: this.removeMeIndexForIndexPath(path),
|
|
otherIndex: nextNode.depth,
|
|
bounds,
|
|
clipFocusBox: true
|
|
};
|
|
}
|
|
getDatumAriaText(datum, description) {
|
|
if (!(datum instanceof this.NodeClass)) {
|
|
import_ag_charts_core214.Logger.error(`datum is not HierarchyNode: ${JSON.stringify(datum)}`);
|
|
return;
|
|
}
|
|
return this.ctx.localeManager.t("ariaAnnounceHierarchyDatum", {
|
|
level: (datum.depth ?? -1) + 1,
|
|
count: datum.children.length,
|
|
description
|
|
});
|
|
}
|
|
getCategoryValue(_datumIndex) {
|
|
return;
|
|
}
|
|
datumIndexForCategoryValue(_categoryValue) {
|
|
return;
|
|
}
|
|
getActiveHighlightNode() {
|
|
if (!this.properties.highlight.enabled) {
|
|
return void 0;
|
|
}
|
|
const highlightedNode = this.ctx.highlightManager?.getActiveHighlight();
|
|
if (highlightedNode?.series !== this) {
|
|
return void 0;
|
|
}
|
|
return highlightedNode;
|
|
}
|
|
getHierarchyHighlightState(isHighlight, highlightedNode, nodeDatum) {
|
|
if (isHighlight) {
|
|
return 1 /* Item */;
|
|
}
|
|
if (highlightedNode == null) {
|
|
return 0 /* None */;
|
|
}
|
|
const nodeRoot = nodeDatum.datumIndex?.[0];
|
|
const highlightRoot = highlightedNode.datumIndex?.[0];
|
|
if (nodeRoot == null || highlightRoot == null) {
|
|
return 0 /* None */;
|
|
}
|
|
return nodeRoot === highlightRoot ? 3 /* Branch */ : 4 /* OtherBranch */;
|
|
}
|
|
getHierarchyHighlightStyles(highlightState, highlight5) {
|
|
switch (highlightState) {
|
|
case 1 /* Item */:
|
|
return (0, import_ag_charts_core214.mergeDefaults)(highlight5.highlightedItem, highlight5.highlightedBranch);
|
|
case 3 /* Branch */:
|
|
return (0, import_ag_charts_core214.mergeDefaults)(highlight5.unhighlightedItem, highlight5.highlightedBranch);
|
|
case 4 /* OtherBranch */:
|
|
return highlight5.unhighlightedBranch;
|
|
default:
|
|
return void 0;
|
|
}
|
|
}
|
|
getHighlightStateString(_datum, isHighlight, datumIndex, _legendItemValues) {
|
|
if (!this.properties.highlight.enabled) {
|
|
return toHierarchyHighlightString(0 /* None */);
|
|
}
|
|
if (datumIndex == null) {
|
|
return toHierarchyHighlightString(0 /* None */);
|
|
}
|
|
const nodeDatum = datumIndex.reduce((node, idx) => node?.children[idx], this.rootNode);
|
|
const highlightedNode = this.getActiveHighlightNode();
|
|
if (nodeDatum == null) {
|
|
return toHierarchyHighlightString(0 /* None */);
|
|
}
|
|
const state = this.getHierarchyHighlightState(isHighlight ?? false, highlightedNode, nodeDatum);
|
|
return toHierarchyHighlightString(state);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/topology/mercatorScale.ts
|
|
var radsInDeg = Math.PI / 180;
|
|
var lonX = (lon) => lon * radsInDeg;
|
|
var latY = (lat) => -Math.log(Math.tan(Math.PI * 0.25 + lat * radsInDeg * 0.5));
|
|
var xLon = (x) => x / radsInDeg;
|
|
var yLat = (y) => (Math.atan(Math.exp(-y)) - Math.PI * 0.25) / (radsInDeg * 0.5);
|
|
var MercatorScale = class _MercatorScale extends AbstractScale {
|
|
constructor(domain, range4) {
|
|
super();
|
|
this.domain = domain;
|
|
this.range = range4;
|
|
this.type = "mercator";
|
|
this.defaultTickCount = 0;
|
|
this.bounds = _MercatorScale.bounds(domain);
|
|
}
|
|
static bounds(domain) {
|
|
const [[lon0, lat0], [lon1, lat1]] = domain;
|
|
const x0 = lonX(lon0);
|
|
const y0 = latY(lat0);
|
|
const x1 = lonX(lon1);
|
|
const y1 = latY(lat1);
|
|
return new BBox(Math.min(x0, x1), Math.min(y0, y1), Math.abs(x1 - x0), Math.abs(y1 - y0));
|
|
}
|
|
static fixedScale() {
|
|
return new _MercatorScale(
|
|
[
|
|
[xLon(0), yLat(0)],
|
|
[xLon(1), yLat(1)]
|
|
],
|
|
[
|
|
[0, 0],
|
|
[1, 1]
|
|
]
|
|
);
|
|
}
|
|
toDomain() {
|
|
return;
|
|
}
|
|
normalizeDomains(...domains) {
|
|
let x0 = -Infinity;
|
|
let x1 = Infinity;
|
|
let y0 = -Infinity;
|
|
let y1 = Infinity;
|
|
for (const input of domains) {
|
|
const domain = input.domain;
|
|
for (const [x, y] of domain) {
|
|
x0 = Math.min(x, x0);
|
|
x1 = Math.max(x, x1);
|
|
y0 = Math.min(y, y0);
|
|
y1 = Math.max(y, y1);
|
|
}
|
|
}
|
|
return {
|
|
domain: [
|
|
[x0, y0],
|
|
[x1, y1]
|
|
],
|
|
animatable: true
|
|
};
|
|
}
|
|
convert([lon, lat]) {
|
|
const [[x0, y0], [x1, y1]] = this.range;
|
|
const xScale = (x1 - x0) / this.bounds.width;
|
|
const yScale = (y1 - y0) / this.bounds.height;
|
|
return [(lonX(lon) - this.bounds.x) * xScale + x0, (latY(lat) - this.bounds.y) * yScale + y0];
|
|
}
|
|
invert([x, y]) {
|
|
const [[x0, y0], [x1, y1]] = this.range;
|
|
const xScale = (x1 - x0) / this.bounds.width;
|
|
const yScale = (y1 - y0) / this.bounds.height;
|
|
return [xLon((x - x0) / xScale + this.bounds.x), yLat((y - y0) / yScale + this.bounds.y)];
|
|
}
|
|
getDomainMinMax() {
|
|
return unpackDomainMinMax(this.domain);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/util/deferredExecutor.ts
|
|
var import_ag_charts_core215 = require("ag-charts-core");
|
|
var DeferredExecutor = class {
|
|
constructor(options) {
|
|
this.minimumDelay = options?.minimumDelay ?? 50;
|
|
this.timeout = options?.timeout ?? 100;
|
|
}
|
|
/**
|
|
* Schedule a computation for deferred execution.
|
|
* If something is already pending, it will be cancelled first.
|
|
*/
|
|
schedule(computation, onComplete) {
|
|
this.cancel();
|
|
this.pending = { computation, onComplete };
|
|
if (this.minimumDelay > 0) {
|
|
this.delayTimeoutId = setTimeout(() => {
|
|
this.delayTimeoutId = void 0;
|
|
this.scheduleIdleCallback();
|
|
}, this.minimumDelay);
|
|
} else {
|
|
this.scheduleIdleCallback();
|
|
}
|
|
}
|
|
/**
|
|
* Force immediate execution if pending.
|
|
* @returns The computation result, or undefined if nothing was pending.
|
|
*/
|
|
demand() {
|
|
if (!this.pending) {
|
|
return void 0;
|
|
}
|
|
this.cancelScheduled();
|
|
return this.execute();
|
|
}
|
|
/**
|
|
* Cancel any pending execution without running it.
|
|
*/
|
|
cancel() {
|
|
this.cancelScheduled();
|
|
this.pending = void 0;
|
|
}
|
|
/**
|
|
* Check if there's pending work.
|
|
*/
|
|
isPending() {
|
|
return this.pending != null;
|
|
}
|
|
scheduleIdleCallback() {
|
|
const window = (0, import_ag_charts_core215.getWindow)();
|
|
const remainingTimeout = Math.max(0, this.timeout - this.minimumDelay);
|
|
if (typeof window.requestIdleCallback === "function") {
|
|
this.idleCallbackId = window.requestIdleCallback(this.execute.bind(this), { timeout: remainingTimeout });
|
|
} else {
|
|
this.idleCallbackId = setTimeout(() => this.execute(), remainingTimeout);
|
|
}
|
|
}
|
|
cancelScheduled() {
|
|
if (this.delayTimeoutId != null) {
|
|
clearTimeout(this.delayTimeoutId);
|
|
this.delayTimeoutId = void 0;
|
|
}
|
|
if (this.idleCallbackId == null) {
|
|
return;
|
|
}
|
|
const window = (0, import_ag_charts_core215.getWindow)();
|
|
if (typeof window.cancelIdleCallback === "function") {
|
|
window.cancelIdleCallback(this.idleCallbackId);
|
|
} else {
|
|
clearTimeout(this.idleCallbackId);
|
|
}
|
|
this.idleCallbackId = void 0;
|
|
}
|
|
execute() {
|
|
const pending = this.pending;
|
|
if (!pending) {
|
|
return void 0;
|
|
}
|
|
this.pending = void 0;
|
|
this.delayTimeoutId = void 0;
|
|
this.idleCallbackId = void 0;
|
|
const result = pending.computation();
|
|
pending.onComplete(result);
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/aggregationManager.ts
|
|
var AggregationManager = class {
|
|
constructor() {
|
|
this._dataLength = 0;
|
|
this.executor = new DeferredExecutor();
|
|
}
|
|
get filters() {
|
|
return this._filters;
|
|
}
|
|
/**
|
|
* Perform aggregation with deferred computation of coarser levels.
|
|
* Returns immediate filters suitable for current zoom level.
|
|
*
|
|
* @param options.computePartial - Function to compute partial aggregation (receives existing filters for reuse)
|
|
* @param options.computeFull - Function to compute full aggregation (receives existing filters for reuse)
|
|
* @param options.targetRange - Current pixel range for determining which level to compute immediately
|
|
* @returns The computed filters (immediate level for partial, or all levels for full)
|
|
*/
|
|
aggregate(options) {
|
|
this.executor.cancel();
|
|
if (options.targetRange > 1 && options.computePartial) {
|
|
const partialResult = options.computePartial(this._filters);
|
|
if (partialResult) {
|
|
const { immediate, computeRemaining } = partialResult;
|
|
if (computeRemaining) {
|
|
this.executor.schedule(computeRemaining, (remaining) => {
|
|
this.mergeFilters(remaining);
|
|
});
|
|
}
|
|
this._filters = immediate;
|
|
return immediate;
|
|
}
|
|
}
|
|
this._filters = options.computeFull(this._filters);
|
|
return this._filters;
|
|
}
|
|
/**
|
|
* Ensure we have an aggregation level suitable for the given range.
|
|
* Forces deferred computation if needed.
|
|
*/
|
|
ensureLevelForRange(range4) {
|
|
const hasLevel = this._filters?.some((f) => f.maxRange > range4);
|
|
if (!hasLevel && this.executor.isPending()) {
|
|
const remaining = this.executor.demand();
|
|
if (remaining) {
|
|
this.mergeFilters(remaining);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Get the best filter for a given range.
|
|
*/
|
|
getFilterForRange(range4) {
|
|
return this._filters?.find((f) => f.maxRange > range4);
|
|
}
|
|
/**
|
|
* Cancel any pending deferred computation.
|
|
*/
|
|
cancel() {
|
|
this.executor.cancel();
|
|
}
|
|
/**
|
|
* Mark filters as stale or discard them based on data size change.
|
|
* When data size changes significantly (>10x), filters are discarded to prevent
|
|
* incorrect array reuse.
|
|
*/
|
|
markStale(dataLength) {
|
|
const ratio10 = this._dataLength > 0 ? dataLength / this._dataLength : 0;
|
|
if (ratio10 > 10 || ratio10 < 0.1 || this._dataLength === 0) {
|
|
this._filters = void 0;
|
|
this._dataLength = dataLength;
|
|
} else if (this._filters) {
|
|
for (const f of this._filters) {
|
|
f.stale = true;
|
|
}
|
|
} else {
|
|
this._dataLength = dataLength;
|
|
}
|
|
this.executor.cancel();
|
|
}
|
|
mergeFilters(deferredFilters) {
|
|
if (!this._filters || deferredFilters.length === 0)
|
|
return;
|
|
const allFilters = [...this._filters, ...deferredFilters];
|
|
allFilters.sort((a, b) => a.maxRange - b.maxRange);
|
|
this._filters = allFilters;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/axis/polarAxis.ts
|
|
var import_ag_charts_core216 = require("ag-charts-core");
|
|
var PolarAxis = class extends Axis {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.shape = "polygon";
|
|
this.innerRadiusRatio = 0;
|
|
this.defaultTickMinSpacing = 20;
|
|
}
|
|
update() {
|
|
super.update();
|
|
this.tickLineGroup.visible = this.tick.enabled;
|
|
this.tickLabelGroup.visible = this.label.enabled;
|
|
}
|
|
layoutCrossLines() {
|
|
const sideFlag = this.label.getSideFlag();
|
|
const crosslinesVisible = this.hasDefinedDomain() || this.hasVisibleSeries();
|
|
const { rotation, parallelFlipRotation, regularFlipRotation } = this.calculateRotations();
|
|
for (const crossLine of this.crossLines) {
|
|
crossLine.sideFlag = -sideFlag;
|
|
crossLine.direction = rotation === -Math.PI / 2 ? import_ag_charts_core216.ChartAxisDirection.Angle : import_ag_charts_core216.ChartAxisDirection.Radius;
|
|
crossLine.parallelFlipRotation = parallelFlipRotation;
|
|
crossLine.regularFlipRotation = regularFlipRotation;
|
|
crossLine.calculateLayout?.(crosslinesVisible, this.reverse);
|
|
}
|
|
}
|
|
updatePosition() {
|
|
super.updatePosition();
|
|
const translationX = Math.floor(this.translation.x);
|
|
const translationY = Math.floor(this.translation.y);
|
|
this.tickLineGroup.translationX = translationX;
|
|
this.tickLineGroup.translationY = translationY;
|
|
this.tickLabelGroup.translationX = translationX;
|
|
this.tickLabelGroup.translationY = translationY;
|
|
this.crossLineRangeGroup.translationX = translationX;
|
|
this.crossLineRangeGroup.translationY = translationY;
|
|
this.crossLineLineGroup.translationX = translationX;
|
|
this.crossLineLineGroup.translationY = translationY;
|
|
this.crossLineLabelGroup.translationX = translationX;
|
|
this.crossLineLabelGroup.translationY = translationY;
|
|
this.tickLabelGroupSelection.each(resetAxisLabelSelectionFn());
|
|
}
|
|
computeLabelsBBox(_options, _seriesRect) {
|
|
return null;
|
|
}
|
|
computeRange() {
|
|
}
|
|
getAxisLinePoints() {
|
|
return void 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core216.Property
|
|
], PolarAxis.prototype, "shape", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core216.Property
|
|
], PolarAxis.prototype, "innerRadiusRatio", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/axis/discreteTimeAxis.ts
|
|
var DiscreteTimeAxis = class extends CategoryAxis {
|
|
calculateGridLine({ index: tickIndex, tickId, translation }, index, p1, p2, ticks) {
|
|
const { gridLine, horizontal, interval, range: range4 } = this;
|
|
if (interval.placement !== "between") {
|
|
return super.calculateGridLine({ index: tickIndex, tickId, translation }, index, p1, p2, ticks);
|
|
}
|
|
const prevTick = ticks[index - 1];
|
|
const offset = prevTick ? translation - (translation - prevTick.translation) / 2 : range4[0];
|
|
const [x1, y1, x2, y2] = horizontal ? [offset, Math.max(p1, p2), offset, Math.min(p1, p2)] : [Math.min(p1, p2), offset, Math.max(p1, p2), offset];
|
|
const { style } = gridLine;
|
|
const { stroke, strokeWidth = 0, lineDash } = style[tickIndex % style.length] ?? {};
|
|
return { tickId, offset, x1, y1, x2, y2, stroke, strokeWidth, lineDash };
|
|
}
|
|
calculateGridFills(ticks, p1, p2) {
|
|
if (this.interval.placement !== "between") {
|
|
return super.calculateGridFills(ticks, p1, p2);
|
|
}
|
|
return ticks.map((tick, index) => this.calculateGridFill(tick, index, tick.index, p1, p2, ticks));
|
|
}
|
|
calculateGridFill({ tickId, translation }, index, gridFillIndex, p1, p2, ticks) {
|
|
const { gridLine, horizontal, interval, range: range4 } = this;
|
|
if (interval.placement !== "between") {
|
|
return super.calculateGridFill({ tickId, translation }, index, gridFillIndex, p1, p2, ticks);
|
|
}
|
|
const prevTick = ticks[index - 1];
|
|
const nextTick = ticks[index + 1];
|
|
const startOffset = prevTick ? translation - (translation - prevTick.translation) / 2 : range4[0];
|
|
const endOffset = nextTick ? translation + (nextTick.translation - translation) / 2 : range4[1];
|
|
const [x1, y1, x2, y2] = horizontal ? [startOffset, Math.max(p1, p2), endOffset, Math.min(p1, p2)] : [Math.min(p1, p2), startOffset, Math.max(p1, p2), endOffset];
|
|
const { fill, fillOpacity } = gridLine.style[gridFillIndex % gridLine.style.length] ?? {};
|
|
return { tickId, x1, y1, x2, y2, fill, fillOpacity };
|
|
}
|
|
calculateTickLine({ isPrimary, tickId, translation }, index, direction, ticks, scrollbarThickness = 0) {
|
|
const { horizontal, interval, primaryTick, range: range4, tick } = this;
|
|
if (interval.placement !== "between") {
|
|
return super.calculateTickLine(
|
|
{ isPrimary, tickId, translation },
|
|
index,
|
|
direction,
|
|
ticks,
|
|
scrollbarThickness
|
|
);
|
|
}
|
|
const datumTick = isPrimary && primaryTick?.enabled ? primaryTick : tick;
|
|
const h = -direction * this.getTickSize(datumTick);
|
|
const prevTick = ticks[index - 1];
|
|
const offset = prevTick ? translation - (translation - prevTick.translation) / 2 : range4[0];
|
|
const tickOffset = -direction * (scrollbarThickness + this.getTickSpacing(datumTick));
|
|
const [x1, y1, x2, y2] = horizontal ? [offset, tickOffset, offset, tickOffset + h] : [tickOffset, offset, tickOffset + h, offset];
|
|
const { stroke, width: strokeWidth } = datumTick;
|
|
const lineDash = void 0;
|
|
return { tickId, offset, x1, y1, x2, y2, stroke, strokeWidth, lineDash };
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/crossline/crossLineLabelPosition.ts
|
|
var horizontalCrosslineTranslationDirections = {
|
|
top: { xTranslationDirection: 0, yTranslationDirection: -1 },
|
|
bottom: { xTranslationDirection: 0, yTranslationDirection: 1 },
|
|
left: { xTranslationDirection: -1, yTranslationDirection: 0 },
|
|
right: { xTranslationDirection: 1, yTranslationDirection: 0 },
|
|
"top-left": { xTranslationDirection: 1, yTranslationDirection: -1 },
|
|
"top-right": { xTranslationDirection: -1, yTranslationDirection: -1 },
|
|
"bottom-left": { xTranslationDirection: 1, yTranslationDirection: 1 },
|
|
"bottom-right": { xTranslationDirection: -1, yTranslationDirection: 1 },
|
|
inside: { xTranslationDirection: 0, yTranslationDirection: 0 },
|
|
"inside-left": { xTranslationDirection: 1, yTranslationDirection: 0 },
|
|
"inside-right": { xTranslationDirection: -1, yTranslationDirection: 0 },
|
|
"inside-top": { xTranslationDirection: 0, yTranslationDirection: 1 },
|
|
"inside-bottom": { xTranslationDirection: 0, yTranslationDirection: -1 },
|
|
"inside-top-left": { xTranslationDirection: 1, yTranslationDirection: 1 },
|
|
"inside-bottom-left": { xTranslationDirection: 1, yTranslationDirection: -1 },
|
|
"inside-top-right": { xTranslationDirection: -1, yTranslationDirection: 1 },
|
|
"inside-bottom-right": { xTranslationDirection: -1, yTranslationDirection: -1 }
|
|
};
|
|
var verticalCrossLineTranslationDirections = {
|
|
top: { xTranslationDirection: 1, yTranslationDirection: 0 },
|
|
bottom: { xTranslationDirection: -1, yTranslationDirection: 0 },
|
|
left: { xTranslationDirection: 0, yTranslationDirection: -1 },
|
|
right: { xTranslationDirection: 0, yTranslationDirection: 1 },
|
|
"top-left": { xTranslationDirection: -1, yTranslationDirection: -1 },
|
|
"top-right": { xTranslationDirection: -1, yTranslationDirection: 1 },
|
|
"bottom-left": { xTranslationDirection: 1, yTranslationDirection: -1 },
|
|
"bottom-right": { xTranslationDirection: 1, yTranslationDirection: 1 },
|
|
inside: { xTranslationDirection: 0, yTranslationDirection: 0 },
|
|
"inside-left": { xTranslationDirection: 0, yTranslationDirection: 1 },
|
|
"inside-right": { xTranslationDirection: 0, yTranslationDirection: -1 },
|
|
"inside-top": { xTranslationDirection: -1, yTranslationDirection: 0 },
|
|
"inside-bottom": { xTranslationDirection: 1, yTranslationDirection: 0 },
|
|
"inside-top-left": { xTranslationDirection: -1, yTranslationDirection: 1 },
|
|
"inside-bottom-left": { xTranslationDirection: 1, yTranslationDirection: 1 },
|
|
"inside-top-right": { xTranslationDirection: -1, yTranslationDirection: -1 },
|
|
"inside-bottom-right": { xTranslationDirection: 1, yTranslationDirection: -1 }
|
|
};
|
|
function calculateLabelTranslation({
|
|
yDirection,
|
|
padding: padding2 = 0,
|
|
position = "top",
|
|
bbox
|
|
}) {
|
|
const crossLineTranslationDirections = yDirection ? horizontalCrosslineTranslationDirections : verticalCrossLineTranslationDirections;
|
|
const { xTranslationDirection, yTranslationDirection } = crossLineTranslationDirections[position];
|
|
const xTranslation = xTranslationDirection * (padding2 + bbox.width / 2);
|
|
const yTranslation = yTranslationDirection * (padding2 + bbox.height / 2);
|
|
return {
|
|
xTranslation,
|
|
yTranslation
|
|
};
|
|
}
|
|
|
|
// packages/ag-charts-community/src/motion/pathMotion.ts
|
|
var import_ag_charts_core217 = require("ag-charts-core");
|
|
function pathMotion(groupId, subId, animationManager, paths, fns) {
|
|
const animate = (phase, path, collapsable, updateFn) => {
|
|
animationManager.animate({
|
|
id: `${groupId}_${subId}_${path.id}_${phase}`,
|
|
groupId,
|
|
from: collapsable ? 1 : 0,
|
|
to: 1,
|
|
ease: import_ag_charts_core217.easeOut,
|
|
collapsable,
|
|
onUpdate(ratio10, preInit) {
|
|
if (preInit && phase !== "removed")
|
|
return;
|
|
path.path.clear(true);
|
|
updateFn(ratio10, path);
|
|
path.checkPathDirty();
|
|
},
|
|
onStop() {
|
|
if (phase !== "added")
|
|
return;
|
|
path.path.clear(true);
|
|
updateFn(1, path);
|
|
path.checkPathDirty();
|
|
},
|
|
phase: NODE_UPDATE_STATE_TO_PHASE_MAPPING[phase]
|
|
});
|
|
};
|
|
const tempPath = new Path();
|
|
const resultsChange = (updateFn) => {
|
|
tempPath.resetPathDirty();
|
|
updateFn(0, tempPath);
|
|
tempPath.resetPathDirty();
|
|
updateFn(1, tempPath);
|
|
tempPath.checkPathDirty();
|
|
return tempPath.isPathDirty();
|
|
};
|
|
const { addPhaseFn, updatePhaseFn, removePhaseFn } = fns;
|
|
for (const path of paths) {
|
|
if (!animationManager.isSkipped()) {
|
|
animate("removed", path, !resultsChange(removePhaseFn), removePhaseFn);
|
|
animate("updated", path, !resultsChange(updatePhaseFn), updatePhaseFn);
|
|
}
|
|
animate("added", path, !resultsChange(addPhaseFn), addPhaseFn);
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/dropShadow.ts
|
|
var import_ag_charts_core218 = require("ag-charts-core");
|
|
var DropShadow = class extends import_ag_charts_core218.ChangeDetectableProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.enabled = true;
|
|
this.color = "rgba(0, 0, 0, 0.5)";
|
|
this.xOffset = 0;
|
|
this.yOffset = 0;
|
|
this.blur = 5;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core218.Property,
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], DropShadow.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core218.Property,
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], DropShadow.prototype, "color", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core218.Property,
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], DropShadow.prototype, "xOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core218.Property,
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], DropShadow.prototype, "yOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core218.Property,
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], DropShadow.prototype, "blur", 2);
|
|
|
|
// packages/ag-charts-community/src/scene/util/sector.ts
|
|
var import_ag_charts_core219 = require("ag-charts-core");
|
|
function sectorBox({ startAngle, endAngle, innerRadius, outerRadius }) {
|
|
let x0 = Infinity;
|
|
let y0 = Infinity;
|
|
let x1 = -Infinity;
|
|
let y1 = -Infinity;
|
|
const addPoint = (x, y) => {
|
|
x0 = Math.min(x, x0);
|
|
y0 = Math.min(y, y0);
|
|
x1 = Math.max(x, x1);
|
|
y1 = Math.max(y, y1);
|
|
};
|
|
addPoint(innerRadius * Math.cos(startAngle), innerRadius * Math.sin(startAngle));
|
|
addPoint(innerRadius * Math.cos(endAngle), innerRadius * Math.sin(endAngle));
|
|
addPoint(outerRadius * Math.cos(startAngle), outerRadius * Math.sin(startAngle));
|
|
addPoint(outerRadius * Math.cos(endAngle), outerRadius * Math.sin(endAngle));
|
|
if ((0, import_ag_charts_core219.isBetweenAngles)(0, startAngle, endAngle)) {
|
|
addPoint(outerRadius, 0);
|
|
}
|
|
if ((0, import_ag_charts_core219.isBetweenAngles)(Math.PI * 0.5, startAngle, endAngle)) {
|
|
addPoint(0, outerRadius);
|
|
}
|
|
if ((0, import_ag_charts_core219.isBetweenAngles)(Math.PI, startAngle, endAngle)) {
|
|
addPoint(-outerRadius, 0);
|
|
}
|
|
if ((0, import_ag_charts_core219.isBetweenAngles)(Math.PI * 1.5, startAngle, endAngle)) {
|
|
addPoint(0, -outerRadius);
|
|
}
|
|
return new BBox(x0, y0, x1 - x0, y1 - y0);
|
|
}
|
|
function isPointInSector(x, y, sector) {
|
|
const radius = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
|
|
const { innerRadius, outerRadius } = sector;
|
|
if (sector.startAngle === sector.endAngle || radius < Math.min(innerRadius, outerRadius) || radius > Math.max(innerRadius, outerRadius)) {
|
|
return false;
|
|
}
|
|
const startAngle = (0, import_ag_charts_core219.normalizeAngle180)(sector.startAngle);
|
|
const endAngle = (0, import_ag_charts_core219.normalizeAngle180)(sector.endAngle);
|
|
const angle = Math.atan2(y, x);
|
|
return startAngle < endAngle ? angle <= endAngle && angle >= startAngle : angle <= endAngle && angle >= -Math.PI || angle >= startAngle && angle <= Math.PI;
|
|
}
|
|
function arcIntersections(cx, cy, r, startAngle, endAngle, counterClockwise, x1, y1, x2, y2) {
|
|
if (Number.isNaN(cx) || Number.isNaN(cy)) {
|
|
return 0;
|
|
}
|
|
if (counterClockwise) {
|
|
[endAngle, startAngle] = [startAngle, endAngle];
|
|
}
|
|
const k = (y2 - y1) / (x2 - x1);
|
|
const y0 = y1 - k * x1;
|
|
const a = Math.pow(k, 2) + 1;
|
|
const b = 2 * (k * (y0 - cy) - cx);
|
|
const c = Math.pow(cx, 2) + Math.pow(y0 - cy, 2) - Math.pow(r, 2);
|
|
const d = Math.pow(b, 2) - 4 * a * c;
|
|
if (d < 0) {
|
|
return 0;
|
|
}
|
|
const i1x = (-b + Math.sqrt(d)) / 2 / a;
|
|
const i2x = (-b - Math.sqrt(d)) / 2 / a;
|
|
let intersections = 0;
|
|
for (const x of [i1x, i2x]) {
|
|
const isXInsideLine = x >= Math.min(x1, x2) && x <= Math.max(x1, x2);
|
|
if (!isXInsideLine) {
|
|
continue;
|
|
}
|
|
const y = k * x + y0;
|
|
const adjacent = x - cx;
|
|
const opposite = y - cy;
|
|
const angle = Math.atan2(opposite, adjacent);
|
|
if ((0, import_ag_charts_core219.isBetweenAngles)(angle, startAngle, endAngle)) {
|
|
intersections++;
|
|
}
|
|
}
|
|
return intersections;
|
|
}
|
|
function lineCollidesSector(line, sector) {
|
|
const { startAngle, endAngle, innerRadius, outerRadius } = sector;
|
|
const outerStart = { x: outerRadius * Math.cos(startAngle), y: outerRadius * Math.sin(startAngle) };
|
|
const outerEnd = { x: outerRadius * Math.cos(endAngle), y: outerRadius * Math.sin(endAngle) };
|
|
const innerStart = innerRadius === 0 ? { x: 0, y: 0 } : { x: innerRadius * Math.cos(startAngle), y: innerRadius * Math.sin(startAngle) };
|
|
const innerEnd = innerRadius === 0 ? { x: 0, y: 0 } : { x: innerRadius * Math.cos(endAngle), y: innerRadius * Math.sin(endAngle) };
|
|
return segmentIntersection(
|
|
line.start.x,
|
|
line.start.y,
|
|
line.end.x,
|
|
line.end.y,
|
|
outerStart.x,
|
|
outerStart.y,
|
|
innerStart.x,
|
|
innerStart.y
|
|
) || segmentIntersection(
|
|
line.start.x,
|
|
line.start.y,
|
|
line.end.x,
|
|
line.end.y,
|
|
outerEnd.x,
|
|
outerEnd.y,
|
|
innerEnd.x,
|
|
innerEnd.y
|
|
) || arcIntersections(
|
|
0,
|
|
0,
|
|
outerRadius,
|
|
startAngle,
|
|
endAngle,
|
|
true,
|
|
line.start.x,
|
|
line.start.y,
|
|
line.end.x,
|
|
line.end.y
|
|
);
|
|
}
|
|
function boxCollidesSector(box, sector) {
|
|
const topLeft = { x: box.x, y: box.y };
|
|
const topRight = { x: box.x + box.width, y: box.y };
|
|
const bottomLeft = { x: box.x, y: box.y + box.height };
|
|
const bottomRight = { x: box.x + box.width, y: box.y + box.height };
|
|
return lineCollidesSector({ start: topLeft, end: topRight }, sector) || lineCollidesSector({ start: bottomLeft, end: bottomRight }, sector);
|
|
}
|
|
function radiiScalingFactor(r, sweep, a, b) {
|
|
if (a === 0 && b === 0)
|
|
return 0;
|
|
const fs1 = Math.asin(Math.abs(1 * a) / (r + 1 * a)) + Math.asin(Math.abs(1 * b) / (r + 1 * b)) - sweep;
|
|
if (fs1 < 0)
|
|
return 1;
|
|
let start = 0;
|
|
let end2 = 1;
|
|
for (let i = 0; i < 8; i += 1) {
|
|
const s = (start + end2) / 2;
|
|
const fs = Math.asin(Math.abs(s * a) / (r + s * a)) + Math.asin(Math.abs(s * b) / (r + s * b)) - sweep;
|
|
if (fs < 0) {
|
|
start = s;
|
|
} else {
|
|
end2 = s;
|
|
}
|
|
}
|
|
return start;
|
|
}
|
|
var delta2 = 1e-6;
|
|
function clockwiseAngle(angle, relativeToStartAngle) {
|
|
if ((0, import_ag_charts_core219.angleBetween)(angle, relativeToStartAngle) < delta2) {
|
|
return relativeToStartAngle;
|
|
} else {
|
|
return (0, import_ag_charts_core219.normalizeAngle360)(angle - relativeToStartAngle) + relativeToStartAngle;
|
|
}
|
|
}
|
|
function clockwiseAngles(startAngle, endAngle, relativeToStartAngle = 0) {
|
|
const fullPie = Math.abs(endAngle - startAngle) >= 2 * Math.PI;
|
|
const sweepAngle = fullPie ? 2 * Math.PI : (0, import_ag_charts_core219.normalizeAngle360)(endAngle - startAngle);
|
|
startAngle = clockwiseAngle(startAngle, relativeToStartAngle);
|
|
endAngle = startAngle + sweepAngle;
|
|
return { startAngle, endAngle };
|
|
}
|
|
function arcRadialLineIntersectionAngle(cx, cy, r, startAngle, endAngle, clipAngle) {
|
|
const sinA = Math.sin(clipAngle);
|
|
const cosA = Math.cos(clipAngle);
|
|
const c = cx ** 2 + cy ** 2 - r ** 2;
|
|
let p0x;
|
|
let p0y;
|
|
let p1x;
|
|
let p1y;
|
|
if (cosA > 0.5) {
|
|
const tanA = sinA / cosA;
|
|
const a = 1 + tanA ** 2;
|
|
const b = -2 * (cx + cy * tanA);
|
|
const d = b ** 2 - 4 * a * c;
|
|
if (d < 0)
|
|
return;
|
|
const x0 = (-b + Math.sqrt(d)) / (2 * a);
|
|
const x1 = (-b - Math.sqrt(d)) / (2 * a);
|
|
p0x = x0;
|
|
p0y = x0 * tanA;
|
|
p1x = x1;
|
|
p1y = x1 * tanA;
|
|
} else {
|
|
const cotA = cosA / sinA;
|
|
const a = 1 + cotA ** 2;
|
|
const b = -2 * (cy + cx * cotA);
|
|
const d = b ** 2 - 4 * a * c;
|
|
if (d < 0)
|
|
return;
|
|
const y0 = (-b + Math.sqrt(d)) / (2 * a);
|
|
const y1 = (-b - Math.sqrt(d)) / (2 * a);
|
|
p0x = y0 * cotA;
|
|
p0y = y0;
|
|
p1x = y1 * cotA;
|
|
p1y = y1;
|
|
}
|
|
const normalisedX = cosA;
|
|
const normalisedY = sinA;
|
|
const p0DotNormalized = p0x * normalisedX + p0y * normalisedY;
|
|
const p1DotNormalized = p1x * normalisedX + p1y * normalisedY;
|
|
const a0 = p0DotNormalized > 0 ? clockwiseAngle(Math.atan2(p0y - cy, p0x - cx), startAngle) : Number.NaN;
|
|
const a1 = p1DotNormalized > 0 ? clockwiseAngle(Math.atan2(p1y - cy, p1x - cx), startAngle) : Number.NaN;
|
|
if (a0 >= startAngle && a0 <= endAngle) {
|
|
return a0;
|
|
} else if (a1 >= startAngle && a1 <= endAngle) {
|
|
return a1;
|
|
}
|
|
}
|
|
function arcCircleIntersectionAngle(cx, cy, r, startAngle, endAngle, circleR) {
|
|
const d = Math.hypot(cx, cy);
|
|
const d1 = (d ** 2 - r ** 2 + circleR ** 2) / (2 * d);
|
|
const d2 = d - d1;
|
|
const theta = Math.atan2(cy, cx);
|
|
const deltaTheta = Math.acos(-d2 / r);
|
|
const a0 = clockwiseAngle(theta + deltaTheta, startAngle);
|
|
const a1 = clockwiseAngle(theta - deltaTheta, startAngle);
|
|
if (a0 >= startAngle && a0 <= endAngle) {
|
|
return a0;
|
|
} else if (a1 >= startAngle && a1 <= endAngle) {
|
|
return a1;
|
|
}
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/shape/svgPath.ts
|
|
var SvgPath = class extends Path {
|
|
constructor(d = "") {
|
|
super();
|
|
this._d = "";
|
|
this.d = d;
|
|
}
|
|
get d() {
|
|
return this._d;
|
|
}
|
|
set d(d) {
|
|
if (d === this._d)
|
|
return;
|
|
this._d = d;
|
|
this.path.clear();
|
|
this.path.appendSvg(d);
|
|
this.checkPathDirty();
|
|
}
|
|
};
|
|
var TranslatableSvgPath = class extends Translatable(SvgPath) {
|
|
isPointInPath(x, y) {
|
|
return super.isPointInPath(x - this.translationX, y - this.translationY);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scale/approximateOrdinalTimeScale.ts
|
|
var import_ag_charts_core220 = require("ag-charts-core");
|
|
var ApproximateOrdinalTimeScale = class _ApproximateOrdinalTimeScale extends OrdinalTimeScale {
|
|
static is(value) {
|
|
return value instanceof _ApproximateOrdinalTimeScale;
|
|
}
|
|
/**
|
|
* Set the source scale that this approximate scale delegates to.
|
|
* All property access (domain, range, etc.) will be delegated to the source.
|
|
*/
|
|
setSourceScale(scale2) {
|
|
this._sourceScale = scale2;
|
|
const delegateProperty = (prop) => {
|
|
Object.defineProperty(this, prop, {
|
|
get: () => scale2[prop],
|
|
set: (value) => {
|
|
scale2[prop] = value;
|
|
},
|
|
configurable: true
|
|
});
|
|
};
|
|
delegateProperty("domain");
|
|
delegateProperty("range");
|
|
delegateProperty("paddingInner");
|
|
delegateProperty("paddingOuter");
|
|
delegateProperty("round");
|
|
const delegateReadOnly = (prop) => {
|
|
Object.defineProperty(this, prop, {
|
|
get: () => scale2[prop],
|
|
configurable: true
|
|
});
|
|
};
|
|
delegateReadOnly("bandwidth");
|
|
delegateReadOnly("step");
|
|
delegateReadOnly("inset");
|
|
delegateReadOnly("rawBandwidth");
|
|
}
|
|
// Delegate bands to source scale (read-only)
|
|
get bands() {
|
|
return this._sourceScale?.bands ?? super.bands;
|
|
}
|
|
// Delegate refresh to ensure source scale is up-to-date
|
|
refresh() {
|
|
this._sourceScale?.["refresh"]?.();
|
|
}
|
|
// Delegate ordinalRange to use source scale's computed values
|
|
ordinalRange(i) {
|
|
if (this._sourceScale) {
|
|
return this._sourceScale.ordinalRange(i);
|
|
}
|
|
return super.ordinalRange(i);
|
|
}
|
|
// Delegate convert to source scale but use our findIndex
|
|
convert(d, options) {
|
|
this.refresh();
|
|
const i = this.findIndex(d, options?.alignment);
|
|
if (i == null || i < 0 || i >= this.bands.length) {
|
|
return Number.NaN;
|
|
}
|
|
return this.ordinalRange(i);
|
|
}
|
|
findIndex(value, alignment = import_ag_charts_core220.ScaleAlignment.Leading) {
|
|
if (value == null) {
|
|
return void 0;
|
|
}
|
|
const { bands, reversed } = this;
|
|
const n = bands.length;
|
|
if (n === 0)
|
|
return void 0;
|
|
if (n === 1)
|
|
return 0;
|
|
const firstBand = bands[0];
|
|
const lastBand = bands[n - 1];
|
|
if (firstBand == null || lastBand == null) {
|
|
return this._sourceScale?.findIndex(value, alignment);
|
|
}
|
|
const target = value.valueOf();
|
|
const first8 = firstBand.valueOf();
|
|
const last = lastBand.valueOf();
|
|
const ratio10 = (target - first8) / (last - first8);
|
|
const rawIndex = reversed ? (1 - ratio10) * (n - 1) : ratio10 * (n - 1);
|
|
if (alignment === import_ag_charts_core220.ScaleAlignment.Leading) {
|
|
return Math.max(0, Math.min(n - 1, Math.floor(rawIndex)));
|
|
} else {
|
|
return Math.max(0, Math.min(n - 1, Math.ceil(rawIndex)));
|
|
}
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/sectorBox.ts
|
|
var SectorBox = class _SectorBox {
|
|
constructor(startAngle, endAngle, innerRadius, outerRadius) {
|
|
this.startAngle = startAngle;
|
|
this.endAngle = endAngle;
|
|
this.innerRadius = innerRadius;
|
|
this.outerRadius = outerRadius;
|
|
}
|
|
clone() {
|
|
const { startAngle, endAngle, innerRadius, outerRadius } = this;
|
|
return new _SectorBox(startAngle, endAngle, innerRadius, outerRadius);
|
|
}
|
|
equals(other) {
|
|
return this.startAngle === other.startAngle && this.endAngle === other.endAngle && this.innerRadius === other.innerRadius && this.outerRadius === other.outerRadius;
|
|
}
|
|
[interpolate](other, d) {
|
|
return new _SectorBox(
|
|
this.startAngle * (1 - d) + other.startAngle * d,
|
|
this.endAngle * (1 - d) + other.endAngle * d,
|
|
this.innerRadius * (1 - d) + other.innerRadius * d,
|
|
this.outerRadius * (1 - d) + other.outerRadius * d
|
|
);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/scene/image.ts
|
|
var Image2 = class extends Node {
|
|
constructor(sourceImage) {
|
|
super();
|
|
this.sourceImage = sourceImage;
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.width = 0;
|
|
this.height = 0;
|
|
this.opacity = 1;
|
|
}
|
|
render(renderCtx) {
|
|
const { ctx } = renderCtx;
|
|
const image = this.sourceImage;
|
|
if (image) {
|
|
ctx.globalAlpha = this.opacity;
|
|
ctx.drawImage(image, 0, 0, image.width, image.height, this.x, this.y, this.width, this.height);
|
|
}
|
|
super.render(renderCtx);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Image2.prototype, "x", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Image2.prototype, "y", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Image2.prototype, "width", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Image2.prototype, "height", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core6.SceneChangeDetection)()
|
|
], Image2.prototype, "opacity", 2);
|
|
|
|
// packages/ag-charts-community/src/scene/shape/arc.ts
|
|
var import_ag_charts_core221 = require("ag-charts-core");
|
|
var Arc = class extends Path {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.centerX = 0;
|
|
this.centerY = 0;
|
|
this.radius = 10;
|
|
this.startAngle = 0;
|
|
this.endAngle = Math.PI * 2;
|
|
this.counterClockwise = false;
|
|
this.type = 0 /* Open */;
|
|
}
|
|
get fullPie() {
|
|
return (0, import_ag_charts_core221.isNumberEqual)((0, import_ag_charts_core221.normalizeAngle360)(this.startAngle), (0, import_ag_charts_core221.normalizeAngle360)(this.endAngle));
|
|
}
|
|
updatePath() {
|
|
const path = this.path;
|
|
path.clear();
|
|
path.arc(this.centerX, this.centerY, this.radius, this.startAngle, this.endAngle, this.counterClockwise);
|
|
if (this.type === 1 /* Chord */) {
|
|
path.closePath();
|
|
} else if (this.type === 2 /* Round */ && !this.fullPie) {
|
|
path.lineTo(this.centerX, this.centerY);
|
|
path.closePath();
|
|
}
|
|
}
|
|
computeBBox() {
|
|
return new BBox(this.centerX - this.radius, this.centerY - this.radius, this.radius * 2, this.radius * 2);
|
|
}
|
|
isPointInPath(x, y) {
|
|
const bbox = this.getBBox();
|
|
return this.type !== 0 /* Open */ && bbox.containsPoint(x, y) && this.path.isPointInPath(x, y);
|
|
}
|
|
};
|
|
Arc.className = "Arc";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core221.SceneChangeDetection)()
|
|
], Arc.prototype, "centerX", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core221.SceneChangeDetection)()
|
|
], Arc.prototype, "centerY", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core221.SceneChangeDetection)()
|
|
], Arc.prototype, "radius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core221.SceneChangeDetection)()
|
|
], Arc.prototype, "startAngle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core221.SceneChangeDetection)()
|
|
], Arc.prototype, "endAngle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core221.SceneChangeDetection)()
|
|
], Arc.prototype, "counterClockwise", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core221.SceneChangeDetection)()
|
|
], Arc.prototype, "type", 2);
|
|
|
|
// packages/ag-charts-community/src/scene/shape/radialColumnShape.ts
|
|
var import_ag_charts_core222 = require("ag-charts-core");
|
|
function rotatePoint2(x, y, rotation) {
|
|
const radius = Math.hypot(x, y);
|
|
const angle = Math.atan2(y, x);
|
|
const rotated = angle + rotation;
|
|
return {
|
|
x: Math.cos(rotated) * radius,
|
|
y: Math.sin(rotated) * radius
|
|
};
|
|
}
|
|
var RadialColumnShape = class extends Path {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.isBeveled = true;
|
|
this.columnWidth = 0;
|
|
this.startAngle = 0;
|
|
this.endAngle = 0;
|
|
this.outerRadius = 0;
|
|
this.innerRadius = 0;
|
|
this.axisInnerRadius = 0;
|
|
this.axisOuterRadius = 0;
|
|
}
|
|
set cornerRadius(_value) {
|
|
}
|
|
computeBBox() {
|
|
const { columnWidth } = this;
|
|
const [innerRadius, outerRadius] = this.normalizeRadii(this.innerRadius, this.outerRadius);
|
|
const rotation = this.getRotation();
|
|
const left = -columnWidth / 2;
|
|
const right = columnWidth / 2;
|
|
const top = -outerRadius;
|
|
const bottom = -innerRadius;
|
|
let x0 = Infinity;
|
|
let y0 = Infinity;
|
|
let x1 = -Infinity;
|
|
let y1 = -Infinity;
|
|
for (let i = 0; i < 4; i += 1) {
|
|
const { x, y } = rotatePoint2(i % 2 === 0 ? left : right, i < 2 ? top : bottom, rotation);
|
|
x0 = Math.min(x, x0);
|
|
y0 = Math.min(y, y0);
|
|
x1 = Math.max(x, x1);
|
|
y1 = Math.max(y, y1);
|
|
}
|
|
return new BBox(x0, y0, x1 - x0, y1 - y0);
|
|
}
|
|
getRotation() {
|
|
const { startAngle, endAngle } = this;
|
|
const midAngle = (0, import_ag_charts_core222.angleBetween)(startAngle, endAngle);
|
|
return (0, import_ag_charts_core222.normalizeAngle360)(startAngle + midAngle / 2 + Math.PI / 2);
|
|
}
|
|
normalizeRadii(innerRadius, outerRadius) {
|
|
if (innerRadius > outerRadius) {
|
|
return [outerRadius, innerRadius];
|
|
}
|
|
return [innerRadius, outerRadius];
|
|
}
|
|
updatePath() {
|
|
const { isBeveled } = this;
|
|
if (isBeveled) {
|
|
this.updateBeveledPath();
|
|
} else {
|
|
this.updateRectangularPath();
|
|
}
|
|
this.checkPathDirty();
|
|
}
|
|
updateRectangularPath() {
|
|
const { columnWidth, path } = this;
|
|
const [innerRadius, outerRadius] = this.normalizeRadii(this.innerRadius, this.outerRadius);
|
|
const left = -columnWidth / 2;
|
|
const right = columnWidth / 2;
|
|
const top = -outerRadius;
|
|
const bottom = -innerRadius;
|
|
const rotation = this.getRotation();
|
|
const points = [
|
|
[left, bottom],
|
|
[left, top],
|
|
[right, top],
|
|
[right, bottom]
|
|
].map(([x, y]) => rotatePoint2(x, y, rotation));
|
|
path.clear(true);
|
|
path.moveTo(points[0].x, points[0].y);
|
|
path.lineTo(points[1].x, points[1].y);
|
|
path.lineTo(points[2].x, points[2].y);
|
|
path.lineTo(points[3].x, points[3].y);
|
|
path.closePath();
|
|
}
|
|
calculateCircleIntersection(x, radiusSquared) {
|
|
const xSquared = x * x;
|
|
if (radiusSquared < xSquared) {
|
|
return null;
|
|
}
|
|
const y = -Math.sqrt(radiusSquared - xSquared);
|
|
const angle = Math.atan2(y, x);
|
|
return { y, angle };
|
|
}
|
|
calculateBothIntersections(left, right, radius) {
|
|
const radiusSquared = radius * radius;
|
|
const leftInt = this.calculateCircleIntersection(left, radiusSquared);
|
|
const rightInt = this.calculateCircleIntersection(right, radiusSquared);
|
|
if (!leftInt || !rightInt) {
|
|
return null;
|
|
}
|
|
return { left: leftInt, right: rightInt };
|
|
}
|
|
calculateAxisOuterIntersections(left, right, axisOuterRadius) {
|
|
const axisOuterRadiusSquared = axisOuterRadius * axisOuterRadius;
|
|
const axisOuterLeft = this.calculateCircleIntersection(left, axisOuterRadiusSquared);
|
|
const axisOuterRight = this.calculateCircleIntersection(right, axisOuterRadiusSquared);
|
|
if (!axisOuterLeft || !axisOuterRight) {
|
|
return null;
|
|
}
|
|
return {
|
|
left: axisOuterLeft,
|
|
right: axisOuterRight,
|
|
radiusSquared: axisOuterRadiusSquared
|
|
};
|
|
}
|
|
moveToRotated(x, y, rotation) {
|
|
const point = rotatePoint2(x, y, rotation);
|
|
this.path.moveTo(point.x, point.y);
|
|
}
|
|
lineToRotated(x, y, rotation) {
|
|
const point = rotatePoint2(x, y, rotation);
|
|
this.path.lineTo(point.x, point.y);
|
|
}
|
|
renderTopWithCornerClipping(axisOuterRadius, axisOuter, geometry) {
|
|
const { path } = this;
|
|
const { right, top, rotation } = geometry;
|
|
const topSquared = top * top;
|
|
const topIntersectionSquared = axisOuter.radiusSquared - topSquared;
|
|
if (topIntersectionSquared <= 0) {
|
|
this.lineToRotated(right, axisOuter.right.y, rotation);
|
|
path.arc(0, 0, axisOuterRadius, rotation + axisOuter.right.angle, rotation + axisOuter.left.angle, true);
|
|
} else {
|
|
const topIntersectionX = Math.sqrt(topIntersectionSquared);
|
|
const topRightAngle = Math.atan2(top, topIntersectionX);
|
|
const topLeftAngle = Math.atan2(top, -topIntersectionX);
|
|
this.lineToRotated(right, axisOuter.right.y, rotation);
|
|
path.arc(0, 0, axisOuterRadius, rotation + axisOuter.right.angle, rotation + topRightAngle, true);
|
|
this.lineToRotated(-topIntersectionX, top, rotation);
|
|
path.arc(0, 0, axisOuterRadius, rotation + topLeftAngle, rotation + axisOuter.left.angle, true);
|
|
}
|
|
}
|
|
updateBeveledPath() {
|
|
const { columnWidth, path, axisInnerRadius, axisOuterRadius } = this;
|
|
const [innerRadius, outerRadius] = this.normalizeRadii(this.innerRadius, this.outerRadius);
|
|
const left = -columnWidth / 2;
|
|
const right = columnWidth / 2;
|
|
const top = -outerRadius;
|
|
const bottom = -innerRadius;
|
|
const rotation = this.getRotation();
|
|
const isTouchingInner = (0, import_ag_charts_core222.isNumberEqual)(innerRadius, axisInnerRadius);
|
|
const isTouchingOuter = (0, import_ag_charts_core222.isNumberEqual)(outerRadius, axisOuterRadius);
|
|
const topCornersBreach = Math.hypot(left, top) > axisOuterRadius || Math.hypot(right, top) > axisOuterRadius;
|
|
if (!isTouchingInner && !isTouchingOuter && !topCornersBreach) {
|
|
this.updateRectangularPath();
|
|
return;
|
|
}
|
|
const inner = isTouchingInner ? this.calculateBothIntersections(left, right, innerRadius) : null;
|
|
const outer = isTouchingOuter ? this.calculateBothIntersections(left, right, outerRadius) : null;
|
|
const axisOuter = topCornersBreach ? this.calculateAxisOuterIntersections(left, right, axisOuterRadius) : null;
|
|
if (isTouchingInner && !inner || isTouchingOuter && !outer || topCornersBreach && !axisOuter) {
|
|
this.updateRectangularPath();
|
|
return;
|
|
}
|
|
path.clear(true);
|
|
const geometry = { left, right, top, bottom, rotation };
|
|
if (inner) {
|
|
this.moveToRotated(left, inner.left.y, rotation);
|
|
} else {
|
|
this.moveToRotated(left, bottom, rotation);
|
|
}
|
|
if (inner) {
|
|
path.arc(0, 0, innerRadius, rotation + inner.left.angle, rotation + inner.right.angle, false);
|
|
} else {
|
|
this.lineToRotated(right, bottom, rotation);
|
|
}
|
|
if (outer) {
|
|
this.lineToRotated(right, outer.right.y, rotation);
|
|
path.arc(0, 0, outerRadius, rotation + outer.right.angle, rotation + outer.left.angle, true);
|
|
} else if (axisOuter) {
|
|
this.renderTopWithCornerClipping(axisOuterRadius, axisOuter, geometry);
|
|
} else {
|
|
this.lineToRotated(right, top, rotation);
|
|
this.lineToRotated(left, top, rotation);
|
|
}
|
|
path.closePath();
|
|
}
|
|
};
|
|
RadialColumnShape.className = "RadialColumnShape";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core222.SceneChangeDetection)()
|
|
], RadialColumnShape.prototype, "isBeveled", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core222.SceneChangeDetection)()
|
|
], RadialColumnShape.prototype, "columnWidth", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core222.SceneChangeDetection)()
|
|
], RadialColumnShape.prototype, "startAngle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core222.SceneChangeDetection)()
|
|
], RadialColumnShape.prototype, "endAngle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core222.SceneChangeDetection)()
|
|
], RadialColumnShape.prototype, "outerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core222.SceneChangeDetection)()
|
|
], RadialColumnShape.prototype, "innerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core222.SceneChangeDetection)()
|
|
], RadialColumnShape.prototype, "axisInnerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core222.SceneChangeDetection)()
|
|
], RadialColumnShape.prototype, "axisOuterRadius", 2);
|
|
function getRadialColumnWidth(startAngle, endAngle, axisOuterRadius, columnWidthRatio, maxColumnWidthRatio) {
|
|
const rotation = (0, import_ag_charts_core222.angleBetween)(startAngle, endAngle);
|
|
const pad = rotation * (1 - columnWidthRatio) / 2;
|
|
startAngle += pad;
|
|
endAngle -= pad;
|
|
if (rotation < 1e-3) {
|
|
return 2 * axisOuterRadius * maxColumnWidthRatio;
|
|
}
|
|
if (rotation >= 2 * Math.PI) {
|
|
const midAngle = startAngle + rotation / 2;
|
|
startAngle = midAngle - Math.PI;
|
|
endAngle = midAngle + Math.PI;
|
|
}
|
|
const startX = axisOuterRadius * Math.cos(startAngle);
|
|
const startY = axisOuterRadius * Math.sin(startAngle);
|
|
const endX = axisOuterRadius * Math.cos(endAngle);
|
|
const endY = axisOuterRadius * Math.sin(endAngle);
|
|
const colWidth = Math.floor(Math.hypot(startX - endX, startY - endY));
|
|
const maxWidth = 2 * axisOuterRadius * maxColumnWidthRatio;
|
|
return Math.max(1, Math.min(maxWidth, colWidth));
|
|
}
|
|
|
|
// packages/ag-charts-community/src/scene/shape/sector.ts
|
|
var import_ag_charts_core223 = require("ag-charts-core");
|
|
var Arc2 = class {
|
|
constructor(cx, cy, r, a0, a1) {
|
|
this.cx = cx;
|
|
this.cy = cy;
|
|
this.r = r;
|
|
this.a0 = a0;
|
|
this.a1 = a1;
|
|
if (this.a0 >= this.a1) {
|
|
this.a0 = Number.NaN;
|
|
this.a1 = Number.NaN;
|
|
}
|
|
}
|
|
isValid() {
|
|
return Number.isFinite(this.a0) && Number.isFinite(this.a1);
|
|
}
|
|
pointAt(a) {
|
|
return {
|
|
x: this.cx + this.r * Math.cos(a),
|
|
y: this.cy + this.r * Math.sin(a)
|
|
};
|
|
}
|
|
clipStart(a) {
|
|
if (a == null || !this.isValid() || a < this.a0)
|
|
return;
|
|
this.a0 = a;
|
|
if (Number.isNaN(a) || this.a0 >= this.a1) {
|
|
this.a0 = Number.NaN;
|
|
this.a1 = Number.NaN;
|
|
}
|
|
}
|
|
clipEnd(a) {
|
|
if (a == null || !this.isValid() || a > this.a1)
|
|
return;
|
|
this.a1 = a;
|
|
if (Number.isNaN(a) || this.a0 >= this.a1) {
|
|
this.a0 = Number.NaN;
|
|
this.a1 = Number.NaN;
|
|
}
|
|
}
|
|
};
|
|
var Sector = class extends Path {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.centerX = 0;
|
|
this.centerY = 0;
|
|
this.innerRadius = 10;
|
|
this.outerRadius = 20;
|
|
this.startAngle = 0;
|
|
this.endAngle = Math.PI * 2;
|
|
this.clipSector = void 0;
|
|
this.concentricEdgeInset = 0;
|
|
this.radialEdgeInset = 0;
|
|
this.startOuterCornerRadius = 0;
|
|
this.endOuterCornerRadius = 0;
|
|
this.startInnerCornerRadius = 0;
|
|
this.endInnerCornerRadius = 0;
|
|
}
|
|
set inset(value) {
|
|
this.concentricEdgeInset = value;
|
|
this.radialEdgeInset = value;
|
|
}
|
|
set cornerRadius(value) {
|
|
this.startOuterCornerRadius = value;
|
|
this.endOuterCornerRadius = value;
|
|
this.startInnerCornerRadius = value;
|
|
this.endInnerCornerRadius = value;
|
|
}
|
|
computeBBox() {
|
|
return sectorBox(this).translate(this.centerX, this.centerY);
|
|
}
|
|
normalizedRadii() {
|
|
const { concentricEdgeInset } = this;
|
|
let { innerRadius, outerRadius } = this;
|
|
innerRadius = innerRadius > 0 ? innerRadius + concentricEdgeInset : 0;
|
|
outerRadius = Math.max(outerRadius - concentricEdgeInset, 0);
|
|
return { innerRadius, outerRadius };
|
|
}
|
|
normalizedClipSector() {
|
|
const { clipSector } = this;
|
|
if (clipSector == null)
|
|
return;
|
|
const { startAngle, endAngle } = clockwiseAngles(this.startAngle, this.endAngle);
|
|
const { innerRadius, outerRadius } = this.normalizedRadii();
|
|
const clipAngles = clockwiseAngles(clipSector.startAngle, clipSector.endAngle, startAngle);
|
|
return new SectorBox(
|
|
Math.max(startAngle, clipAngles.startAngle),
|
|
Math.min(endAngle, clipAngles.endAngle),
|
|
Math.max(innerRadius, clipSector.innerRadius),
|
|
Math.min(outerRadius, clipSector.outerRadius)
|
|
);
|
|
}
|
|
getAngleOffset(radius) {
|
|
return radius > 0 ? this.radialEdgeInset / radius : 0;
|
|
}
|
|
arc(r, angleSweep, a0, a1, outerArc, innerArc, start, inner) {
|
|
if (r <= 0)
|
|
return;
|
|
const { startAngle, endAngle } = clockwiseAngles(this.startAngle, this.endAngle);
|
|
const { innerRadius, outerRadius } = this.normalizedRadii();
|
|
const clipSector = this.normalizedClipSector();
|
|
if (inner && innerRadius <= 0)
|
|
return;
|
|
const angleOffset = inner ? this.getAngleOffset(innerRadius + r) : this.getAngleOffset(outerRadius - r);
|
|
const angle = start ? startAngle + angleOffset + angleSweep : endAngle - angleOffset - angleSweep;
|
|
const radius = inner ? innerRadius + r : outerRadius - r;
|
|
const cx = radius * Math.cos(angle);
|
|
const cy = radius * Math.sin(angle);
|
|
if (clipSector != null) {
|
|
const delta3 = 1e-6;
|
|
if (!start && !(angle >= startAngle - delta3 && angle <= clipSector.endAngle - delta3))
|
|
return;
|
|
if (start && !(angle >= clipSector.startAngle + delta3 && angle <= endAngle - delta3))
|
|
return;
|
|
if (inner && radius < clipSector.innerRadius - delta3)
|
|
return;
|
|
if (!inner && radius > clipSector.outerRadius + delta3)
|
|
return;
|
|
}
|
|
const arc = new Arc2(cx, cy, r, a0, a1);
|
|
if (clipSector != null) {
|
|
if (inner) {
|
|
arc.clipStart(arcRadialLineIntersectionAngle(cx, cy, r, a0, a1, clipSector.endAngle));
|
|
arc.clipEnd(arcRadialLineIntersectionAngle(cx, cy, r, a0, a1, clipSector.startAngle));
|
|
} else {
|
|
arc.clipStart(arcRadialLineIntersectionAngle(cx, cy, r, a0, a1, clipSector.startAngle));
|
|
arc.clipEnd(arcRadialLineIntersectionAngle(cx, cy, r, a0, a1, clipSector.endAngle));
|
|
}
|
|
let circleClipStart;
|
|
let circleClipEnd;
|
|
if (start) {
|
|
circleClipStart = arcCircleIntersectionAngle(cx, cy, r, a0, a1, clipSector.innerRadius);
|
|
circleClipEnd = arcCircleIntersectionAngle(cx, cy, r, a0, a1, clipSector.outerRadius);
|
|
} else {
|
|
circleClipStart = arcCircleIntersectionAngle(cx, cy, r, a0, a1, clipSector.outerRadius);
|
|
circleClipEnd = arcCircleIntersectionAngle(cx, cy, r, a0, a1, clipSector.innerRadius);
|
|
}
|
|
arc.clipStart(circleClipStart);
|
|
arc.clipEnd(circleClipEnd);
|
|
if (circleClipStart != null) {
|
|
const { x: x2, y: y2 } = arc.pointAt(circleClipStart);
|
|
const theta2 = clockwiseAngle(Math.atan2(y2, x2), startAngle);
|
|
if (start) {
|
|
innerArc?.clipStart(theta2);
|
|
} else {
|
|
outerArc.clipEnd(theta2);
|
|
}
|
|
}
|
|
if (circleClipEnd != null) {
|
|
const { x: x2, y: y2 } = arc.pointAt(circleClipEnd);
|
|
const theta2 = clockwiseAngle(Math.atan2(y2, x2), startAngle);
|
|
if (start) {
|
|
outerArc.clipStart(theta2);
|
|
} else {
|
|
innerArc?.clipEnd(theta2);
|
|
}
|
|
}
|
|
}
|
|
if (clipSector != null) {
|
|
const { x: x2, y: y2 } = arc.pointAt((arc.a0 + arc.a1) / 2);
|
|
if (!isPointInSector(x2, y2, clipSector))
|
|
return;
|
|
}
|
|
const { x, y } = arc.pointAt(start === inner ? arc.a0 : arc.a1);
|
|
const theta = clockwiseAngle(Math.atan2(y, x), startAngle);
|
|
const radialArc = inner ? innerArc : outerArc;
|
|
if (start) {
|
|
radialArc?.clipStart(theta);
|
|
} else {
|
|
radialArc?.clipEnd(theta);
|
|
}
|
|
return arc;
|
|
}
|
|
updatePath() {
|
|
const delta3 = 1e-6;
|
|
const { path, centerX, centerY, concentricEdgeInset, radialEdgeInset } = this;
|
|
let { startOuterCornerRadius, endOuterCornerRadius, startInnerCornerRadius, endInnerCornerRadius } = this;
|
|
const { startAngle, endAngle } = clockwiseAngles(this.startAngle, this.endAngle);
|
|
const { innerRadius, outerRadius } = this.normalizedRadii();
|
|
const clipSector = this.normalizedClipSector();
|
|
const sweepAngle = endAngle - startAngle;
|
|
const fullPie = sweepAngle >= 2 * Math.PI - delta3;
|
|
path.clear();
|
|
const innerAngleOffset = this.getAngleOffset(innerRadius);
|
|
const adjustedSweep = sweepAngle - 2 * innerAngleOffset;
|
|
const radialLength = outerRadius - innerRadius;
|
|
const innerCornerDistance = innerRadius > 0 && adjustedSweep > 0 ? 2 * innerRadius * Math.sin(adjustedSweep / 2) : 0;
|
|
const outerCornerDistance = outerRadius > 0 && adjustedSweep > 0 ? 2 * outerRadius * Math.sin(adjustedSweep / 2) : 0;
|
|
startOuterCornerRadius = Math.floor(
|
|
Math.max(0, Math.min(startOuterCornerRadius, outerCornerDistance / 2, radialLength / 2))
|
|
);
|
|
endOuterCornerRadius = Math.floor(
|
|
Math.max(0, Math.min(endOuterCornerRadius, outerCornerDistance / 2, radialLength / 2))
|
|
);
|
|
startInnerCornerRadius = Math.floor(
|
|
Math.max(0, Math.min(startInnerCornerRadius, innerCornerDistance / 2, radialLength / 2))
|
|
);
|
|
endInnerCornerRadius = Math.floor(
|
|
Math.max(0, Math.min(endInnerCornerRadius, innerCornerDistance / 2, radialLength / 2))
|
|
);
|
|
const isInvalid = innerRadius === 0 && outerRadius === 0 || innerRadius > outerRadius || innerCornerDistance < 0 || outerCornerDistance <= 0;
|
|
if (isInvalid) {
|
|
return;
|
|
} else if ((clipSector?.startAngle ?? startAngle) === (clipSector?.endAngle ?? endAngle)) {
|
|
return;
|
|
} else if (fullPie && this.clipSector == null && startOuterCornerRadius === 0 && endOuterCornerRadius === 0 && startInnerCornerRadius === 0 && endInnerCornerRadius === 0) {
|
|
path.moveTo(centerX + outerRadius * Math.cos(startAngle), centerY + outerRadius * Math.sin(startAngle));
|
|
path.arc(centerX, centerY, outerRadius, startAngle, endAngle);
|
|
if (innerRadius > concentricEdgeInset) {
|
|
path.moveTo(centerX + innerRadius * Math.cos(endAngle), centerY + innerRadius * Math.sin(endAngle));
|
|
path.arc(centerX, centerY, innerRadius, endAngle, startAngle, true);
|
|
}
|
|
path.closePath();
|
|
return;
|
|
} else if (this.clipSector == null && Math.abs(innerRadius - outerRadius) < 1e-6) {
|
|
path.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
|
|
path.arc(centerX, centerY, outerRadius, endAngle, startAngle, true);
|
|
path.closePath();
|
|
return;
|
|
}
|
|
const outerAngleOffset = this.getAngleOffset(outerRadius);
|
|
const outerAngleExceeded = sweepAngle < 2 * outerAngleOffset;
|
|
if (outerAngleExceeded)
|
|
return;
|
|
const hasInnerSweep = (clipSector?.innerRadius ?? innerRadius) > concentricEdgeInset;
|
|
const innerAngleExceeded = innerRadius < concentricEdgeInset || sweepAngle < 2 * innerAngleOffset;
|
|
const maxRadialLength = Math.max(
|
|
startOuterCornerRadius,
|
|
startInnerCornerRadius,
|
|
endOuterCornerRadius,
|
|
endInnerCornerRadius
|
|
);
|
|
const initialScalingFactor = maxRadialLength > 0 ? Math.min(radialLength / maxRadialLength, 1) : 1;
|
|
startOuterCornerRadius *= initialScalingFactor;
|
|
endOuterCornerRadius *= initialScalingFactor;
|
|
startInnerCornerRadius *= initialScalingFactor;
|
|
endInnerCornerRadius *= initialScalingFactor;
|
|
const outerScalingFactor = radiiScalingFactor(
|
|
outerRadius,
|
|
sweepAngle - 2 * outerAngleOffset,
|
|
-startOuterCornerRadius,
|
|
-endOuterCornerRadius
|
|
);
|
|
startOuterCornerRadius *= outerScalingFactor;
|
|
endOuterCornerRadius *= outerScalingFactor;
|
|
if (!innerAngleExceeded && hasInnerSweep) {
|
|
const innerScalingFactor = radiiScalingFactor(
|
|
innerRadius,
|
|
sweepAngle - 2 * innerAngleOffset,
|
|
startInnerCornerRadius,
|
|
endInnerCornerRadius
|
|
);
|
|
startInnerCornerRadius *= innerScalingFactor;
|
|
endInnerCornerRadius *= innerScalingFactor;
|
|
} else {
|
|
startInnerCornerRadius = 0;
|
|
endInnerCornerRadius = 0;
|
|
}
|
|
const maxCombinedRadialLength = Math.max(
|
|
startOuterCornerRadius + startInnerCornerRadius,
|
|
endOuterCornerRadius + endInnerCornerRadius
|
|
);
|
|
const edgesScalingFactor = maxCombinedRadialLength > 0 ? Math.min(radialLength / maxCombinedRadialLength, 1) : 1;
|
|
startOuterCornerRadius *= edgesScalingFactor;
|
|
endOuterCornerRadius *= edgesScalingFactor;
|
|
startInnerCornerRadius *= edgesScalingFactor;
|
|
endInnerCornerRadius *= edgesScalingFactor;
|
|
let startOuterCornerRadiusAngleSweep = 0;
|
|
let endOuterCornerRadiusAngleSweep = 0;
|
|
const startOuterCornerRadiusSweep = startOuterCornerRadius / (outerRadius - startOuterCornerRadius);
|
|
const endOuterCornerRadiusSweep = endOuterCornerRadius / (outerRadius - endOuterCornerRadius);
|
|
if (startOuterCornerRadiusSweep >= 0 && startOuterCornerRadiusSweep < 1 - delta3) {
|
|
startOuterCornerRadiusAngleSweep = Math.asin(startOuterCornerRadiusSweep);
|
|
} else {
|
|
startOuterCornerRadiusAngleSweep = sweepAngle / 2;
|
|
const maxStartOuterCornerRadius = outerRadius / (1 / Math.sin(startOuterCornerRadiusAngleSweep) + 1);
|
|
startOuterCornerRadius = Math.min(maxStartOuterCornerRadius, startOuterCornerRadius);
|
|
}
|
|
if (endOuterCornerRadiusSweep >= 0 && endOuterCornerRadiusSweep < 1 - delta3) {
|
|
endOuterCornerRadiusAngleSweep = Math.asin(endOuterCornerRadiusSweep);
|
|
} else {
|
|
endOuterCornerRadiusAngleSweep = sweepAngle / 2;
|
|
const maxEndOuterCornerRadius = outerRadius / (1 / Math.sin(endOuterCornerRadiusAngleSweep) + 1);
|
|
endOuterCornerRadius = Math.min(maxEndOuterCornerRadius, endOuterCornerRadius);
|
|
}
|
|
const startInnerCornerRadiusAngleSweep = Math.asin(
|
|
startInnerCornerRadius / (innerRadius + startInnerCornerRadius)
|
|
);
|
|
const endInnerCornerRadiusAngleSweep = Math.asin(endInnerCornerRadius / (innerRadius + endInnerCornerRadius));
|
|
const outerArcRadius = clipSector?.outerRadius ?? outerRadius;
|
|
const outerArcRadiusOffset = this.getAngleOffset(outerArcRadius);
|
|
const outerArc = new Arc2(
|
|
0,
|
|
0,
|
|
outerArcRadius,
|
|
startAngle + outerArcRadiusOffset,
|
|
endAngle - outerArcRadiusOffset
|
|
);
|
|
const innerArcRadius = clipSector?.innerRadius ?? innerRadius;
|
|
const innerArcRadiusOffset = this.getAngleOffset(innerArcRadius);
|
|
const innerArc = hasInnerSweep ? new Arc2(0, 0, innerArcRadius, startAngle + innerArcRadiusOffset, endAngle - innerArcRadiusOffset) : void 0;
|
|
if (clipSector != null) {
|
|
outerArc.clipStart(clipSector.startAngle);
|
|
outerArc.clipEnd(clipSector.endAngle);
|
|
innerArc?.clipStart(clipSector.startAngle);
|
|
innerArc?.clipEnd(clipSector.endAngle);
|
|
}
|
|
const startOuterArc = this.arc(
|
|
startOuterCornerRadius,
|
|
startOuterCornerRadiusAngleSweep,
|
|
startAngle - Math.PI * 0.5,
|
|
startAngle + startOuterCornerRadiusAngleSweep,
|
|
outerArc,
|
|
innerArc,
|
|
true,
|
|
false
|
|
);
|
|
const endOuterArc = this.arc(
|
|
endOuterCornerRadius,
|
|
endOuterCornerRadiusAngleSweep,
|
|
endAngle - endOuterCornerRadiusAngleSweep,
|
|
endAngle + Math.PI * 0.5,
|
|
outerArc,
|
|
innerArc,
|
|
false,
|
|
false
|
|
);
|
|
const endInnerArc = this.arc(
|
|
endInnerCornerRadius,
|
|
endInnerCornerRadiusAngleSweep,
|
|
endAngle + Math.PI * 0.5,
|
|
endAngle + Math.PI - endInnerCornerRadiusAngleSweep,
|
|
outerArc,
|
|
innerArc,
|
|
false,
|
|
true
|
|
);
|
|
const startInnerArc = this.arc(
|
|
startInnerCornerRadius,
|
|
startInnerCornerRadiusAngleSweep,
|
|
startAngle + Math.PI + startInnerCornerRadiusAngleSweep,
|
|
startAngle + Math.PI * 1.5,
|
|
outerArc,
|
|
innerArc,
|
|
true,
|
|
true
|
|
);
|
|
if (innerAngleExceeded && hasInnerSweep) {
|
|
} else if (innerAngleExceeded) {
|
|
const x = sweepAngle < Math.PI * 0.5 ? radialEdgeInset * (1 + Math.cos(sweepAngle)) / Math.sin(sweepAngle) : Number.NaN;
|
|
let r;
|
|
if (x > 0 && x < outerRadius) {
|
|
r = Math.max(Math.hypot(radialEdgeInset, x), innerRadius);
|
|
} else {
|
|
r = radialEdgeInset;
|
|
}
|
|
r = Math.max(r, innerRadius);
|
|
const midAngle = startAngle + sweepAngle * 0.5;
|
|
path.moveTo(centerX + r * Math.cos(midAngle), centerY + r * Math.sin(midAngle));
|
|
} else if (startInnerArc?.isValid() === true || innerArc?.isValid() === true) {
|
|
} else {
|
|
const midAngle = startAngle + sweepAngle / 2;
|
|
const cx = innerRadius * Math.cos(midAngle);
|
|
const cy = innerRadius * Math.sin(midAngle);
|
|
path.moveTo(centerX + cx, centerY + cy);
|
|
}
|
|
if (startOuterArc?.isValid() === true) {
|
|
const { cx, cy, r, a0, a1 } = startOuterArc;
|
|
path.arc(centerX + cx, centerY + cy, r, a0, a1);
|
|
}
|
|
if (outerArc.isValid()) {
|
|
const { r, a0, a1 } = outerArc;
|
|
path.arc(centerX, centerY, r, a0, a1);
|
|
}
|
|
if (endOuterArc?.isValid() === true) {
|
|
const { cx, cy, r, a0, a1 } = endOuterArc;
|
|
path.arc(centerX + cx, centerY + cy, r, a0, a1);
|
|
}
|
|
if (!innerAngleExceeded) {
|
|
if (endInnerArc?.isValid() === true) {
|
|
const { cx, cy, r, a0, a1 } = endInnerArc;
|
|
path.arc(centerX + cx, centerY + cy, r, a0, a1);
|
|
}
|
|
if (innerArc?.isValid() === true) {
|
|
const { r, a0, a1 } = innerArc;
|
|
path.arc(centerX, centerY, r, a1, a0, true);
|
|
}
|
|
if (startInnerArc?.isValid() === true) {
|
|
const { cx, cy, r, a0, a1 } = startInnerArc;
|
|
path.arc(centerX + cx, centerY + cy, r, a0, a1);
|
|
}
|
|
}
|
|
path.closePath();
|
|
}
|
|
isPointInPath(x, y) {
|
|
const { startAngle, endAngle, innerRadius, outerRadius } = this.clipSector ?? this;
|
|
return isPointInSector(x - this.centerX, y - this.centerY, {
|
|
startAngle,
|
|
endAngle,
|
|
innerRadius: Math.min(innerRadius, outerRadius),
|
|
outerRadius: Math.max(innerRadius, outerRadius)
|
|
});
|
|
}
|
|
};
|
|
Sector.className = "Sector";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "centerX", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "centerY", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "innerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "outerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "startAngle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "endAngle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneObjectChangeDetection)({ equals: (lhs, rhs) => lhs.equals(rhs) })
|
|
], Sector.prototype, "clipSector", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "concentricEdgeInset", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "radialEdgeInset", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "startOuterCornerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "endOuterCornerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "startInnerCornerRadius", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core223.SceneChangeDetection)()
|
|
], Sector.prototype, "endInnerCornerRadius", 2);
|
|
|
|
// packages/ag-charts-community/src/components/menu/menu.ts
|
|
var import_ag_charts_core228 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/widget/menuItemWidget.ts
|
|
var import_ag_charts_core224 = require("ag-charts-core");
|
|
var MenuItemWidget = class extends AbstractButtonWidget {
|
|
constructor() {
|
|
super((0, import_ag_charts_core224.createElement)("div"), "menuitem");
|
|
}
|
|
};
|
|
var MenuItemRadioWidget = class extends AbstractButtonWidget {
|
|
constructor() {
|
|
super((0, import_ag_charts_core224.createElement)("div"), "menuitemradio");
|
|
}
|
|
setChecked(checked) {
|
|
(0, import_ag_charts_core224.setAttribute)(this.elem, "aria-checked", checked);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/widget/menuWidget.ts
|
|
var import_ag_charts_core225 = require("ag-charts-core");
|
|
var closeKeys = ["Escape", "ArrowLeft"];
|
|
var MenuWidget = class _MenuWidget extends RovingTabContainerWidget {
|
|
constructor(orientation = "vertical") {
|
|
super(orientation, "menu");
|
|
this.handleMouseEnter = (ev, current) => {
|
|
if (!current.hasPopup()) {
|
|
this.expandSubMenu(ev, void 0);
|
|
}
|
|
};
|
|
this.handleMouseMove = (_ev, current) => {
|
|
current.focus({ preventScroll: true });
|
|
};
|
|
}
|
|
destructor() {
|
|
this.collapse({ mode: "2" /* DESTROY */ });
|
|
}
|
|
addSeparator() {
|
|
const sep = (0, import_ag_charts_core225.getDocument)().createElement("div");
|
|
(0, import_ag_charts_core225.setAttribute)(sep, "role", "separator");
|
|
this.elem.appendChild(sep);
|
|
return sep;
|
|
}
|
|
onChildAdded(child) {
|
|
super.onChildAdded(child);
|
|
child.addListener("mouseenter", this.handleMouseEnter);
|
|
child.addListener("mousemove", this.handleMouseMove);
|
|
}
|
|
onChildRemoved(child) {
|
|
super.onChildRemoved(child);
|
|
child.removeListener("mouseenter", this.handleMouseEnter);
|
|
child.removeListener("mousemove", this.handleMouseMove);
|
|
}
|
|
addSubMenu() {
|
|
const subMenuButton = new MenuItemWidget();
|
|
const subMenu = new _MenuWidget(this.orientation);
|
|
subMenu.id = (0, import_ag_charts_core225.createElementId)();
|
|
const expand = () => {
|
|
this.collapseExpandedSubMenu(subMenu);
|
|
subMenuButton.expandControlled();
|
|
};
|
|
const arrowRightOpener = (ev) => {
|
|
if ((0, import_ag_charts_core225.hasNoModifiers)(ev.sourceEvent) && ev.sourceEvent.code === "ArrowRight") {
|
|
this.collapseExpandedSubMenu(subMenu);
|
|
subMenuButton.expandControlled();
|
|
}
|
|
};
|
|
subMenuButton.setControlled(subMenu);
|
|
subMenuButton.setAriaHasPopup("menu");
|
|
subMenuButton.addListener("click", expand);
|
|
subMenuButton.addListener("mouseenter", expand);
|
|
subMenuButton.addListener("keydown", arrowRightOpener);
|
|
this.addChild(subMenuButton);
|
|
return { subMenuButton, subMenu };
|
|
}
|
|
expandSubMenu(ev, subMenu) {
|
|
const { expansionScope } = this;
|
|
if (!expansionScope)
|
|
return;
|
|
this.collapseExpandedSubMenu(subMenu);
|
|
subMenu?.expand(ev);
|
|
}
|
|
collapseExpandedSubMenu(newSubMenu) {
|
|
const { expansionScope } = this;
|
|
if (!expansionScope)
|
|
return;
|
|
expansionScope.expandedSubMenu?.collapse({ mode: "4" /* SIDLING_OPENED */ });
|
|
expansionScope.expandedSubMenu = newSubMenu;
|
|
}
|
|
expand(opts) {
|
|
if (this.expansionScope != null)
|
|
return;
|
|
this.expansionScope = {
|
|
lastFocus: (0, import_ag_charts_core225.getLastFocus)(opts.sourceEvent),
|
|
expandedSubMenu: void 0,
|
|
abort: () => this.collapse({ mode: "1" /* ABORT */ }),
|
|
close: () => this.collapse({ mode: "0" /* CLOSE */ }),
|
|
removers: new import_ag_charts_core225.CleanupRegistry()
|
|
};
|
|
const scope = this.expansionScope;
|
|
const buttons = this.children.map((value) => value.getElement());
|
|
(0, import_ag_charts_core225.setAttribute)(scope.lastFocus, "aria-expanded", true);
|
|
scope.removers.register(
|
|
(0, import_ag_charts_core225.addMouseCloseListener)(this.elem, scope.abort),
|
|
(0, import_ag_charts_core225.addTouchCloseListener)(this.elem, scope.abort),
|
|
...this.children.map((child) => (0, import_ag_charts_core225.addEscapeEventListener)(child.getElement(), scope.close, closeKeys)),
|
|
opts?.overrideFocusVisible && (0, import_ag_charts_core225.addOverrideFocusVisibleEventListener)(this.elem, buttons, opts.overrideFocusVisible)
|
|
);
|
|
this.internalListener?.dispatch("expand-widget", this, { type: "expand-widget" });
|
|
this.children[0]?.focus({ preventScroll: true });
|
|
}
|
|
collapse(opts) {
|
|
const { mode = "0" /* CLOSE */ } = opts ?? {};
|
|
if (this.expansionScope === void 0)
|
|
return;
|
|
const { lastFocus, removers, expandedSubMenu } = this.expansionScope;
|
|
this.expansionScope = void 0;
|
|
expandedSubMenu?.collapse({ mode: "3" /* PARENT_CLOSED */ });
|
|
(0, import_ag_charts_core225.setAttribute)(lastFocus, "aria-expanded", false);
|
|
if (mode === "0" /* CLOSE */) {
|
|
lastFocus?.focus({ preventScroll: true });
|
|
}
|
|
removers.flush();
|
|
this.internalListener?.dispatch("collapse-widget", this, { type: "collapse-widget", mode });
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/components/popover/anchoredPopover.ts
|
|
var import_ag_charts_core227 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/components/popover/popover.ts
|
|
var import_ag_charts_core226 = require("ag-charts-core");
|
|
var canvasOverlay = "canvas-overlay";
|
|
var Popover = class extends import_ag_charts_core226.AbstractModuleInstance {
|
|
constructor(ctx, id, options) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.hideFns = [];
|
|
this.setOwnedWidget = /* @__PURE__ */ (() => {
|
|
let ownedWidget;
|
|
return (owns) => {
|
|
ownedWidget?.destroy();
|
|
ownedWidget = owns;
|
|
};
|
|
})();
|
|
this.moduleId = `popover-${id}`;
|
|
if (options?.detached) {
|
|
this.element = (0, import_ag_charts_core226.createElement)("div");
|
|
} else {
|
|
this.element = ctx.domManager.addChild(canvasOverlay, this.moduleId);
|
|
}
|
|
this.element.setAttribute("role", "presentation");
|
|
this.hideFns.push(() => this.setOwnedWidget(void 0));
|
|
this.cleanup.register(() => ctx.domManager.removeChild(canvasOverlay, this.moduleId));
|
|
}
|
|
attachTo(popover) {
|
|
if (this.element.parentElement)
|
|
return;
|
|
popover.element.append(this.element);
|
|
}
|
|
hide(opts) {
|
|
const { lastFocus = this.lastFocus } = opts ?? {};
|
|
if (this.element.children.length === 0)
|
|
return;
|
|
for (const fn of this.hideFns) {
|
|
fn();
|
|
}
|
|
lastFocus?.focus();
|
|
this.lastFocus = void 0;
|
|
}
|
|
removeChildren() {
|
|
this.element.replaceChildren();
|
|
}
|
|
initPopoverElement(popover, options) {
|
|
if (!this.element.parentElement) {
|
|
throw new Error("Can not show popover that has not been attached to a parent.");
|
|
}
|
|
popover ?? (popover = (0, import_ag_charts_core226.createElement)("div", "ag-charts-popover"));
|
|
popover.classList.toggle("ag-charts-popover", true);
|
|
if (options.ariaLabel != null) {
|
|
popover.setAttribute("aria-label", options.ariaLabel);
|
|
}
|
|
if (options.class != null) {
|
|
popover.classList.add(options.class);
|
|
}
|
|
this.element.replaceChildren(popover);
|
|
return popover;
|
|
}
|
|
showWidget(controller, owns, options) {
|
|
this.setOwnedWidget(owns);
|
|
this.initPopoverElement(owns.getElement(), options);
|
|
owns.addListener("collapse-widget", () => {
|
|
controller.setControlled(void 0);
|
|
this.setOwnedWidget(void 0);
|
|
});
|
|
controller.setControlled(owns);
|
|
controller.expandControlled();
|
|
}
|
|
showWithChildren(children, options) {
|
|
const popover = this.initPopoverElement(void 0, options);
|
|
popover.replaceChildren(...children);
|
|
this.hideFns.push(() => this.removeChildren());
|
|
if (options.onHide) {
|
|
this.hideFns.push(options.onHide);
|
|
}
|
|
if (options.initialFocus && options.sourceEvent) {
|
|
const lastFocus = (0, import_ag_charts_core226.getLastFocus)(options.sourceEvent);
|
|
if (lastFocus !== void 0) {
|
|
this.lastFocus = lastFocus;
|
|
this.initialFocus = options.initialFocus;
|
|
}
|
|
}
|
|
return popover;
|
|
}
|
|
getPopoverElement() {
|
|
return this.element.firstElementChild;
|
|
}
|
|
updatePosition(position) {
|
|
const popover = this.getPopoverElement();
|
|
if (!popover)
|
|
return;
|
|
popover.style.setProperty("right", "unset");
|
|
popover.style.setProperty("bottom", "unset");
|
|
if (position.x != null)
|
|
popover.style.setProperty("left", `${Math.floor(position.x)}px`);
|
|
if (position.y != null)
|
|
popover.style.setProperty("top", `${Math.floor(position.y)}px`);
|
|
this.initialFocus?.focus();
|
|
this.initialFocus = void 0;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/components/popover/anchoredPopover.ts
|
|
var AnchoredPopover = class extends Popover {
|
|
setAnchor(anchor, fallbackAnchor) {
|
|
this.anchor = anchor;
|
|
this.fallbackAnchor = fallbackAnchor;
|
|
this.updatePosition(anchor);
|
|
this.repositionWithinBounds();
|
|
}
|
|
updateAnchor(options) {
|
|
const anchor = options.anchor ?? this.anchor;
|
|
const fallbackAnchor = options.fallbackAnchor ?? this.fallbackAnchor;
|
|
if (anchor) {
|
|
this.setAnchor(anchor, fallbackAnchor);
|
|
}
|
|
}
|
|
showWidget(controller, owns, options) {
|
|
super.showWidget(controller, owns, options);
|
|
this.updateAnchor(options);
|
|
}
|
|
showWithChildren(children, options) {
|
|
const popover = super.showWithChildren(children, options);
|
|
this.updateAnchor(options);
|
|
(0, import_ag_charts_core227.getWindow)().requestAnimationFrame(() => {
|
|
this.repositionWithinBounds();
|
|
});
|
|
return popover;
|
|
}
|
|
repositionWithinBounds() {
|
|
const { anchor, ctx, fallbackAnchor } = this;
|
|
const popover = this.getPopoverElement();
|
|
if (!anchor || !popover)
|
|
return;
|
|
const canvasRect = ctx.domManager.getBoundingClientRect();
|
|
const { offsetWidth: width, offsetHeight: height } = popover;
|
|
let x = (0, import_ag_charts_core227.clamp)(0, anchor.x, canvasRect.width - width);
|
|
let y = (0, import_ag_charts_core227.clamp)(0, anchor.y, canvasRect.height - height);
|
|
if (x !== anchor.x && fallbackAnchor?.x != null) {
|
|
x = (0, import_ag_charts_core227.clamp)(0, fallbackAnchor.x - width, canvasRect.width - width);
|
|
}
|
|
if (y !== anchor.y && fallbackAnchor?.y != null) {
|
|
y = (0, import_ag_charts_core227.clamp)(0, fallbackAnchor.y - height, canvasRect.height - height);
|
|
}
|
|
this.updatePosition({ x, y });
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/components/menu/menu.ts
|
|
var Menu = class extends AnchoredPopover {
|
|
show(controller, options) {
|
|
const menu = new MenuWidget("vertical");
|
|
for (const item of options.items) {
|
|
menu.addChild(this.createRow(options, item, menu));
|
|
}
|
|
menu.addClass("ag-charts-menu");
|
|
this.showWidget(controller, menu, options);
|
|
}
|
|
allocRow(options, item) {
|
|
if (options.menuItemRole == null || options.menuItemRole === "menuitem") {
|
|
return new MenuItemWidget();
|
|
} else {
|
|
options.menuItemRole;
|
|
const result = new MenuItemRadioWidget();
|
|
result.setChecked(options.value === item.value);
|
|
return result;
|
|
}
|
|
}
|
|
createRow(options, item, menu) {
|
|
const active = item.value === options.value;
|
|
const row = this.allocRow(options, item);
|
|
row.addClass("ag-charts-menu__row");
|
|
row.toggleClass(`ag-charts-menu__row--active`, active);
|
|
if (typeof item.value === "string") {
|
|
row.getElement().dataset.popoverId = item.value;
|
|
}
|
|
if (item.icon != null) {
|
|
const icon = (0, import_ag_charts_core228.createElement)("span", `ag-charts-menu__icon ${(0, import_ag_charts_core228.getIconClassNames)(item.icon)}`);
|
|
row.getElement().appendChild(icon);
|
|
}
|
|
const strokeWidthVisible = item.strokeWidth != null;
|
|
if (strokeWidthVisible) {
|
|
row.toggleClass(`ag-charts-menu__row--stroke-width-visible`, strokeWidthVisible);
|
|
row.setCSSVariable("--strokeWidth", strokeWidthVisible ? `${item.strokeWidth}px` : null);
|
|
}
|
|
if (item.label != null) {
|
|
const label = (0, import_ag_charts_core228.createElement)("span", "ag-charts-menu__label");
|
|
label.textContent = this.ctx.localeManager.t(item.label);
|
|
row.getElement().appendChild(label);
|
|
}
|
|
if ("altText" in item) {
|
|
row.setAriaLabel(this.ctx.localeManager.t(item.altText));
|
|
}
|
|
row.addListener("click", ({ sourceEvent }) => {
|
|
options.onPress?.(item);
|
|
sourceEvent.preventDefault();
|
|
sourceEvent.stopPropagation();
|
|
menu.collapse();
|
|
});
|
|
return row;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/components/popover/draggablePopover.ts
|
|
var import_ag_charts_core229 = require("ag-charts-core");
|
|
var DraggablePopover = class extends Popover {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.dragged = false;
|
|
}
|
|
setDragHandle(dragHandle) {
|
|
dragHandle.addListener("drag-start", (event) => {
|
|
dragHandle.addClass(this.dragHandleDraggingClass);
|
|
this.onDragStart(event);
|
|
});
|
|
dragHandle.addListener("drag-move", this.onDragMove.bind(this));
|
|
dragHandle.addListener("drag-end", () => {
|
|
dragHandle.removeClass(this.dragHandleDraggingClass);
|
|
this.onDragEnd.bind(this);
|
|
});
|
|
}
|
|
onDragStart(event) {
|
|
const popover = this.getPopoverElement();
|
|
if (!popover)
|
|
return;
|
|
event.sourceEvent.preventDefault();
|
|
this.dragged = true;
|
|
this.dragStartState = {
|
|
client: import_ag_charts_core229.Vec2.from(event.clientX, event.clientY),
|
|
position: import_ag_charts_core229.Vec2.from(
|
|
Number(popover.style.getPropertyValue("left").replace("px", "")),
|
|
Number(popover.style.getPropertyValue("top").replace("px", ""))
|
|
)
|
|
};
|
|
}
|
|
onDragMove(event) {
|
|
const { dragStartState } = this;
|
|
const popover = this.getPopoverElement();
|
|
if (!dragStartState || !popover)
|
|
return;
|
|
const offset = import_ag_charts_core229.Vec2.sub(import_ag_charts_core229.Vec2.from(event.clientX, event.clientY), dragStartState.client);
|
|
const position = import_ag_charts_core229.Vec2.add(dragStartState.position, offset);
|
|
const bounds = this.ctx.domManager.getBoundingClientRect();
|
|
const partialPosition = {};
|
|
if (position.x >= 0 && position.x + popover.offsetWidth <= bounds.width) {
|
|
partialPosition.x = position.x;
|
|
}
|
|
if (position.y >= 0 && position.y + popover.offsetHeight <= bounds.height) {
|
|
partialPosition.y = position.y;
|
|
}
|
|
this.updatePosition(partialPosition);
|
|
}
|
|
onDragEnd() {
|
|
this.dragStartState = void 0;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/components/toolbar/toolbarButtonWidget.ts
|
|
var import_ag_charts_core230 = require("ag-charts-core");
|
|
var ARIA_HASPOPUP = {
|
|
"disjoint-channel": "false",
|
|
"fibonacci-menu": "menu",
|
|
"fibonacci-retracement": "false",
|
|
"fibonacci-retracement-trend-based": "false",
|
|
"fill-color": "dialog",
|
|
"horizontal-line": "false",
|
|
"line-color": "dialog",
|
|
"line-menu": "menu",
|
|
"line-stroke-width": "menu",
|
|
"line-style-type": "menu",
|
|
"measurer-menu": "menu",
|
|
"pan-end": "false",
|
|
"pan-left": "false",
|
|
"pan-right": "false",
|
|
"pan-start": "false",
|
|
"parallel-channel": "false",
|
|
"shape-menu": "menu",
|
|
"text-color": "dialog",
|
|
"text-menu": "menu",
|
|
"text-size": "menu",
|
|
"vertical-line": "false",
|
|
"zoom-in": "false",
|
|
"zoom-out": "false",
|
|
callout: "false",
|
|
clear: "false",
|
|
comment: "false",
|
|
delete: "false",
|
|
line: "false",
|
|
lock: "false",
|
|
menu: "menu",
|
|
note: "false",
|
|
reset: "false",
|
|
settings: "dialog",
|
|
text: "false"
|
|
};
|
|
function getAriaHasPopupOfValue(value) {
|
|
if (typeof value !== "string")
|
|
return "false";
|
|
return ARIA_HASPOPUP[value];
|
|
}
|
|
var ToolbarButtonWidget = class extends ButtonWidget {
|
|
constructor(localeManager) {
|
|
super();
|
|
this.localeManager = localeManager;
|
|
}
|
|
update(options) {
|
|
const { localeManager } = this;
|
|
if (options.tooltip) {
|
|
const tooltip = localeManager.t(options.tooltip);
|
|
if (tooltip !== this.lastTooltip) {
|
|
this.elem.title = tooltip;
|
|
this.lastTooltip = tooltip;
|
|
}
|
|
}
|
|
let innerHTML = "";
|
|
if (options.icon != null) {
|
|
innerHTML = `<span class="${(0, import_ag_charts_core230.getIconClassNames)(options.icon)} ag-charts-toolbar__icon"></span>`;
|
|
}
|
|
if (options.label != null) {
|
|
const label = localeManager.t(options.label);
|
|
innerHTML = `${innerHTML}<span class="ag-charts-toolbar__label">${label}</span>`;
|
|
}
|
|
const haspopup = getAriaHasPopupOfValue(options.value);
|
|
if (haspopup == "false") {
|
|
this.setAriaHasPopup(void 0);
|
|
this.setAriaExpanded(void 0);
|
|
} else {
|
|
this.setAriaHasPopup(haspopup);
|
|
this.setAriaExpanded(false);
|
|
}
|
|
if (innerHTML !== this.lastInnerHTML) {
|
|
this.elem.innerHTML = innerHTML;
|
|
this.lastInnerHTML = innerHTML;
|
|
}
|
|
}
|
|
setChecked(checked) {
|
|
(0, import_ag_charts_core230.setAttribute)(this.elem, "aria-checked", checked);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/components/toolbar/toolbar.ts
|
|
var import_ag_charts_core231 = require("ag-charts-core");
|
|
var BUTTON_ACTIVE_CLASS = "ag-charts-toolbar__button--active";
|
|
var BaseToolbar = class extends ToolbarWidget {
|
|
constructor({ eventsHub, localeManager }, ariaLabelId, orientation) {
|
|
super(orientation);
|
|
this.ariaLabelId = ariaLabelId;
|
|
this.horizontalSpacing = 10;
|
|
this.verticalSpacing = 10;
|
|
this.events = new Listeners();
|
|
this.hasPrefix = false;
|
|
this.buttonWidgets = [];
|
|
this.updateAriaLabel = () => this.setAriaLabel(this.localeManager.t(this.ariaLabelId));
|
|
this.eventsHub = eventsHub;
|
|
this.localeManager = localeManager;
|
|
this.addClass("ag-charts-toolbar");
|
|
this.toggleClass("ag-charts-toolbar--horizontal", orientation === "horizontal");
|
|
this.toggleClass("ag-charts-toolbar--vertical", orientation === "vertical");
|
|
this.eventsHub.on("locale:change", this.updateAriaLabel);
|
|
this.updateAriaLabel();
|
|
}
|
|
setAriaLabelId(ariaLabelId) {
|
|
this.ariaLabelId = ariaLabelId;
|
|
this.updateAriaLabel();
|
|
}
|
|
addToolbarListener(eventType, handler) {
|
|
return this.events.addListener(eventType, handler);
|
|
}
|
|
clearButtons() {
|
|
this.expanded?.collapse({ mode: "2" /* DESTROY */ });
|
|
for (const button of this.buttonWidgets) {
|
|
button.destroy();
|
|
}
|
|
this.buttonWidgets.splice(0);
|
|
}
|
|
updateButtons(buttons) {
|
|
const { buttonWidgets } = this;
|
|
for (const [index, button] of buttons.entries()) {
|
|
const buttonWidget = this.buttonWidgets.at(index) ?? this.createButton(index, button);
|
|
buttonWidget.update(button);
|
|
}
|
|
for (let index = buttons.length; index < buttonWidgets.length; index++) {
|
|
const button = this.buttonWidgets.at(index);
|
|
button?.destroy();
|
|
}
|
|
this.buttonWidgets.splice(buttons.length);
|
|
this.refreshButtonClasses();
|
|
}
|
|
updateButtonByIndex(index, button) {
|
|
this.buttonWidgets.at(index)?.update(button);
|
|
}
|
|
clearActiveButton() {
|
|
for (const button of this.buttonWidgets) {
|
|
button.toggleClass(BUTTON_ACTIVE_CLASS, false);
|
|
}
|
|
}
|
|
toggleActiveButtonByIndex(index) {
|
|
if (index === -1)
|
|
return;
|
|
for (const [buttonIndex, button] of this.buttonWidgets.entries()) {
|
|
button.toggleClass(BUTTON_ACTIVE_CLASS, index != null && index === buttonIndex);
|
|
}
|
|
}
|
|
toggleButtonEnabledByIndex(index, enabled) {
|
|
if (index === -1)
|
|
return;
|
|
this.buttonWidgets.at(index)?.setEnabled(enabled);
|
|
}
|
|
toggleSwitchCheckedByIndex(index, checked) {
|
|
if (index === -1)
|
|
return;
|
|
this.buttonWidgets.at(index)?.setChecked(checked);
|
|
}
|
|
getButtonBounds() {
|
|
return this.buttonWidgets.map((buttonWidget) => this.getButtonWidgetBounds(buttonWidget));
|
|
}
|
|
setButtonHiddenByIndex(index, hidden) {
|
|
this.buttonWidgets.at(index)?.setHidden(hidden);
|
|
}
|
|
getButtonWidgetBounds(buttonWidget) {
|
|
const parent = this.getBounds();
|
|
const bounds = buttonWidget.getBounds();
|
|
return new BBox(bounds.x + parent.x, bounds.y + parent.y, bounds.width, bounds.height);
|
|
}
|
|
refreshButtonClasses() {
|
|
const { buttonWidgets, hasPrefix } = this;
|
|
let first8;
|
|
let last;
|
|
let section;
|
|
for (const [index, buttonWidget] of buttonWidgets.entries()) {
|
|
first8 = !hasPrefix && index === 0 || section != buttonWidget.section;
|
|
last = index === buttonWidgets.length - 1 || buttonWidget.section != buttonWidgets.at(index + 1)?.section;
|
|
buttonWidget.toggleClass("ag-charts-toolbar__button--first", first8);
|
|
buttonWidget.toggleClass("ag-charts-toolbar__button--last", last);
|
|
buttonWidget.toggleClass("ag-charts-toolbar__button--gap", index > 0 && first8);
|
|
section = buttonWidget.section;
|
|
}
|
|
}
|
|
createButton(index, button) {
|
|
const buttonWidget = this.createButtonWidget();
|
|
buttonWidget.addClass("ag-charts-toolbar__button");
|
|
buttonWidget.addListener("click", (event) => {
|
|
const buttonOptions = { index, ...button instanceof import_ag_charts_core231.BaseProperties ? button.toJson() : button };
|
|
const buttonBounds = this.getButtonWidgetBounds(buttonWidget);
|
|
const params = {
|
|
event,
|
|
button: buttonOptions,
|
|
buttonBounds,
|
|
buttonWidget
|
|
};
|
|
this.events.dispatch("button-pressed", params);
|
|
});
|
|
buttonWidget.addListener("focus", () => {
|
|
const params = { button: { index } };
|
|
this.events.dispatch("button-focused", params);
|
|
});
|
|
buttonWidget.addListener("expand-controlled-widget", (e) => {
|
|
this.expanded?.collapse({ mode: "4" /* SIDLING_OPENED */ });
|
|
this.expanded = e.controlled;
|
|
const removeListener = this.expanded.addListener("collapse-widget", () => {
|
|
this.expanded = void 0;
|
|
removeListener();
|
|
});
|
|
});
|
|
if (button.section) {
|
|
buttonWidget.section = button.section;
|
|
}
|
|
this.buttonWidgets.push(buttonWidget);
|
|
this.addChild(buttonWidget);
|
|
return buttonWidget;
|
|
}
|
|
};
|
|
var Toolbar = class extends BaseToolbar {
|
|
createButtonWidget() {
|
|
return new ToolbarButtonWidget(this.localeManager);
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/components/toolbar/floatingToolbar.ts
|
|
var import_ag_charts_core232 = require("ag-charts-core");
|
|
var FloatingToolbarPopover = class extends DraggablePopover {
|
|
constructor(ctx, id, onPopoverMoved) {
|
|
super(ctx, id);
|
|
this.onPopoverMoved = onPopoverMoved;
|
|
this.dragHandleDraggingClass = "ag-charts-floating-toolbar__drag-handle--dragging";
|
|
}
|
|
show(children, options = {}) {
|
|
this.showWithChildren(children, {
|
|
...options,
|
|
class: "ag-charts-floating-toolbar"
|
|
});
|
|
}
|
|
hide() {
|
|
this.dragged = false;
|
|
super.hide();
|
|
}
|
|
getBounds() {
|
|
const element2 = this.getPopoverElement();
|
|
return new BBox(
|
|
element2?.offsetLeft ?? 0,
|
|
element2?.offsetTop ?? 0,
|
|
element2?.offsetWidth ?? 0,
|
|
element2?.offsetHeight ?? 0
|
|
);
|
|
}
|
|
hasBeenDragged() {
|
|
return this.dragged;
|
|
}
|
|
setAnchor(anchor, horizontalSpacing, verticalSpacing) {
|
|
const element2 = this.getPopoverElement();
|
|
if (!element2)
|
|
return;
|
|
const position = anchor.position ?? "above";
|
|
const { offsetWidth: width, offsetHeight: height } = element2;
|
|
let top = anchor.y - height - verticalSpacing;
|
|
let left = anchor.x - width / 2;
|
|
if (position === "below") {
|
|
top = anchor.y + verticalSpacing;
|
|
} else if (position === "right") {
|
|
top = anchor.y - height / 2;
|
|
left = anchor.x + horizontalSpacing;
|
|
} else if (position === "above-left") {
|
|
left = anchor.x;
|
|
}
|
|
this.updatePosition({ x: left, y: top });
|
|
}
|
|
ignorePointerEvents() {
|
|
const element2 = this.getPopoverElement();
|
|
if (element2)
|
|
element2.style.pointerEvents = "none";
|
|
}
|
|
capturePointerEvents() {
|
|
const element2 = this.getPopoverElement();
|
|
if (element2)
|
|
element2.style.pointerEvents = "unset";
|
|
}
|
|
updatePosition(position) {
|
|
const bounds = this.getBounds();
|
|
const canvasRect = this.ctx.domManager.getBoundingClientRect();
|
|
position.x = Math.floor((0, import_ag_charts_core232.clamp)(0, position.x, canvasRect.width - bounds.width));
|
|
position.y = Math.floor((0, import_ag_charts_core232.clamp)(0, position.y, canvasRect.height - bounds.height));
|
|
super.updatePosition(position);
|
|
this.onPopoverMoved();
|
|
}
|
|
};
|
|
var FloatingToolbar = class extends BaseToolbar {
|
|
constructor(ctx, ariaLabelId, id) {
|
|
super(ctx, ariaLabelId, "horizontal");
|
|
this.hasPrefix = true;
|
|
this.popover = new FloatingToolbarPopover(ctx, id, this.onPopoverMoved.bind(this));
|
|
this.dragHandle = new DragHandleWidget(ctx.localeManager.t("toolbarAnnotationsDragHandle"));
|
|
this.popover.setDragHandle(this.dragHandle);
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.popover.destroy();
|
|
}
|
|
show(options = {}) {
|
|
this.popover.show([this.dragHandle.getElement(), this.getElement()], options);
|
|
}
|
|
hide() {
|
|
this.popover.hide();
|
|
}
|
|
setAnchor(anchor) {
|
|
this.popover.setAnchor(anchor, this.horizontalSpacing, this.verticalSpacing);
|
|
}
|
|
hasBeenDragged() {
|
|
return this.popover.hasBeenDragged();
|
|
}
|
|
ignorePointerEvents() {
|
|
this.popover.ignorePointerEvents();
|
|
}
|
|
capturePointerEvents() {
|
|
this.popover.capturePointerEvents();
|
|
}
|
|
onPopoverMoved() {
|
|
const popoverBounds = this.popover.getBounds();
|
|
if (this.popoverBounds?.equals(popoverBounds))
|
|
return;
|
|
this.popoverBounds = popoverBounds.clone();
|
|
const buttonBounds = this.getButtonBounds();
|
|
this.events.dispatch("toolbar-moved", { popoverBounds, buttonBounds });
|
|
}
|
|
getButtonWidgetBounds(buttonWidget) {
|
|
const popoverBounds = this.popover.getBounds();
|
|
const bounds = super.getButtonWidgetBounds(buttonWidget);
|
|
const dragHandleBounds = this.dragHandle.getBounds();
|
|
return new BBox(
|
|
bounds.x + popoverBounds.x - dragHandleBounds.width,
|
|
bounds.y + popoverBounds.y,
|
|
bounds.width,
|
|
bounds.height
|
|
);
|
|
}
|
|
};
|
|
var DragHandleWidget = class extends NativeWidget {
|
|
constructor(title) {
|
|
super((0, import_ag_charts_core232.createElement)("div", "ag-charts-floating-toolbar__drag-handle"));
|
|
const icon = new NativeWidget(
|
|
(0, import_ag_charts_core232.createElement)("span", `${(0, import_ag_charts_core232.getIconClassNames)("drag-handle")} ag-charts-toolbar__icon`)
|
|
);
|
|
icon.setAriaHidden(true);
|
|
this.addChild(icon);
|
|
this.elem.title = title;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/module-support.ts
|
|
var motion = { ...fromToMotion_exports, ...resetMotion_exports };
|
|
|
|
// packages/ag-charts-community/src/widget/exports.ts
|
|
var exports_exports = {};
|
|
__export(exports_exports, {
|
|
ButtonWidget: () => ButtonWidget,
|
|
MenuItemRadioWidget: () => MenuItemRadioWidget,
|
|
MenuItemWidget: () => MenuItemWidget,
|
|
MenuWidget: () => MenuWidget,
|
|
NativeWidget: () => NativeWidget,
|
|
SliderWidget: () => SliderWidget,
|
|
ToolbarWidget: () => ToolbarWidget,
|
|
WIDGET_HTML_EVENTS: () => WIDGET_HTML_EVENTS,
|
|
Widget: () => Widget,
|
|
WidgetEventUtil: () => WidgetEventUtil
|
|
});
|
|
|
|
// packages/ag-charts-community/src/api/preset/presetModules.ts
|
|
var import_ag_charts_core234 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/api/preset/sparkline.ts
|
|
var import_ag_charts_core233 = require("ag-charts-core");
|
|
var commonAxisProperties = {
|
|
title: {
|
|
enabled: false
|
|
},
|
|
label: {
|
|
enabled: false
|
|
},
|
|
line: {
|
|
enabled: false
|
|
},
|
|
gridLine: {
|
|
enabled: false
|
|
},
|
|
crosshair: {
|
|
enabled: false,
|
|
stroke: import_ag_charts_core233.DEFAULT_SPARKLINE_CROSSHAIR_STROKE,
|
|
lineDash: [0],
|
|
label: {
|
|
enabled: false
|
|
}
|
|
}
|
|
};
|
|
var numericAxisProperties = {
|
|
...commonAxisProperties,
|
|
nice: false
|
|
};
|
|
var chartTooltipDefaults = {
|
|
mode: "compact",
|
|
position: {
|
|
anchorTo: "node",
|
|
placement: ["right", "left"]
|
|
},
|
|
showArrow: false
|
|
};
|
|
var barGridLineDefaults = {
|
|
style: [{ stroke: { $ref: "gridLineColor" } }],
|
|
width: 2
|
|
};
|
|
var barAxisDefaults = {
|
|
number: {
|
|
gridLine: barGridLineDefaults
|
|
},
|
|
time: {
|
|
gridLine: barGridLineDefaults
|
|
},
|
|
category: {
|
|
gridLine: barGridLineDefaults
|
|
}
|
|
};
|
|
var SPARKLINE_THEME = {
|
|
overrides: {
|
|
common: {
|
|
animation: { enabled: false },
|
|
contextMenu: { enabled: false },
|
|
keyboard: { enabled: false },
|
|
background: { visible: false },
|
|
navigator: { enabled: false },
|
|
padding: {
|
|
top: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
left: 0
|
|
},
|
|
axes: {
|
|
number: {
|
|
...numericAxisProperties,
|
|
interval: {
|
|
values: [0]
|
|
}
|
|
},
|
|
log: {
|
|
...numericAxisProperties
|
|
},
|
|
time: {
|
|
...numericAxisProperties
|
|
},
|
|
category: {
|
|
...commonAxisProperties
|
|
}
|
|
}
|
|
},
|
|
bar: {
|
|
series: {
|
|
crisp: false,
|
|
label: {
|
|
placement: "inside-end",
|
|
padding: 4
|
|
},
|
|
// @ts-expect-error undocumented option
|
|
sparklineMode: true
|
|
},
|
|
tooltip: {
|
|
...chartTooltipDefaults,
|
|
position: {
|
|
...chartTooltipDefaults.position,
|
|
anchorTo: "pointer"
|
|
},
|
|
range: "nearest"
|
|
},
|
|
axes: barAxisDefaults
|
|
},
|
|
line: {
|
|
seriesArea: {
|
|
padding: {
|
|
top: 2,
|
|
right: 2,
|
|
bottom: 2,
|
|
left: 2
|
|
}
|
|
},
|
|
series: {
|
|
// @ts-expect-error undocumented option
|
|
sparklineMode: true,
|
|
strokeWidth: 1,
|
|
marker: {
|
|
enabled: false,
|
|
size: 3
|
|
}
|
|
},
|
|
tooltip: chartTooltipDefaults
|
|
},
|
|
area: {
|
|
seriesArea: {
|
|
padding: {
|
|
top: 1,
|
|
right: 0,
|
|
bottom: 1,
|
|
left: 0
|
|
}
|
|
},
|
|
series: {
|
|
strokeWidth: 1,
|
|
fillOpacity: 0.4
|
|
},
|
|
tooltip: chartTooltipDefaults
|
|
}
|
|
}
|
|
};
|
|
var setInitialBaseTheme = (0, import_ag_charts_core233.simpleMemorize)(createInitialBaseTheme);
|
|
function createInitialBaseTheme(baseTheme, initialBaseTheme) {
|
|
if (typeof baseTheme === "string") {
|
|
return {
|
|
...initialBaseTheme,
|
|
baseTheme
|
|
};
|
|
}
|
|
if (baseTheme != null) {
|
|
return {
|
|
...baseTheme,
|
|
// @ts-expect-error internal implementation
|
|
baseTheme: setInitialBaseTheme(baseTheme.baseTheme, initialBaseTheme)
|
|
};
|
|
}
|
|
return initialBaseTheme;
|
|
}
|
|
function sparklineDataPreset(data) {
|
|
if (Array.isArray(data) && data.length !== 0) {
|
|
const firstItem = data.find((v) => v != null);
|
|
if (typeof firstItem === "number") {
|
|
const mappedData = data.map((y, x) => ({ x, y }));
|
|
return { data: mappedData, series: [{ xKey: "x", yKey: "y" }], datumKey: "y" };
|
|
} else if (Array.isArray(firstItem)) {
|
|
const mappedData = data.map((datum) => ({ x: datum?.[0], y: datum?.[1], datum }));
|
|
return { data: mappedData, series: [{ xKey: "x", yKey: "y" }], datumKey: "datum" };
|
|
}
|
|
} else if (data?.length === 0) {
|
|
return { data, series: [{ xKey: "x", yKey: "y" }], datumKey: "y" };
|
|
}
|
|
return { data };
|
|
}
|
|
function axisPreset(opts) {
|
|
switch (opts?.type) {
|
|
case "number": {
|
|
const { reverse, min, max } = opts ?? {};
|
|
return {
|
|
type: "number",
|
|
reverse,
|
|
min,
|
|
max
|
|
};
|
|
}
|
|
case "time": {
|
|
const { reverse, min, max } = opts ?? {};
|
|
return {
|
|
type: "time",
|
|
reverse,
|
|
min,
|
|
max
|
|
};
|
|
}
|
|
case "category":
|
|
default: {
|
|
if (opts == null) {
|
|
return { type: "category" };
|
|
}
|
|
const { reverse, paddingInner, paddingOuter } = opts;
|
|
return {
|
|
type: "category",
|
|
reverse,
|
|
paddingInner,
|
|
paddingOuter
|
|
};
|
|
}
|
|
}
|
|
}
|
|
function gridLinePreset(opts, defaultEnabled, sparkOpts) {
|
|
const gridLineOpts = {};
|
|
if (opts?.stroke != null) {
|
|
gridLineOpts.style = [{ stroke: opts?.stroke }];
|
|
gridLineOpts.enabled ?? (gridLineOpts.enabled = true);
|
|
}
|
|
if (opts?.strokeWidth != null) {
|
|
gridLineOpts.width = opts?.strokeWidth;
|
|
gridLineOpts.enabled ?? (gridLineOpts.enabled = true);
|
|
}
|
|
if (sparkOpts.type === "bar" && sparkOpts.direction !== "horizontal") {
|
|
gridLineOpts.enabled ?? (gridLineOpts.enabled = true);
|
|
}
|
|
if (opts?.visible != null) {
|
|
gridLineOpts.enabled = opts.visible;
|
|
}
|
|
gridLineOpts.enabled ?? (gridLineOpts.enabled = defaultEnabled);
|
|
return gridLineOpts;
|
|
}
|
|
var tooltipRendererFn = (0, import_ag_charts_core233.simpleMemorize)((context, tooltip, datumKey) => {
|
|
return (params) => {
|
|
const xValue = params.datum[params.xKey];
|
|
const yValue = params.datum[params.yKey];
|
|
const datum = datumKey == null ? params.datum : params.datum[datumKey];
|
|
const userContent = tooltip?.renderer?.({ context, datum, xValue, yValue });
|
|
if ((0, import_ag_charts_core233.isString)(userContent) || (0, import_ag_charts_core233.isNumber)(userContent) || (0, import_ag_charts_core233.isDate)(userContent)) {
|
|
return (0, import_ag_charts_core233.toTextString)(userContent);
|
|
}
|
|
const content = userContent?.content ?? yValue.toFixed(2);
|
|
return userContent?.title ? {
|
|
heading: void 0,
|
|
title: void 0,
|
|
data: [{ label: userContent.title, value: content }]
|
|
} : {
|
|
heading: void 0,
|
|
title: content,
|
|
data: []
|
|
};
|
|
};
|
|
});
|
|
function sparkline(opts) {
|
|
const {
|
|
background,
|
|
container,
|
|
foreground,
|
|
height,
|
|
listeners,
|
|
locale,
|
|
minHeight,
|
|
minWidth,
|
|
overrideDevicePixelRatio,
|
|
padding: padding2,
|
|
width,
|
|
theme: baseTheme,
|
|
data: baseData,
|
|
crosshair,
|
|
axis,
|
|
min,
|
|
max,
|
|
tooltip,
|
|
context,
|
|
styleNonce,
|
|
...seriesOptions
|
|
} = opts;
|
|
const chartOpts = {
|
|
background,
|
|
container,
|
|
foreground,
|
|
height,
|
|
listeners,
|
|
locale,
|
|
minHeight,
|
|
minWidth,
|
|
overrideDevicePixelRatio,
|
|
padding: padding2,
|
|
width,
|
|
styleNonce
|
|
};
|
|
const { data, series: [seriesOverrides] = [], datumKey } = sparklineDataPreset(baseData);
|
|
const seriesConfig = seriesOptions;
|
|
if (seriesOverrides != null) {
|
|
Object.assign(seriesConfig, seriesOverrides);
|
|
}
|
|
seriesConfig.tooltip = {
|
|
...tooltip,
|
|
renderer: tooltipRendererFn(context, tooltip, datumKey)
|
|
};
|
|
chartOpts.theme = setInitialBaseTheme(baseTheme, SPARKLINE_THEME);
|
|
chartOpts.data = data;
|
|
chartOpts.series = [seriesConfig];
|
|
const swapAxes = seriesConfig.type === "bar" && seriesConfig.direction === "horizontal";
|
|
const [crossAxisPosition, numberAxisPosition] = swapAxes ? ["left", "bottom"] : ["bottom", "left"];
|
|
const crossAxis = {
|
|
...axisPreset(axis),
|
|
position: crossAxisPosition,
|
|
...crosshair == null ? {} : { crosshair }
|
|
};
|
|
const numberAxis = {
|
|
type: "number",
|
|
gridLine: gridLinePreset(axis, false, opts),
|
|
position: numberAxisPosition,
|
|
...min == null ? {} : { min },
|
|
...max == null ? {} : { max }
|
|
};
|
|
chartOpts.axes = swapAxes ? { x: numberAxis, y: crossAxis } : { x: crossAxis, y: numberAxis };
|
|
return chartOpts;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/api/preset/presetModules.ts
|
|
var commonSparklineOmit = [
|
|
"showInLegend",
|
|
"showInMiniChart",
|
|
"grouped",
|
|
"stacked",
|
|
"stackGroup",
|
|
"tooltip",
|
|
"listeners",
|
|
"errorBar",
|
|
"xKey",
|
|
"yKey",
|
|
"type"
|
|
];
|
|
var commonSparklineAxisOptionsDef = {
|
|
visible: import_ag_charts_core234.boolean,
|
|
reverse: import_ag_charts_core234.boolean,
|
|
stroke: import_ag_charts_core234.color,
|
|
strokeWidth: import_ag_charts_core234.positiveNumber
|
|
};
|
|
var commonSparklineOptionsDef = {
|
|
context: () => true,
|
|
tooltip: import_ag_charts_core234.defined,
|
|
theme: import_ag_charts_core234.defined,
|
|
background: import_ag_charts_core234.defined,
|
|
container: import_ag_charts_core234.defined,
|
|
width: import_ag_charts_core234.defined,
|
|
height: import_ag_charts_core234.defined,
|
|
minWidth: import_ag_charts_core234.defined,
|
|
minHeight: import_ag_charts_core234.defined,
|
|
padding: import_ag_charts_core234.defined,
|
|
listeners: import_ag_charts_core234.defined,
|
|
locale: import_ag_charts_core234.defined,
|
|
data: import_ag_charts_core234.defined,
|
|
styleNonce: import_ag_charts_core234.string,
|
|
axis: (0, import_ag_charts_core234.typeUnion)(
|
|
{
|
|
number: {
|
|
...commonSparklineAxisOptionsDef,
|
|
min: (0, import_ag_charts_core234.and)(import_ag_charts_core234.number, (0, import_ag_charts_core234.lessThan)("max")),
|
|
max: (0, import_ag_charts_core234.and)(import_ag_charts_core234.number, (0, import_ag_charts_core234.greaterThan)("min"))
|
|
},
|
|
category: {
|
|
...commonSparklineAxisOptionsDef,
|
|
paddingInner: import_ag_charts_core234.ratio,
|
|
paddingOuter: import_ag_charts_core234.ratio
|
|
},
|
|
time: {
|
|
...commonSparklineAxisOptionsDef,
|
|
min: (0, import_ag_charts_core234.and)((0, import_ag_charts_core234.or)(import_ag_charts_core234.number, import_ag_charts_core234.date), (0, import_ag_charts_core234.lessThan)("max")),
|
|
max: (0, import_ag_charts_core234.and)((0, import_ag_charts_core234.or)(import_ag_charts_core234.number, import_ag_charts_core234.date), (0, import_ag_charts_core234.greaterThan)("min"))
|
|
}
|
|
},
|
|
"axis options",
|
|
"category"
|
|
),
|
|
min: (0, import_ag_charts_core234.and)(import_ag_charts_core234.number, (0, import_ag_charts_core234.lessThan)("max")),
|
|
max: (0, import_ag_charts_core234.and)(import_ag_charts_core234.number, (0, import_ag_charts_core234.greaterThan)("min")),
|
|
crosshair: {
|
|
enabled: import_ag_charts_core234.boolean,
|
|
snap: import_ag_charts_core234.boolean,
|
|
...import_ag_charts_core234.strokeOptionsDef,
|
|
...import_ag_charts_core234.lineDashOptionsDef
|
|
},
|
|
xKey: import_ag_charts_core234.string,
|
|
yKey: import_ag_charts_core234.string
|
|
};
|
|
commonSparklineOptionsDef.overrideDevicePixelRatio = (0, import_ag_charts_core234.undocumented)(import_ag_charts_core234.number);
|
|
commonSparklineOptionsDef.foreground = (0, import_ag_charts_core234.undocumented)(import_ag_charts_core234.defined);
|
|
var SparklinePresetModule = {
|
|
type: "preset",
|
|
name: "sparkline",
|
|
version: VERSION,
|
|
options: (0, import_ag_charts_core234.typeUnion)(
|
|
{
|
|
area: {
|
|
...commonSparklineOptionsDef,
|
|
...(0, import_ag_charts_core234.without)(areaSeriesOptionsDef, commonSparklineOmit)
|
|
},
|
|
bar: {
|
|
...commonSparklineOptionsDef,
|
|
...(0, import_ag_charts_core234.without)(barSeriesOptionsDef, commonSparklineOmit)
|
|
},
|
|
line: {
|
|
...commonSparklineOptionsDef,
|
|
...(0, import_ag_charts_core234.without)(lineSeriesOptionsDef, commonSparklineOmit)
|
|
}
|
|
},
|
|
"sparkline options"
|
|
),
|
|
create: sparkline,
|
|
processData: sparklineDataPreset
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/cartesianChartModule.ts
|
|
var import_ag_charts_core236 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/cartesianChart.ts
|
|
var import_ag_charts_core235 = require("ag-charts-core");
|
|
var directions = ["top", "right", "bottom", "left"];
|
|
var _CartesianChart = class _CartesianChart extends Chart {
|
|
constructor(options, resources) {
|
|
super(options, resources);
|
|
// TODO should come from theme
|
|
/** Integrated Charts feature state - not used in Standalone Charts. */
|
|
this.paired = true;
|
|
this.axes = this.createChartAxes();
|
|
this.lastUpdateClipRect = void 0;
|
|
this.lastLayoutWidth = Number.NaN;
|
|
this.lastLayoutHeight = Number.NaN;
|
|
}
|
|
createChartAxes() {
|
|
return new CartesianChartAxes();
|
|
}
|
|
onAxisChange(newValue, oldValue) {
|
|
super.onAxisChange(newValue, oldValue);
|
|
this.syncAxisChanges(newValue, oldValue);
|
|
if (this.ctx != null) {
|
|
this.ctx.zoomManager.setAxes(newValue);
|
|
}
|
|
}
|
|
destroySeries(series) {
|
|
super.destroySeries(series);
|
|
this.lastLayoutWidth = Number.NaN;
|
|
this.lastLayoutHeight = Number.NaN;
|
|
}
|
|
getChartType() {
|
|
return "cartesian";
|
|
}
|
|
setRootClipRects(clipRect) {
|
|
const { seriesRoot, annotationRoot } = this;
|
|
seriesRoot.setClipRect(clipRect);
|
|
annotationRoot.setClipRect(clipRect);
|
|
}
|
|
async processData() {
|
|
await super.processData();
|
|
if (this.syncStatus === "init") {
|
|
this.syncStatus = "domains-calculated";
|
|
}
|
|
this.ctx.updateService.dispatchProcessData({ series: { shouldFlipXY: this.shouldFlipXY() } });
|
|
}
|
|
async processDomains() {
|
|
await super.processDomains();
|
|
for (const axis of this.axes) {
|
|
const syncedDomain = await this.getSyncedDomain(axis);
|
|
if (syncedDomain != null) {
|
|
axis.setDomains({ domain: syncedDomain });
|
|
}
|
|
}
|
|
}
|
|
performLayout(ctx) {
|
|
const { seriesRoot, annotationRoot } = this;
|
|
const { clipSeries, seriesRect, visible } = this.updateAxes(ctx);
|
|
this.seriesRoot.visible = visible;
|
|
this.seriesRect = seriesRect;
|
|
this.animationRect = ctx.layoutBox;
|
|
const { x, y } = seriesRect;
|
|
if (ctx.width !== this.lastLayoutWidth || ctx.height !== this.lastLayoutHeight) {
|
|
for (const group of [seriesRoot, annotationRoot]) {
|
|
group.translationX = Math.floor(x);
|
|
group.translationY = Math.floor(y);
|
|
}
|
|
} else {
|
|
const { translationX, translationY } = seriesRoot;
|
|
staticFromToMotion(
|
|
this.id,
|
|
"seriesRect",
|
|
this.ctx.animationManager,
|
|
[seriesRoot, annotationRoot],
|
|
{ translationX, translationY },
|
|
{ translationX: Math.floor(x), translationY: Math.floor(y) },
|
|
{ phase: "update" }
|
|
);
|
|
}
|
|
this.lastLayoutWidth = ctx.width;
|
|
this.lastLayoutHeight = ctx.height;
|
|
const seriesPaddedRect = seriesRect.clone().grow(this.seriesArea.getPadding());
|
|
const alwaysClip = this.series.some((s) => s.alwaysClip);
|
|
const enableClip = alwaysClip || (this.seriesArea.clip ?? false) || clipSeries;
|
|
const clipRect = enableClip ? seriesPaddedRect : void 0;
|
|
const { lastUpdateClipRect } = this;
|
|
this.lastUpdateClipRect = clipRect;
|
|
if (this.ctx.animationManager.isActive() && lastUpdateClipRect != null) {
|
|
this.ctx.animationManager.animate({
|
|
id: this.id,
|
|
groupId: "clip-rect",
|
|
phase: "update",
|
|
from: lastUpdateClipRect,
|
|
to: seriesPaddedRect,
|
|
onUpdate: (interpolatedClipRect) => this.setRootClipRects(interpolatedClipRect),
|
|
onStop: () => this.setRootClipRects(clipRect),
|
|
onComplete: () => this.setRootClipRects(clipRect)
|
|
});
|
|
} else {
|
|
this.setRootClipRects(clipRect);
|
|
}
|
|
this.ctx.layoutManager.emitLayoutComplete(ctx, {
|
|
axes: (0, import_ag_charts_core235.fromPairs)(this.axes.map((axis) => [axis.id, axis.getLayoutState()])),
|
|
series: {
|
|
visible,
|
|
rect: seriesRect,
|
|
paddedRect: seriesPaddedRect
|
|
},
|
|
clipSeries
|
|
});
|
|
stackCartesianSeries(this.series);
|
|
}
|
|
updateAxes(layoutContext) {
|
|
const { layoutBox, scrollbars } = layoutContext;
|
|
const { clipSeries, seriesRect, overflows } = this.resolveAxesLayout(layoutBox, scrollbars);
|
|
for (const axis of this.axes) {
|
|
axis.update();
|
|
axis.setCrossLinesVisible(!overflows);
|
|
this.clipAxis(axis, seriesRect, layoutBox);
|
|
}
|
|
return { clipSeries, seriesRect, visible: !overflows };
|
|
}
|
|
// Iteratively try to resolve axis widths - since X axis width affects Y axis range,
|
|
// and vice-versa, we need to iteratively try and find a fit for the axes and their
|
|
// ticks/labels.
|
|
resolveAxesLayout(layoutBox, scrollbars) {
|
|
let newState;
|
|
let prevState;
|
|
let iterations = 0;
|
|
const maxIterations = 10;
|
|
const crossAtAxes = this.axes.filter((axis) => axis.crossAt?.value != null);
|
|
do {
|
|
prevState = newState ?? this.getDefaultState();
|
|
newState = this.updateAxesPass(
|
|
new Map(prevState.axisAreaWidths),
|
|
layoutBox.clone(),
|
|
crossAtAxes,
|
|
scrollbars
|
|
);
|
|
if (iterations++ > maxIterations) {
|
|
import_ag_charts_core235.Logger.warn("Max iterations reached. Unable to stabilize axes layout.");
|
|
break;
|
|
}
|
|
} while (!this.isLayoutStable(newState, prevState));
|
|
this.lastAreaWidths = newState.axisAreaWidths;
|
|
return newState;
|
|
}
|
|
updateAxesPass(axisAreaWidths, axisAreaBound, crossAtAxes, scrollbars) {
|
|
const axisWidths = /* @__PURE__ */ new Map();
|
|
const primaryTickCounts = {};
|
|
let overflows = false;
|
|
let clipSeries = false;
|
|
const seriesAreaPadding = this.seriesArea.getPadding();
|
|
for (const dir of directions) {
|
|
const padding2 = seriesAreaPadding[dir] ?? 0;
|
|
const axis = this.axes.findLast((a) => a.position === dir);
|
|
if (axis) {
|
|
axis.seriesAreaPadding = padding2;
|
|
} else {
|
|
axisAreaBound.shrink(padding2, dir);
|
|
}
|
|
}
|
|
const totalWidth = (axisAreaWidths.get("left") ?? 0) + (axisAreaWidths.get("right") ?? 0);
|
|
const totalHeight = (axisAreaWidths.get("top") ?? 0) + (axisAreaWidths.get("bottom") ?? 0);
|
|
const crossLinePadding = this.buildCrossLinePadding(axisAreaWidths);
|
|
const crossLineHPadding = crossLinePadding.left + crossLinePadding.right;
|
|
const crossLineVPadding = crossLinePadding.top + crossLinePadding.bottom;
|
|
if (axisAreaBound.width <= totalWidth + crossLineHPadding || axisAreaBound.height <= totalHeight + crossLineVPadding) {
|
|
overflows = true;
|
|
} else {
|
|
axisAreaBound.shrink(crossLinePadding);
|
|
}
|
|
const { scene } = this.ctx;
|
|
const seriesRect = axisAreaBound.clone().shrink(Object.fromEntries(axisAreaWidths));
|
|
for (const axis of this.axes) {
|
|
const { position = "left", direction } = axis;
|
|
const isVertical = direction === import_ag_charts_core235.ChartAxisDirection.Y;
|
|
let axisWidth;
|
|
this.sizeAxis(axis, seriesRect, position);
|
|
if (axis.thickness == null) {
|
|
const availableSize = getSize(isVertical, scene);
|
|
axisWidth = availableSize * (axis.maxThicknessRatio ?? 1);
|
|
} else {
|
|
axisWidth = axis.thickness;
|
|
}
|
|
const chartLayout = {
|
|
sizeLimit: axisWidth - axis.label.spacing,
|
|
padding: this.padding,
|
|
scrollbars
|
|
};
|
|
const { primaryTickCount, bbox } = axis.calculateLayout(
|
|
axis.nice ? primaryTickCounts[direction] : void 0,
|
|
chartLayout
|
|
);
|
|
primaryTickCounts[direction] ?? (primaryTickCounts[direction] = primaryTickCount);
|
|
clipSeries || (clipSeries = axis.dataDomain.clipped || axis.visibleRange[0] > 0 || axis.visibleRange[1] < 1);
|
|
if (axis.thickness == null) {
|
|
axisWidth = Math.min(getSize(isVertical, bbox) ?? 0, axisWidth);
|
|
}
|
|
axisWidths.set(axis.id, Math.ceil(axisWidth));
|
|
}
|
|
let crossPositions;
|
|
if (crossAtAxes.length > 0) {
|
|
crossPositions = this.calculateAxesCrossPositions(axisWidths, seriesRect, crossAtAxes);
|
|
}
|
|
const axisGroups = (0, import_ag_charts_core235.groupBy)(this.axes, (axis) => axis.position ?? "left");
|
|
const newAxisAreaWidths = /* @__PURE__ */ new Map();
|
|
const axisOffsets = /* @__PURE__ */ new Map();
|
|
for (const [position, axes] of (0, import_ag_charts_core235.entries)(axisGroups)) {
|
|
let currentOffset = getSize(position !== "left" && position !== "right", scene) % scene.pixelRatio;
|
|
let totalAxisWidth = 0;
|
|
for (const axis of axes ?? []) {
|
|
axisOffsets.set(axis.id, currentOffset);
|
|
const axisThickness = axisWidths.get(axis.id) ?? 0;
|
|
totalAxisWidth = Math.max(totalAxisWidth, currentOffset + axisThickness);
|
|
if (axis.layoutConstraints.stacked) {
|
|
currentOffset += axisThickness + _CartesianChart.AxesPadding;
|
|
}
|
|
}
|
|
newAxisAreaWidths.set(position, Math.ceil(totalAxisWidth));
|
|
}
|
|
for (const [position, axes] of (0, import_ag_charts_core235.entries)(axisGroups)) {
|
|
this.positionAxes({
|
|
axes: axes ?? [],
|
|
position,
|
|
axisWidths,
|
|
axisOffsets,
|
|
axisAreaWidths: newAxisAreaWidths,
|
|
axisBound: axisAreaBound,
|
|
seriesRect
|
|
});
|
|
}
|
|
if (crossPositions != null) {
|
|
this.applyAxisCrossing(seriesRect, crossPositions);
|
|
}
|
|
return { clipSeries, seriesRect, axisAreaWidths: newAxisAreaWidths, overflows };
|
|
}
|
|
calculateAxesCrossPositions(axisWidths, seriesRect, crossAtAxes) {
|
|
const crossPositions = /* @__PURE__ */ new Map();
|
|
for (const axis of crossAtAxes) {
|
|
const { crossPosition, visible } = this.calculateAxisCrossPosition(axis);
|
|
axis.setAxisVisible(visible);
|
|
this.adjustAxisWidth(axis, axisWidths, crossPosition, seriesRect, visible);
|
|
if (crossPosition == void 0)
|
|
continue;
|
|
crossPositions.set(axis.id, crossPosition);
|
|
}
|
|
return crossPositions;
|
|
}
|
|
calculateAxisCrossPosition(axis) {
|
|
const perpendicularAxis = this.axes.perpendicular(axis);
|
|
const {
|
|
scale: { domain, bandwidth },
|
|
range: range4
|
|
} = perpendicularAxis;
|
|
const halfBandwidth = (bandwidth ?? 0) / 2;
|
|
const crossPosition = perpendicularAxis.scale.convert(axis.crossAt?.value, { clamp: false }) + halfBandwidth;
|
|
if (perpendicularAxis.inRange(crossPosition))
|
|
return { crossPosition, visible: true };
|
|
if (axis.crossAt?.sticky === false) {
|
|
return { crossPosition: void 0, visible: false };
|
|
}
|
|
const clampedPosition = Number.isNaN(crossPosition) ? range4[domain[0]] : (0, import_ag_charts_core235.clampArray)(crossPosition, range4);
|
|
return { crossPosition: clampedPosition, visible: true };
|
|
}
|
|
adjustAxisWidth(axis, axisWidths, crossPosition, seriesRect, visible) {
|
|
const crosshairModule = axis.getModuleMap().getModule("crosshair");
|
|
if (crosshairModule?.enabled)
|
|
return;
|
|
const annotationsModule = this.modulesManager.getModule("annotations");
|
|
const hasAnnotations = annotationsModule?.enabled === true || this.ctx.annotationManager.createMemento().some((annotation) => {
|
|
switch (annotation.type) {
|
|
case "vertical-line":
|
|
return axis.direction === import_ag_charts_core235.ChartAxisDirection.X;
|
|
case "horizontal-line":
|
|
return axis.direction === import_ag_charts_core235.ChartAxisDirection.Y;
|
|
}
|
|
});
|
|
if (hasAnnotations)
|
|
return;
|
|
const currentWidth = axisWidths.get(axis.id) ?? 0;
|
|
const adjustedWidth = visible ? this.calculateAxisBleedingWidth(axis, currentWidth, crossPosition, seriesRect) : 0;
|
|
axisWidths.set(axis.id, adjustedWidth);
|
|
}
|
|
calculateAxisBleedingWidth(axis, actualWidth, crossPosition, seriesRect) {
|
|
if (crossPosition == null)
|
|
return actualWidth;
|
|
switch (axis.position) {
|
|
case "left":
|
|
case "top":
|
|
return Math.max(0, actualWidth - crossPosition);
|
|
case "right":
|
|
return Math.max(0, crossPosition + actualWidth - seriesRect.width);
|
|
case "bottom":
|
|
return Math.max(0, crossPosition + actualWidth - seriesRect.height);
|
|
default:
|
|
return actualWidth;
|
|
}
|
|
}
|
|
applyAxisCrossing(seriesRect, crossPositions) {
|
|
for (const axis of this.axes) {
|
|
const crossPosition = crossPositions.get(axis.id);
|
|
if (crossPosition == null) {
|
|
axis.crossAxisTranslation.x = 0;
|
|
axis.crossAxisTranslation.y = 0;
|
|
continue;
|
|
}
|
|
const isXDirection = axis.direction === import_ag_charts_core235.ChartAxisDirection.X;
|
|
axis.crossAxisTranslation.x = isXDirection ? 0 : seriesRect.x + crossPosition - axis.translation.x;
|
|
axis.crossAxisTranslation.y = isXDirection ? seriesRect.y + crossPosition - axis.translation.y : 0;
|
|
}
|
|
}
|
|
buildCrossLinePadding(axisAreaSize) {
|
|
var _a;
|
|
const crossLinePadding = { top: 0, right: 0, bottom: 0, left: 0 };
|
|
for (const axis of this.axes) {
|
|
const { position, label } = axis;
|
|
if (axis.crossLines) {
|
|
for (const crossLine of axis.crossLines) {
|
|
if (crossLine instanceof CartesianCrossLine) {
|
|
crossLine.position = position ?? "top";
|
|
(_a = crossLine.label).parallel ?? (_a.parallel = label.parallel);
|
|
}
|
|
crossLine.calculatePadding?.(crossLinePadding);
|
|
}
|
|
}
|
|
}
|
|
for (const [side, padding2 = 0] of (0, import_ag_charts_core235.entries)(crossLinePadding)) {
|
|
crossLinePadding[side] = Math.max(padding2 - (axisAreaSize.get(side) ?? 0), 0);
|
|
}
|
|
return crossLinePadding;
|
|
}
|
|
clampToOutsideSeriesRect(seriesRect, value, dimension, direction) {
|
|
const bound = dimension === "x" ? seriesRect.x : seriesRect.y;
|
|
const size = dimension === "x" ? seriesRect.width : seriesRect.height;
|
|
return direction === 1 ? Math.min(value, bound + size) : Math.max(value, bound);
|
|
}
|
|
async getSyncedDomain(axis) {
|
|
const syncModule = this.modulesManager.getModule("sync");
|
|
if (!syncModule?.enabled)
|
|
return;
|
|
return await syncModule.getSyncedDomain(axis);
|
|
}
|
|
syncAxisChanges(newValue, oldValue) {
|
|
const syncModule = this.modulesManager.getModule("sync");
|
|
if (!syncModule?.enabled)
|
|
return;
|
|
const removed = new Set(oldValue ?? []);
|
|
for (const axis of newValue) {
|
|
removed.delete(axis);
|
|
}
|
|
for (const removedAxis of removed) {
|
|
syncModule.removeAxis(removedAxis);
|
|
}
|
|
}
|
|
sizeAxis(axis, seriesRect, position) {
|
|
const isNumberAxis = axis instanceof NumberAxis;
|
|
const isLeftRight = position === "left" || position === "right";
|
|
const { width, height } = seriesRect;
|
|
const maxEnd = isLeftRight ? height : width;
|
|
let start = 0;
|
|
let end2 = maxEnd;
|
|
let { min, max } = this.ctx.zoomManager.getAxisZoom(axis.id);
|
|
const { width: axisWidth, unit, align: align2 } = axis.layoutConstraints;
|
|
if (unit === "px") {
|
|
end2 = start + axisWidth;
|
|
} else {
|
|
end2 = end2 * axisWidth / 100;
|
|
}
|
|
const size = end2 - start;
|
|
if (align2 === "end") {
|
|
start = maxEnd - size;
|
|
end2 = maxEnd;
|
|
} else if (align2 === "center") {
|
|
const center = start + (maxEnd - start) / 2;
|
|
start = center - size / 2;
|
|
end2 = center + size / 2;
|
|
} else if (align2 === "justify") {
|
|
end2 = maxEnd;
|
|
}
|
|
if (isLeftRight) {
|
|
if (isNumberAxis) {
|
|
[start, end2] = [end2, start];
|
|
} else {
|
|
[min, max] = [1 - max, 1 - min];
|
|
}
|
|
}
|
|
axis.range = [start, end2];
|
|
axis.visibleRange = [min, max];
|
|
axis.gridLength = isLeftRight ? width : height;
|
|
axis.lineRange = isLeftRight ? [height, 0] : [0, width];
|
|
}
|
|
positionAxes(opts) {
|
|
const { axes, axisBound, axisWidths, axisOffsets, axisAreaWidths, seriesRect, position } = opts;
|
|
const axisAreaWidth = axisAreaWidths.get(position) ?? 0;
|
|
let mainDimension = "x";
|
|
let minorDimension = "y";
|
|
let direction = 1;
|
|
if (position === "top" || position === "bottom") {
|
|
mainDimension = "y";
|
|
minorDimension = "x";
|
|
}
|
|
let axisBoundMainOffset = axisBound[mainDimension];
|
|
if (position === "right" || position === "bottom") {
|
|
direction = -1;
|
|
axisBoundMainOffset += mainDimension === "x" ? axisBound.width : axisBound.height;
|
|
}
|
|
for (const axis of axes) {
|
|
const minorOffset = axisAreaWidths.get(minorDimension === "x" ? "left" : "top") ?? 0;
|
|
const axisThickness = axisWidths.get(axis.id) ?? 0;
|
|
const axisOffset = axisOffsets.get(axis.id) ?? 0;
|
|
axis.gridPadding = axisAreaWidth - axisOffset - axisThickness;
|
|
axis.translation[minorDimension] = axisBound[minorDimension] + minorOffset;
|
|
axis.translation[mainDimension] = this.clampToOutsideSeriesRect(
|
|
seriesRect,
|
|
axisBoundMainOffset + direction * (axisOffset + axisThickness),
|
|
mainDimension,
|
|
direction
|
|
);
|
|
}
|
|
}
|
|
shouldFlipXY() {
|
|
return this.series.every((series) => series instanceof CartesianSeries && series.shouldFlipXY());
|
|
}
|
|
getDefaultState() {
|
|
const axisAreaWidths = /* @__PURE__ */ new Map();
|
|
if (this.lastAreaWidths) {
|
|
for (const { position = "left" } of this.axes) {
|
|
const areaWidth = this.lastAreaWidths.get(position);
|
|
if (areaWidth != null) {
|
|
axisAreaWidths.set(position, areaWidth);
|
|
}
|
|
}
|
|
}
|
|
return { axisAreaWidths, clipSeries: false, overflows: false };
|
|
}
|
|
isLayoutStable(newState, prevState) {
|
|
if (prevState.overflows !== newState.overflows || prevState.clipSeries !== newState.clipSeries) {
|
|
return false;
|
|
}
|
|
for (const key of newState.axisAreaWidths.keys()) {
|
|
if (!prevState.axisAreaWidths.has(key)) {
|
|
return false;
|
|
}
|
|
}
|
|
for (const [p, w] of prevState.axisAreaWidths.entries()) {
|
|
const otherW = newState.axisAreaWidths.get(p);
|
|
if ((w != null || otherW != null) && w !== otherW) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
clipAxis(axis, seriesRect, layoutBBox) {
|
|
const gridLinePadding = Math.ceil(axis.gridLine?.width ?? 0);
|
|
const axisLinePadding = Math.ceil(axis.line?.width ?? 0);
|
|
let { width, height } = seriesRect;
|
|
width += axis.direction === import_ag_charts_core235.ChartAxisDirection.X ? gridLinePadding : axisLinePadding;
|
|
height += axis.direction === import_ag_charts_core235.ChartAxisDirection.Y ? gridLinePadding : axisLinePadding;
|
|
axis.clipGrid(seriesRect.x, seriesRect.y, width, height);
|
|
switch (axis.position) {
|
|
case "left":
|
|
case "right":
|
|
axis.clipTickLines(
|
|
layoutBBox.x,
|
|
seriesRect.y - gridLinePadding,
|
|
layoutBBox.width + gridLinePadding,
|
|
seriesRect.height + gridLinePadding * 2
|
|
);
|
|
break;
|
|
case "top":
|
|
case "bottom":
|
|
axis.clipTickLines(
|
|
seriesRect.x - gridLinePadding,
|
|
layoutBBox.y,
|
|
seriesRect.width + gridLinePadding * 2,
|
|
layoutBBox.height + gridLinePadding
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
_CartesianChart.className = "CartesianChart";
|
|
_CartesianChart.type = "cartesian";
|
|
_CartesianChart.AxesPadding = 15;
|
|
__decorateClass([
|
|
(0, import_ag_charts_core235.ActionOnSet)({
|
|
changeValue(newValue, oldValue) {
|
|
this.onAxisChange(newValue, oldValue);
|
|
}
|
|
})
|
|
], _CartesianChart.prototype, "axes", 2);
|
|
var CartesianChart = _CartesianChart;
|
|
function getSize(isVertical, bounds) {
|
|
return isVertical ? bounds?.width : bounds?.height;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/cartesianChartModule.ts
|
|
var histogramAxisTypes = /* @__PURE__ */ new Set(["number", "log", "time"]);
|
|
var invalidHistogramAxis = (axis) => (0, import_ag_charts_core236.isObject)(axis) && axis.type != null && !histogramAxisTypes.has(axis.type);
|
|
var CartesianChartModule = {
|
|
type: "chart",
|
|
name: "cartesian",
|
|
version: VERSION,
|
|
options: cartesianChartOptionsDefs,
|
|
create(options, resources) {
|
|
return new CartesianChart(options, resources);
|
|
},
|
|
validate(options, optionsDefs4, path) {
|
|
const additionalErrors = [];
|
|
if (options?.series?.[0]?.type === "histogram") {
|
|
if (Object.values(options?.axes ?? {}).some(invalidHistogramAxis)) {
|
|
additionalErrors.push(
|
|
new import_ag_charts_core236.ValidationError(
|
|
"invalid",
|
|
"only continuous axis types when histogram series is used",
|
|
options.axes,
|
|
path,
|
|
"axes"
|
|
)
|
|
);
|
|
options = (0, import_ag_charts_core236.without)(options, ["axes"]);
|
|
}
|
|
}
|
|
const result = (0, import_ag_charts_core236.validate)(options, optionsDefs4, path);
|
|
result.invalid.push(...additionalErrors);
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/polarChartModule.ts
|
|
var import_ag_charts_core238 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/polarChart.ts
|
|
var import_ag_charts_core237 = require("ag-charts-core");
|
|
var PolarChart = class extends Chart {
|
|
constructor(options, resources) {
|
|
super(options, resources);
|
|
this.axes = this.createChartAxes();
|
|
this.padding = new import_ag_charts_core237.Padding(40);
|
|
this.ctx.axisManager.axisGroup.zIndex = import_ag_charts_core237.ZIndexMap.AXIS_FOREGROUND;
|
|
}
|
|
createChartAxes() {
|
|
return new PolarChartAxes();
|
|
}
|
|
getChartType() {
|
|
return "polar";
|
|
}
|
|
isDataTransactionSupported() {
|
|
return !this.series.some((s) => s.type === "pie" || s.type === "donut");
|
|
}
|
|
async performLayout(ctx) {
|
|
const seriesRect = ctx.layoutBox.clone().shrink(this.seriesArea.getPadding());
|
|
this.seriesRect = seriesRect;
|
|
this.animationRect = seriesRect;
|
|
this.seriesRoot.translationX = seriesRect.x;
|
|
this.seriesRoot.translationY = seriesRect.y;
|
|
await this.computeCircle(seriesRect);
|
|
for (const axis of this.axes) {
|
|
axis.update();
|
|
}
|
|
let maxMarkerSize = 0;
|
|
for (const series of this.series) {
|
|
maxMarkerSize = Math.max(maxMarkerSize, series.properties.marker?.size ?? 0);
|
|
}
|
|
for (const series of this.series.filter(isPolarSeries)) {
|
|
series.maxChartMarkerSize = maxMarkerSize;
|
|
}
|
|
this.ctx.layoutManager.emitLayoutComplete(ctx, {
|
|
series: { visible: true, rect: seriesRect, paddedRect: ctx.layoutBox }
|
|
});
|
|
}
|
|
updateAxes(seriesBox, cx, cy, radius) {
|
|
if (this.axes.length === 0)
|
|
return;
|
|
const angleAxis = this.axes[import_ag_charts_core237.ChartAxisDirection.Angle];
|
|
const radiusAxis = this.axes[import_ag_charts_core237.ChartAxisDirection.Radius];
|
|
const angleScale = angleAxis.scale;
|
|
const innerRadiusRatio = radiusAxis.innerRadiusRatio;
|
|
angleAxis.innerRadiusRatio = innerRadiusRatio;
|
|
angleAxis.computeRange();
|
|
angleAxis.gridLength = radius;
|
|
radiusAxis.gridAngles = angleScale.ticks({
|
|
nice: [angleAxis.nice, angleAxis.nice],
|
|
interval: void 0,
|
|
tickCount: void 0,
|
|
minTickCount: 0,
|
|
maxTickCount: Infinity
|
|
})?.ticks?.map((value) => angleScale.convert(value));
|
|
radiusAxis.gridRange = angleAxis.range;
|
|
radiusAxis.range = [radius, radius * innerRadiusRatio];
|
|
for (const axis of [angleAxis, radiusAxis]) {
|
|
axis.translation.x = seriesBox.x + cx;
|
|
axis.translation.y = seriesBox.y + cy;
|
|
axis.calculateLayout();
|
|
}
|
|
}
|
|
async computeCircle(seriesBox) {
|
|
const polarSeries = this.series.filter(isPolarSeries);
|
|
const setSeriesCircle = (cx, cy, r) => {
|
|
this.updateAxes(seriesBox, cx, cy, r);
|
|
for (const series of polarSeries) {
|
|
series.centerX = cx;
|
|
series.centerY = cy;
|
|
series.radius = r;
|
|
}
|
|
const pieSeries = polarSeries.filter((s) => s.type === "donut" || s.type === "pie");
|
|
if (pieSeries.length > 1) {
|
|
const innerRadii = pieSeries.map((series) => {
|
|
const innerRadius = series.getInnerRadius();
|
|
return { series, innerRadius };
|
|
}).sort((a, b) => a.innerRadius - b.innerRadius);
|
|
innerRadii.at(-1).series.surroundingRadius = void 0;
|
|
for (let i = 0; i < innerRadii.length - 1; i++) {
|
|
innerRadii[i].series.surroundingRadius = innerRadii[i + 1].innerRadius;
|
|
}
|
|
}
|
|
};
|
|
const centerX = seriesBox.width / 2;
|
|
const centerY = seriesBox.height / 2;
|
|
const initialRadius = Math.max(0, Math.min(seriesBox.width, seriesBox.height) / 2);
|
|
let radius = initialRadius;
|
|
setSeriesCircle(centerX, centerY, radius);
|
|
const shake = async ({ hideWhenNecessary = false } = {}) => {
|
|
const labelBoxes = [];
|
|
for (const series of (0, import_ag_charts_core237.iterate)(this.axes, polarSeries)) {
|
|
const box = await series.computeLabelsBBox({ hideWhenNecessary }, seriesBox);
|
|
if (box) {
|
|
labelBoxes.push(box);
|
|
}
|
|
}
|
|
if (labelBoxes.length === 0) {
|
|
setSeriesCircle(centerX, centerY, initialRadius);
|
|
return;
|
|
}
|
|
const labelBox = BBox.merge(labelBoxes);
|
|
const refined = this.refineCircle(labelBox, radius, seriesBox);
|
|
setSeriesCircle(refined.centerX, refined.centerY, refined.radius);
|
|
radius = refined.radius;
|
|
};
|
|
await shake();
|
|
await shake();
|
|
await shake();
|
|
await shake({ hideWhenNecessary: true });
|
|
await shake({ hideWhenNecessary: true });
|
|
for (const series of (0, import_ag_charts_core237.iterate)(this.axes, polarSeries)) {
|
|
await series.computeLabelsBBox({ hideWhenNecessary: true }, seriesBox);
|
|
}
|
|
return { radius, centerX, centerY };
|
|
}
|
|
refineCircle(labelsBox, radius, seriesBox) {
|
|
const minCircleRatio = 0.5;
|
|
const circleLeft = -radius;
|
|
const circleTop = -radius;
|
|
const circleRight = radius;
|
|
const circleBottom = radius;
|
|
let padLeft = Math.max(0, circleLeft - labelsBox.x);
|
|
let padTop = Math.max(0, circleTop - labelsBox.y);
|
|
let padRight = Math.max(0, labelsBox.x + labelsBox.width - circleRight);
|
|
let padBottom = Math.max(0, labelsBox.y + labelsBox.height - circleBottom);
|
|
padLeft = padRight = Math.max(padLeft, padRight);
|
|
padTop = padBottom = Math.max(padTop, padBottom);
|
|
const availCircleWidth = seriesBox.width - padLeft - padRight;
|
|
const availCircleHeight = seriesBox.height - padTop - padBottom;
|
|
let newRadius = Math.min(availCircleWidth, availCircleHeight) / 2;
|
|
const minHorizontalRadius = minCircleRatio * seriesBox.width / 2;
|
|
const minVerticalRadius = minCircleRatio * seriesBox.height / 2;
|
|
const minRadius = Math.min(minHorizontalRadius, minVerticalRadius);
|
|
if (newRadius < minRadius) {
|
|
newRadius = minRadius;
|
|
const horizontalPadding = padLeft + padRight;
|
|
const verticalPadding = padTop + padBottom;
|
|
if (2 * newRadius + verticalPadding > seriesBox.height) {
|
|
const padHeight = seriesBox.height - 2 * newRadius;
|
|
if (Math.min(padTop, padBottom) * 2 > padHeight) {
|
|
padTop = padHeight / 2;
|
|
padBottom = padHeight / 2;
|
|
} else if (padTop > padBottom) {
|
|
padTop = padHeight - padBottom;
|
|
} else {
|
|
padBottom = padHeight - padTop;
|
|
}
|
|
}
|
|
if (2 * newRadius + horizontalPadding > seriesBox.width) {
|
|
const padWidth = seriesBox.width - 2 * newRadius;
|
|
if (Math.min(padLeft, padRight) * 2 > padWidth) {
|
|
padLeft = padWidth / 2;
|
|
padRight = padWidth / 2;
|
|
} else if (padLeft > padRight) {
|
|
padLeft = padWidth - padRight;
|
|
} else {
|
|
padRight = padWidth - padLeft;
|
|
}
|
|
}
|
|
}
|
|
const newWidth = padLeft + 2 * newRadius + padRight;
|
|
const newHeight = padTop + 2 * newRadius + padBottom;
|
|
return {
|
|
centerX: (seriesBox.width - newWidth) / 2 + padLeft + newRadius,
|
|
centerY: (seriesBox.height - newHeight) / 2 + padTop + newRadius,
|
|
radius: newRadius
|
|
};
|
|
}
|
|
};
|
|
PolarChart.className = "PolarChart";
|
|
PolarChart.type = "polar";
|
|
function isPolarSeries(series) {
|
|
return series instanceof PolarSeries;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/polarChartModule.ts
|
|
var PolarChartModule = {
|
|
type: "chart",
|
|
name: "polar",
|
|
version: VERSION,
|
|
options: polarChartOptionsDefs,
|
|
create(options, resources) {
|
|
return new PolarChart(options, resources);
|
|
},
|
|
validate(options, optionsDefs4, path) {
|
|
const additionalErrors = [];
|
|
const baseType = options?.series?.[0]?.type;
|
|
if (baseType === "pie" || baseType === "donut") {
|
|
if (options?.axes) {
|
|
additionalErrors.push(new import_ag_charts_core238.UnknownError([], options.axes, path, "axes"));
|
|
options = (0, import_ag_charts_core238.without)(options, ["axes"]);
|
|
}
|
|
}
|
|
const result = (0, import_ag_charts_core238.validate)(options, optionsDefs4, path);
|
|
result.invalid.push(...additionalErrors);
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/legend/legendModule.ts
|
|
var import_ag_charts_core244 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/legend/legend.ts
|
|
var import_ag_charts_core243 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/gridLayout.ts
|
|
function gridLayout({
|
|
orientation,
|
|
bboxes,
|
|
maxHeight,
|
|
maxWidth,
|
|
itemPaddingY = 0,
|
|
itemPaddingX = 0,
|
|
forceResult = false
|
|
}) {
|
|
const horizontal = orientation === "horizontal";
|
|
const primary = {
|
|
max: horizontal ? maxWidth : maxHeight,
|
|
fn: horizontal ? (b) => b.width : (b) => b.height,
|
|
padding: horizontal ? itemPaddingX : itemPaddingY
|
|
};
|
|
const secondary = {
|
|
max: horizontal ? maxHeight : maxWidth,
|
|
fn: horizontal ? (b) => b.height : (b) => b.width,
|
|
padding: horizontal ? itemPaddingY : itemPaddingX
|
|
};
|
|
let processedBBoxCount = 0;
|
|
const rawPages = [];
|
|
while (processedBBoxCount < bboxes.length) {
|
|
const unprocessedBBoxes = bboxes.slice(processedBBoxCount);
|
|
const result = processBBoxes(unprocessedBBoxes, processedBBoxCount, primary, secondary, forceResult);
|
|
if (!result) {
|
|
return;
|
|
}
|
|
processedBBoxCount += result.processedBBoxCount;
|
|
rawPages.push(result.pageIndices);
|
|
}
|
|
return buildPages(rawPages, orientation, bboxes, itemPaddingY, itemPaddingX);
|
|
}
|
|
function processBBoxes(bboxes, indexOffset, primary, secondary, forceResult) {
|
|
const minGuess = 1;
|
|
let startingGuess = estimateStartingGuess(bboxes, primary);
|
|
if (startingGuess < minGuess) {
|
|
if (!forceResult) {
|
|
return;
|
|
}
|
|
startingGuess = minGuess;
|
|
}
|
|
let guess = startingGuess;
|
|
while (guess >= minGuess) {
|
|
const pageIndices = calculatePage(bboxes, indexOffset, guess, primary, secondary, forceResult);
|
|
if (pageIndices == null && guess <= minGuess) {
|
|
return;
|
|
}
|
|
if (pageIndices == null) {
|
|
guess--;
|
|
continue;
|
|
}
|
|
if (typeof pageIndices === "number") {
|
|
if (pageIndices <= minGuess) {
|
|
return;
|
|
}
|
|
guess = pageIndices < guess && pageIndices > minGuess ? pageIndices : guess;
|
|
guess--;
|
|
continue;
|
|
}
|
|
const processedBBoxCount = pageIndices.length * pageIndices[0].length;
|
|
return { processedBBoxCount, pageIndices };
|
|
}
|
|
}
|
|
function calculatePage(bboxes, indexOffset, primaryCount, primary, secondary, forceResult) {
|
|
const result = [];
|
|
let sumSecondary = 0;
|
|
let currentMaxSecondary = 0;
|
|
let currentPrimaryIndices = [];
|
|
const maxPrimaryValues = [];
|
|
for (let bboxIndex = 0; bboxIndex < bboxes.length; bboxIndex++) {
|
|
const primaryValueIdx = (bboxIndex + primaryCount) % primaryCount;
|
|
if (primaryValueIdx === 0) {
|
|
sumSecondary += currentMaxSecondary;
|
|
currentMaxSecondary = 0;
|
|
if (currentPrimaryIndices.length > 0) {
|
|
result.push(currentPrimaryIndices);
|
|
}
|
|
currentPrimaryIndices = [];
|
|
}
|
|
const primaryValue = primary.fn(bboxes[bboxIndex]) + primary.padding;
|
|
maxPrimaryValues[primaryValueIdx] = Math.max(maxPrimaryValues[primaryValueIdx] ?? 0, primaryValue);
|
|
currentMaxSecondary = Math.max(currentMaxSecondary, secondary.fn(bboxes[bboxIndex]) + secondary.padding);
|
|
const currentSecondaryDimension = sumSecondary + currentMaxSecondary;
|
|
const returnResult = !forceResult || result.length > 0;
|
|
if (currentSecondaryDimension > secondary.max && returnResult) {
|
|
currentPrimaryIndices = [];
|
|
break;
|
|
}
|
|
const sumPrimary = maxPrimaryValues.reduce((sum, next) => sum + next, 0);
|
|
if (sumPrimary > primary.max && !forceResult) {
|
|
if (maxPrimaryValues.length < primaryCount) {
|
|
return maxPrimaryValues.length;
|
|
}
|
|
return;
|
|
}
|
|
currentPrimaryIndices.push(bboxIndex + indexOffset);
|
|
}
|
|
if (currentPrimaryIndices.length > 0) {
|
|
result.push(currentPrimaryIndices);
|
|
}
|
|
return result.length > 0 ? result : void 0;
|
|
}
|
|
function buildPages(rawPages, orientation, bboxes, itemPaddingY, itemPaddingX) {
|
|
let maxPageWidth = 0;
|
|
let maxPageHeight = 0;
|
|
const pages = rawPages.map((indices) => {
|
|
if (orientation === "horizontal") {
|
|
indices = transpose(indices);
|
|
}
|
|
let endIndex = 0;
|
|
const columns = indices.map((colIndices) => {
|
|
const colBBoxes = colIndices.map((bboxIndex) => {
|
|
endIndex = Math.max(bboxIndex, endIndex);
|
|
return bboxes[bboxIndex];
|
|
});
|
|
let columnHeight = 0;
|
|
let columnWidth = 0;
|
|
for (const bbox of colBBoxes) {
|
|
columnHeight += bbox.height + itemPaddingY;
|
|
columnWidth = Math.max(columnWidth, bbox.width + itemPaddingX);
|
|
}
|
|
return {
|
|
indices: colIndices,
|
|
bboxes: colBBoxes,
|
|
columnHeight: Math.ceil(columnHeight),
|
|
columnWidth: Math.ceil(columnWidth)
|
|
};
|
|
});
|
|
let pageWidth = 0;
|
|
let pageHeight = 0;
|
|
for (const column of columns) {
|
|
pageWidth += column.columnWidth;
|
|
pageHeight = Math.max(pageHeight, column.columnHeight);
|
|
}
|
|
maxPageWidth = Math.max(pageWidth, maxPageWidth);
|
|
maxPageHeight = Math.max(pageHeight, maxPageHeight);
|
|
return {
|
|
columns,
|
|
startIndex: indices[0][0],
|
|
endIndex,
|
|
pageWidth,
|
|
pageHeight
|
|
};
|
|
});
|
|
return { pages, maxPageWidth, maxPageHeight };
|
|
}
|
|
function transpose(data) {
|
|
const result = [];
|
|
for (const _ of data[0]) {
|
|
result.push([]);
|
|
}
|
|
for (const [dataIdx, innerData] of data.entries()) {
|
|
for (const [itemIdx, item] of innerData.entries()) {
|
|
result[itemIdx][dataIdx] = item;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function estimateStartingGuess(bboxes, primary) {
|
|
const n = bboxes.length;
|
|
let primarySum = 0;
|
|
for (let bboxIndex = 0; bboxIndex < n; bboxIndex++) {
|
|
primarySum += primary.fn(bboxes[bboxIndex]) + primary.padding;
|
|
if (primarySum > primary.max) {
|
|
const ratio10 = n / bboxIndex;
|
|
if (ratio10 < 2) {
|
|
return Math.ceil(n / 2);
|
|
}
|
|
return bboxIndex;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/pagination/pagination.ts
|
|
var import_ag_charts_core239 = require("ag-charts-core");
|
|
var PaginationLabel = class extends import_ag_charts_core239.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.color = "black";
|
|
this.fontStyle = void 0;
|
|
this.fontWeight = void 0;
|
|
this.fontSize = import_ag_charts_core239.FONT_SIZE.SMALL;
|
|
this.fontFamily = "Verdana, sans-serif";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationLabel.prototype, "color", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationLabel.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationLabel.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationLabel.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationLabel.prototype, "fontFamily", 2);
|
|
var PaginationMarkerStyle = class extends import_ag_charts_core239.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.size = 15;
|
|
this.fill = void 0;
|
|
this.fillOpacity = void 0;
|
|
this.stroke = void 0;
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationMarkerStyle.prototype, "size", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationMarkerStyle.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationMarkerStyle.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationMarkerStyle.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationMarkerStyle.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationMarkerStyle.prototype, "strokeOpacity", 2);
|
|
var PaginationMarker = class extends import_ag_charts_core239.BaseProperties {
|
|
constructor(parent) {
|
|
super();
|
|
this.parent = parent;
|
|
this.shape = "triangle";
|
|
this.size = 15;
|
|
this.padding = 8;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core239.ActionOnSet)({
|
|
changeValue() {
|
|
if (this.parent.marker === this) {
|
|
this.parent.onMarkerShapeChange();
|
|
}
|
|
}
|
|
})
|
|
], PaginationMarker.prototype, "shape", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationMarker.prototype, "size", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], PaginationMarker.prototype, "padding", 2);
|
|
var Pagination = class extends import_ag_charts_core239.BaseProperties {
|
|
constructor(chartUpdateCallback, pageUpdateCallback) {
|
|
super();
|
|
this.chartUpdateCallback = chartUpdateCallback;
|
|
this.pageUpdateCallback = pageUpdateCallback;
|
|
this.id = (0, import_ag_charts_core239.createId)(this);
|
|
this.marker = new PaginationMarker(this);
|
|
this.activeStyle = new PaginationMarkerStyle();
|
|
this.inactiveStyle = new PaginationMarkerStyle();
|
|
this.highlightStyle = new PaginationMarkerStyle();
|
|
this.label = new PaginationLabel();
|
|
this.group = new TranslatableGroup({ name: "pagination" });
|
|
this.labelNode = new Text();
|
|
this.totalPages = 0;
|
|
this.currentPage = 0;
|
|
this.translationX = 0;
|
|
this.translationY = 0;
|
|
this.nextButtonDisabled = false;
|
|
this.previousButtonDisabled = false;
|
|
this._visible = true;
|
|
this._enabled = true;
|
|
this._orientation = "vertical";
|
|
this.nextButton = new Marker();
|
|
this.previousButton = new Marker();
|
|
this.labelNode.setProperties({
|
|
textBaseline: "middle",
|
|
fontSize: import_ag_charts_core239.FONT_SIZE.SMALL,
|
|
fontFamily: "Verdana, sans-serif",
|
|
fill: "black",
|
|
y: 1
|
|
});
|
|
this.group.append([this.nextButton, this.previousButton, this.labelNode]);
|
|
this.update();
|
|
this.updateMarkers();
|
|
}
|
|
set visible(value) {
|
|
this._visible = value;
|
|
this.updateGroupVisibility();
|
|
}
|
|
get visible() {
|
|
return this._visible;
|
|
}
|
|
set enabled(value) {
|
|
this._enabled = value;
|
|
this.updateGroupVisibility();
|
|
}
|
|
get enabled() {
|
|
return this._enabled;
|
|
}
|
|
updateGroupVisibility() {
|
|
this.group.visible = this.enabled && this.visible;
|
|
}
|
|
set orientation(value) {
|
|
this._orientation = value;
|
|
switch (value) {
|
|
case "horizontal": {
|
|
this.previousButton.rotation = -Math.PI / 2;
|
|
this.nextButton.rotation = Math.PI / 2;
|
|
break;
|
|
}
|
|
case "vertical":
|
|
default: {
|
|
this.previousButton.rotation = 0;
|
|
this.nextButton.rotation = Math.PI;
|
|
}
|
|
}
|
|
}
|
|
get orientation() {
|
|
return this._orientation;
|
|
}
|
|
update() {
|
|
this.updateLabel();
|
|
this.updatePositions();
|
|
this.enableOrDisableButtons();
|
|
}
|
|
updatePositions() {
|
|
this.group.translationX = this.translationX;
|
|
this.group.translationY = this.translationY;
|
|
this.updateLabelPosition();
|
|
this.updateNextButtonPosition();
|
|
}
|
|
updateLabelPosition() {
|
|
const { size: markerSize, padding: markerPadding } = this.marker;
|
|
this.nextButton.size = markerSize;
|
|
this.previousButton.size = markerSize;
|
|
this.labelNode.x = markerSize / 2 + markerPadding;
|
|
}
|
|
updateNextButtonPosition() {
|
|
const labelBBox = this.labelNode.getBBox();
|
|
this.nextButton.translationX = labelBBox.width + (this.marker.size / 2 + this.marker.padding) * 2;
|
|
}
|
|
updateLabel() {
|
|
const {
|
|
currentPage,
|
|
totalPages: pages,
|
|
labelNode,
|
|
label: { color: color8, fontStyle, fontWeight: fontWeight2, fontSize, fontFamily }
|
|
} = this;
|
|
labelNode.text = `${currentPage + 1} / ${pages}`;
|
|
labelNode.fill = color8;
|
|
labelNode.fontStyle = fontStyle;
|
|
labelNode.fontWeight = fontWeight2;
|
|
labelNode.fontSize = fontSize;
|
|
labelNode.fontFamily = fontFamily;
|
|
}
|
|
updateMarkers() {
|
|
const {
|
|
nextButton,
|
|
previousButton,
|
|
nextButtonDisabled,
|
|
previousButtonDisabled,
|
|
activeStyle,
|
|
inactiveStyle,
|
|
highlightStyle,
|
|
highlightActive
|
|
} = this;
|
|
const buttonStyle = (button, disabled) => {
|
|
if (disabled) {
|
|
return inactiveStyle;
|
|
} else if (button === highlightActive) {
|
|
return highlightStyle;
|
|
}
|
|
return activeStyle;
|
|
};
|
|
this.updateMarker(nextButton, buttonStyle("next", nextButtonDisabled));
|
|
this.updateMarker(previousButton, buttonStyle("previous", previousButtonDisabled));
|
|
}
|
|
updateMarker(marker, style) {
|
|
const { shape, size } = this.marker;
|
|
marker.shape = shape;
|
|
marker.size = size;
|
|
marker.fill = style.fill;
|
|
marker.fillOpacity = style.fillOpacity ?? 1;
|
|
marker.stroke = style.stroke;
|
|
marker.strokeWidth = style.strokeWidth;
|
|
marker.strokeOpacity = style.strokeOpacity;
|
|
}
|
|
enableOrDisableButtons() {
|
|
const { currentPage, totalPages } = this;
|
|
const zeroPagesToDisplay = totalPages === 0;
|
|
const onLastPage = currentPage === totalPages - 1;
|
|
const onFirstPage = currentPage === 0;
|
|
this.nextButtonDisabled = onLastPage || zeroPagesToDisplay;
|
|
this.previousButtonDisabled = onFirstPage || zeroPagesToDisplay;
|
|
}
|
|
setPage(pageNumber) {
|
|
pageNumber = (0, import_ag_charts_core239.clamp)(0, pageNumber, Math.max(0, this.totalPages - 1));
|
|
if (this.currentPage !== pageNumber) {
|
|
this.currentPage = pageNumber;
|
|
this.onPaginationChanged();
|
|
}
|
|
}
|
|
getCursor(node) {
|
|
return { previous: this.previousButtonDisabled, next: this.nextButtonDisabled }[node] ? void 0 : "pointer";
|
|
}
|
|
onClick(event, node) {
|
|
event.preventDefault();
|
|
if (node === "next" && !this.nextButtonDisabled) {
|
|
this.incrementPage();
|
|
this.onPaginationChanged();
|
|
} else if (node === "previous" && !this.previousButtonDisabled) {
|
|
this.decrementPage();
|
|
this.onPaginationChanged();
|
|
}
|
|
}
|
|
onMouseHover(node) {
|
|
this.highlightActive = node;
|
|
this.updateMarkers();
|
|
this.chartUpdateCallback(import_ag_charts_core239.ChartUpdateType.SCENE_RENDER);
|
|
}
|
|
onPaginationChanged() {
|
|
this.pageUpdateCallback(this.currentPage);
|
|
}
|
|
incrementPage() {
|
|
this.currentPage = Math.min(this.currentPage + 1, this.totalPages - 1);
|
|
}
|
|
decrementPage() {
|
|
this.currentPage = Math.max(this.currentPage - 1, 0);
|
|
}
|
|
onMarkerShapeChange() {
|
|
this.updatePositions();
|
|
this.updateMarkers();
|
|
this.chartUpdateCallback(import_ag_charts_core239.ChartUpdateType.SCENE_RENDER);
|
|
}
|
|
attachPagination(node) {
|
|
node.append(this.group);
|
|
}
|
|
getBBox() {
|
|
return this.group.getBBox();
|
|
}
|
|
computeCSSBounds() {
|
|
const prev = Transformable.toCanvas(this.previousButton);
|
|
const next = Transformable.toCanvas(this.nextButton);
|
|
return { prev, next };
|
|
}
|
|
};
|
|
Pagination.className = "Pagination";
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], Pagination.prototype, "marker", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], Pagination.prototype, "activeStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], Pagination.prototype, "inactiveStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], Pagination.prototype, "highlightStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core239.Property
|
|
], Pagination.prototype, "label", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/legend/legendDOMProxy.ts
|
|
var import_ag_charts_core240 = require("ag-charts-core");
|
|
var LegendDOMProxy = class {
|
|
constructor(ctx, idPrefix) {
|
|
this.dirty = true;
|
|
this.itemList = ctx.proxyInteractionService.createProxyContainer({
|
|
type: "list",
|
|
domManagerId: `${idPrefix}-toolbar`,
|
|
classList: ["ag-charts-proxy-legend-toolbar"],
|
|
ariaLabel: { id: "ariaLabelLegend" }
|
|
});
|
|
this.paginationGroup = ctx.proxyInteractionService.createProxyContainer({
|
|
type: "group",
|
|
domManagerId: `${idPrefix}-pagination`,
|
|
classList: ["ag-charts-proxy-legend-pagination"],
|
|
ariaLabel: { id: "ariaLabelLegendPagination" }
|
|
});
|
|
this.itemDescription = (0, import_ag_charts_core240.createElement)("p");
|
|
this.itemDescription.style.display = "none";
|
|
this.itemDescription.id = (0, import_ag_charts_core240.createElementId)();
|
|
this.itemDescription.textContent = this.getItemAriaDescription(ctx.localeManager);
|
|
this.itemList.getElement().append(this.itemDescription);
|
|
}
|
|
initLegendList(params) {
|
|
if (!this.dirty)
|
|
return;
|
|
const { ctx, itemSelection, datumReader, itemListener } = params;
|
|
const lm = ctx.localeManager;
|
|
const count = itemSelection.length;
|
|
itemSelection.each((markerLabel, datum, index) => {
|
|
markerLabel.proxyButton?.destroy();
|
|
markerLabel.proxyButton = ctx.proxyInteractionService.createProxyElement({
|
|
type: "listswitch",
|
|
textContent: this.getItemAriaText(lm, (0, import_ag_charts_core240.toPlainText)(datumReader.getItemLabel(datum)), index, count),
|
|
ariaChecked: !!markerLabel.datum.enabled,
|
|
ariaDescribedBy: this.itemDescription.id,
|
|
parent: this.itemList
|
|
});
|
|
const button = markerLabel.proxyButton;
|
|
button.addListener("click", (ev) => itemListener.onClick(ev.sourceEvent, markerLabel.datum, button));
|
|
button.addListener("dblclick", (ev) => itemListener.onDoubleClick(ev.sourceEvent, markerLabel.datum));
|
|
button.addListener("mouseenter", (ev) => itemListener.onHover(ev.sourceEvent, markerLabel));
|
|
button.addListener("mouseleave", () => itemListener.onLeave());
|
|
button.addListener("contextmenu", (ev) => itemListener.onContextClick(ev, markerLabel));
|
|
button.addListener("blur", () => itemListener.onLeave());
|
|
button.addListener("focus", (ev) => itemListener.onHover(ev.sourceEvent, markerLabel));
|
|
button.addListener("drag-start", () => {
|
|
});
|
|
});
|
|
this.dirty = false;
|
|
}
|
|
update(params) {
|
|
if (params.visible) {
|
|
this.initLegendList(params);
|
|
this.updateItemProxyButtons(params);
|
|
this.updatePaginationProxyButtons(params, true);
|
|
}
|
|
this.updateVisibility(params.visible);
|
|
}
|
|
updateVisibility(visible) {
|
|
this.itemList.setHidden(!visible);
|
|
this.paginationGroup.setHidden(!visible);
|
|
}
|
|
updateItemProxyButtons({ itemSelection, group, pagination, interactive }) {
|
|
const groupBBox = Transformable.toCanvas(group);
|
|
this.itemList.setBounds(groupBBox);
|
|
const maxHeight = Math.max(...itemSelection.nodes().map((l) => l.getTextMeasureBBox().height));
|
|
itemSelection.each((l, _datum) => {
|
|
if (l.proxyButton) {
|
|
const visible = l.pageIndex === pagination.currentPage;
|
|
const { x, y, height, width } = Transformable.toCanvas(l, l.getTextMeasureBBox());
|
|
const margin = (maxHeight - height) / 2;
|
|
const bbox = { x: x - groupBBox.x, y: y - margin - groupBBox.y, height: maxHeight, width };
|
|
const enabled = interactive && visible;
|
|
l.proxyButton.setCursor("pointer");
|
|
l.proxyButton.setEnabled(enabled);
|
|
l.proxyButton.setPointerEvents(enabled ? void 0 : "none");
|
|
l.proxyButton.setBounds(bbox);
|
|
}
|
|
});
|
|
}
|
|
updatePaginationProxyButtons(params, init) {
|
|
const { pagination } = params;
|
|
this.paginationGroup.setHidden(!pagination.visible);
|
|
if (init && "ctx" in params) {
|
|
const { oldPages, newPages } = params;
|
|
const oldNeedsButtons = (oldPages?.length ?? newPages.length) > 1;
|
|
const newNeedsButtons = newPages.length > 1;
|
|
if (oldNeedsButtons !== newNeedsButtons) {
|
|
if (newNeedsButtons) {
|
|
this.createPaginationButtons(params);
|
|
} else {
|
|
this.destroyPaginationButtons();
|
|
}
|
|
}
|
|
this.paginationGroup.setAriaHidden(newNeedsButtons ? void 0 : true);
|
|
}
|
|
if (this.prevButton && this.nextButton) {
|
|
const { prev, next } = pagination.computeCSSBounds();
|
|
const group = BBox.merge([prev, next]);
|
|
prev.x -= group.x;
|
|
prev.y -= group.y;
|
|
next.x -= group.x;
|
|
next.y -= group.y;
|
|
this.paginationGroup.setBounds(group);
|
|
this.prevButton.setBounds(prev);
|
|
this.nextButton.setBounds(next);
|
|
this.prevButton.setEnabled(pagination.currentPage !== 0);
|
|
this.nextButton.setEnabled(pagination.currentPage !== pagination.totalPages - 1);
|
|
this.nextButton.setCursor(pagination.getCursor("next"));
|
|
this.prevButton.setCursor(pagination.getCursor("previous"));
|
|
}
|
|
}
|
|
createPaginationButtons(params) {
|
|
const { ctx, pagination } = params;
|
|
if (!this.prevButton) {
|
|
this.prevButton = ctx.proxyInteractionService.createProxyElement({
|
|
type: "button",
|
|
textContent: { id: "ariaLabelLegendPagePrevious" },
|
|
tabIndex: 0,
|
|
parent: this.paginationGroup
|
|
});
|
|
this.prevButton.addListener("click", (ev) => this.onPageButton(params, ev, "previous"));
|
|
this.prevButton.addListener("mouseenter", () => pagination.onMouseHover("previous"));
|
|
this.prevButton.addListener("mouseleave", () => pagination.onMouseHover(void 0));
|
|
}
|
|
if (!this.nextButton) {
|
|
this.nextButton = ctx.proxyInteractionService.createProxyElement({
|
|
type: "button",
|
|
textContent: { id: "ariaLabelLegendPageNext" },
|
|
tabIndex: 0,
|
|
parent: this.paginationGroup
|
|
});
|
|
this.nextButton.addListener("click", (ev) => this.onPageButton(params, ev, "next"));
|
|
this.nextButton.addListener("mouseenter", () => pagination.onMouseHover("next"));
|
|
this.nextButton.addListener("mouseleave", () => pagination.onMouseHover(void 0));
|
|
}
|
|
}
|
|
destroyPaginationButtons() {
|
|
this.nextButton?.destroy();
|
|
this.prevButton?.destroy();
|
|
this.nextButton = void 0;
|
|
this.prevButton = void 0;
|
|
}
|
|
onPageButton(params, ev, node) {
|
|
params.pagination.onClick(ev.sourceEvent, node);
|
|
this.updatePaginationProxyButtons(params, false);
|
|
}
|
|
onDataUpdate(oldData, newData) {
|
|
this.dirty = oldData.length !== newData.length || oldData.some((_v, index, _a) => {
|
|
const [newValue, oldValue] = [newData[index], oldData[index]];
|
|
return newValue.id !== oldValue.id;
|
|
});
|
|
}
|
|
onLocaleChanged(localeManager, itemSelection, datumReader) {
|
|
const count = itemSelection.length;
|
|
itemSelection.each(({ proxyButton }, datum, index) => {
|
|
const button = proxyButton?.getElement();
|
|
if (button != null) {
|
|
const label = (0, import_ag_charts_core240.toPlainText)(datumReader.getItemLabel(datum));
|
|
button.textContent = this.getItemAriaText(localeManager, label, index, count);
|
|
}
|
|
});
|
|
this.itemDescription.textContent = this.getItemAriaDescription(localeManager);
|
|
}
|
|
onPageChange(params) {
|
|
this.updateItemProxyButtons(params);
|
|
this.updatePaginationProxyButtons(params, false);
|
|
}
|
|
getItemAriaText(localeManager, label, index, count) {
|
|
if (index >= 0 && label) {
|
|
index++;
|
|
return localeManager.t("ariaLabelLegendItem", { label, index, count });
|
|
}
|
|
return localeManager.t("ariaLabelLegendItemUnknown");
|
|
}
|
|
getItemAriaDescription(localeManager) {
|
|
return localeManager.t("ariaDescriptionLegendItem");
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/legend/legendEvent.ts
|
|
var import_ag_charts_core241 = require("ag-charts-core");
|
|
function makeLegendItemEvent(type, { itemId, seriesId, label: { text } }, event) {
|
|
const result = {
|
|
defaultPrevented: false,
|
|
apiEvent: {
|
|
type,
|
|
itemId,
|
|
// FIXME: AG-16068
|
|
seriesId,
|
|
event,
|
|
text: (0, import_ag_charts_core241.toPlainText)(text),
|
|
preventDefault: () => result.defaultPrevented = true
|
|
}
|
|
};
|
|
return result;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/legend/legendMarkerLabel.ts
|
|
var import_ag_charts_core242 = require("ag-charts-core");
|
|
var LegendMarkerLabel = class extends TranslatableGroup {
|
|
constructor() {
|
|
super({ name: "markerLabelGroup" });
|
|
this.symbolsGroup = this.appendChild(
|
|
new Group({
|
|
name: "legend-markerLabel-symbols",
|
|
renderToOffscreenCanvas: true,
|
|
optimizeForInfrequentRedraws: true
|
|
})
|
|
);
|
|
this.label = this.appendChild(new Text());
|
|
this.enabled = true;
|
|
this.pageIndex = Number.NaN;
|
|
this.spacing = 0;
|
|
this.length = 0;
|
|
this.isCustomMarker = false;
|
|
this.marker = this.symbolsGroup.appendChild(new Marker({ zIndex: 1 }));
|
|
this.line = this.symbolsGroup.appendChild(new Line({ zIndex: 0 }));
|
|
this.line.visible = false;
|
|
this.label.textBaseline = "middle";
|
|
this.label.y = 1;
|
|
}
|
|
destroy() {
|
|
super.destroy();
|
|
this.proxyButton?.destroy();
|
|
}
|
|
setEnabled(enabled) {
|
|
this.enabled = enabled;
|
|
this.refreshVisibilities();
|
|
}
|
|
getTextMeasureBBox() {
|
|
this.layout();
|
|
return BBox.merge([this.symbolsGroup.getBBox(), this.label.getTextMeasureBBox()]);
|
|
}
|
|
refreshVisibilities() {
|
|
const opacity = this.enabled ? 1 : 0.5;
|
|
this.label.opacity = opacity;
|
|
this.opacity = opacity;
|
|
}
|
|
layout() {
|
|
const { marker, line, length, isCustomMarker } = this;
|
|
let centerTranslateX = 0;
|
|
let centerTranslateY = 0;
|
|
if (marker.visible) {
|
|
const { size } = marker;
|
|
const anchor = Marker.anchor(marker.shape);
|
|
centerTranslateX = (anchor.x - 0.5) * size + length / 2;
|
|
centerTranslateY = (anchor.y - 0.5) * size;
|
|
if (isCustomMarker) {
|
|
marker.x = 0;
|
|
marker.y = 0;
|
|
marker.translationX = centerTranslateX;
|
|
marker.translationY = centerTranslateY;
|
|
} else {
|
|
marker.x = centerTranslateX;
|
|
marker.y = centerTranslateY;
|
|
marker.translationX = 0;
|
|
marker.translationY = 0;
|
|
}
|
|
}
|
|
if (line.visible) {
|
|
line.x1 = 0;
|
|
line.x2 = length;
|
|
line.y1 = 0;
|
|
line.y2 = 0;
|
|
}
|
|
}
|
|
preRender(renderCtx) {
|
|
const out = super.preRender(renderCtx);
|
|
this.layout();
|
|
return out;
|
|
}
|
|
layoutLabel() {
|
|
const { length, spacing } = this;
|
|
this.label.x = length + spacing;
|
|
}
|
|
computeBBox() {
|
|
this.layout();
|
|
return super.computeBBox();
|
|
}
|
|
};
|
|
LegendMarkerLabel.className = "MarkerLabel";
|
|
__decorateClass([
|
|
(0, import_ag_charts_core242.ProxyPropertyOnWrite)("label")
|
|
], LegendMarkerLabel.prototype, "text", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core242.ProxyPropertyOnWrite)("label")
|
|
], LegendMarkerLabel.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core242.ProxyPropertyOnWrite)("label")
|
|
], LegendMarkerLabel.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core242.ProxyPropertyOnWrite)("label")
|
|
], LegendMarkerLabel.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core242.ProxyPropertyOnWrite)("label")
|
|
], LegendMarkerLabel.prototype, "fontFamily", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core242.ProxyPropertyOnWrite)("label", "fill")
|
|
], LegendMarkerLabel.prototype, "color", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core242.ObserveChanges)((target) => target.layoutLabel())
|
|
], LegendMarkerLabel.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core242.ObserveChanges)((target) => target.layoutLabel())
|
|
], LegendMarkerLabel.prototype, "length", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core242.SceneChangeDetection)()
|
|
], LegendMarkerLabel.prototype, "isCustomMarker", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/legend/legend.ts
|
|
function toHighlightNodeDatum(series, legendDatum) {
|
|
switch (typeof legendDatum.itemId) {
|
|
case "number":
|
|
return {
|
|
series,
|
|
itemId: void 0,
|
|
datum: void 0,
|
|
datumIndex: legendDatum.itemId,
|
|
legendItemName: legendDatum.legendItemName
|
|
};
|
|
case "string":
|
|
return {
|
|
series,
|
|
itemId: legendDatum.itemId,
|
|
datum: void 0,
|
|
datumIndex: void 0,
|
|
legendItemName: legendDatum.legendItemName
|
|
};
|
|
default:
|
|
return legendDatum.itemId;
|
|
}
|
|
}
|
|
var LegendLabel = class extends import_ag_charts_core243.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.maxLength = void 0;
|
|
this.color = "black";
|
|
this.fontStyle = void 0;
|
|
this.fontWeight = void 0;
|
|
this.fontSize = import_ag_charts_core243.FONT_SIZE.SMALL;
|
|
this.fontFamily = "Verdana, sans-serif";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendLabel.prototype, "maxLength", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendLabel.prototype, "color", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendLabel.prototype, "fontStyle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendLabel.prototype, "fontWeight", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendLabel.prototype, "fontSize", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendLabel.prototype, "fontFamily", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendLabel.prototype, "formatter", 2);
|
|
var LegendMarker = class extends import_ag_charts_core243.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.shape = void 0;
|
|
this.size = 15;
|
|
this.padding = 8;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendMarker.prototype, "shape", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendMarker.prototype, "size", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendMarker.prototype, "padding", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendMarker.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendMarker.prototype, "enabled", 2);
|
|
var LegendLine = class extends import_ag_charts_core243.BaseProperties {
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendLine.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendLine.prototype, "length", 2);
|
|
var LegendItem = class extends import_ag_charts_core243.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.paddingX = 16;
|
|
this.paddingY = 8;
|
|
this.showSeriesStroke = false;
|
|
this.marker = new LegendMarker();
|
|
this.label = new LegendLabel();
|
|
this.line = new LegendLine();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendItem.prototype, "maxWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendItem.prototype, "paddingX", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendItem.prototype, "paddingY", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendItem.prototype, "showSeriesStroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendItem.prototype, "marker", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendItem.prototype, "label", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendItem.prototype, "line", 2);
|
|
var LegendListeners = class extends import_ag_charts_core243.BaseProperties {
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendListeners.prototype, "legendItemClick", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], LegendListeners.prototype, "legendItemDoubleClick", 2);
|
|
var fillGradientDefaults = {
|
|
type: "gradient",
|
|
bounds: "item",
|
|
gradient: "linear",
|
|
colorStops: [{ color: "black" }],
|
|
rotation: 0,
|
|
reverse: false,
|
|
colorSpace: "rgb"
|
|
};
|
|
var fillPatternDefaults = {
|
|
type: "pattern",
|
|
pattern: "forward-slanted-lines",
|
|
width: 8,
|
|
height: 8,
|
|
padding: 1,
|
|
fill: "black",
|
|
fillOpacity: 1,
|
|
backgroundFill: "white",
|
|
backgroundFillOpacity: 1,
|
|
stroke: "black",
|
|
strokeOpacity: 1,
|
|
strokeWidth: 1,
|
|
rotation: 0,
|
|
scale: 1
|
|
};
|
|
var fillImageDefaults = {
|
|
type: "image",
|
|
backgroundFill: "black",
|
|
backgroundFillOpacity: 1,
|
|
rotation: 0,
|
|
repeat: "no-repeat",
|
|
fit: "contain",
|
|
width: 8,
|
|
height: 8
|
|
};
|
|
var Legend = class extends import_ag_charts_core243.BaseProperties {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.id = (0, import_ag_charts_core243.createId)(this);
|
|
this.group = new TranslatableGroup({ name: "legend", zIndex: import_ag_charts_core243.ZIndexMap.LEGEND });
|
|
this.itemSelection = Selection.select(
|
|
this.group,
|
|
LegendMarkerLabel
|
|
);
|
|
this.containerNode = this.group.appendChild(new Rect({ name: "legend-container" }));
|
|
this.oldSize = [0, 0];
|
|
this.pages = [];
|
|
this.maxPageSize = [0, 0];
|
|
/** Item index to track on re-pagination, so current page updates appropriately. */
|
|
this.paginationTrackingIndex = 0;
|
|
this.truncatedItems = /* @__PURE__ */ new Set();
|
|
this._data = [];
|
|
this.toggleSeries = true;
|
|
this.item = new LegendItem();
|
|
this.listeners = new LegendListeners();
|
|
this.enabled = false;
|
|
this.position = "bottom";
|
|
this.border = new import_ag_charts_core243.Border(this.containerNode);
|
|
this.cornerRadius = 0;
|
|
this.fillOpacity = 1;
|
|
this.padding = 4;
|
|
this.spacing = 0;
|
|
this.cleanup = new import_ag_charts_core243.CleanupRegistry();
|
|
this.size = [0, 0];
|
|
this._visible = true;
|
|
this.pagination = new Pagination(
|
|
(type) => ctx.updateService.update(type),
|
|
(page) => this.updatePageNumber(page)
|
|
);
|
|
this.pagination.attachPagination(this.group);
|
|
const { items } = ctx.contextMenuRegistry.builtins;
|
|
items["toggle-series-visibility"].action = (params) => this.contextToggleVisibility(params);
|
|
items["toggle-other-series"].action = (params) => this.contextToggleOtherSeries(params);
|
|
this.cleanup.register(
|
|
ctx.eventsHub.on("active:load-memento", (event) => this.onActiveLoadMemento(event)),
|
|
ctx.eventsHub.on("active:update", (event) => this.onActiveUpdate(event)),
|
|
ctx.eventsHub.on("legend:change", this.onLegendDataChange.bind(this)),
|
|
ctx.eventsHub.on("legend:change-partial", this.onLegendDataChangePartial.bind(this)),
|
|
ctx.layoutManager.registerElement(1 /* Legend */, (e) => this.positionLegend(e)),
|
|
ctx.eventsHub.on("locale:change", () => this.onLocaleChanged()),
|
|
() => delete items["toggle-series-visibility"].action,
|
|
() => delete items["toggle-other-series"].action,
|
|
() => this.group.remove()
|
|
);
|
|
this.domProxy = new LegendDOMProxy(this.ctx, this.id);
|
|
this.ctx.historyManager.addMementoOriginator(ctx.legendManager);
|
|
}
|
|
set data(value) {
|
|
if ((0, import_ag_charts_core243.objectsEqual)(value, this._data))
|
|
return;
|
|
this.domProxy.onDataUpdate(this._data, value);
|
|
this._data = value;
|
|
this.updateGroupVisibility();
|
|
}
|
|
get data() {
|
|
return this._data;
|
|
}
|
|
onLegendDataChange({ legendData = [] }) {
|
|
if (!this.enabled)
|
|
return;
|
|
this.data = legendData.filter((datum) => !datum.hideInLegend);
|
|
}
|
|
onLegendDataChangePartial(event) {
|
|
this.itemSelection.each(({ proxyButton }, { itemId }) => {
|
|
if (proxyButton == null)
|
|
return;
|
|
for (const eventElem of event.legendData) {
|
|
if (eventElem.itemId === itemId) {
|
|
proxyButton.setChecked(eventElem.enabled);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
destroy() {
|
|
this.ctx.domManager.removeChild("canvas-overlay", `${this.id}-toolbar`);
|
|
this.ctx.domManager.removeChild("canvas-overlay", `${this.id}-pagination`);
|
|
this.cleanup.flush();
|
|
this.itemSelection.clear();
|
|
}
|
|
getOrientation() {
|
|
return this.orientation ?? "horizontal";
|
|
}
|
|
set visible(value) {
|
|
this._visible = value;
|
|
this.updateGroupVisibility();
|
|
}
|
|
get visible() {
|
|
return this._visible;
|
|
}
|
|
updateGroupVisibility() {
|
|
this.group.visible = this.enabled && this.visible && this.data.length > 0;
|
|
}
|
|
updateItemSelection() {
|
|
const data = [...this.data];
|
|
if (this.reverseOrder) {
|
|
data.reverse();
|
|
}
|
|
this.itemSelection.update(data);
|
|
}
|
|
isInteractive() {
|
|
const {
|
|
toggleSeries,
|
|
listeners: { legendItemClick, legendItemDoubleClick }
|
|
} = this;
|
|
return toggleSeries || legendItemDoubleClick != null || legendItemClick != null;
|
|
}
|
|
checkInteractionState() {
|
|
return this.ctx.interactionManager.isState(1 /* Frozen */);
|
|
}
|
|
attachLegend(scene) {
|
|
scene.appendChild(this.group);
|
|
}
|
|
getItemLabel(datum) {
|
|
const { formatter } = this.item.label;
|
|
if (formatter) {
|
|
const seriesDatum = datum.datum;
|
|
return this.cachedCallWithContext(formatter, {
|
|
itemId: datum.itemId,
|
|
value: datum.label.text,
|
|
seriesId: datum.seriesId,
|
|
...seriesDatum && { datum: seriesDatum }
|
|
});
|
|
}
|
|
return datum.label.text;
|
|
}
|
|
/**
|
|
* The method is given the desired size of the legend, which only serves as a hint.
|
|
* The vertically oriented legend will take as much horizontal space as needed, but will
|
|
* respect the height constraints, and the horizontal legend will take as much vertical
|
|
* space as needed in an attempt not to exceed the given width.
|
|
* After the layout is done, the {@link size} will contain the actual size of the legend.
|
|
* If the actual size is not the same as the previous actual size, the legend will fire
|
|
* the 'layoutChange' event to communicate that another layout is needed, and the above
|
|
* process should be repeated.
|
|
* @param width
|
|
* @param height
|
|
*/
|
|
calcLayout(width, height) {
|
|
const {
|
|
paddingX,
|
|
paddingY,
|
|
label,
|
|
maxWidth,
|
|
label: { maxLength = Infinity, fontStyle, fontWeight: fontWeight2, fontSize, fontFamily }
|
|
} = this.item;
|
|
this.updateItemSelection();
|
|
const bboxes = [];
|
|
const measurer = (0, import_ag_charts_core243.cachedTextMeasurer)(label);
|
|
const itemMaxWidthPercentage = 0.8;
|
|
const maxItemWidth = maxWidth ?? width * itemMaxWidthPercentage;
|
|
const { markerWidth, anyLineEnabled } = this.calculateMarkerWidth();
|
|
this.itemSelection.each((markerLabel, datum) => {
|
|
markerLabel.fontStyle = fontStyle;
|
|
markerLabel.fontWeight = fontWeight2;
|
|
markerLabel.fontSize = fontSize;
|
|
markerLabel.fontFamily = fontFamily;
|
|
const paddedSymbolWidth = this.updateMarkerLabel(markerLabel, datum, markerWidth, anyLineEnabled);
|
|
const id = datum.itemId ?? datum.id;
|
|
const labelText = this.getItemLabel(datum);
|
|
const text = (0, import_ag_charts_core243.toPlainText)(labelText, "<unknown>").replace(import_ag_charts_core243.LineSplitter, " ");
|
|
markerLabel.text = this.truncate(text, maxLength, maxItemWidth, paddedSymbolWidth, measurer, id);
|
|
bboxes.push(markerLabel.getTextMeasureBBox());
|
|
});
|
|
width = Math.max(1, width);
|
|
height = Math.max(1, height);
|
|
if (!Number.isFinite(width)) {
|
|
return {};
|
|
}
|
|
[width, height] = this.updateContainer(width, height);
|
|
const size = this.size;
|
|
const oldSize = this.oldSize;
|
|
size[0] = width;
|
|
size[1] = height;
|
|
if (size[0] !== oldSize[0] || size[1] !== oldSize[1]) {
|
|
oldSize[0] = size[0];
|
|
oldSize[1] = size[1];
|
|
}
|
|
const { pages, maxPageHeight, maxPageWidth } = this.updatePagination(bboxes, width, height);
|
|
const oldPages = this.pages;
|
|
this.pages = pages;
|
|
this.maxPageSize = [maxPageWidth - paddingX, maxPageHeight - paddingY];
|
|
const pageNumber = this.pagination.currentPage;
|
|
const page = this.pages[pageNumber];
|
|
if (this.pages.length < 1 || !page) {
|
|
this.visible = false;
|
|
return { oldPages };
|
|
}
|
|
this.visible = true;
|
|
this.updatePositions(pageNumber);
|
|
this.update();
|
|
return { oldPages };
|
|
}
|
|
isCustomMarker(markerEnabled2, shape) {
|
|
return markerEnabled2 && shape !== void 0 && typeof shape !== "string";
|
|
}
|
|
calcSymbolsEnabled(symbol) {
|
|
const { showSeriesStroke, marker } = this.item;
|
|
const markerEnabled2 = !!marker.enabled || !showSeriesStroke || (symbol.marker.enabled ?? true);
|
|
const lineEnabled = !!(symbol.line && showSeriesStroke);
|
|
const isCustomMarker = this.isCustomMarker(markerEnabled2, symbol.marker.shape);
|
|
return { markerEnabled: markerEnabled2, lineEnabled, isCustomMarker };
|
|
}
|
|
calcSymbolsLengths(symbol, markerEnabled2, lineEnabled) {
|
|
const { marker, line } = this.item;
|
|
let customMarkerSize;
|
|
const { shape } = symbol.marker;
|
|
if (this.isCustomMarker(markerEnabled2, shape)) {
|
|
const tmpShape = new Marker();
|
|
tmpShape.shape = shape;
|
|
tmpShape.updatePath();
|
|
const bbox = tmpShape.getBBox();
|
|
customMarkerSize = Math.max(bbox.width, bbox.height);
|
|
}
|
|
const markerLength = markerEnabled2 ? marker.size : 0;
|
|
const lineLength = lineEnabled ? line.length ?? 25 : 0;
|
|
return { markerLength, lineLength, customMarkerSize };
|
|
}
|
|
calculateMarkerWidth() {
|
|
let markerWidth = 0;
|
|
let anyLineEnabled = false;
|
|
this.itemSelection.each((_, datum) => {
|
|
const { symbol } = datum;
|
|
const { lineEnabled, markerEnabled: markerEnabled2 } = this.calcSymbolsEnabled(symbol);
|
|
const {
|
|
markerLength,
|
|
lineLength,
|
|
customMarkerSize = -Infinity
|
|
} = this.calcSymbolsLengths(symbol, markerEnabled2, lineEnabled);
|
|
markerWidth = Math.max(markerWidth, lineLength, customMarkerSize, markerLength);
|
|
anyLineEnabled || (anyLineEnabled = lineEnabled);
|
|
});
|
|
return { markerWidth, anyLineEnabled };
|
|
}
|
|
updateMarkerLabel(markerLabel, datum, markerWidth, anyLineEnabled) {
|
|
const { marker: itemMarker, paddingX } = this.item;
|
|
const { symbol } = datum;
|
|
let paddedSymbolWidth = paddingX;
|
|
const { markerEnabled: markerEnabled2, isCustomMarker } = this.calcSymbolsEnabled(symbol);
|
|
const spacing = itemMarker.padding;
|
|
if (markerEnabled2 || anyLineEnabled) {
|
|
paddedSymbolWidth += spacing + markerWidth;
|
|
}
|
|
const { marker, line } = markerLabel;
|
|
marker.visible = markerEnabled2;
|
|
if (marker.visible) {
|
|
marker.shape = itemMarker.shape ?? symbol.marker.shape ?? "square";
|
|
marker.size = itemMarker.size;
|
|
marker.setStyleProperties(this.getMarkerStyles((0, import_ag_charts_core243.deepClone)(symbol)));
|
|
}
|
|
line.visible = anyLineEnabled;
|
|
if (line.visible) {
|
|
line.setStyleProperties(this.getLineStyles(symbol));
|
|
}
|
|
markerLabel.length = markerWidth;
|
|
markerLabel.spacing = spacing;
|
|
markerLabel.isCustomMarker = isCustomMarker;
|
|
return paddedSymbolWidth;
|
|
}
|
|
updateContainer(width, height) {
|
|
const containerStyles = this.getContainerStyles();
|
|
this.containerNode.width = 0;
|
|
this.containerNode.height = 0;
|
|
this.containerNode.setStyleProperties(containerStyles);
|
|
this.containerNode.cornerRadius = containerStyles.cornerRadius;
|
|
width -= containerStyles.strokeWidth * 2 + containerStyles.padding.left + containerStyles.padding.right;
|
|
height -= containerStyles.strokeWidth * 2 + containerStyles.padding.top + containerStyles.padding.bottom;
|
|
return [width, height];
|
|
}
|
|
truncate(text, maxCharLength, maxItemWidth, paddedMarkerWidth, measurer, id) {
|
|
let addEllipsis = false;
|
|
if (text.length > maxCharLength) {
|
|
text = text.substring(0, maxCharLength);
|
|
addEllipsis = true;
|
|
}
|
|
const result = (0, import_ag_charts_core243.truncateLine)(text, measurer, maxItemWidth - paddedMarkerWidth, addEllipsis);
|
|
if ((0, import_ag_charts_core243.isTextTruncated)(result)) {
|
|
this.truncatedItems.add(id);
|
|
} else {
|
|
this.truncatedItems.delete(id);
|
|
}
|
|
return result;
|
|
}
|
|
updatePagination(bboxes, width, height) {
|
|
const orientation = this.getOrientation();
|
|
const trackingIndex = Math.min(this.paginationTrackingIndex, bboxes.length);
|
|
this.pagination.orientation = orientation;
|
|
this.pagination.translationX = 0;
|
|
this.pagination.translationY = 0;
|
|
const { pages, maxPageHeight, maxPageWidth, paginationBBox, paginationVertical } = this.calculatePagination(
|
|
bboxes,
|
|
width,
|
|
height
|
|
);
|
|
const newCurrentPage = pages.findIndex((p) => p.endIndex >= trackingIndex);
|
|
this.pagination.currentPage = (0, import_ag_charts_core243.clamp)(0, newCurrentPage, pages.length - 1);
|
|
const { paddingX: itemPaddingX, paddingY: itemPaddingY } = this.item;
|
|
const paginationComponentPadding = 8;
|
|
const legendItemsWidth = maxPageWidth - itemPaddingX;
|
|
const legendItemsHeight = maxPageHeight - itemPaddingY;
|
|
let paginationX = 0;
|
|
let paginationY = -paginationBBox.y - this.item.marker.size / 2;
|
|
if (paginationVertical) {
|
|
paginationY += legendItemsHeight + paginationComponentPadding;
|
|
} else {
|
|
paginationX += -paginationBBox.x + legendItemsWidth + paginationComponentPadding;
|
|
paginationY += (legendItemsHeight - paginationBBox.height) / 2;
|
|
}
|
|
this.pagination.translationX = paginationX;
|
|
this.pagination.translationY = paginationY;
|
|
this.pagination.update();
|
|
this.pagination.updateMarkers();
|
|
let pageIndex = 0;
|
|
this.itemSelection.each((markerLabel, _, nodeIndex) => {
|
|
if (nodeIndex > (pages[pageIndex]?.endIndex ?? Infinity)) {
|
|
pageIndex++;
|
|
}
|
|
markerLabel.pageIndex = pageIndex;
|
|
});
|
|
return {
|
|
maxPageHeight,
|
|
maxPageWidth,
|
|
pages
|
|
};
|
|
}
|
|
calculatePagination(bboxes, width, height) {
|
|
const { paddingX: itemPaddingX, paddingY: itemPaddingY } = this.item;
|
|
const vertPositions = [
|
|
"left",
|
|
"left-top",
|
|
"left-bottom",
|
|
"right",
|
|
"right-top",
|
|
"right-bottom"
|
|
];
|
|
const { placement } = (0, import_ag_charts_core243.expandLegendPosition)(this.position);
|
|
const orientation = this.getOrientation();
|
|
const paginationVertical = vertPositions.includes(placement);
|
|
let paginationBBox = this.pagination.getBBox();
|
|
let lastPassPaginationBBox = new BBox(0, 0, 0, 0);
|
|
let pages = [];
|
|
let maxPageWidth = 0;
|
|
let maxPageHeight = 0;
|
|
let count = 0;
|
|
const stableOutput = (bbox) => {
|
|
return bbox.width === paginationBBox.width && bbox.height === paginationBBox.height;
|
|
};
|
|
const forceResult = this.maxWidth !== void 0 && this.maxHeight !== void 0;
|
|
do {
|
|
if (count++ > 10) {
|
|
import_ag_charts_core243.Logger.warn("unable to find stable legend layout.");
|
|
break;
|
|
}
|
|
paginationBBox = lastPassPaginationBBox;
|
|
const maxWidth = width - (paginationVertical ? 0 : paginationBBox.width);
|
|
const maxHeight = height - (paginationVertical ? paginationBBox.height : 0);
|
|
const layout = gridLayout({
|
|
orientation,
|
|
bboxes,
|
|
maxHeight,
|
|
maxWidth,
|
|
itemPaddingY,
|
|
itemPaddingX,
|
|
forceResult
|
|
});
|
|
pages = layout?.pages ?? [];
|
|
maxPageWidth = layout?.maxPageWidth ?? 0;
|
|
maxPageHeight = layout?.maxPageHeight ?? 0;
|
|
const totalPages = pages.length;
|
|
this.pagination.visible = totalPages > 1;
|
|
this.pagination.totalPages = totalPages;
|
|
this.pagination.update();
|
|
this.pagination.updateMarkers();
|
|
lastPassPaginationBBox = this.pagination.getBBox();
|
|
if (!this.pagination.visible) {
|
|
break;
|
|
}
|
|
} while (!stableOutput(lastPassPaginationBBox));
|
|
return { maxPageWidth, maxPageHeight, pages, paginationBBox: lastPassPaginationBBox, paginationVertical };
|
|
}
|
|
updatePositions(pageNumber = 0) {
|
|
const {
|
|
item: { paddingY },
|
|
itemSelection,
|
|
pages
|
|
} = this;
|
|
if (pages.length < 1 || !pages[pageNumber]) {
|
|
return;
|
|
}
|
|
const { columns, startIndex: visibleStart, endIndex: visibleEnd } = pages[pageNumber];
|
|
let x = 0;
|
|
let y = 0;
|
|
const columnCount = columns.length;
|
|
const rowCount = columns[0].indices.length;
|
|
const horizontal = this.getOrientation() === "horizontal";
|
|
const itemHeight = columns[0].bboxes[0].height + paddingY;
|
|
const rowSumColumnWidths = [];
|
|
itemSelection.each((markerLabel, _, i) => {
|
|
if (i < visibleStart || i > visibleEnd) {
|
|
markerLabel.visible = false;
|
|
return;
|
|
}
|
|
const pageIndex = i - visibleStart;
|
|
let columnIndex;
|
|
let rowIndex;
|
|
if (horizontal) {
|
|
columnIndex = pageIndex % columnCount;
|
|
rowIndex = Math.floor(pageIndex / columnCount);
|
|
} else {
|
|
columnIndex = Math.floor(pageIndex / rowCount);
|
|
rowIndex = pageIndex % rowCount;
|
|
}
|
|
markerLabel.visible = true;
|
|
const column = columns[columnIndex];
|
|
if (!column) {
|
|
return;
|
|
}
|
|
y = Math.floor(itemHeight * rowIndex);
|
|
x = Math.floor(rowSumColumnWidths[rowIndex] ?? 0);
|
|
rowSumColumnWidths[rowIndex] = (rowSumColumnWidths[rowIndex] ?? 0) + column.columnWidth;
|
|
markerLabel.translationX = x;
|
|
markerLabel.translationY = y;
|
|
});
|
|
}
|
|
updatePageNumber(pageNumber) {
|
|
const { itemSelection, group, pagination, pages } = this;
|
|
const { startIndex, endIndex } = pages[pageNumber];
|
|
if (startIndex === 0) {
|
|
this.paginationTrackingIndex = 0;
|
|
} else if (pageNumber === pages.length - 1) {
|
|
this.paginationTrackingIndex = endIndex;
|
|
} else {
|
|
this.paginationTrackingIndex = Math.floor((startIndex + endIndex) / 2);
|
|
}
|
|
this.pagination.update();
|
|
this.pagination.updateMarkers();
|
|
this.updatePositions(pageNumber);
|
|
this.domProxy.onPageChange({ itemSelection, group, pagination, interactive: this.isInteractive() });
|
|
this.ctx.updateService.update(import_ag_charts_core243.ChartUpdateType.SCENE_RENDER);
|
|
}
|
|
update() {
|
|
const {
|
|
label: { color: color8 }
|
|
} = this.item;
|
|
this.itemSelection.each((markerLabel, datum) => {
|
|
markerLabel.setEnabled(datum.enabled);
|
|
markerLabel.color = color8;
|
|
});
|
|
this.updateContextMenu();
|
|
}
|
|
updateContextMenu() {
|
|
const action = this.toggleSeries ? "show" : "hide";
|
|
this.ctx.contextMenuRegistry.toggle("toggle-series-visibility", action);
|
|
this.ctx.contextMenuRegistry.toggle("toggle-other-series", action);
|
|
}
|
|
getLineStyles(datum) {
|
|
const { stroke, strokeOpacity = 1, strokeWidth, lineDash } = datum.line ?? {};
|
|
const defaultLineStrokeWidth = Math.min(2, strokeWidth ?? 1);
|
|
return {
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth: this.item.line.strokeWidth ?? defaultLineStrokeWidth,
|
|
lineDash
|
|
};
|
|
}
|
|
getMarkerStyles({ marker }) {
|
|
const { fill, stroke, strokeOpacity = 1, fillOpacity = 1, strokeWidth, lineDash, lineDashOffset } = marker;
|
|
const defaultLineStrokeWidth = Math.min(2, strokeWidth ?? 1);
|
|
if ((0, import_ag_charts_core243.isPatternFill)(fill)) {
|
|
fill.width = 8;
|
|
fill.height = 8;
|
|
fill.padding = 1;
|
|
fill.strokeWidth = Math.min(2, fill.strokeWidth ?? 2);
|
|
}
|
|
if ((0, import_ag_charts_core243.isImageFill)(fill)) {
|
|
fill.fit = "contain";
|
|
fill.width = void 0;
|
|
fill.height = void 0;
|
|
fill.repeat = "no-repeat";
|
|
}
|
|
return getShapeStyle(
|
|
{
|
|
fill,
|
|
stroke,
|
|
strokeOpacity,
|
|
fillOpacity,
|
|
strokeWidth: this.item.marker.strokeWidth ?? defaultLineStrokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
},
|
|
fillGradientDefaults,
|
|
fillPatternDefaults,
|
|
fillImageDefaults
|
|
);
|
|
}
|
|
getContainerStyles() {
|
|
const { stroke, strokeOpacity, strokeWidth } = this.border;
|
|
const { cornerRadius, fill, fillOpacity, padding: padding2 } = this;
|
|
const isPaddingNumber = typeof padding2 === "number";
|
|
return getShapeStyle(
|
|
{
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
padding: {
|
|
top: isPaddingNumber ? padding2 : padding2.top ?? 0,
|
|
right: isPaddingNumber ? padding2 : padding2.right ?? 0,
|
|
bottom: isPaddingNumber ? padding2 : padding2.bottom ?? 0,
|
|
left: isPaddingNumber ? padding2 : padding2.left ?? 0
|
|
},
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth: this.border.enabled ? strokeWidth : 0
|
|
},
|
|
fillGradientDefaults,
|
|
fillPatternDefaults,
|
|
fillImageDefaults
|
|
);
|
|
}
|
|
computePagedBBox() {
|
|
const actualBBox = Group.computeChildrenBBox(this.group.excludeChildren({ name: "legend-container" }));
|
|
if (this.pages.length > 1) {
|
|
const [maxPageWidth, maxPageHeight] = this.maxPageSize;
|
|
actualBBox.height = Math.max(maxPageHeight, actualBBox.height);
|
|
actualBBox.width = Math.max(maxPageWidth, actualBBox.width);
|
|
}
|
|
const { strokeWidth, padding: padding2 } = this.getContainerStyles();
|
|
actualBBox.grow(padding2).grow(strokeWidth);
|
|
return actualBBox;
|
|
}
|
|
findNode(params) {
|
|
const { datum, proxyButton } = this.itemSelection.select((ml) => ml.datum?.itemId === params.itemId)[0] ?? {};
|
|
if (datum === void 0 || proxyButton === void 0) {
|
|
throw new Error(
|
|
`AG Charts - Missing required properties { datum: ${datum}, proxyButton: ${JSON.stringify(proxyButton)} }`
|
|
);
|
|
}
|
|
return { datum, proxyButton };
|
|
}
|
|
contextToggleVisibility(params) {
|
|
const { datum, proxyButton } = this.findNode(params);
|
|
this.doClick(params.event, datum, proxyButton);
|
|
this.clearHighlight();
|
|
}
|
|
contextToggleOtherSeries(params) {
|
|
this.doDoubleClick(params.event, this.findNode(params).datum);
|
|
this.clearHighlight();
|
|
}
|
|
onContextClick(widgetEvent, node) {
|
|
if (this.checkInteractionState())
|
|
return;
|
|
const { sourceEvent } = widgetEvent;
|
|
const legendItem = node.datum;
|
|
this.clearHighlight();
|
|
if (this.preventHidingAll && this.contextMenuDatum?.enabled && this.getVisibleItemCount() <= 1) {
|
|
this.ctx.contextMenuRegistry.builtins.items["toggle-series-visibility"].enabled = false;
|
|
} else {
|
|
this.ctx.contextMenuRegistry.builtins.items["toggle-series-visibility"].enabled = true;
|
|
}
|
|
const toggleOtherSeriesVisible = this.ctx.chartService.series.length > 1 && this.ctx.chartService.series[0]?.getLegendData("category")[0]?.hideToggleOtherSeries !== true;
|
|
const action = toggleOtherSeriesVisible ? "show" : "hide";
|
|
this.ctx.contextMenuRegistry.toggle("toggle-other-series", action);
|
|
const { offsetX, offsetY } = sourceEvent;
|
|
const { x: canvasX, y: canvasY } = Transformable.toCanvasPoint(node, offsetX, offsetY);
|
|
this.ctx.contextMenuRegistry.dispatchContext("legend-item", { widgetEvent, canvasX, canvasY }, { legendItem });
|
|
}
|
|
onClick(event, datum, proxyButton) {
|
|
if (this.checkInteractionState())
|
|
return;
|
|
if (this.doClick(event, datum, proxyButton)) {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
getVisibleItemCount() {
|
|
return this.ctx.chartService.series.flatMap((s) => s.getLegendData("category")).filter((d) => d.enabled).length;
|
|
}
|
|
doClick(event, datum, proxyButton) {
|
|
const {
|
|
listeners: { legendItemClick },
|
|
ctx: { chartService },
|
|
preventHidingAll,
|
|
toggleSeries
|
|
} = this;
|
|
if (!datum) {
|
|
return false;
|
|
}
|
|
const { legendType, seriesId, itemId, enabled, legendItemName } = datum;
|
|
const series = chartService.series.find((s) => s.id === seriesId);
|
|
if (!series) {
|
|
return false;
|
|
}
|
|
let newEnabled = enabled;
|
|
const clickEvent = makeLegendItemEvent("click", datum, event);
|
|
if (legendItemClick) {
|
|
(0, import_ag_charts_core243.callWithContext)([series.properties, this.ctx.chartService], legendItemClick, clickEvent.apiEvent);
|
|
}
|
|
if (clickEvent.defaultPrevented)
|
|
return true;
|
|
if (toggleSeries) {
|
|
newEnabled = !enabled;
|
|
if (preventHidingAll && !newEnabled) {
|
|
const numVisibleItems = this.getVisibleItemCount();
|
|
if (numVisibleItems < 2) {
|
|
newEnabled = true;
|
|
}
|
|
}
|
|
proxyButton.setChecked(newEnabled);
|
|
this.ctx.eventsHub.emit("legend:item-click", {
|
|
legendType,
|
|
series,
|
|
itemId,
|
|
enabled: newEnabled,
|
|
legendItemName
|
|
});
|
|
}
|
|
this.updateHighlight(newEnabled, datum, series);
|
|
this.ctx.legendManager.update();
|
|
this.ctx.updateService.update(import_ag_charts_core243.ChartUpdateType.PROCESS_DATA, {
|
|
forceNodeDataRefresh: true,
|
|
skipAnimations: datum.skipAnimations ?? false
|
|
});
|
|
return true;
|
|
}
|
|
onDoubleClick(event, datum) {
|
|
if (this.checkInteractionState())
|
|
return;
|
|
if (this.doDoubleClick(event, datum)) {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
doDoubleClick(event, datum) {
|
|
const {
|
|
listeners: { legendItemDoubleClick },
|
|
ctx: { chartService },
|
|
toggleSeries
|
|
} = this;
|
|
if (!datum) {
|
|
return false;
|
|
}
|
|
const { legendType, id, itemId, seriesId } = datum;
|
|
const series = chartService.series.find((s) => s.id === id);
|
|
if (!series) {
|
|
return false;
|
|
}
|
|
const doubleClickEvent = makeLegendItemEvent("dblclick", datum, event);
|
|
if (legendItemDoubleClick) {
|
|
(0, import_ag_charts_core243.callWithContext)(
|
|
[series.properties, this.ctx.chartService],
|
|
legendItemDoubleClick,
|
|
doubleClickEvent.apiEvent
|
|
);
|
|
}
|
|
if (doubleClickEvent.defaultPrevented)
|
|
return true;
|
|
if (toggleSeries) {
|
|
const legendData = chartService.series.flatMap((s) => s.getLegendData("category"));
|
|
let numVisibleItems = 0;
|
|
const visibleLegendItemNames = /* @__PURE__ */ new Set();
|
|
for (const d of legendData) {
|
|
if (!d.enabled)
|
|
continue;
|
|
numVisibleItems += 1;
|
|
if (d.legendItemName != null) {
|
|
visibleLegendItemNames.add(d.legendItemName);
|
|
}
|
|
}
|
|
if (visibleLegendItemNames.size > 0) {
|
|
numVisibleItems = visibleLegendItemNames.size;
|
|
}
|
|
const clickedItem = legendData.find((d) => d.itemId === itemId && d.seriesId === seriesId);
|
|
this.ctx.eventsHub.emit("legend:item-double-click", {
|
|
legendType,
|
|
series,
|
|
itemId,
|
|
numVisibleItems,
|
|
enabled: clickedItem?.enabled ?? false,
|
|
legendItemName: clickedItem?.legendItemName
|
|
});
|
|
}
|
|
this.ctx.legendManager.update();
|
|
this.ctx.updateService.update(import_ag_charts_core243.ChartUpdateType.PROCESS_DATA, { forceNodeDataRefresh: true });
|
|
return true;
|
|
}
|
|
toTooltipMeta(event, node) {
|
|
let point;
|
|
if (event instanceof FocusEvent) {
|
|
point = Transformable.toCanvas(node).computeCenter();
|
|
} else {
|
|
event.preventDefault();
|
|
point = Transformable.toCanvasPoint(node, event.offsetX, event.offsetY);
|
|
}
|
|
return { canvasX: point.x, canvasY: point.y, showArrow: false };
|
|
}
|
|
onHover(event, node) {
|
|
if (this.checkInteractionState())
|
|
return;
|
|
if (!this.enabled)
|
|
throw new Error("AG Charts - onHover handler called on disabled legend");
|
|
this.pagination.setPage(node.pageIndex);
|
|
const datum = node.datum;
|
|
const series = datum ? this.ctx.chartService.series.find((s) => s.id === datum?.id) : void 0;
|
|
if (datum && this.truncatedItems.has(datum.itemId ?? datum.id)) {
|
|
const meta = this.toTooltipMeta(event, node);
|
|
this.ctx.tooltipManager.updateTooltip(this.id, meta, [
|
|
{ type: "structured", title: this.getItemLabel(datum) }
|
|
]);
|
|
} else {
|
|
this.ctx.tooltipManager.removeTooltip(this.id, void 0, true);
|
|
}
|
|
this.updateHighlight(datum?.enabled, datum, series);
|
|
}
|
|
onLeave() {
|
|
if (this.checkInteractionState())
|
|
return;
|
|
this.ctx.tooltipManager.removeTooltip(this.id, void 0, true);
|
|
this.clearHighlight();
|
|
}
|
|
clearHighlight() {
|
|
this.updateHighlight(void 0, void 0, void 0);
|
|
}
|
|
updateHighlight(enabled, legendDatum, series, event) {
|
|
const updateManagers = (opts) => {
|
|
if (opts === void 0) {
|
|
this.ctx.activeManager.clear();
|
|
} else {
|
|
const seriesId = opts.nodeDatum.series.id;
|
|
const itemId = opts.itemId;
|
|
this.ctx.activeManager.update({ type: "legend", seriesId, itemId }, void 0);
|
|
}
|
|
this.ctx.highlightManager.updateHighlight(this.id, opts?.nodeDatum);
|
|
};
|
|
const highlightNodeDatum = (opts) => {
|
|
if (this.ctx.interactionManager.isState(64 /* Default */) || event?.initialState) {
|
|
updateManagers(opts);
|
|
} else if (this.ctx.interactionManager.isState(4 /* Animation */)) {
|
|
this.ctx.animationManager.onBatchStop(() => {
|
|
updateManagers(opts);
|
|
});
|
|
} else if (opts === void 0) {
|
|
updateManagers(opts);
|
|
}
|
|
};
|
|
if (enabled === true && series !== void 0 && legendDatum !== void 0) {
|
|
const itemId = legendDatum.itemId;
|
|
const nodeDatum = toHighlightNodeDatum(series, legendDatum);
|
|
highlightNodeDatum({ itemId, nodeDatum });
|
|
} else {
|
|
highlightNodeDatum(void 0);
|
|
}
|
|
}
|
|
onActiveUpdate(activeItem) {
|
|
if (activeItem?.type === "series-node") {
|
|
this.ctx.highlightManager.updateHighlight(this.id, void 0);
|
|
}
|
|
}
|
|
onActiveLoadMemento(event) {
|
|
const { activeItem } = event;
|
|
if (activeItem?.type !== "legend") {
|
|
return this.ctx.highlightManager.updateHighlight(this.id, void 0);
|
|
}
|
|
const datum = this.data.find((d) => d.seriesId === activeItem.seriesId && d.itemId === activeItem.itemId);
|
|
const series = this.ctx.chartService.series.find((s) => s.id === activeItem.seriesId);
|
|
if (series === void 0) {
|
|
import_ag_charts_core243.Logger.warn(`Cannot find seriesId: "${activeItem.seriesId}"`);
|
|
event.reject();
|
|
} else if (datum === void 0) {
|
|
const json = JSON.stringify({ seriesId: activeItem.seriesId, itemId: activeItem.itemId });
|
|
import_ag_charts_core243.Logger.warn(`cannot find legend item: ${json}`);
|
|
event.reject();
|
|
} else {
|
|
this.updateHighlight(datum.enabled, datum, series, event);
|
|
}
|
|
}
|
|
onLocaleChanged() {
|
|
this.updateItemSelection();
|
|
this.domProxy.onLocaleChanged(this.ctx.localeManager, this.itemSelection, this);
|
|
}
|
|
positionLegend(ctx) {
|
|
const oldPages = this.positionLegendScene(ctx);
|
|
this.positionLegendDOM(oldPages);
|
|
}
|
|
positionLegendScene(ctx) {
|
|
if (!this.enabled || !this.data.length)
|
|
return;
|
|
const { placement, floating, xOffset, yOffset } = (0, import_ag_charts_core243.expandLegendPosition)(this.position);
|
|
const layoutBox = floating ? new BBox(0, 0, ctx.width, ctx.height) : ctx.layoutBox;
|
|
const { x, y, width, height } = layoutBox;
|
|
const [legendWidth, legendHeight] = this.calculateLegendDimensions(layoutBox);
|
|
const { oldPages } = this.calcLayout(legendWidth, legendHeight);
|
|
const legendBBox = this.computePagedBBox();
|
|
if (this.visible) {
|
|
let unreachable2 = function(_a) {
|
|
return void 0;
|
|
};
|
|
var unreachable = unreachable2;
|
|
const legendSpacing = this.spacing;
|
|
let translationX;
|
|
let translationY;
|
|
switch (placement) {
|
|
case "top":
|
|
translationX = (width - legendBBox.width) / 2;
|
|
translationY = 0;
|
|
break;
|
|
case "bottom":
|
|
translationX = (width - legendBBox.width) / 2;
|
|
translationY = height - legendBBox.height;
|
|
break;
|
|
case "right":
|
|
translationX = width - legendBBox.width;
|
|
translationY = (height - legendBBox.height) / 2;
|
|
break;
|
|
case "left":
|
|
translationX = 0;
|
|
translationY = (height - legendBBox.height) / 2;
|
|
break;
|
|
case "top-right":
|
|
case "right-top":
|
|
translationX = width - legendBBox.width;
|
|
translationY = 0;
|
|
break;
|
|
case "top-left":
|
|
case "left-top":
|
|
translationX = 0;
|
|
translationY = 0;
|
|
break;
|
|
case "bottom-right":
|
|
case "right-bottom":
|
|
translationX = width - legendBBox.width;
|
|
translationY = height - legendBBox.height;
|
|
break;
|
|
case "bottom-left":
|
|
case "left-bottom":
|
|
translationX = 0;
|
|
translationY = height - legendBBox.height;
|
|
break;
|
|
default:
|
|
unreachable2(placement);
|
|
}
|
|
if (!floating) {
|
|
let shrinkAmount;
|
|
let shrinkDirection;
|
|
switch (placement) {
|
|
case "top":
|
|
case "top-right":
|
|
case "top-left":
|
|
shrinkAmount = legendBBox.height + legendSpacing;
|
|
shrinkDirection = "top";
|
|
break;
|
|
case "bottom":
|
|
case "bottom-right":
|
|
case "bottom-left":
|
|
shrinkAmount = legendBBox.height + legendSpacing;
|
|
shrinkDirection = "bottom";
|
|
break;
|
|
case "left":
|
|
case "left-top":
|
|
case "left-bottom":
|
|
shrinkAmount = legendBBox.width + legendSpacing;
|
|
shrinkDirection = "left";
|
|
break;
|
|
case "right":
|
|
case "right-top":
|
|
case "right-bottom":
|
|
shrinkAmount = legendBBox.width + legendSpacing;
|
|
shrinkDirection = "right";
|
|
break;
|
|
default:
|
|
unreachable2(placement);
|
|
}
|
|
layoutBox.shrink(shrinkAmount, shrinkDirection);
|
|
}
|
|
translationX += xOffset;
|
|
translationY += yOffset;
|
|
this.group.translationX = Math.floor(x + translationX - legendBBox.x);
|
|
this.group.translationY = Math.floor(y + translationY - legendBBox.y);
|
|
this.containerNode.x = legendBBox.x;
|
|
this.containerNode.y = legendBBox.y;
|
|
this.containerNode.width = legendBBox.width;
|
|
this.containerNode.height = legendBBox.height;
|
|
}
|
|
return oldPages;
|
|
}
|
|
positionLegendDOM(oldPages) {
|
|
const { ctx, itemSelection, pagination, pages: newPages, group } = this;
|
|
const visible = this.visible && this.enabled;
|
|
const interactive = this.isInteractive();
|
|
this.domProxy.update({
|
|
visible,
|
|
interactive,
|
|
ctx,
|
|
itemSelection,
|
|
group,
|
|
pagination,
|
|
oldPages,
|
|
newPages,
|
|
datumReader: this,
|
|
itemListener: this
|
|
});
|
|
}
|
|
calculateLegendDimensions(shrinkRect) {
|
|
const { width, height } = shrinkRect;
|
|
const { placement } = (0, import_ag_charts_core243.expandLegendPosition)(this.position);
|
|
const aspectRatio = width / height;
|
|
const maxCoefficient = 0.5;
|
|
const minHeightCoefficient = 0.2;
|
|
const minWidthCoefficient = 0.25;
|
|
let legendWidth, legendHeight;
|
|
function unreachable(_a) {
|
|
return void 0;
|
|
}
|
|
switch (placement) {
|
|
case "top":
|
|
case "top-left":
|
|
case "top-right":
|
|
case "bottom":
|
|
case "bottom-left":
|
|
case "bottom-right": {
|
|
const heightCoefficient = aspectRatio < 1 ? Math.min(maxCoefficient, minHeightCoefficient * (1 / aspectRatio)) : minHeightCoefficient;
|
|
legendWidth = this.maxWidth ? Math.min(this.maxWidth, width) : width;
|
|
legendHeight = this.maxHeight ? Math.min(this.maxHeight, height) : Math.round(height * heightCoefficient);
|
|
break;
|
|
}
|
|
case "left":
|
|
case "left-top":
|
|
case "left-bottom":
|
|
case "right":
|
|
case "right-top":
|
|
case "right-bottom": {
|
|
const widthCoefficient = aspectRatio > 1 ? Math.min(maxCoefficient, minWidthCoefficient * aspectRatio) : minWidthCoefficient;
|
|
legendWidth = this.maxWidth ? Math.min(this.maxWidth, width) : Math.round(width * widthCoefficient);
|
|
legendHeight = this.maxHeight ? Math.min(this.maxHeight, height) : height;
|
|
break;
|
|
}
|
|
default:
|
|
unreachable(placement);
|
|
}
|
|
return [legendWidth, legendHeight];
|
|
}
|
|
cachedCallWithContext(fn, params) {
|
|
const { callbackCache, chartService } = this.ctx;
|
|
return callbackCache.call([this, chartService], fn, params);
|
|
}
|
|
};
|
|
Legend.className = "Legend";
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "toggleSeries", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "pagination", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "item", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "listeners", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core243.ObserveChanges)((target, newValue, oldValue) => {
|
|
target.updateGroupVisibility();
|
|
if (newValue === oldValue) {
|
|
return;
|
|
}
|
|
const {
|
|
ctx: { legendManager, stateManager }
|
|
} = target;
|
|
if (oldValue === false && newValue === true) {
|
|
stateManager.restoreState(legendManager);
|
|
}
|
|
}),
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "enabled", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "position", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "maxWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "maxHeight", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "reverseOrder", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "orientation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "preventHidingAll", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "border", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "padding", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "spacing", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "xOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core243.Property
|
|
], Legend.prototype, "yOffset", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/legend/legendModule.ts
|
|
var LegendModule = {
|
|
type: "plugin",
|
|
name: "legend",
|
|
version: VERSION,
|
|
// TODO fix missing behaviour
|
|
// removable: 'standalone-only',
|
|
options: {
|
|
enabled: import_ag_charts_core244.boolean,
|
|
position: import_ag_charts_core244.legendPositionValidator,
|
|
orientation: (0, import_ag_charts_core244.union)("horizontal", "vertical"),
|
|
maxWidth: import_ag_charts_core244.positiveNumber,
|
|
maxHeight: import_ag_charts_core244.positiveNumber,
|
|
spacing: import_ag_charts_core244.positiveNumber,
|
|
border: import_ag_charts_core244.borderOptionsDef,
|
|
cornerRadius: import_ag_charts_core244.number,
|
|
padding: import_ag_charts_core244.padding,
|
|
fill: import_ag_charts_core244.colorUnion,
|
|
fillOpacity: import_ag_charts_core244.ratio,
|
|
preventHidingAll: import_ag_charts_core244.boolean,
|
|
reverseOrder: import_ag_charts_core244.boolean,
|
|
toggleSeries: import_ag_charts_core244.boolean,
|
|
item: {
|
|
marker: {
|
|
size: import_ag_charts_core244.positiveNumber,
|
|
shape: import_ag_charts_core244.shapeValidator,
|
|
padding: import_ag_charts_core244.positiveNumber,
|
|
strokeWidth: import_ag_charts_core244.positiveNumber
|
|
},
|
|
line: {
|
|
length: import_ag_charts_core244.positiveNumber,
|
|
strokeWidth: import_ag_charts_core244.positiveNumber
|
|
},
|
|
label: {
|
|
maxLength: import_ag_charts_core244.positiveNumber,
|
|
formatter: import_ag_charts_core244.callback,
|
|
...import_ag_charts_core244.fontOptionsDef
|
|
},
|
|
maxWidth: import_ag_charts_core244.positiveNumber,
|
|
paddingX: import_ag_charts_core244.positiveNumber,
|
|
paddingY: import_ag_charts_core244.positiveNumber,
|
|
showSeriesStroke: import_ag_charts_core244.boolean
|
|
},
|
|
pagination: {
|
|
marker: {
|
|
size: import_ag_charts_core244.positiveNumber,
|
|
shape: import_ag_charts_core244.shapeValidator,
|
|
padding: import_ag_charts_core244.positiveNumber
|
|
},
|
|
activeStyle: {
|
|
...import_ag_charts_core244.fillOptionsDef,
|
|
...import_ag_charts_core244.strokeOptionsDef
|
|
},
|
|
inactiveStyle: {
|
|
...import_ag_charts_core244.fillOptionsDef,
|
|
...import_ag_charts_core244.strokeOptionsDef
|
|
},
|
|
highlightStyle: {
|
|
...import_ag_charts_core244.fillOptionsDef,
|
|
...import_ag_charts_core244.strokeOptionsDef
|
|
},
|
|
label: import_ag_charts_core244.fontOptionsDef
|
|
},
|
|
listeners: {
|
|
legendItemClick: import_ag_charts_core244.callback,
|
|
legendItemDoubleClick: import_ag_charts_core244.callback
|
|
}
|
|
},
|
|
themeTemplate: {
|
|
...import_ag_charts_core244.LEGEND_CONTAINER_THEME,
|
|
enabled: {
|
|
$and: [
|
|
{ $greaterThan: [{ $size: { $path: "/series" } }, 1] },
|
|
{
|
|
$or: [
|
|
{ $isChartType: "cartesian" },
|
|
{ $isChartType: "standalone" },
|
|
{
|
|
$and: [
|
|
{ $isChartType: "polar" },
|
|
{ $not: { $isSeriesType: "pie" } },
|
|
{ $not: { $isSeriesType: "donut" } }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
position: import_ag_charts_core244.CARTESIAN_POSITION.BOTTOM,
|
|
orientation: {
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $eq: [{ $path: "./position" }, import_ag_charts_core244.CARTESIAN_POSITION.LEFT] },
|
|
{ $eq: [{ $path: "./position" }, import_ag_charts_core244.CARTESIAN_POSITION.LEFT_TOP] },
|
|
{ $eq: [{ $path: "./position" }, import_ag_charts_core244.CARTESIAN_POSITION.LEFT_BOTTOM] },
|
|
{ $eq: [{ $path: "./position" }, import_ag_charts_core244.CARTESIAN_POSITION.RIGHT] },
|
|
{ $eq: [{ $path: "./position" }, import_ag_charts_core244.CARTESIAN_POSITION.RIGHT_TOP] },
|
|
{ $eq: [{ $path: "./position" }, import_ag_charts_core244.CARTESIAN_POSITION.RIGHT_BOTTOM] },
|
|
{ $eq: [{ $path: "./position/placement" }, import_ag_charts_core244.CARTESIAN_POSITION.LEFT] },
|
|
{ $eq: [{ $path: "./position/placement" }, import_ag_charts_core244.CARTESIAN_POSITION.LEFT_TOP] },
|
|
{ $eq: [{ $path: "./position/placement" }, import_ag_charts_core244.CARTESIAN_POSITION.LEFT_BOTTOM] },
|
|
{ $eq: [{ $path: "./position/placement" }, import_ag_charts_core244.CARTESIAN_POSITION.RIGHT] },
|
|
{ $eq: [{ $path: "./position/placement" }, import_ag_charts_core244.CARTESIAN_POSITION.RIGHT_TOP] },
|
|
{ $eq: [{ $path: "./position/placement" }, import_ag_charts_core244.CARTESIAN_POSITION.RIGHT_BOTTOM] }
|
|
]
|
|
},
|
|
"vertical",
|
|
"horizontal"
|
|
]
|
|
},
|
|
spacing: 30,
|
|
listeners: {},
|
|
toggleSeries: true,
|
|
item: {
|
|
paddingX: 16,
|
|
paddingY: 8,
|
|
marker: { size: 15, padding: 8 },
|
|
showSeriesStroke: true,
|
|
label: {
|
|
color: { $ref: "textColor" },
|
|
fontSize: { $rem: import_ag_charts_core244.FONT_SIZE_RATIO.SMALL },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" }
|
|
}
|
|
},
|
|
reverseOrder: false,
|
|
pagination: {
|
|
marker: { size: 12 },
|
|
activeStyle: { fill: { $ref: "foregroundColor" } },
|
|
inactiveStyle: { fill: { $ref: "subtleTextColor" } },
|
|
highlightStyle: { fill: { $ref: "foregroundColor" } },
|
|
label: { color: { $ref: "textColor" } }
|
|
},
|
|
fill: {
|
|
$if: [{ $path: ["./position/floating", false] }, { $ref: "chartBackgroundColor" }, "transparent"]
|
|
}
|
|
},
|
|
create: (ctx) => {
|
|
const moduleInstance = new Legend(ctx);
|
|
moduleInstance.attachLegend(ctx.scene);
|
|
return moduleInstance;
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/areaSeriesModule.ts
|
|
var import_ag_charts_core249 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/areaSeries.ts
|
|
var import_ag_charts_core248 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/axis/logAxis.ts
|
|
var import_ag_charts_core245 = require("ag-charts-core");
|
|
var LogAxis = class extends NumberAxis {
|
|
getVisibleDomain(domain) {
|
|
const [d0, d1] = domain;
|
|
const [r0, r1] = this.visibleRange;
|
|
if (domain.length < 2) {
|
|
return [d0, d1];
|
|
}
|
|
const min = Math.min(d0, d1);
|
|
const max = Math.max(d0, d1);
|
|
if (min >= 0) {
|
|
const log0 = Math.log(d0);
|
|
const log1 = Math.log(d1);
|
|
const span = log1 - log0;
|
|
return [Math.exp(log0 + r0 * span), Math.exp(log0 + r1 * span)];
|
|
}
|
|
if (max <= 0) {
|
|
const log0 = -Math.log(-d0);
|
|
const log1 = -Math.log(-d1);
|
|
const span = log1 - log0;
|
|
return [-Math.exp(-(log0 + r0 * span)), -Math.exp(-(log0 + r1 * span))];
|
|
}
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
normaliseDataDomain(d) {
|
|
const { min, max, preferredMin, preferredMax } = this;
|
|
const { extent: extent6, clipped } = (0, import_ag_charts_core245.normalisedExtentWithMetadata)(
|
|
d.domain,
|
|
min,
|
|
max,
|
|
preferredMin,
|
|
preferredMax,
|
|
void 0,
|
|
d.sortMetadata?.sortOrder
|
|
);
|
|
if (extent6[0] < 0 && extent6[1] > 0 || d.domain[0] < 0 && d.domain[1] > 0) {
|
|
import_ag_charts_core245.Logger.warn(
|
|
`The log axis domain crosses zero, the chart data cannot be rendered. See log axis documentation for more information.`
|
|
);
|
|
return { domain: [], clipped };
|
|
} else if (extent6[0] === 0 || extent6[1] === 0 || d.domain[0] === 0 || d.domain[1] === 0) {
|
|
import_ag_charts_core245.Logger.warn(
|
|
`The log axis domain contains a value of 0, the chart data cannot be rendered. See log axis documentation for more information.`
|
|
);
|
|
return { domain: [], clipped };
|
|
}
|
|
return { domain: extent6, clipped };
|
|
}
|
|
set base(value) {
|
|
this.scale.base = value;
|
|
}
|
|
get base() {
|
|
return this.scale.base;
|
|
}
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, new LogScale());
|
|
}
|
|
};
|
|
LogAxis.className = "LogAxis";
|
|
LogAxis.type = "log";
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/areaAggregation.ts
|
|
var import_ag_charts_core246 = require("ag-charts-core");
|
|
var MAX_POINTS = 10;
|
|
function aggregationIndexType(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf) {
|
|
const xValue = xValues[datumIndex];
|
|
if (xValue === void 0)
|
|
return -1;
|
|
const xRatio = Number.isFinite(d0) ? (0, import_ag_charts_core246.aggregationXRatioForXValue)(xValue, d0, d1, xNeedsValueOf) : (0, import_ag_charts_core246.aggregationXRatioForDatumIndex)(datumIndex, xValues.length);
|
|
const aggIndex = (0, import_ag_charts_core246.aggregationIndexForXRatio)(xRatio, maxRange);
|
|
if (datumIndex === indexData[aggIndex + import_ag_charts_core246.AGGREGATION_INDEX_X_MIN] || datumIndex === indexData[aggIndex + import_ag_charts_core246.AGGREGATION_INDEX_X_MAX] || datumIndex === indexData[aggIndex + import_ag_charts_core246.AGGREGATION_INDEX_Y_MIN] || datumIndex === indexData[aggIndex + import_ag_charts_core246.AGGREGATION_INDEX_Y_MAX]) {
|
|
return aggIndex;
|
|
}
|
|
return -1;
|
|
}
|
|
function buildIndicesFromAggregation(xValues, d0, d1, indexData, maxRange, xNeedsValueOf, xValuesLength, reuseIndices, reuseMetaIndices) {
|
|
let indicesCount = 0;
|
|
let metaIndicesCount = 0;
|
|
let currentGroup = -1;
|
|
for (let datumIndex = 0; datumIndex < xValuesLength; datumIndex++) {
|
|
const group = aggregationIndexType(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf);
|
|
if (group === -1)
|
|
continue;
|
|
indicesCount++;
|
|
if (group !== currentGroup) {
|
|
metaIndicesCount++;
|
|
currentGroup = group;
|
|
}
|
|
}
|
|
metaIndicesCount++;
|
|
const indices = reuseIndices?.length === indicesCount ? reuseIndices : new Uint32Array(indicesCount);
|
|
const metaIndices = reuseMetaIndices?.length === metaIndicesCount ? reuseMetaIndices : new Uint32Array(metaIndicesCount);
|
|
let indicesIdx = 0;
|
|
let metaIndicesIdx = 0;
|
|
currentGroup = -1;
|
|
for (let datumIndex = 0; datumIndex < xValuesLength; datumIndex++) {
|
|
const group = aggregationIndexType(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf);
|
|
if (group === -1)
|
|
continue;
|
|
if (group !== currentGroup) {
|
|
metaIndices[metaIndicesIdx++] = indicesIdx;
|
|
currentGroup = group;
|
|
}
|
|
indices[indicesIdx++] = datumIndex;
|
|
}
|
|
metaIndices[metaIndicesIdx] = indicesCount - 1;
|
|
return { indices, metaIndices };
|
|
}
|
|
function computeAreaAggregation(domain, xValues, yValues, options) {
|
|
const xValuesLength = xValues.length;
|
|
if (xValuesLength < import_ag_charts_core246.AGGREGATION_THRESHOLD)
|
|
return;
|
|
const [d0, d1] = domain;
|
|
const { xNeedsValueOf, yNeedsValueOf, existingFilters } = options;
|
|
let maxRange = (0, import_ag_charts_core246.aggregationRangeFittingPoints)(xValues, d0, d1, { xNeedsValueOf });
|
|
const existingFilter = existingFilters?.find((f) => f.maxRange === maxRange);
|
|
let { indexData, valueData } = (0, import_ag_charts_core246.createAggregationIndices)(xValues, yValues, yValues, d0, d1, maxRange, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
reuseIndexData: existingFilter?.indexData,
|
|
reuseValueData: existingFilter?.valueData
|
|
});
|
|
let { indices, metaIndices } = buildIndicesFromAggregation(
|
|
xValues,
|
|
d0,
|
|
d1,
|
|
indexData,
|
|
maxRange,
|
|
xNeedsValueOf,
|
|
xValuesLength,
|
|
existingFilter?.indices,
|
|
existingFilter?.metaIndices
|
|
);
|
|
const filters = [{ maxRange, metaIndices, indices, indexData, valueData }];
|
|
while (indices.length > MAX_POINTS && maxRange > import_ag_charts_core246.AGGREGATION_MIN_RANGE) {
|
|
const currentMaxRange = maxRange;
|
|
const nextMaxRange = Math.trunc(currentMaxRange / 2);
|
|
const nextExistingFilter = existingFilters?.find((f) => f.maxRange === nextMaxRange);
|
|
const compacted = (0, import_ag_charts_core246.compactAggregationIndices)(indexData, valueData, currentMaxRange, {
|
|
reuseIndexData: nextExistingFilter?.indexData,
|
|
reuseValueData: nextExistingFilter?.valueData
|
|
});
|
|
maxRange = compacted.maxRange;
|
|
indexData = compacted.indexData;
|
|
valueData = compacted.valueData;
|
|
const previousIndices = indices;
|
|
let indicesCount = 0;
|
|
let metaIndicesCount = 0;
|
|
let currentGroup = -1;
|
|
for (const datumIndex of previousIndices) {
|
|
const group = aggregationIndexType(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf);
|
|
if (group === -1)
|
|
continue;
|
|
indicesCount++;
|
|
if (group !== currentGroup) {
|
|
metaIndicesCount++;
|
|
currentGroup = group;
|
|
}
|
|
}
|
|
metaIndicesCount++;
|
|
const newIndices = nextExistingFilter?.indices?.length === indicesCount ? nextExistingFilter.indices : new Uint32Array(indicesCount);
|
|
const newMetaIndices = nextExistingFilter?.metaIndices?.length === metaIndicesCount ? nextExistingFilter.metaIndices : new Uint32Array(metaIndicesCount);
|
|
let indicesIdx = 0;
|
|
let metaIndicesIdx = 0;
|
|
currentGroup = -1;
|
|
for (const datumIndex of previousIndices) {
|
|
const group = aggregationIndexType(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf);
|
|
if (group === -1)
|
|
continue;
|
|
if (group !== currentGroup) {
|
|
newMetaIndices[metaIndicesIdx++] = indicesIdx;
|
|
currentGroup = group;
|
|
}
|
|
newIndices[indicesIdx++] = datumIndex;
|
|
}
|
|
newMetaIndices[metaIndicesIdx] = indicesCount - 1;
|
|
indices = newIndices;
|
|
metaIndices = newMetaIndices;
|
|
filters.push({ maxRange, metaIndices, indices, indexData, valueData });
|
|
}
|
|
filters.reverse();
|
|
return filters;
|
|
}
|
|
function computeAreaAggregationPartial(domain, xValues, yValues, options) {
|
|
const xValuesLength = xValues.length;
|
|
if (xValuesLength < import_ag_charts_core246.AGGREGATION_THRESHOLD)
|
|
return;
|
|
const [d0, d1] = domain;
|
|
const { xNeedsValueOf, yNeedsValueOf, targetRange, existingFilters } = options;
|
|
const finestMaxRange = (0, import_ag_charts_core246.aggregationRangeFittingPoints)(xValues, d0, d1, { xNeedsValueOf });
|
|
const targetMaxRange = Math.min(finestMaxRange, (0, import_ag_charts_core246.nextPowerOf2)(Math.max(targetRange, import_ag_charts_core246.AGGREGATION_MIN_RANGE)));
|
|
const existingFilter = existingFilters?.find((f) => f.maxRange === targetMaxRange);
|
|
const { indexData, valueData } = (0, import_ag_charts_core246.createAggregationIndices)(xValues, yValues, yValues, d0, d1, targetMaxRange, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
reuseIndexData: existingFilter?.indexData,
|
|
reuseValueData: existingFilter?.valueData
|
|
});
|
|
const { indices, metaIndices } = buildIndicesFromAggregation(
|
|
xValues,
|
|
d0,
|
|
d1,
|
|
indexData,
|
|
targetMaxRange,
|
|
xNeedsValueOf,
|
|
xValuesLength,
|
|
existingFilter?.indices,
|
|
existingFilter?.metaIndices
|
|
);
|
|
const immediateLevel = {
|
|
maxRange: targetMaxRange,
|
|
indices,
|
|
metaIndices,
|
|
indexData,
|
|
valueData
|
|
};
|
|
function computeRemaining() {
|
|
const allLevels = computeAreaAggregation([d0, d1], xValues, yValues, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
return allLevels?.filter((level) => level.maxRange !== targetMaxRange) ?? [];
|
|
}
|
|
return { immediate: [immediateLevel], computeRemaining };
|
|
}
|
|
function aggregateAreaData(scale2, xValues, yValues, domainInput, xNeedsValueOf, yNeedsValueOf) {
|
|
const [d0, d1] = (0, import_ag_charts_core246.aggregationDomain)(scale2, domainInput);
|
|
return computeAreaAggregation([d0, d1], xValues, yValues, { xNeedsValueOf, yNeedsValueOf });
|
|
}
|
|
var memoizedAggregateAreaData = (0, import_ag_charts_core246.simpleMemorize2)(aggregateAreaData);
|
|
function aggregateAreaDataFromDataModel(scale2, dataModel, processedData, yKey, series, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const yValues = dataModel.resolveColumnById(series, yKey, processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, yKey, processedData);
|
|
if (existingFilters) {
|
|
const [d0, d1] = (0, import_ag_charts_core246.aggregationDomain)(scale2, domainInput);
|
|
return computeAreaAggregation([d0, d1], xValues, yValues, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
}
|
|
return memoizedAggregateAreaData(scale2, xValues, yValues, domainInput, xNeedsValueOf, yNeedsValueOf);
|
|
}
|
|
function aggregateAreaDataFromDataModelPartial(scale2, dataModel, processedData, yKey, series, targetRange, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const yValues = dataModel.resolveColumnById(series, yKey, processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, yKey, processedData);
|
|
const [d0, d1] = (0, import_ag_charts_core246.aggregationDomain)(scale2, domainInput);
|
|
return computeAreaAggregationPartial([d0, d1], xValues, yValues, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
targetRange,
|
|
existingFilters
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/areaSeriesProperties.ts
|
|
var import_ag_charts_core247 = require("ag-charts-core");
|
|
var AreaSeriesProperties = class extends CartesianSeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.xName = void 0;
|
|
this.fill = "#c16068";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "#874349";
|
|
this.strokeWidth = 2;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.interpolation = new import_ag_charts_core247.InterpolationProperties();
|
|
this.shadow = new DropShadow();
|
|
this.marker = new SeriesMarker();
|
|
this.label = new Label();
|
|
this.tooltip = makeSeriesTooltip();
|
|
this.connectMissingData = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "yKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "yFilterKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "stackGroup", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "normalizedTo", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "interpolation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "shadow", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "marker", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "tooltip", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core247.Property
|
|
], AreaSeriesProperties.prototype, "connectMissingData", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/areaSeries.ts
|
|
var CROSS_FILTER_AREA_FILL_OPACITY_FACTOR = 0.125;
|
|
var CROSS_FILTER_AREA_STROKE_OPACITY_FACTOR = 0.25;
|
|
var AreaSeries = class extends CartesianSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
propertyKeys: DEFAULT_CARTESIAN_DIRECTION_KEYS,
|
|
propertyNames: DEFAULT_CARTESIAN_DIRECTION_NAMES,
|
|
categoryKey: "xValue",
|
|
pathsPerSeries: ["fill", "stroke"],
|
|
pathsZIndexSubOrderOffset: [0, 1e3],
|
|
datumSelectionGarbageCollection: false,
|
|
segmentedDataNodes: false,
|
|
pickModes: [2 /* AXIS_ALIGNED */, 0 /* EXACT_SHAPE_MATCH */],
|
|
animationResetFns: {
|
|
path: buildResetPathFn({ getVisible: () => this.visible, getOpacity: () => this.getOpacity() }),
|
|
label: resetLabelFn,
|
|
datum: (node, datum) => ({ ...resetMarkerFn(node), ...resetMarkerPositionFn(node, datum) })
|
|
},
|
|
clipFocusBox: false
|
|
});
|
|
this.properties = new AreaSeriesProperties();
|
|
this.connectsToYAxis = true;
|
|
this.aggregationManager = new AggregationManager();
|
|
this.backgroundGroup = new Group({
|
|
name: `${this.id}-background`,
|
|
zIndex: import_ag_charts_core248.SeriesZIndexMap.BACKGROUND
|
|
});
|
|
this._isStacked = void 0;
|
|
this.fillSpans = [];
|
|
this.phantomSpans = [];
|
|
this.strokeSpans = [];
|
|
}
|
|
get pickModeAxis() {
|
|
return "main";
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
const hasMarkers = (this.contextNodeData?.nodeData?.length ?? 0) > 0;
|
|
return super.renderToOffscreenCanvas() || hasMarkers && this.getDrawingMode(false) === "cutout" || this.contextNodeData != null && (this.contextNodeData.fillData.spans.length > RENDER_TO_OFFSCREEN_CANVAS_THRESHOLD || this.contextNodeData.strokeData.spans.length > RENDER_TO_OFFSCREEN_CANVAS_THRESHOLD);
|
|
}
|
|
attachSeries(seriesContentNode, seriesNode, annotationNode) {
|
|
super.attachSeries(seriesContentNode, seriesNode, annotationNode);
|
|
seriesContentNode.appendChild(this.backgroundGroup);
|
|
}
|
|
detachSeries(seriesContentNode, seriesNode, annotationNode) {
|
|
super.detachSeries(seriesContentNode, seriesNode, annotationNode);
|
|
this.backgroundGroup.remove();
|
|
}
|
|
attachPaths([fill, stroke]) {
|
|
this.backgroundGroup.appendChild(fill);
|
|
this.contentGroup.appendChild(stroke);
|
|
stroke.zIndex = -1;
|
|
}
|
|
detachPaths([fill, stroke]) {
|
|
fill.remove();
|
|
stroke.remove();
|
|
}
|
|
isStacked() {
|
|
const stackCount = this.seriesGrouping?.stackCount ?? 1;
|
|
return stackCount > 1;
|
|
}
|
|
isNormalized() {
|
|
return this.properties.normalizedTo != null;
|
|
}
|
|
setSeriesIndex(index) {
|
|
const isStacked = this.isStacked();
|
|
const isStackedChanged = isStacked === this._isStacked;
|
|
this._isStacked = isStackedChanged;
|
|
return super.setSeriesIndex(index, isStackedChanged);
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
if (this.isStacked()) {
|
|
this.backgroundGroup.zIndex = [import_ag_charts_core248.SeriesZIndexMap.BACKGROUND, zIndex];
|
|
this.contentGroup.zIndex = [import_ag_charts_core248.SeriesZIndexMap.ANY_CONTENT, zIndex, import_ag_charts_core248.SeriesContentZIndexMap.FOREGROUND];
|
|
} else {
|
|
this.backgroundGroup.zIndex = [import_ag_charts_core248.SeriesZIndexMap.ANY_CONTENT, zIndex, import_ag_charts_core248.SeriesContentZIndexMap.FOREGROUND, 0];
|
|
this.contentGroup.zIndex = [import_ag_charts_core248.SeriesZIndexMap.ANY_CONTENT, zIndex, import_ag_charts_core248.SeriesContentZIndexMap.FOREGROUND, 1];
|
|
}
|
|
}
|
|
async processData(dataController) {
|
|
if (this.data == null)
|
|
return;
|
|
const { data, visible, seriesGrouping: { groupIndex = this.id, stackCount = 1 } = {} } = this;
|
|
const { xKey, yKey, yFilterKey, connectMissingData, normalizedTo } = this.properties;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const xScale = this.axes[import_ag_charts_core248.ChartAxisDirection.X]?.scale;
|
|
const yScale = this.axes[import_ag_charts_core248.ChartAxisDirection.Y]?.scale;
|
|
const { xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const stacked = stackCount > 1 || normalizedTo != null;
|
|
const idMap = {
|
|
value: `area-stack-${groupIndex}-yValue`,
|
|
marker: `area-stack-${groupIndex}-yValues-marker`
|
|
};
|
|
const common = { invalidValue: null };
|
|
if (((0, import_ag_charts_core248.isDefined)(normalizedTo) || connectMissingData) && stackCount > 1) {
|
|
common.invalidValue = 0;
|
|
}
|
|
if (!visible) {
|
|
common.forceValue = 0;
|
|
}
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const props = [
|
|
keyProperty(xKey, xScaleType, { id: "xValue", allowNullKey }),
|
|
valueProperty(yKey, yScaleType, { id: `yValueRaw`, ...common }),
|
|
...yFilterKey == null ? [] : [valueProperty(yFilterKey, yScaleType, { id: "yFilterRaw" })]
|
|
];
|
|
if (stacked) {
|
|
props.push(
|
|
...groupAccumulativeValueProperty(
|
|
yKey,
|
|
"normal",
|
|
{ id: `yValueCumulative`, ...common, groupId: idMap.marker },
|
|
yScaleType
|
|
)
|
|
);
|
|
}
|
|
if ((0, import_ag_charts_core248.isDefined)(normalizedTo)) {
|
|
props.push(
|
|
valueProperty(yKey, yScaleType, { id: `yValue`, ...common, groupId: idMap.value }),
|
|
normaliseGroupTo(Object.values(idMap), normalizedTo)
|
|
);
|
|
}
|
|
if (animationEnabled) {
|
|
props.push(animationValidation());
|
|
}
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, data, {
|
|
props,
|
|
groupByKeys: stacked,
|
|
groupByData: !stacked
|
|
});
|
|
this.aggregateData(dataModel, processedData);
|
|
this.animationState.transition("updateData");
|
|
}
|
|
xCoordinateRange(xValue, pixelSize) {
|
|
const { marker } = this.properties;
|
|
const x = this.axes[import_ag_charts_core248.ChartAxisDirection.X].scale.convert(xValue);
|
|
const r = marker.enabled ? 0.5 * marker.size * pixelSize : 0;
|
|
return [x - r, x + r];
|
|
}
|
|
yCoordinateRange(yValues, pixelSize) {
|
|
const { marker } = this.properties;
|
|
const y = this.axes[import_ag_charts_core248.ChartAxisDirection.Y].scale.convert(yValues[0]);
|
|
const r = marker.enabled ? 0.5 * marker.size * pixelSize : 0;
|
|
return [y - r, y + r];
|
|
}
|
|
yValueKey() {
|
|
return this.isNormalized() ? "yValue" : "yValueRaw";
|
|
}
|
|
yCumulativeKey(processData) {
|
|
return processData.type === "grouped" ? "yValueCumulative" : this.yValueKey();
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { dataModel, processedData, axes } = this;
|
|
if (!dataModel || !processedData)
|
|
return { domain: [] };
|
|
const yAxis = axes[import_ag_charts_core248.ChartAxisDirection.Y];
|
|
if (direction === import_ag_charts_core248.ChartAxisDirection.X) {
|
|
const keyDef = dataModel.resolveProcessedDataDefById(this, `xValue`);
|
|
const keys = dataModel.getDomain(this, `xValue`, "key", processedData);
|
|
if (keyDef?.def.type === "key" && keyDef.def.valueType === "category") {
|
|
return keys;
|
|
}
|
|
return { domain: fixNumericExtent((0, import_ag_charts_core248.extent)(keys.domain)) };
|
|
}
|
|
const yExtent = this.domainForClippedRange(
|
|
import_ag_charts_core248.ChartAxisDirection.Y,
|
|
[this.yCumulativeKey(processedData)],
|
|
"xValue"
|
|
);
|
|
if (yAxis instanceof NumberAxis && !(yAxis instanceof LogAxis)) {
|
|
const fixedYExtent = Number.isFinite(yExtent[1] - yExtent[0]) ? [Math.min(yExtent[0], 0), Math.max(yExtent[1], 0)] : [];
|
|
return { domain: fixNumericExtent(fixedYExtent) };
|
|
} else {
|
|
return { domain: fixNumericExtent(yExtent) };
|
|
}
|
|
}
|
|
getSeriesRange(_direction, visibleRange) {
|
|
const [y0, y1] = this.domainForVisibleRange(
|
|
import_ag_charts_core248.ChartAxisDirection.Y,
|
|
[this.yCumulativeKey(this.processedData)],
|
|
"xValue",
|
|
visibleRange
|
|
);
|
|
return [Math.min(y0, 0), Math.max(y1, 0)];
|
|
}
|
|
getZoomRangeFittingItems(xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
return this.zoomFittingVisibleItems(
|
|
"xValue",
|
|
[this.yCumulativeKey(this.processedData)],
|
|
xVisibleRange,
|
|
yVisibleRange,
|
|
minVisibleItems
|
|
);
|
|
}
|
|
getVisibleItems(xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
return this.countVisibleItems(
|
|
"xValue",
|
|
[this.yCumulativeKey(this.processedData)],
|
|
xVisibleRange,
|
|
yVisibleRange,
|
|
minVisibleItems
|
|
);
|
|
}
|
|
aggregateData(dataModel, processedData) {
|
|
this.aggregationManager.markStale(processedData.input.count);
|
|
if (processedDataIsAnimatable(processedData))
|
|
return;
|
|
const xAxis = this.axes[import_ag_charts_core248.ChartAxisDirection.X];
|
|
if (xAxis == null)
|
|
return;
|
|
const targetRange = this.estimateTargetRange();
|
|
this.aggregationManager.aggregate({
|
|
computePartial: (existingFilters) => aggregateAreaDataFromDataModelPartial(
|
|
xAxis.scale.type,
|
|
dataModel,
|
|
processedData,
|
|
this.yCumulativeKey(processedData),
|
|
this,
|
|
targetRange,
|
|
existingFilters
|
|
),
|
|
computeFull: (existingFilters) => aggregateAreaDataFromDataModel(
|
|
xAxis.scale.type,
|
|
dataModel,
|
|
processedData,
|
|
this.yCumulativeKey(processedData),
|
|
this,
|
|
existingFilters
|
|
),
|
|
targetRange
|
|
});
|
|
const filters = this.aggregationManager.filters;
|
|
if (filters && filters.length > 0) {
|
|
import_ag_charts_core248.DebugMetrics.record(
|
|
`${this.type}:aggregation`,
|
|
filters.map((f) => f.maxRange)
|
|
);
|
|
}
|
|
}
|
|
estimateTargetRange() {
|
|
const xAxis = this.axes[import_ag_charts_core248.ChartAxisDirection.X];
|
|
if (xAxis?.scale?.range) {
|
|
const [r0, r1] = xAxis.scale.range;
|
|
return Math.abs(r1 - r0);
|
|
}
|
|
return this.ctx.scene?.canvas?.width ?? 800;
|
|
}
|
|
stackAggregatedData(aggregation) {
|
|
const { indices, metaIndices } = aggregation;
|
|
const { visible, axes, dataModel, processedData, seriesBelowStackContext } = this;
|
|
const xAxis = axes[import_ag_charts_core248.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core248.ChartAxisDirection.Y];
|
|
if (!visible) {
|
|
this.phantomSpans = [];
|
|
this.fillSpans = [];
|
|
this.strokeSpans = [];
|
|
return seriesBelowStackContext;
|
|
}
|
|
if (xAxis == null || yAxis == null || dataModel == null || processedData == null)
|
|
return;
|
|
const { scale: xScale } = xAxis;
|
|
const { scale: yScale } = yAxis;
|
|
const xOffset = (xScale.bandwidth ?? 0) / 2;
|
|
const connectMissingData = !this.isStacked() && this.properties.connectMissingData;
|
|
const invalidData = processedData.invalidData?.get(this.id);
|
|
const xValues = dataModel.resolveKeysById(this, "xValue", processedData);
|
|
const yValues = dataModel.resolveColumnById(this, this.yCumulativeKey(processedData), processedData);
|
|
let [m0, m1] = visibleRangeIndices(1, metaIndices.length - 1, xAxis.range, (metaIndex) => {
|
|
const startIndex = metaIndices[metaIndex];
|
|
const endIndex = metaIndices[metaIndex + 1];
|
|
const startDatumIndex = indices[startIndex];
|
|
const endDatumIndex = indices[endIndex];
|
|
const xValue0 = xValues[startDatumIndex];
|
|
const xValue1 = xValues[endDatumIndex];
|
|
const { 0: x0 } = this.xCoordinateRange(xValue0, 0);
|
|
const { 1: x1 } = this.xCoordinateRange(xValue1, 0);
|
|
return [x0, x1];
|
|
});
|
|
m0 = Math.max(m0 - 1, 0);
|
|
m1 = Math.min(m1 + 1, metaIndices.length - 1);
|
|
let phantomSpans = [];
|
|
if (seriesBelowStackContext?.fillSpans) {
|
|
phantomSpans = seriesBelowStackContext?.fillSpans;
|
|
} else {
|
|
for (let metaIndex = m0; metaIndex < m1; metaIndex += 1) {
|
|
const startIndex = metaIndices[metaIndex];
|
|
const endIndex = metaIndices[metaIndex + 1];
|
|
const startDatumIndex = indices[startIndex];
|
|
const endDatumIndex = indices[endIndex];
|
|
const xValue0 = xValues[startDatumIndex];
|
|
const xValue1 = xValues[endDatumIndex];
|
|
const span = {
|
|
type: "linear",
|
|
moveTo: false,
|
|
x0: xScale.convert(xValue0) + xOffset,
|
|
y0: yScale.convert(0),
|
|
x1: xScale.convert(xValue1) + xOffset,
|
|
y1: yScale.convert(0)
|
|
};
|
|
phantomSpans.push({
|
|
span,
|
|
xValue0,
|
|
xValue1,
|
|
yValue0: 0,
|
|
yValue1: 0
|
|
});
|
|
}
|
|
}
|
|
this.phantomSpans = phantomSpans;
|
|
const fillSpans = [];
|
|
const strokeSpans = [];
|
|
let phantomIndex = 0;
|
|
for (let metaIndex = m0; metaIndex < m1; metaIndex += 1) {
|
|
const startIndex = metaIndices[metaIndex];
|
|
const endIndex = metaIndices[metaIndex + 1];
|
|
const startDatumIndex = indices[startIndex];
|
|
const endDatumIndex = indices[endIndex];
|
|
const spanInvalid = !connectMissingData && this.hasInvalidDatumsInRange(invalidData, yValues, startDatumIndex, endDatumIndex);
|
|
const phantomSpanDatum = phantomSpans[phantomIndex++];
|
|
if (spanInvalid) {
|
|
fillSpans.push(phantomSpanDatum);
|
|
strokeSpans.push(phantomSpanDatum);
|
|
continue;
|
|
}
|
|
const bucketPoints = [];
|
|
for (let i = startIndex; i <= endIndex; i++) {
|
|
const datumIndex = indices[i];
|
|
if (invalidData?.[datumIndex])
|
|
continue;
|
|
const yValue = yValues[datumIndex];
|
|
if (!Number.isFinite(yValue))
|
|
continue;
|
|
const xDatum = xValues[datumIndex];
|
|
bucketPoints.push({
|
|
point: {
|
|
x: xScale.convert(xDatum) + xOffset,
|
|
y: yScale.convert(yValue)
|
|
},
|
|
xDatum,
|
|
yDatum: yValue
|
|
});
|
|
}
|
|
if (bucketPoints.length < 2) {
|
|
fillSpans.push(phantomSpanDatum);
|
|
strokeSpans.push(phantomSpanDatum);
|
|
continue;
|
|
}
|
|
const startPoint = bucketPoints[0];
|
|
const endPoint = bucketPoints.at(-1);
|
|
const midPoints = bucketPoints.slice(1, -1).map((p) => p.point);
|
|
const span = {
|
|
type: "multi-line",
|
|
moveTo: false,
|
|
x0: startPoint.point.x,
|
|
y0: startPoint.point.y,
|
|
x1: endPoint.point.x,
|
|
y1: endPoint.point.y,
|
|
midPoints
|
|
};
|
|
const spanDatum = {
|
|
span,
|
|
xValue0: startPoint.xDatum,
|
|
xValue1: endPoint.xDatum,
|
|
yValue0: startPoint.yDatum,
|
|
yValue1: endPoint.yDatum
|
|
};
|
|
fillSpans.push(spanDatum);
|
|
strokeSpans.push(spanDatum);
|
|
}
|
|
this.fillSpans = fillSpans;
|
|
this.strokeSpans = strokeSpans;
|
|
return {
|
|
stack: [],
|
|
fillSpans,
|
|
strokeSpans
|
|
};
|
|
}
|
|
hasInvalidDatumsInRange(invalidData, yValues, startIndex, endIndex) {
|
|
const rangeStart = Math.min(startIndex, endIndex);
|
|
const rangeEnd = Math.max(startIndex, endIndex);
|
|
for (let datumIndex = rangeStart; datumIndex <= rangeEnd; datumIndex++) {
|
|
if (invalidData?.[datumIndex]) {
|
|
return true;
|
|
}
|
|
const yValue = yValues[datumIndex];
|
|
if (!Number.isFinite(yValue)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
stackYValueData() {
|
|
const { visible, axes, dataModel, processedData, seriesBelowStackContext, properties } = this;
|
|
const xAxis = axes[import_ag_charts_core248.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core248.ChartAxisDirection.Y];
|
|
if (xAxis == null || yAxis == null || dataModel == null || processedData == null)
|
|
return;
|
|
const { interpolation } = properties;
|
|
const { scale: xScale } = xAxis;
|
|
const { scale: yScale } = yAxis;
|
|
const xOffset = (xScale.bandwidth ?? 0) / 2;
|
|
let xValues = dataModel.resolveKeysById(this, "xValue", processedData);
|
|
let yValues = dataModel.resolveColumnById(this, this.yValueKey(), processedData);
|
|
const connectMissingData = !this.isStacked() && this.properties.connectMissingData;
|
|
const invalidKeys = processedData.invalidKeys?.get(this.id);
|
|
const invalidData = connectMissingData ? processedData.invalidData?.get(this.id) : void 0;
|
|
const indexFilter = invalidData ?? invalidKeys;
|
|
if (indexFilter != null) {
|
|
xValues = xValues.filter((_, datumIndex) => indexFilter[datumIndex] === false);
|
|
yValues = yValues.filter((_, datumIndex) => indexFilter[datumIndex] === false);
|
|
}
|
|
let [startIndex, endIndex] = visibleRangeIndices(
|
|
1,
|
|
xValues.length,
|
|
xAxis.range,
|
|
(datumIndex) => this.xCoordinateRange(xValues[datumIndex], 0)
|
|
);
|
|
startIndex = Math.max(startIndex - 2, 0);
|
|
endIndex = Math.min(endIndex + 2, xValues.length);
|
|
let phantomSpans;
|
|
if (seriesBelowStackContext?.fillSpans) {
|
|
phantomSpans = seriesBelowStackContext?.fillSpans;
|
|
} else {
|
|
const phantomSpanPoints = [];
|
|
for (let datumIndex = startIndex; datumIndex < endIndex; datumIndex += 1) {
|
|
const xDatum = xValues[datumIndex];
|
|
phantomSpanPoints.push({
|
|
point: {
|
|
x: xScale.convert(xDatum) + xOffset,
|
|
y: yScale.convert(0)
|
|
},
|
|
xDatum,
|
|
yDatum: 0
|
|
});
|
|
}
|
|
phantomSpans = interpolatePoints(phantomSpanPoints, { type: "linear" });
|
|
}
|
|
this.phantomSpans = phantomSpans;
|
|
if (!visible) {
|
|
this.fillSpans = phantomSpans;
|
|
this.strokeSpans = [];
|
|
return seriesBelowStackContext;
|
|
}
|
|
let bottomStack = seriesBelowStackContext?.stack;
|
|
if (bottomStack == null) {
|
|
bottomStack = [];
|
|
for (let datumIndex = startIndex; datumIndex < endIndex - 1; datumIndex += 1) {
|
|
bottomStack.push({ leading: 0, trailing: 0, dataValid: true, breakBefore: false });
|
|
}
|
|
}
|
|
const topStack = bottomStack.slice();
|
|
let trackingValidData = false;
|
|
for (let stackIndex = 0; stackIndex < topStack.length; stackIndex += 1) {
|
|
const leadingIndex = startIndex + stackIndex;
|
|
const trailingIndex = startIndex + stackIndex + 1;
|
|
let { leading, trailing, breakBefore } = bottomStack[stackIndex];
|
|
const leadingValue = yValues[leadingIndex];
|
|
const trailingValue = yValues[trailingIndex];
|
|
const missingLeading = !Number.isFinite(leadingValue);
|
|
const missingTrailing = !Number.isFinite(trailingValue);
|
|
const dataValid = !missingLeading && !missingTrailing;
|
|
if (dataValid) {
|
|
leading += leadingValue;
|
|
trailing += trailingValue;
|
|
}
|
|
if (stackIndex !== 0 && dataValid !== trackingValidData) {
|
|
breakBefore = true;
|
|
}
|
|
trackingValidData = dataValid;
|
|
topStack[stackIndex] = { leading, trailing, dataValid, breakBefore };
|
|
}
|
|
const fillSpans = [];
|
|
const strokeSpans = [];
|
|
const topSpanPoints = [];
|
|
for (let stackIndex = 0; stackIndex < topStack.length; stackIndex += 1) {
|
|
const { leading, dataValid, breakBefore } = topStack[stackIndex];
|
|
const leadingIndex = startIndex + stackIndex;
|
|
if (breakBefore) {
|
|
if (topSpanPoints.length !== 0) {
|
|
const previousStack = topStack[stackIndex - 1];
|
|
const previousPoint = {
|
|
point: {
|
|
x: xScale.convert(xValues[leadingIndex]) + xOffset,
|
|
y: yScale.convert(previousStack.trailing)
|
|
},
|
|
xDatum: xValues[leadingIndex],
|
|
yDatum: previousStack.trailing
|
|
};
|
|
topSpanPoints.push(previousPoint);
|
|
const spans = interpolatePoints(topSpanPoints, interpolation);
|
|
fillSpans.push(...spans);
|
|
strokeSpans.push(...spans);
|
|
}
|
|
topSpanPoints.length = 0;
|
|
}
|
|
if (dataValid) {
|
|
const leadingPoint = {
|
|
point: {
|
|
x: xScale.convert(xValues[leadingIndex]) + xOffset,
|
|
y: yScale.convert(leading)
|
|
},
|
|
xDatum: xValues[leadingIndex],
|
|
yDatum: leading
|
|
};
|
|
topSpanPoints.push(leadingPoint);
|
|
} else {
|
|
fillSpans.push(phantomSpans[stackIndex]);
|
|
}
|
|
}
|
|
if (topSpanPoints.length !== 0) {
|
|
const previousStack = topStack.at(-1);
|
|
const trailingIndex = startIndex + topStack.length;
|
|
const trailingPoint = {
|
|
point: {
|
|
x: xScale.convert(xValues[trailingIndex]) + xOffset,
|
|
y: yScale.convert(previousStack.trailing)
|
|
},
|
|
xDatum: xValues[trailingIndex],
|
|
yDatum: previousStack.trailing
|
|
};
|
|
topSpanPoints.push(trailingPoint);
|
|
const spans = interpolatePoints(topSpanPoints, interpolation);
|
|
fillSpans.push(...spans);
|
|
strokeSpans.push(...spans);
|
|
topSpanPoints.length = 0;
|
|
}
|
|
this.fillSpans = fillSpans;
|
|
this.strokeSpans = strokeSpans;
|
|
return {
|
|
stack: topStack,
|
|
fillSpans,
|
|
strokeSpans
|
|
};
|
|
}
|
|
createStackContext() {
|
|
const xAxis = this.axes[import_ag_charts_core248.ChartAxisDirection.X];
|
|
if (xAxis == null)
|
|
return;
|
|
const { scale: xScale } = xAxis;
|
|
const [r0, r1] = xScale.range;
|
|
const range4 = Math.abs(r1 - r0);
|
|
this.aggregationManager.ensureLevelForRange(range4);
|
|
const dataAggregationFilter = this.aggregationManager.getFilterForRange(range4);
|
|
if (dataAggregationFilter) {
|
|
return this.stackAggregatedData(dataAggregationFilter);
|
|
} else {
|
|
return this.stackYValueData();
|
|
}
|
|
}
|
|
/**
|
|
* Creates the context object with cached lookups for createNodeData().
|
|
* All expensive operations (data resolution, scale lookups) are performed once here.
|
|
*/
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return void 0;
|
|
const {
|
|
xKey,
|
|
xName,
|
|
yFilterKey,
|
|
yKey,
|
|
yName,
|
|
legendItemName,
|
|
marker,
|
|
label,
|
|
fill: seriesFill,
|
|
stroke: seriesStroke,
|
|
normalizedTo
|
|
} = this.properties;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const { isContinuousY } = this.getScaleInformation({ xScale, yScale });
|
|
const stacked = processedData.type === "grouped";
|
|
const [r0, r1] = xScale.range;
|
|
const range4 = Math.abs(r1 - r0);
|
|
this.aggregationManager.ensureLevelForRange(range4);
|
|
const dataAggregationFilter = this.aggregationManager.getFilterForRange(range4);
|
|
const existingNodeData = this.contextNodeData?.nodeData;
|
|
const canIncrementallyUpdate = existingNodeData != null && this.canIncrementallyUpdateNodes(dataAggregationFilter != null);
|
|
return {
|
|
// Axes (from template method parameters)
|
|
xAxis,
|
|
yAxis,
|
|
// Data arrays (resolved once)
|
|
rawData: processedData.dataSources.get(this.id)?.data ?? [],
|
|
xValues: dataModel.resolveKeysById(this, "xValue", processedData),
|
|
yRawValues: dataModel.resolveColumnById(this, "yValueRaw", processedData),
|
|
yCumulativeValues: stacked ? dataModel.resolveColumnById(this, "yValueCumulative", processedData) : dataModel.resolveColumnById(this, "yValueRaw", processedData),
|
|
yFilterValues: yFilterKey == null ? void 0 : dataModel.resolveColumnById(this, "yFilterRaw", processedData),
|
|
invalidData: processedData.invalidData?.get(this.id),
|
|
// Scales (cached)
|
|
xScale,
|
|
yScale,
|
|
xOffset: (xScale.bandwidth ?? 0) / 2,
|
|
yOffset: 0,
|
|
// Aggregation
|
|
indices: dataAggregationFilter?.indices,
|
|
// Pre-computed flags
|
|
isContinuousY,
|
|
labelsEnabled: label.enabled,
|
|
normalizedTo,
|
|
canIncrementallyUpdate,
|
|
animationEnabled: !this.ctx.animationManager.isSkipped(),
|
|
// Property caches
|
|
xKey,
|
|
yKey,
|
|
xName,
|
|
yName,
|
|
legendItemName,
|
|
markerSize: marker.size,
|
|
markerFill: marker.fill ?? seriesFill,
|
|
markerStroke: marker.stroke ?? seriesStroke,
|
|
markerStrokeWidth: marker.strokeWidth ?? this.properties.strokeWidth,
|
|
yDomain: this.getSeriesDomain(import_ag_charts_core248.ChartAxisDirection.Y).domain,
|
|
// Mutable state (nodes instead of markerData to match base interface)
|
|
nodes: canIncrementallyUpdate ? existingNodeData : [],
|
|
labelData: [],
|
|
nodeIndex: 0,
|
|
crossFiltering: false
|
|
};
|
|
}
|
|
/**
|
|
* Computes the marker coordinate for a datum.
|
|
* Uses cached context values to avoid repeated lookups.
|
|
*/
|
|
computeMarkerCoordinate(ctx, scratch) {
|
|
let currY;
|
|
if ((0, import_ag_charts_core248.isDefined)(ctx.normalizedTo) ? ctx.isContinuousY && (0, import_ag_charts_core248.isContinuous)(scratch.yDatum) : !Number.isNaN(scratch.yDatum)) {
|
|
currY = scratch.yCumulative;
|
|
}
|
|
scratch.x = ctx.xScale.convert(scratch.xDatum) + ctx.xOffset;
|
|
scratch.y = ctx.yScale.convert(currY);
|
|
if (!Number.isFinite(scratch.x)) {
|
|
scratch.validPoint = false;
|
|
}
|
|
}
|
|
/**
|
|
* Processes a single datum and updates the context's marker/label data.
|
|
* Uses scratch object to avoid allocations in tight loops.
|
|
*/
|
|
handleDatum(ctx, scratch, datumIndex) {
|
|
scratch.xDatum = ctx.xValues[datumIndex];
|
|
if (scratch.xDatum === void 0 && !this.properties.allowNullKeys)
|
|
return;
|
|
scratch.datum = ctx.rawData[datumIndex];
|
|
scratch.yDatum = ctx.yRawValues[datumIndex];
|
|
scratch.yCumulative = +ctx.yCumulativeValues[datumIndex];
|
|
scratch.validPoint = Number.isFinite(scratch.yDatum) && ctx.invalidData?.[datumIndex] !== true;
|
|
this.computeMarkerCoordinate(ctx, scratch);
|
|
scratch.selected = ctx.yFilterValues == null ? void 0 : ctx.yFilterValues[datumIndex] === scratch.yDatum;
|
|
if (scratch.selected === false) {
|
|
ctx.crossFiltering = true;
|
|
}
|
|
if (scratch.validPoint) {
|
|
const canReuseNode = ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodes.length;
|
|
if (canReuseNode) {
|
|
const existingNode = ctx.nodes[ctx.nodeIndex];
|
|
existingNode.datum = scratch.datum;
|
|
existingNode.datumIndex = datumIndex;
|
|
existingNode.midPoint = { x: scratch.x, y: scratch.y };
|
|
existingNode.cumulativeValue = scratch.yCumulative;
|
|
existingNode.yValue = scratch.yDatum;
|
|
existingNode.xValue = scratch.xDatum;
|
|
existingNode.point = { x: scratch.x, y: scratch.y, size: ctx.markerSize };
|
|
existingNode.selected = scratch.selected;
|
|
} else {
|
|
ctx.nodes.push({
|
|
series: this,
|
|
datum: scratch.datum,
|
|
datumIndex,
|
|
midPoint: { x: scratch.x, y: scratch.y },
|
|
cumulativeValue: scratch.yCumulative,
|
|
yValue: scratch.yDatum,
|
|
xValue: scratch.xDatum,
|
|
yKey: ctx.yKey,
|
|
xKey: ctx.xKey,
|
|
point: { x: scratch.x, y: scratch.y, size: ctx.markerSize },
|
|
fill: ctx.markerFill,
|
|
stroke: ctx.markerStroke,
|
|
strokeWidth: ctx.markerStrokeWidth,
|
|
selected: scratch.selected
|
|
});
|
|
}
|
|
ctx.nodeIndex++;
|
|
}
|
|
if (ctx.labelsEnabled && scratch.validPoint) {
|
|
const labelText = this.getLabelText(
|
|
scratch.yDatum,
|
|
scratch.datum,
|
|
ctx.yKey,
|
|
"y",
|
|
ctx.yDomain,
|
|
this.properties.label,
|
|
{
|
|
value: scratch.yDatum,
|
|
datum: scratch.datum,
|
|
xKey: ctx.xKey,
|
|
yKey: ctx.yKey,
|
|
xName: ctx.xName,
|
|
yName: ctx.yName,
|
|
legendItemName: ctx.legendItemName
|
|
}
|
|
);
|
|
ctx.labelData.push({
|
|
series: this,
|
|
datum: scratch.datum,
|
|
datumIndex,
|
|
x: scratch.x,
|
|
y: scratch.y,
|
|
labelText
|
|
});
|
|
}
|
|
}
|
|
// ============================================================================
|
|
// Template Method Hooks
|
|
// ============================================================================
|
|
/**
|
|
* Populates the node data array by iterating over visible data.
|
|
*/
|
|
populateNodeData(ctx) {
|
|
const scratch = {
|
|
datum: void 0,
|
|
xDatum: void 0,
|
|
yDatum: void 0,
|
|
yCumulative: 0,
|
|
selected: void 0,
|
|
x: 0,
|
|
y: 0,
|
|
validPoint: false
|
|
};
|
|
let [startIndex, endIndex] = this.visibleRangeIndices("xValue", ctx.xAxis.range, ctx.indices);
|
|
startIndex = Math.max(startIndex - 2, 0);
|
|
endIndex = Math.min(endIndex + 2, ctx.indices?.length ?? ctx.xValues.length);
|
|
if (this.processedData.input.count < 1e3) {
|
|
startIndex = 0;
|
|
endIndex = this.processedData.input.count;
|
|
}
|
|
for (let i = startIndex; i < endIndex; i += 1) {
|
|
const datumIndex = ctx.indices?.[i] ?? i;
|
|
this.handleDatum(ctx, scratch, datumIndex);
|
|
}
|
|
}
|
|
/**
|
|
* Initializes the result context object with default values.
|
|
* Called before populate phase to allow early return for invisible series.
|
|
*
|
|
* Note: We use the actual fillSpans/strokeSpans/phantomSpans because createStackContext()
|
|
* runs BEFORE createNodeData() and populates these instance fields. They are valid
|
|
* even in the early return case when !visible.
|
|
*/
|
|
initializeResult(ctx) {
|
|
const { visibleSameStackCount } = this.ctx.seriesStateManager.getVisiblePeerGroupIndex(this);
|
|
return {
|
|
itemId: ctx.yKey,
|
|
// Use actual spans from createStackContext() - valid even for early return
|
|
fillData: { spans: this.fillSpans, phantomSpans: this.phantomSpans },
|
|
strokeData: { spans: this.strokeSpans },
|
|
labelData: ctx.labelData,
|
|
nodeData: ctx.nodes,
|
|
scales: this.calculateScaling(),
|
|
visible: this.visible,
|
|
stackVisible: visibleSameStackCount > 0,
|
|
crossFiltering: ctx.crossFiltering,
|
|
styles: getMarkerStyles(this, this.properties, this.properties.marker),
|
|
segments: void 0
|
|
};
|
|
}
|
|
/**
|
|
* Assembles the final result with computed fields.
|
|
* Note: fillData/strokeData are already set in initializeResult() from instance fields.
|
|
*/
|
|
assembleResult(ctx, result) {
|
|
result.segments = calculateSegments(
|
|
this.properties.segmentation,
|
|
ctx.xAxis,
|
|
ctx.yAxis,
|
|
this.chart.seriesRect,
|
|
this.ctx.scene,
|
|
false
|
|
);
|
|
return result;
|
|
}
|
|
isPathOrSelectionDirty() {
|
|
return this.properties.marker.isDirty();
|
|
}
|
|
updatePathNodes(opts) {
|
|
const {
|
|
paths: [fillPaths, strokePaths],
|
|
visible,
|
|
animationEnabled
|
|
} = opts;
|
|
const crossFiltering = this.contextNodeData?.crossFiltering === true;
|
|
const segments = this.contextNodeData?.segments;
|
|
const merged = (0, import_ag_charts_core248.mergeDefaults)(this.getHighlightStyle(), this.getStyle());
|
|
const { strokeWidth, stroke, strokeOpacity, lineDash, lineDashOffset, fill, fillOpacity, opacity } = merged;
|
|
strokePaths.setProperties({
|
|
segments,
|
|
fill: void 0,
|
|
lineCap: "round",
|
|
lineJoin: "round",
|
|
pointerEvents: 1 /* None */,
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity: strokeOpacity * (crossFiltering ? CROSS_FILTER_AREA_STROKE_OPACITY_FACTOR : 1),
|
|
lineDash,
|
|
lineDashOffset,
|
|
opacity,
|
|
visible: visible || animationEnabled
|
|
});
|
|
strokePaths.datum = segments;
|
|
fillPaths.setStyleProperties(
|
|
{
|
|
fill,
|
|
stroke: void 0,
|
|
fillOpacity: fillOpacity * (crossFiltering ? CROSS_FILTER_AREA_FILL_OPACITY_FACTOR : 1)
|
|
},
|
|
this.getShapeFillBBox()
|
|
);
|
|
fillPaths.setProperties({
|
|
segments,
|
|
lineJoin: "round",
|
|
pointerEvents: 1 /* None */,
|
|
fillShadow: this.properties.shadow,
|
|
opacity,
|
|
visible: visible || animationEnabled
|
|
});
|
|
fillPaths.datum = segments;
|
|
updateClipPath(this, strokePaths);
|
|
updateClipPath(this, fillPaths);
|
|
}
|
|
updatePaths(opts) {
|
|
this.updateAreaPaths(opts.paths, opts.contextData);
|
|
}
|
|
updateAreaPaths(paths, contextData) {
|
|
for (const path of paths) {
|
|
path.visible = contextData.visible;
|
|
}
|
|
if (contextData.visible) {
|
|
this.updateFillPath(paths, contextData);
|
|
this.updateStrokePath(paths, contextData);
|
|
} else {
|
|
for (const path of paths) {
|
|
path.path.clear();
|
|
path.markDirty("AreaSeries");
|
|
}
|
|
}
|
|
}
|
|
updateFillPath(paths, contextData) {
|
|
const [fill] = paths;
|
|
fill.path.clear();
|
|
plotAreaPathFill(fill, contextData.fillData);
|
|
fill.markDirty("AreaSeries");
|
|
}
|
|
updateStrokePath(paths, contextData) {
|
|
const { spans } = contextData.strokeData;
|
|
const [, stroke] = paths;
|
|
stroke.path.clear();
|
|
plotLinePathStroke(stroke, spans);
|
|
stroke.markDirty("AreaSeries");
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const { nodeData, datumSelection } = opts;
|
|
const { contextNodeData, processedData, axes, properties } = this;
|
|
const { marker, styler } = properties;
|
|
const markerStyle = styler ? this.getStyle().marker : void 0;
|
|
const markersEnabled = contextNodeData?.crossFiltering === true || markerEnabled(processedData.input.count, axes[import_ag_charts_core248.ChartAxisDirection.X].scale, marker, markerStyle);
|
|
if (marker.isDirty()) {
|
|
datumSelection.clear();
|
|
datumSelection.cleanup();
|
|
}
|
|
const data = markersEnabled ? nodeData : [];
|
|
if (!processedDataIsAnimatable(this.processedData)) {
|
|
return datumSelection.update(data);
|
|
}
|
|
return datumSelection.update(data, void 0, (datum) => createDatumId(datum.xValue));
|
|
}
|
|
updateDatumStyles(opts) {
|
|
const { datumSelection, isHighlight } = opts;
|
|
const { marker } = this.properties;
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
datumSelection.each((node, datum) => {
|
|
if (!datumSelection.isGarbage(node)) {
|
|
const highlightState = this.getHighlightState(highlightedDatum, opts.isHighlight, datum.datumIndex);
|
|
const stylerStyle = this.getStyle(highlightState);
|
|
const { stroke, strokeWidth, strokeOpacity } = stylerStyle;
|
|
const params = this.makeItemStylerParams(
|
|
this.dataModel,
|
|
this.processedData,
|
|
datum.datumIndex,
|
|
stylerStyle.marker
|
|
);
|
|
datum.style = this.getMarkerStyle(
|
|
marker,
|
|
datum,
|
|
params,
|
|
{ isHighlight, highlightState },
|
|
stylerStyle.marker,
|
|
{
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity
|
|
}
|
|
);
|
|
}
|
|
});
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const { datumSelection, isHighlight } = opts;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const drawingMode = this.getDrawingMode(isHighlight, opts.drawingMode);
|
|
datumSelection.each((node, datum) => {
|
|
const state = this.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex);
|
|
const style = datum.style ?? contextNodeData.styles[state];
|
|
this.applyMarkerStyle(style, node, datum.point, fillBBox, { selected: datum.selected });
|
|
node.drawingMode = this.resolveMarkerDrawingModeForState(drawingMode, style);
|
|
});
|
|
if (!isHighlight) {
|
|
this.properties.marker.markClean();
|
|
}
|
|
}
|
|
updateLabelSelection(opts) {
|
|
return opts.labelSelection.update(this.isLabelEnabled() ? opts.labelData : []);
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const { isHighlight = false } = opts;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const params = this.makeLabelFormatterParams();
|
|
opts.labelSelection.each((text, datum) => {
|
|
const style = getLabelStyles(this, datum, params, this.properties.label, isHighlight, activeHighlight);
|
|
const { enabled, fontStyle, fontWeight: fontWeight2, fontSize, fontFamily, color: color8 } = style;
|
|
if (enabled && datum?.labelText) {
|
|
text.fontStyle = fontStyle;
|
|
text.fontWeight = fontWeight2;
|
|
text.fontSize = fontSize;
|
|
text.fontFamily = fontFamily;
|
|
text.textAlign = "center";
|
|
text.textBaseline = "bottom";
|
|
text.text = datum.labelText;
|
|
text.x = datum.x;
|
|
text.y = datum.y - 10;
|
|
text.fill = color8;
|
|
text.visible = true;
|
|
text.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex).opacity ?? 1;
|
|
text.setBoxing(style);
|
|
} else {
|
|
text.visible = false;
|
|
}
|
|
});
|
|
}
|
|
makeStylerParams(highlightStateEnum) {
|
|
const { id: seriesId } = this;
|
|
const { marker, fill, fillOpacity, lineDash, lineDashOffset, stroke, strokeOpacity, strokeWidth, xKey, yKey } = this.properties;
|
|
const highlightState = toHighlightString(highlightStateEnum ?? 0 /* None */);
|
|
return {
|
|
marker: {
|
|
fill: marker.fill,
|
|
fillOpacity: marker.fillOpacity,
|
|
size: marker.size,
|
|
shape: marker.shape,
|
|
stroke: marker.stroke,
|
|
strokeOpacity: marker.strokeOpacity,
|
|
strokeWidth: marker.strokeWidth,
|
|
lineDash: marker.lineDash,
|
|
lineDashOffset: marker.lineDashOffset
|
|
},
|
|
highlightState,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
seriesId,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
xKey,
|
|
yKey
|
|
};
|
|
}
|
|
makeItemStylerParams(dataModel, processedData, datumIndex, style) {
|
|
const { xKey, yKey } = this.properties;
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValueRaw`, processedData)[datumIndex];
|
|
const xDomain = dataModel.getDomain(this, `xValue`, "key", processedData).domain;
|
|
const yDomain = dataModel.getDomain(this, this.yCumulativeKey(processedData), "value", processedData).domain;
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
...datumStylerProperties(xValue, yValue, xKey, yKey, xDomain, yDomain),
|
|
xValue,
|
|
yValue,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
makeLabelFormatterParams() {
|
|
const { xKey, xName, yKey, yName, legendItemName } = this.properties;
|
|
return { xKey, xName, yKey, yName, legendItemName };
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, axes, properties } = this;
|
|
const { xKey, xName, yKey, yName, tooltip, legendItemName } = properties;
|
|
const allowNullKeys = properties.allowNullKeys ?? false;
|
|
const xAxis = axes[import_ag_charts_core248.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core248.ChartAxisDirection.Y];
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data?.[datumIndex];
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValueRaw`, processedData)[datumIndex];
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const stylerStyle = this.getStyle();
|
|
const params = this.makeItemStylerParams(dataModel, processedData, datumIndex, stylerStyle.marker);
|
|
const format = this.getMarkerStyle(
|
|
this.properties.marker,
|
|
{ datumIndex, datum },
|
|
params,
|
|
{ isHighlight: false },
|
|
stylerStyle.marker
|
|
);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName, allowNullKeys),
|
|
symbol: this.legendItemSymbol(),
|
|
data: [
|
|
{
|
|
label: yName,
|
|
fallbackLabel: yKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", yValue, datum, yKey, legendItemName),
|
|
missing: isTooltipValueMissing(yValue)
|
|
}
|
|
]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: yName,
|
|
xKey,
|
|
xName,
|
|
yKey,
|
|
yName,
|
|
...format,
|
|
...this.getModuleTooltipParams()
|
|
}
|
|
);
|
|
}
|
|
legendItemSymbol() {
|
|
const { fill, stroke, fillOpacity, strokeOpacity, strokeWidth, lineDash, marker } = this.getStyle();
|
|
const useAreaFill = !marker.enabled || marker.fill == null;
|
|
const legendMarkerFill = useAreaFill ? fill : marker.fill;
|
|
const markerStyle = this.getMarkerStyle(
|
|
this.properties.marker,
|
|
{},
|
|
void 0,
|
|
{ isHighlight: false, checkForHighlight: false },
|
|
{
|
|
size: marker.size,
|
|
shape: marker.shape,
|
|
fill: legendMarkerFill,
|
|
fillOpacity: useAreaFill ? fillOpacity : marker.fillOpacity,
|
|
stroke: marker.stroke
|
|
}
|
|
);
|
|
return {
|
|
marker: {
|
|
...markerStyle,
|
|
enabled: marker.enabled || strokeWidth <= 0
|
|
},
|
|
line: {
|
|
enabled: true,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
const { yKey: itemId, yName, legendItemName, showInLegend } = this.properties;
|
|
return [
|
|
{
|
|
legendType,
|
|
id: seriesId,
|
|
itemId,
|
|
legendItemName,
|
|
seriesId,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId }),
|
|
label: {
|
|
text: legendItemName ?? yName ?? itemId
|
|
},
|
|
symbol: this.legendItemSymbol(),
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
resetDatumAnimation(data) {
|
|
resetMarkerSelectionsDirect([data.datumSelection]);
|
|
}
|
|
animateEmptyUpdateReady(animationData) {
|
|
const { datumSelection, labelSelection, contextData, paths } = animationData;
|
|
const { animationManager } = this.ctx;
|
|
this.updateAreaPaths(paths, contextData);
|
|
pathSwipeInAnimation(this, animationManager, ...paths);
|
|
resetMotion([datumSelection], resetMarkerPositionFn);
|
|
markerSwipeScaleInAnimation(
|
|
this,
|
|
animationManager,
|
|
{ ...this.getAnimationDrawingModes(), phase: "initial" },
|
|
datumSelection
|
|
);
|
|
seriesLabelFadeInAnimation(this, "labels", animationManager, labelSelection);
|
|
}
|
|
animateReadyResize(animationData) {
|
|
const { contextData, paths } = animationData;
|
|
this.updateAreaPaths(paths, contextData);
|
|
super.animateReadyResize(animationData);
|
|
}
|
|
animateWaitingUpdateReady(animationData) {
|
|
const { animationManager } = this.ctx;
|
|
const { datumSelection, labelSelection, contextData, paths, previousContextData } = animationData;
|
|
const [fill, stroke] = paths;
|
|
if (contextData.visible === false && previousContextData?.visible === false)
|
|
return;
|
|
if (fill == null && stroke == null)
|
|
return;
|
|
this.resetDatumAnimation(animationData);
|
|
this.resetLabelAnimation(animationData);
|
|
const update = () => {
|
|
this.resetPathAnimation(animationData);
|
|
this.updateAreaPaths(paths, contextData);
|
|
};
|
|
const skip = () => {
|
|
animationManager.skipCurrentBatch();
|
|
update();
|
|
};
|
|
if (contextData == null || previousContextData == null) {
|
|
update();
|
|
markerFadeInAnimation(this, animationManager, "added", this.getAnimationDrawingModes(), datumSelection);
|
|
pathFadeInAnimation(this, "fill_path_properties", animationManager, "add", fill);
|
|
pathFadeInAnimation(this, "stroke_path_properties", animationManager, "add", stroke);
|
|
seriesLabelFadeInAnimation(this, "labels", animationManager, labelSelection);
|
|
return;
|
|
}
|
|
if (contextData.crossFiltering !== previousContextData.crossFiltering) {
|
|
skip();
|
|
return;
|
|
}
|
|
const fns = prepareAreaPathAnimation(contextData, previousContextData);
|
|
if (fns === void 0) {
|
|
skip();
|
|
return;
|
|
} else if (fns.status === "no-op") {
|
|
return;
|
|
}
|
|
markerFadeInAnimation(this, animationManager, void 0, this.getAnimationDrawingModes(), datumSelection);
|
|
fromToMotion(this.id, "fill_path_properties", animationManager, [fill], fns.fill.pathProperties);
|
|
pathMotion(this.id, "fill_path_update", animationManager, [fill], fns.fill.path);
|
|
fromToMotion(this.id, "stroke_path_properties", animationManager, [stroke], fns.stroke.pathProperties);
|
|
pathMotion(this.id, "stroke_path_update", animationManager, [stroke], fns.stroke.path);
|
|
seriesLabelFadeInAnimation(this, "labels", animationManager, labelSelection);
|
|
this.ctx.animationManager.animate({
|
|
id: this.id,
|
|
groupId: "reset_after_animation",
|
|
phase: "trailing",
|
|
from: {},
|
|
to: {},
|
|
onComplete: () => this.updateAreaPaths(paths, contextData)
|
|
});
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.label.enabled;
|
|
}
|
|
nodeFactory() {
|
|
return new Marker();
|
|
}
|
|
getStyle(highlightState) {
|
|
const { styler, marker, fill, fillOpacity, lineDash, lineDashOffset, stroke, strokeOpacity, strokeWidth } = this.properties;
|
|
const { size, shape, fill: markerFill = "transparent", fillOpacity: markerFillOpacity } = marker;
|
|
let stylerResult = {};
|
|
if (styler) {
|
|
const stylerParams = this.makeStylerParams(highlightState);
|
|
const cbResult = this.cachedCallWithContext(styler, stylerParams) ?? {};
|
|
const resolved = this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
cbResult,
|
|
{ pick: false }
|
|
);
|
|
stylerResult = resolved ?? {};
|
|
}
|
|
stylerResult.marker ?? (stylerResult.marker = {});
|
|
return {
|
|
fill: stylerResult.fill ?? fill,
|
|
fillOpacity: stylerResult.fillOpacity ?? fillOpacity,
|
|
lineDash: stylerResult.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.lineDashOffset ?? lineDashOffset,
|
|
stroke: stylerResult.stroke ?? stroke,
|
|
strokeOpacity: stylerResult.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.strokeWidth ?? strokeWidth,
|
|
marker: {
|
|
enabled: stylerResult.marker.enabled ?? marker.enabled,
|
|
fill: stylerResult.marker.fill ?? markerFill,
|
|
fillOpacity: stylerResult.marker.fillOpacity ?? markerFillOpacity,
|
|
shape: stylerResult.marker.shape ?? shape,
|
|
size: stylerResult.marker.size ?? size,
|
|
lineDash: stylerResult.marker.lineDash ?? marker.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.marker.lineDashOffset ?? marker.lineDashOffset ?? lineDashOffset,
|
|
stroke: stylerResult.marker.stroke ?? marker.stroke ?? stroke,
|
|
strokeOpacity: stylerResult.marker.strokeOpacity ?? marker.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.marker.strokeWidth ?? marker.strokeWidth ?? strokeWidth
|
|
}
|
|
};
|
|
}
|
|
getFormattedMarkerStyle(datum) {
|
|
const stylerStyle = this.getStyle();
|
|
const params = this.makeItemStylerParams(
|
|
this.dataModel,
|
|
this.processedData,
|
|
datum.datumIndex,
|
|
stylerStyle.marker
|
|
);
|
|
return this.getMarkerStyle(
|
|
this.properties.marker,
|
|
datum,
|
|
params,
|
|
{ isHighlight: true },
|
|
void 0,
|
|
stylerStyle
|
|
);
|
|
}
|
|
isPointInArea(x, y) {
|
|
let fillPath;
|
|
for (const child of this.backgroundGroup.children()) {
|
|
if (child instanceof Path) {
|
|
fillPath = child;
|
|
break;
|
|
}
|
|
}
|
|
if (!fillPath?.getBBox().containsPoint(x, y)) {
|
|
return false;
|
|
}
|
|
return fillPath.isPointInPath(x, y);
|
|
}
|
|
computeFocusBounds(opts) {
|
|
return computeMarkerFocusBounds(this, opts);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.styler != null || this.properties.marker.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
AreaSeries.className = "AreaSeries";
|
|
AreaSeries.type = "area";
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/areaSeriesModule.ts
|
|
var themeTemplate = {
|
|
series: {
|
|
nodeClickRange: "nearest",
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", import_ag_charts_core249.FILL_GRADIENT_LINEAR_DEFAULTS],
|
|
["image", import_ag_charts_core249.FILL_IMAGE_DEFAULTS],
|
|
["pattern", import_ag_charts_core249.FILL_PATTERN_DEFAULTS]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
fillOpacity: 0.8,
|
|
strokeOpacity: 1,
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] },
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
shadow: {
|
|
enabled: false,
|
|
color: import_ag_charts_core249.DEFAULT_SHADOW_COLOUR,
|
|
xOffset: 3,
|
|
yOffset: 3,
|
|
blur: 5
|
|
},
|
|
interpolation: {
|
|
type: "linear"
|
|
},
|
|
marker: {
|
|
enabled: false,
|
|
shape: "circle",
|
|
size: 7,
|
|
strokeWidth: { $isUserOption: ["./stroke", 1, 0] },
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", import_ag_charts_core249.FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS],
|
|
["pattern", import_ag_charts_core249.FILL_PATTERN_DEFAULTS]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" }
|
|
},
|
|
label: {
|
|
...import_ag_charts_core249.LABEL_BOXING_DEFAULTS,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
tooltip: {
|
|
range: { $path: ["/tooltip/range", "nearest"] },
|
|
position: {
|
|
anchorTo: { $path: ["/tooltip/position/anchorTo", "node"] }
|
|
}
|
|
},
|
|
highlight: import_ag_charts_core249.MARKER_SERIES_HIGHLIGHT_STYLE,
|
|
segmentation: import_ag_charts_core249.SEGMENTATION_DEFAULTS
|
|
}
|
|
};
|
|
var AreaSeriesModule = {
|
|
type: "series",
|
|
name: "area",
|
|
chartType: "cartesian",
|
|
stackable: true,
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: areaSeriesOptionsDef,
|
|
predictAxis: predictCartesianNonPrimitiveAxis,
|
|
defaultAxes: {
|
|
y: {
|
|
type: import_ag_charts_core249.CARTESIAN_AXIS_TYPE.NUMBER,
|
|
position: import_ag_charts_core249.CARTESIAN_POSITION.LEFT
|
|
},
|
|
x: {
|
|
type: import_ag_charts_core249.CARTESIAN_AXIS_TYPE.CATEGORY,
|
|
position: import_ag_charts_core249.CARTESIAN_POSITION.BOTTOM
|
|
}
|
|
},
|
|
axisKeys: { [import_ag_charts_core249.ChartAxisDirection.X]: "xKeyAxis", [import_ag_charts_core249.ChartAxisDirection.Y]: "yKeyAxis" },
|
|
themeTemplate,
|
|
create: (ctx) => new AreaSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/barSeriesModule.ts
|
|
var import_ag_charts_core254 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/barSeries.ts
|
|
var import_ag_charts_core253 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/scene/shape/barShape.ts
|
|
var import_ag_charts_core250 = require("ag-charts-core");
|
|
var FEATHERED_THRESHOLD = 1e-3;
|
|
var BarShape = class extends Rect {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.direction = "x";
|
|
this.featherRatio = 0;
|
|
}
|
|
// optimised field accessor
|
|
/**
|
|
* High-performance static property setter that bypasses the decorator system entirely.
|
|
* Writes directly to backing fields (__propertyName) to avoid:
|
|
* - Decorator setter chains and equality checks
|
|
* - Multiple onChangeDetection calls per property
|
|
* - Object.keys() iteration in assignIfNotStrictlyEqual
|
|
* - Object allocation overhead
|
|
*
|
|
* A single markDirty() call at the end ensures the scene graph is properly invalidated.
|
|
* WARNING: Only use for hot paths where performance is critical and properties don't need
|
|
* individual change detection (e.g., when updating many nodes in a loop).
|
|
*/
|
|
setStaticProperties(drawingMode, topLeftCornerRadius, topRightCornerRadius, bottomRightCornerRadius, bottomLeftCornerRadius, visible, crisp, fillShadow, direction, featherRatio) {
|
|
this.__direction = direction ?? "x";
|
|
this.__featherRatio = featherRatio ?? 0;
|
|
super.setStaticProperties(
|
|
drawingMode,
|
|
topLeftCornerRadius,
|
|
topRightCornerRadius,
|
|
bottomRightCornerRadius,
|
|
bottomLeftCornerRadius,
|
|
visible,
|
|
crisp,
|
|
fillShadow
|
|
);
|
|
}
|
|
get feathered() {
|
|
return Math.abs(this.featherRatio) > FEATHERED_THRESHOLD;
|
|
}
|
|
isPointInPath(x, y) {
|
|
if (!this.feathered) {
|
|
return super.isPointInPath(x, y);
|
|
}
|
|
const bbox = this.getBBox();
|
|
return bbox.containsPoint(x, y);
|
|
}
|
|
updatePath() {
|
|
if (!this.feathered) {
|
|
super.updatePath();
|
|
return;
|
|
}
|
|
const {
|
|
path,
|
|
borderPath,
|
|
__direction: direction,
|
|
__featherRatio: featherRatio,
|
|
__x: x,
|
|
__y: y,
|
|
__width: width,
|
|
__height: height
|
|
} = this;
|
|
path.clear();
|
|
borderPath.clear();
|
|
if (direction === "x") {
|
|
const featherInsetX = Math.abs(featherRatio) * width;
|
|
if (featherRatio > 0) {
|
|
path.moveTo(x, y);
|
|
path.lineTo(x + width - featherInsetX, y);
|
|
path.lineTo(x + width, y + height / 2);
|
|
path.lineTo(x + width - featherInsetX, y + height);
|
|
path.lineTo(x, y + height);
|
|
path.closePath();
|
|
} else {
|
|
path.moveTo(x + featherInsetX, y);
|
|
path.lineTo(x + width, y);
|
|
path.lineTo(x + width, y + height);
|
|
path.lineTo(x + featherInsetX, y + height);
|
|
path.lineTo(x, y + height / 2);
|
|
path.closePath();
|
|
}
|
|
} else {
|
|
const featherInsetY = Math.abs(featherRatio) * height;
|
|
if (featherRatio > 0) {
|
|
path.moveTo(x, y + featherInsetY);
|
|
path.lineTo(x + width / 2, y);
|
|
path.lineTo(x + width, y + featherInsetY);
|
|
path.lineTo(x + width, y + height);
|
|
path.lineTo(x, y + height);
|
|
path.closePath();
|
|
} else {
|
|
path.moveTo(x, y);
|
|
path.lineTo(x + width, y);
|
|
path.lineTo(x + width, y + height - featherInsetY);
|
|
path.lineTo(x + width / 2, y + height);
|
|
path.lineTo(x, y + height - featherInsetY);
|
|
path.closePath();
|
|
}
|
|
}
|
|
}
|
|
renderStroke(ctx) {
|
|
if (!this.feathered) {
|
|
super.renderStroke(ctx);
|
|
return;
|
|
}
|
|
const {
|
|
__stroke: stroke,
|
|
__strokeWidth: strokeWidth,
|
|
__lineDash: lineDash,
|
|
__lineDashOffset: lineDashOffset,
|
|
__lineCap: lineCap,
|
|
__lineJoin: lineJoin,
|
|
path
|
|
} = this;
|
|
if (stroke && strokeWidth) {
|
|
const { globalAlpha } = ctx;
|
|
this.applyStrokeAndAlpha(ctx);
|
|
ctx.lineWidth = strokeWidth;
|
|
if (lineDash) {
|
|
ctx.setLineDash(lineDash);
|
|
}
|
|
if (lineDashOffset) {
|
|
ctx.lineDashOffset = lineDashOffset;
|
|
}
|
|
if (lineCap) {
|
|
ctx.lineCap = lineCap;
|
|
}
|
|
if (lineJoin) {
|
|
ctx.lineJoin = lineJoin;
|
|
}
|
|
ctx.stroke(path.getPath2D());
|
|
ctx.globalAlpha = globalAlpha;
|
|
}
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core250.DeclaredSceneChangeDetection)()
|
|
], BarShape.prototype, "direction", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core250.DeclaredSceneChangeDetection)()
|
|
], BarShape.prototype, "featherRatio", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/barAggregation.ts
|
|
var import_ag_charts_core251 = require("ag-charts-core");
|
|
function computeBarAggregation(domain, xValues, yStartValues, yEndValues, options) {
|
|
if (xValues.length < import_ag_charts_core251.AGGREGATION_THRESHOLD)
|
|
return;
|
|
const [d0, d1] = domain;
|
|
const { smallestKeyInterval, xNeedsValueOf, yNeedsValueOf, existingFilters } = options;
|
|
let maxRange = (0, import_ag_charts_core251.aggregationRangeFittingPoints)(xValues, d0, d1, { smallestKeyInterval, xNeedsValueOf });
|
|
const existingFilter = existingFilters?.find((f) => f.maxRange === maxRange);
|
|
let {
|
|
indexData: positiveIndexData,
|
|
valueData: positiveValueData,
|
|
negativeIndexData,
|
|
negativeValueData
|
|
} = (0, import_ag_charts_core251.createAggregationIndices)(xValues, yEndValues, yStartValues ?? yEndValues, d0, d1, maxRange, {
|
|
split: true,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
reuseIndexData: existingFilter?.positiveIndexData,
|
|
reuseValueData: existingFilter?.positiveValueData,
|
|
reuseNegativeIndexData: existingFilter?.negativeIndexData,
|
|
reuseNegativeValueData: existingFilter?.negativeValueData
|
|
});
|
|
if (!negativeIndexData || !negativeValueData) {
|
|
throw new Error("Negative aggregation data missing in split mode");
|
|
}
|
|
let positiveIndices = (0, import_ag_charts_core251.getMidpointsForIndices)(maxRange, positiveIndexData, existingFilter?.positiveIndices);
|
|
let negativeIndices = (0, import_ag_charts_core251.getMidpointsForIndices)(maxRange, negativeIndexData, existingFilter?.negativeIndices);
|
|
const filters = [
|
|
{
|
|
maxRange,
|
|
positiveIndices,
|
|
positiveIndexData,
|
|
positiveValueData,
|
|
negativeIndices,
|
|
negativeIndexData,
|
|
negativeValueData
|
|
}
|
|
];
|
|
while (maxRange > 64) {
|
|
const currentMaxRange = maxRange;
|
|
const nextMaxRange = Math.trunc(currentMaxRange / 2);
|
|
const nextExistingFilter = existingFilters?.find((f) => f.maxRange === nextMaxRange);
|
|
const positiveCompacted = (0, import_ag_charts_core251.compactAggregationIndices)(positiveIndexData, positiveValueData, currentMaxRange, {
|
|
reuseIndexData: nextExistingFilter?.positiveIndexData,
|
|
reuseValueData: nextExistingFilter?.positiveValueData
|
|
});
|
|
const negativeCompacted = (0, import_ag_charts_core251.compactAggregationIndices)(negativeIndexData, negativeValueData, currentMaxRange, {
|
|
reuseIndexData: nextExistingFilter?.negativeIndexData,
|
|
reuseValueData: nextExistingFilter?.negativeValueData
|
|
});
|
|
maxRange = positiveCompacted.maxRange;
|
|
positiveIndexData = positiveCompacted.indexData;
|
|
positiveValueData = positiveCompacted.valueData;
|
|
positiveIndices = positiveCompacted.midpointData ?? (0, import_ag_charts_core251.getMidpointsForIndices)(maxRange, positiveIndexData, nextExistingFilter?.positiveIndices);
|
|
negativeIndexData = negativeCompacted.indexData;
|
|
negativeValueData = negativeCompacted.valueData;
|
|
negativeIndices = negativeCompacted.midpointData ?? (0, import_ag_charts_core251.getMidpointsForIndices)(maxRange, negativeIndexData, nextExistingFilter?.negativeIndices);
|
|
filters.push({
|
|
maxRange,
|
|
positiveIndices,
|
|
positiveIndexData,
|
|
positiveValueData,
|
|
negativeIndices,
|
|
negativeIndexData,
|
|
negativeValueData
|
|
});
|
|
}
|
|
filters.reverse();
|
|
return filters;
|
|
}
|
|
function computeBarAggregationPartial(domain, xValues, yStartValues, yEndValues, options) {
|
|
if (xValues.length < import_ag_charts_core251.AGGREGATION_THRESHOLD)
|
|
return;
|
|
const [d0, d1] = domain;
|
|
const { smallestKeyInterval, xNeedsValueOf, yNeedsValueOf, targetRange, existingFilters } = options;
|
|
const finestMaxRange = (0, import_ag_charts_core251.aggregationRangeFittingPoints)(xValues, d0, d1, { smallestKeyInterval, xNeedsValueOf });
|
|
const targetMaxRange = Math.min(finestMaxRange, (0, import_ag_charts_core251.nextPowerOf2)(Math.max(targetRange, import_ag_charts_core251.AGGREGATION_MIN_RANGE)));
|
|
const existingFilter = existingFilters?.find((f) => f.maxRange === targetMaxRange);
|
|
const {
|
|
indexData: positiveIndexData,
|
|
valueData: positiveValueData,
|
|
negativeIndexData,
|
|
negativeValueData
|
|
} = (0, import_ag_charts_core251.createAggregationIndices)(xValues, yEndValues, yStartValues ?? yEndValues, d0, d1, targetMaxRange, {
|
|
split: true,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
reuseIndexData: existingFilter?.positiveIndexData,
|
|
reuseValueData: existingFilter?.positiveValueData,
|
|
reuseNegativeIndexData: existingFilter?.negativeIndexData,
|
|
reuseNegativeValueData: existingFilter?.negativeValueData
|
|
});
|
|
if (!negativeIndexData || !negativeValueData) {
|
|
throw new Error("Negative aggregation data missing in split mode");
|
|
}
|
|
const immediateLevel = {
|
|
maxRange: targetMaxRange,
|
|
positiveIndices: (0, import_ag_charts_core251.getMidpointsForIndices)(targetMaxRange, positiveIndexData, existingFilter?.positiveIndices),
|
|
positiveIndexData,
|
|
positiveValueData,
|
|
negativeIndices: (0, import_ag_charts_core251.getMidpointsForIndices)(targetMaxRange, negativeIndexData, existingFilter?.negativeIndices),
|
|
negativeIndexData,
|
|
negativeValueData
|
|
};
|
|
function computeRemaining() {
|
|
const allLevels = computeBarAggregation([d0, d1], xValues, yStartValues, yEndValues, {
|
|
smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
return allLevels?.filter((level) => level.maxRange !== targetMaxRange) ?? [];
|
|
}
|
|
return { immediate: [immediateLevel], computeRemaining };
|
|
}
|
|
function aggregateBarData(scale2, xValues, yStartValues, yEndValues, domainInput, smallestKeyInterval, xNeedsValueOf, yNeedsValueOf) {
|
|
const [d0, d1] = (0, import_ag_charts_core251.aggregationDomain)(scale2, domainInput);
|
|
return computeBarAggregation([d0, d1], xValues, yStartValues, yEndValues, {
|
|
smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
});
|
|
}
|
|
var memoizedAggregateBarData = (0, import_ag_charts_core251.simpleMemorize2)(aggregateBarData);
|
|
function aggregateBarDataFromDataModel(scale2, dataModel, processedData, series, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const isStacked = dataModel.hasColumnById(series, "yValue-start");
|
|
const yStartValues = isStacked ? dataModel.resolveColumnById(series, "yValue-start", processedData) : void 0;
|
|
const yEndValues = isStacked ? dataModel.resolveColumnById(series, "yValue-end", processedData) : dataModel.resolveColumnById(series, "yValue-raw", processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(
|
|
series,
|
|
isStacked ? "yValue-end" : "yValue-raw",
|
|
processedData
|
|
);
|
|
if (existingFilters) {
|
|
const [d0, d1] = (0, import_ag_charts_core251.aggregationDomain)(scale2, domainInput);
|
|
return computeBarAggregation([d0, d1], xValues, yStartValues, yEndValues, {
|
|
smallestKeyInterval: processedData.reduced?.smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
}
|
|
return memoizedAggregateBarData(
|
|
scale2,
|
|
xValues,
|
|
yStartValues,
|
|
yEndValues,
|
|
domainInput,
|
|
processedData.reduced?.smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
);
|
|
}
|
|
function aggregateBarDataFromDataModelPartial(scale2, dataModel, processedData, series, targetRange, existingFilters) {
|
|
const xValues = dataModel.resolveKeysById(series, "xValue", processedData);
|
|
const isStacked = dataModel.hasColumnById(series, "yValue-start");
|
|
const yStartValues = isStacked ? dataModel.resolveColumnById(series, "yValue-start", processedData) : void 0;
|
|
const yEndValues = isStacked ? dataModel.resolveColumnById(series, "yValue-end", processedData) : dataModel.resolveColumnById(series, "yValue-raw", processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "key", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(
|
|
series,
|
|
isStacked ? "yValue-end" : "yValue-raw",
|
|
processedData
|
|
);
|
|
const [d0, d1] = (0, import_ag_charts_core251.aggregationDomain)(scale2, domainInput);
|
|
return computeBarAggregationPartial([d0, d1], xValues, yStartValues, yEndValues, {
|
|
smallestKeyInterval: processedData.reduced?.smallestKeyInterval,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
targetRange,
|
|
existingFilters
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/barSeriesProperties.ts
|
|
var import_ag_charts_core252 = require("ag-charts-core");
|
|
var BarSeriesLabel = class extends Label {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.placement = "inside-center";
|
|
this.spacing = 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesLabel.prototype, "placement", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesLabel.prototype, "spacing", 2);
|
|
var BarSeriesProperties = class extends AbstractBarSeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "#c16068";
|
|
this.fillOpacity = 1;
|
|
this.stroke = "#874349";
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.cornerRadius = 0;
|
|
this.crisp = void 0;
|
|
this.shadow = new DropShadow();
|
|
this.label = new BarSeriesLabel();
|
|
this.tooltip = makeSeriesTooltip();
|
|
this.sparklineMode = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "yKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "yFilterKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "stackGroup", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "normalizedTo", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "crisp", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "simpleItemStyler", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "shadow", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "tooltip", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core252.Property
|
|
], BarSeriesProperties.prototype, "sparklineMode", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/barSeries.ts
|
|
var BarSeries = class extends AbstractBarSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
propertyKeys: DEFAULT_CARTESIAN_DIRECTION_KEYS,
|
|
propertyNames: DEFAULT_CARTESIAN_DIRECTION_NAMES,
|
|
categoryKey: "xValue",
|
|
pickModes: [
|
|
2 /* AXIS_ALIGNED */,
|
|
// Only used in sparklineMode
|
|
1 /* NEAREST_NODE */,
|
|
0 /* EXACT_SHAPE_MATCH */
|
|
],
|
|
pathsPerSeries: [],
|
|
datumSelectionGarbageCollection: false,
|
|
animationAlwaysUpdateSelections: true,
|
|
animationResetFns: {
|
|
datum: resetBarSelectionsFn,
|
|
label: resetLabelFn
|
|
}
|
|
});
|
|
this.properties = new BarSeriesProperties();
|
|
this.connectsToYAxis = true;
|
|
this.aggregationManager = new AggregationManager();
|
|
this.phantomGroup = this.contentGroup.appendChild(new Group({ name: "phantom", zIndex: -1 }));
|
|
this.phantomSelection = Selection.select(
|
|
this.phantomGroup,
|
|
() => this.nodeFactory(),
|
|
false
|
|
);
|
|
this.phantomHighlightGroup = this.highlightGroup.appendChild(
|
|
new Group({ name: `${this.internalId}-highlight-node` })
|
|
);
|
|
this.phantomHighlightSelection = Selection.select(
|
|
this.phantomHighlightGroup,
|
|
() => this.nodeFactory(),
|
|
false
|
|
);
|
|
this.phantomGroup.opacity = 0.2;
|
|
this.phantomHighlightGroup.opacity = 0.2;
|
|
}
|
|
get pickModeAxis() {
|
|
return this.properties.sparklineMode ? "main" : void 0;
|
|
}
|
|
crossFilteringEnabled() {
|
|
return this.properties.yFilterKey != null && (this.seriesGrouping == null || this.seriesGrouping.stackIndex === 0);
|
|
}
|
|
async processData(dataController) {
|
|
if (!this.data)
|
|
return;
|
|
const { xKey, yKey, yFilterKey, normalizedTo } = this.properties;
|
|
const { seriesGrouping: { groupIndex = this.id } = {}, data } = this;
|
|
const stackCount = this.seriesGrouping?.stackCount ?? 0;
|
|
const stacked = stackCount > 1 || normalizedTo != null;
|
|
const grouped = stacked;
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const xScale = this.getCategoryAxis()?.scale;
|
|
const yScale = this.getValueAxis()?.scale;
|
|
const { isContinuousX, xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const stackGroupName = `bar-stack-${groupIndex}-yValues`;
|
|
const stackGroupTrailingName = `${stackGroupName}-trailing`;
|
|
const visibleProps = this.visible ? {} : { forceValue: 0 };
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const props = [
|
|
keyProperty(xKey, xScaleType, { id: "xValue", allowNullKey }),
|
|
valueProperty(yKey, yScaleType, { id: `yValue-raw`, invalidValue: null, ...visibleProps })
|
|
];
|
|
if (this.crossFilteringEnabled()) {
|
|
props.push(
|
|
valueProperty(yFilterKey, yScaleType, {
|
|
id: `yFilterValue`,
|
|
invalidValue: null,
|
|
...visibleProps
|
|
})
|
|
);
|
|
}
|
|
if (stacked) {
|
|
props.push(
|
|
...groupAccumulativeValueProperty(
|
|
yKey,
|
|
"normal",
|
|
{
|
|
id: `yValue-end`,
|
|
rangeId: `yValue-range`,
|
|
invalidValue: null,
|
|
missingValue: 0,
|
|
groupId: stackGroupName,
|
|
separateNegative: true,
|
|
...visibleProps
|
|
},
|
|
yScaleType
|
|
),
|
|
...groupAccumulativeValueProperty(
|
|
yKey,
|
|
"trailing",
|
|
{
|
|
id: `yValue-start`,
|
|
invalidValue: null,
|
|
missingValue: 0,
|
|
groupId: stackGroupTrailingName,
|
|
separateNegative: true,
|
|
...visibleProps
|
|
},
|
|
yScaleType
|
|
)
|
|
);
|
|
}
|
|
if (isContinuousX) {
|
|
props.push(SMALLEST_KEY_INTERVAL, LARGEST_KEY_INTERVAL);
|
|
}
|
|
if ((0, import_ag_charts_core253.isFiniteNumber)(normalizedTo)) {
|
|
props.push(normaliseGroupTo([stackGroupName, stackGroupTrailingName], Math.abs(normalizedTo)));
|
|
}
|
|
if (this.needsDataModelDiff() && this.processedData) {
|
|
props.push(diff(this.id, this.processedData));
|
|
}
|
|
if (animationEnabled || !grouped) {
|
|
props.push(animationValidation());
|
|
}
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, data, {
|
|
props,
|
|
groupByKeys: grouped,
|
|
groupByData: !grouped
|
|
});
|
|
this.aggregateData(dataModel, processedData);
|
|
this.smallestDataInterval = processedData.reduced?.smallestKeyInterval;
|
|
this.largestDataInterval = processedData.reduced?.largestKeyInterval;
|
|
this.animationState.transition("updateData");
|
|
}
|
|
yCumulativeKey(dataModel) {
|
|
return dataModel.hasColumnById(this, `yValue-end`) ? "yValue-end" : "yValue-raw";
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { processedData, dataModel } = this;
|
|
if (dataModel == null || processedData == null)
|
|
return { domain: [] };
|
|
if (direction === this.getCategoryDirection()) {
|
|
const keyDef = dataModel.resolveProcessedDataDefById(this, `xValue`);
|
|
const keys = dataModel.getDomain(this, `xValue`, "key", processedData);
|
|
if (keyDef?.def.type === "key" && keyDef.def.valueType === "category") {
|
|
return keys;
|
|
}
|
|
return { domain: this.padBandExtent(keys.domain) };
|
|
}
|
|
const yKey = this.yCumulativeKey(dataModel);
|
|
let yExtent = this.domainForClippedRange(direction, [yKey], "xValue");
|
|
const yFilterExtent = this.crossFilteringEnabled() ? dataModel.getDomain(this, `yFilterValue`, "value", processedData).domain : void 0;
|
|
if (yFilterExtent != null) {
|
|
yExtent = [Math.min(yExtent[0], yFilterExtent[0]), Math.max(yExtent[1], yFilterExtent[1])];
|
|
}
|
|
const yAxis = this.getValueAxis();
|
|
if (yAxis instanceof NumberAxis && !(yAxis instanceof LogAxis)) {
|
|
const fixedYExtent = Number.isFinite(yExtent[1] - yExtent[0]) ? [Math.min(0, yExtent[0]), Math.max(0, yExtent[1])] : [];
|
|
return { domain: fixNumericExtent(fixedYExtent) };
|
|
} else {
|
|
return { domain: fixNumericExtent(yExtent) };
|
|
}
|
|
}
|
|
getSeriesRange(direction, visibleRange) {
|
|
const selfDirection = this.properties.direction === "horizontal" ? import_ag_charts_core253.ChartAxisDirection.X : import_ag_charts_core253.ChartAxisDirection.Y;
|
|
if (selfDirection !== direction)
|
|
return [];
|
|
const yKey = this.yCumulativeKey(this.dataModel);
|
|
const [y0, y1] = this.domainForVisibleRange(import_ag_charts_core253.ChartAxisDirection.Y, [yKey], "xValue", visibleRange);
|
|
return [Math.min(y0, 0), Math.max(y1, 0)];
|
|
}
|
|
getZoomRangeFittingItems(xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
const yKey = this.yCumulativeKey(this.dataModel);
|
|
return this.zoomFittingVisibleItems("xValue", [yKey], xVisibleRange, yVisibleRange, minVisibleItems);
|
|
}
|
|
getVisibleItems(xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
const yKey = this.yCumulativeKey(this.dataModel);
|
|
return this.countVisibleItems("xValue", [yKey], xVisibleRange, yVisibleRange, minVisibleItems);
|
|
}
|
|
aggregateData(dataModel, processedData) {
|
|
this.aggregationManager.markStale(processedData.input.count);
|
|
if (processedDataIsAnimatable(processedData))
|
|
return;
|
|
const xAxis = this.axes[import_ag_charts_core253.ChartAxisDirection.X];
|
|
if (xAxis == null)
|
|
return;
|
|
const targetRange = this.estimateTargetRange();
|
|
this.aggregationManager.aggregate({
|
|
computePartial: (existingFilters) => aggregateBarDataFromDataModelPartial(
|
|
xAxis.scale.type,
|
|
dataModel,
|
|
processedData,
|
|
this,
|
|
targetRange,
|
|
existingFilters
|
|
),
|
|
computeFull: (existingFilters) => aggregateBarDataFromDataModel(xAxis.scale.type, dataModel, processedData, this, existingFilters),
|
|
targetRange
|
|
});
|
|
const filters = this.aggregationManager.filters;
|
|
if (filters && filters.length > 0) {
|
|
import_ag_charts_core253.DebugMetrics.record(
|
|
`${this.type}:aggregation`,
|
|
filters.map((f) => f.maxRange)
|
|
);
|
|
}
|
|
}
|
|
estimateTargetRange() {
|
|
const xAxis = this.axes[import_ag_charts_core253.ChartAxisDirection.X];
|
|
if (xAxis?.scale?.range) {
|
|
const [r0, r1] = xAxis.scale.range;
|
|
return Math.abs(r1 - r0);
|
|
}
|
|
return this.ctx.scene?.canvas?.width ?? 800;
|
|
}
|
|
/**
|
|
* Creates shared context for node datum creation/update operations.
|
|
* This context is instantiated once and reused across all datum operations
|
|
* to minimize memory allocations. Only caches values that are expensive to
|
|
* compute - cheap property lookups use `this` directly.
|
|
*/
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return void 0;
|
|
const rawData = processedData.dataSources?.get(this.id);
|
|
if (rawData == null)
|
|
return void 0;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const range4 = Math.abs(xScale.range[1] - xScale.range[0]);
|
|
this.aggregationManager.ensureLevelForRange(range4);
|
|
const dataAggregationFilter = this.aggregationManager.getFilterForRange(range4);
|
|
const isStacked = dataModel.hasColumnById(this, `yValue-start`);
|
|
const { label } = this.properties;
|
|
const canIncrementallyUpdate = this.canIncrementallyUpdateNodes(dataAggregationFilter != null);
|
|
const { groupOffset, barOffset, barWidth } = this.getBarDimensions();
|
|
return {
|
|
dataSource: rawData,
|
|
rawData: rawData.data,
|
|
xValues: dataModel.resolveKeysById(this, `xValue`, processedData),
|
|
yRawValues: dataModel.resolveColumnById(this, `yValue-raw`, processedData),
|
|
yFilterValues: this.crossFilteringEnabled() ? dataModel.resolveColumnById(this, `yFilterValue`, processedData) : void 0,
|
|
yStartValues: isStacked ? dataModel.resolveColumnById(this, `yValue-start`, processedData) : void 0,
|
|
yEndValues: isStacked ? dataModel.resolveColumnById(this, `yValue-end`, processedData) : void 0,
|
|
xScale,
|
|
yScale,
|
|
xAxis,
|
|
yAxis,
|
|
groupOffset,
|
|
barOffset,
|
|
barWidth,
|
|
range: range4,
|
|
yReversed: yAxis.isReversed(),
|
|
bboxBottom: yScale.convert(0),
|
|
labelSpacing: label.spacing + (typeof label.padding === "number" ? label.padding : 0),
|
|
crisp: dataAggregationFilter == null && (this.properties.crisp ?? checkCrisp(xAxis?.scale, xAxis?.visibleRange, this.smallestDataInterval, this.largestDataInterval)),
|
|
isStacked,
|
|
animationEnabled: !this.ctx.animationManager.isSkipped(),
|
|
dataAggregationFilter,
|
|
canIncrementallyUpdate,
|
|
phantomNodes: canIncrementallyUpdate ? this.contextNodeData.phantomNodeData ?? [] : [],
|
|
nodes: canIncrementallyUpdate ? this.contextNodeData.nodeData : [],
|
|
labels: canIncrementallyUpdate ? this.contextNodeData.labelData : [],
|
|
nodeIndex: 0,
|
|
phantomIndex: 0,
|
|
barAlongX: this.getBarDirection() === import_ag_charts_core253.ChartAxisDirection.X,
|
|
shouldFlipXY: this.shouldFlipXY(),
|
|
xKey: this.properties.xKey,
|
|
yKey: this.properties.yKey,
|
|
xName: this.properties.xName,
|
|
yName: this.properties.yName,
|
|
legendItemName: this.properties.legendItemName,
|
|
label,
|
|
yDomain: this.getSeriesDomain(import_ag_charts_core253.ChartAxisDirection.Y).domain
|
|
};
|
|
}
|
|
/**
|
|
* Computes the x position for a datum at the given index.
|
|
*/
|
|
computeXPosition(ctx, datumIndex) {
|
|
const x = ctx.xScale.convert(ctx.xValues[datumIndex]);
|
|
if (!Number.isFinite(x))
|
|
return Number.NaN;
|
|
return x + ctx.groupOffset + ctx.barOffset;
|
|
}
|
|
prepareNodeDatumState(ctx, nodeDatumScratch, datumIndex, yStart, yEnd) {
|
|
if (!Number.isFinite(yEnd)) {
|
|
return void 0;
|
|
}
|
|
const xValue = ctx.xValues[datumIndex];
|
|
if (xValue === void 0 && !this.properties.allowNullKeys) {
|
|
return void 0;
|
|
}
|
|
const datum = ctx.dataSource?.data[datumIndex];
|
|
const yRawValue = ctx.yRawValues[datumIndex];
|
|
const yFilterValue = ctx.yFilterValues == null ? void 0 : Number(ctx.yFilterValues[datumIndex]);
|
|
if (yFilterValue != null && !Number.isFinite(yFilterValue)) {
|
|
return void 0;
|
|
}
|
|
const labelText = ctx.label.enabled && yRawValue != null ? this.getLabelText(
|
|
yFilterValue ?? yRawValue,
|
|
datum,
|
|
ctx.yKey,
|
|
"y",
|
|
ctx.yDomain,
|
|
ctx.label,
|
|
{
|
|
datum,
|
|
value: yFilterValue ?? yRawValue,
|
|
xKey: ctx.xKey,
|
|
yKey: ctx.yKey,
|
|
xName: ctx.xName,
|
|
yName: ctx.yName,
|
|
legendItemName: ctx.legendItemName
|
|
}
|
|
) : void 0;
|
|
const isPositive = yRawValue >= 0 && !Object.is(yRawValue, -0);
|
|
nodeDatumScratch.datum = datum;
|
|
nodeDatumScratch.xValue = xValue;
|
|
nodeDatumScratch.yRawValue = yRawValue;
|
|
nodeDatumScratch.yFilterValue = yFilterValue;
|
|
nodeDatumScratch.labelText = labelText;
|
|
nodeDatumScratch.inset = yFilterValue != null && yFilterValue > yRawValue;
|
|
nodeDatumScratch.isPositive = isPositive;
|
|
nodeDatumScratch.precomputedBottomY = yFilterValue == null ? void 0 : ctx.yScale.convert(yStart);
|
|
nodeDatumScratch.precomputedIsUpward = yFilterValue == null ? void 0 : isPositive !== ctx.yReversed;
|
|
return nodeDatumScratch;
|
|
}
|
|
/**
|
|
* Creates a skeleton BarNodeDatum with minimal required fields.
|
|
* The node will be populated by updateNodeDatum.
|
|
*/
|
|
createSkeletonNodeDatum(ctx, params, phantom) {
|
|
const scratch = params.nodeDatumScratch;
|
|
return {
|
|
series: this,
|
|
datum: scratch.datum,
|
|
datumIndex: params.datumIndex,
|
|
cumulativeValue: 0,
|
|
// Will be updated by updateNodeDatum
|
|
phantom,
|
|
xValue: scratch.xValue ?? "",
|
|
yValue: 0,
|
|
// Will be updated by updateNodeDatum
|
|
yKey: ctx.yKey,
|
|
xKey: ctx.xKey,
|
|
capDefaults: {
|
|
lengthRatioMultiplier: 0,
|
|
// Will be updated by updateNodeDatum
|
|
lengthMax: 0
|
|
// Will be updated by updateNodeDatum
|
|
},
|
|
x: 0,
|
|
// Will be updated by updateNodeDatum
|
|
y: 0,
|
|
// Will be updated by updateNodeDatum
|
|
width: 0,
|
|
// Will be updated by updateNodeDatum
|
|
height: 0,
|
|
// Will be updated by updateNodeDatum
|
|
midPoint: { x: 0, y: 0 },
|
|
// Required - updated in place by updateNodeDatum
|
|
opacity: params.opacity,
|
|
featherRatio: params.featherRatio,
|
|
topLeftCornerRadius: false,
|
|
// Will be updated by updateNodeDatum
|
|
topRightCornerRadius: false,
|
|
// Will be updated by updateNodeDatum
|
|
bottomRightCornerRadius: false,
|
|
// Will be updated by updateNodeDatum
|
|
bottomLeftCornerRadius: false,
|
|
// Will be updated by updateNodeDatum
|
|
clipBBox: void 0,
|
|
// Will be created/updated by updateNodeDatum
|
|
crisp: ctx.crisp,
|
|
label: void 0,
|
|
// Will be created/updated by updateNodeDatum
|
|
missing: false,
|
|
// Will be updated by updateNodeDatum
|
|
focusable: !phantom
|
|
};
|
|
}
|
|
/**
|
|
* Creates a BarNodeDatum (and optionally a phantom node) for a single data point.
|
|
* Creates skeleton nodes and uses updateNodeDatum to populate them with calculated values.
|
|
*/
|
|
createNodeDatum(ctx, params) {
|
|
const prepared = this.prepareNodeDatumState(
|
|
ctx,
|
|
params.nodeDatumScratch,
|
|
params.datumIndex,
|
|
params.yStart,
|
|
params.yEnd
|
|
);
|
|
if (!prepared) {
|
|
return { nodeData: void 0, phantomNodeData: void 0 };
|
|
}
|
|
const nodeData = this.createSkeletonNodeDatum(ctx, params, false);
|
|
this.updateNodeDatum(ctx, nodeData, params, prepared);
|
|
let phantomNodeData;
|
|
if (prepared.yFilterValue != null) {
|
|
phantomNodeData = this.createSkeletonNodeDatum(ctx, params, true);
|
|
this.updateNodeDatum(ctx, phantomNodeData, params);
|
|
}
|
|
return { nodeData, phantomNodeData };
|
|
}
|
|
/**
|
|
* Updates an existing BarNodeDatum in-place for value-only changes.
|
|
* This is more efficient than recreating the entire node when only data values change
|
|
* but the structure (insertions/removals) remains the same.
|
|
*/
|
|
updateNodeDatum(ctx, node, params, prepared) {
|
|
prepared ?? (prepared = this.prepareNodeDatumState(
|
|
ctx,
|
|
params.nodeDatumScratch,
|
|
params.datumIndex,
|
|
params.yStart,
|
|
params.yEnd
|
|
));
|
|
if (!prepared) {
|
|
return;
|
|
}
|
|
const mutableNode = node;
|
|
const phantom = node.phantom;
|
|
const prevY = params.yStart;
|
|
const yValue = phantom ? prepared.yFilterValue : prepared.yFilterValue ?? prepared.yRawValue;
|
|
const cumulativeValue = phantom ? prepared.yFilterValue : prepared.yFilterValue ?? params.yEnd;
|
|
const nodeLabelText = phantom ? void 0 : prepared.labelText;
|
|
let currY;
|
|
if (phantom) {
|
|
currY = params.yEnd;
|
|
} else if (prepared.yFilterValue == null) {
|
|
currY = params.yEnd;
|
|
} else {
|
|
currY = params.yStart + prepared.yFilterValue;
|
|
}
|
|
let nodeYRange;
|
|
if (phantom) {
|
|
nodeYRange = params.yRange;
|
|
} else {
|
|
nodeYRange = Math.max(params.yStart + (prepared.yFilterValue ?? -Infinity), params.yRange);
|
|
}
|
|
let crossScale;
|
|
if (phantom) {
|
|
crossScale = void 0;
|
|
} else if (prepared.inset) {
|
|
crossScale = 0.6;
|
|
} else {
|
|
crossScale = void 0;
|
|
}
|
|
const isUpward = prepared.precomputedIsUpward ?? prepared.isPositive !== ctx.yReversed;
|
|
const y = ctx.yScale.convert(currY);
|
|
const bottomY = prepared.precomputedBottomY ?? ctx.yScale.convert(prevY);
|
|
const bboxHeight = ctx.yScale.convert(nodeYRange);
|
|
const xOffset = params.width * 0.5 * (1 - (crossScale ?? 1));
|
|
const rectX = ctx.barAlongX ? Math.min(y, bottomY) : params.x + xOffset;
|
|
const rectY = ctx.barAlongX ? params.x + xOffset : Math.min(y, bottomY);
|
|
const rectWidth = ctx.barAlongX ? Math.abs(bottomY - y) : params.width * (crossScale ?? 1);
|
|
const rectHeight = ctx.barAlongX ? params.width * (crossScale ?? 1) : Math.abs(bottomY - y);
|
|
const barRectX = ctx.barAlongX ? Math.min(ctx.bboxBottom, bboxHeight) : params.x + xOffset;
|
|
const barRectY = ctx.barAlongX ? params.x + xOffset : Math.min(ctx.bboxBottom, bboxHeight);
|
|
const barRectWidth = ctx.barAlongX ? Math.abs(ctx.bboxBottom - bboxHeight) : params.width * (crossScale ?? 1);
|
|
const barRectHeight = ctx.barAlongX ? params.width * (crossScale ?? 1) : Math.abs(ctx.bboxBottom - bboxHeight);
|
|
mutableNode.datum = prepared.datum;
|
|
mutableNode.datumIndex = params.datumIndex;
|
|
mutableNode.cumulativeValue = cumulativeValue;
|
|
mutableNode.xValue = prepared.xValue;
|
|
mutableNode.yValue = yValue;
|
|
mutableNode.x = barRectX;
|
|
mutableNode.y = barRectY;
|
|
mutableNode.width = barRectWidth;
|
|
mutableNode.height = barRectHeight;
|
|
const mutableMidPoint = mutableNode.midPoint;
|
|
mutableMidPoint.x = rectX + rectWidth / 2;
|
|
mutableMidPoint.y = rectY + rectHeight / 2;
|
|
const lengthRatioMultiplier = ctx.shouldFlipXY ? rectHeight : rectWidth;
|
|
mutableNode.capDefaults.lengthRatioMultiplier = lengthRatioMultiplier;
|
|
mutableNode.capDefaults.lengthMax = lengthRatioMultiplier;
|
|
mutableNode.opacity = params.opacity;
|
|
mutableNode.featherRatio = params.featherRatio;
|
|
mutableNode.topLeftCornerRadius = ctx.barAlongX !== isUpward;
|
|
mutableNode.topRightCornerRadius = isUpward;
|
|
mutableNode.bottomRightCornerRadius = ctx.barAlongX === isUpward;
|
|
mutableNode.bottomLeftCornerRadius = !isUpward;
|
|
const existingClipBBox = mutableNode.clipBBox;
|
|
if (existingClipBBox) {
|
|
existingClipBBox.x = rectX;
|
|
existingClipBBox.y = rectY;
|
|
existingClipBBox.width = rectWidth;
|
|
existingClipBBox.height = rectHeight;
|
|
} else {
|
|
mutableNode.clipBBox = new BBox(rectX, rectY, rectWidth, rectHeight);
|
|
}
|
|
mutableNode.crisp = ctx.crisp;
|
|
if (nodeLabelText == null) {
|
|
mutableNode.label = void 0;
|
|
} else {
|
|
const labelPlacement = adjustLabelPlacement({
|
|
isUpward,
|
|
isVertical: !ctx.barAlongX,
|
|
placement: ctx.label.placement,
|
|
spacing: ctx.labelSpacing,
|
|
rect: { x: rectX, y: rectY, width: rectWidth, height: rectHeight }
|
|
});
|
|
const existingLabel = mutableNode.label;
|
|
if (existingLabel) {
|
|
existingLabel.text = nodeLabelText;
|
|
existingLabel.x = labelPlacement.x;
|
|
existingLabel.y = labelPlacement.y;
|
|
existingLabel.textAlign = labelPlacement.textAlign;
|
|
existingLabel.textBaseline = labelPlacement.textBaseline;
|
|
} else {
|
|
mutableNode.label = {
|
|
text: nodeLabelText,
|
|
...labelPlacement
|
|
};
|
|
}
|
|
}
|
|
mutableNode.missing = isTooltipValueMissing(yValue);
|
|
}
|
|
/**
|
|
* Creates node data using aggregation filters for large datasets.
|
|
*/
|
|
createNodeDataWithAggregation(ctx, xPosition, nodeDatumParamsScratch) {
|
|
const sign = ctx.yReversed ? -1 : 1;
|
|
for (let p = 0; p < 2; p += 1) {
|
|
const positive = p === 0;
|
|
const indices = positive ? ctx.dataAggregationFilter.positiveIndices : ctx.dataAggregationFilter.negativeIndices;
|
|
const indexData = positive ? ctx.dataAggregationFilter.positiveIndexData : ctx.dataAggregationFilter.negativeIndexData;
|
|
const Y_MIN = positive ? import_ag_charts_core253.AGGREGATION_INDEX_Y_MIN : import_ag_charts_core253.AGGREGATION_INDEX_Y_MAX;
|
|
const Y_MAX = positive ? import_ag_charts_core253.AGGREGATION_INDEX_Y_MAX : import_ag_charts_core253.AGGREGATION_INDEX_Y_MIN;
|
|
const visibleRange = this.visibleRangeIndices("xValue", ctx.xAxis.range, indices);
|
|
const start = visibleRange[0];
|
|
const end2 = visibleRange[1];
|
|
for (let i = start; i < end2; i += 1) {
|
|
const aggIndex = i * import_ag_charts_core253.AGGREGATION_SPAN;
|
|
const xMinIndex = indexData[aggIndex + import_ag_charts_core253.AGGREGATION_INDEX_X_MIN];
|
|
const xMaxIndex = indexData[aggIndex + import_ag_charts_core253.AGGREGATION_INDEX_X_MAX];
|
|
const yMinIndex = indexData[aggIndex + Y_MIN];
|
|
const yMaxIndex = indexData[aggIndex + Y_MAX];
|
|
if (xMinIndex === import_ag_charts_core253.AGGREGATION_INDEX_UNSET)
|
|
continue;
|
|
if (ctx.xValues[yMaxIndex] == null || ctx.xValues[yMinIndex] == null)
|
|
continue;
|
|
const x = xPosition(Math.trunc((xMinIndex + xMaxIndex) / 2));
|
|
const width = Math.abs(xPosition(xMaxIndex) - xPosition(xMinIndex)) + ctx.barWidth;
|
|
if (x - width < 0 || x > ctx.range)
|
|
continue;
|
|
const bandCount = Math.abs(xMaxIndex - xMinIndex) + 1;
|
|
const opacity = BandScale.is(ctx.xScale) ? Math.min(ctx.xScale.bandwidth * Math.max(bandCount - 1, 1) / (ctx.xScale.step * bandCount), 1) : 1;
|
|
nodeDatumParamsScratch.datumIndex = yMaxIndex;
|
|
nodeDatumParamsScratch.x = x;
|
|
nodeDatumParamsScratch.width = width;
|
|
nodeDatumParamsScratch.opacity = opacity;
|
|
if (ctx.isStacked) {
|
|
nodeDatumParamsScratch.yStart = Number(ctx.yStartValues[yMinIndex]);
|
|
nodeDatumParamsScratch.yEnd = Number(ctx.yEndValues[yMaxIndex]);
|
|
nodeDatumParamsScratch.featherRatio = 0;
|
|
} else {
|
|
const yEndMax = Number(ctx.yRawValues[yMaxIndex]);
|
|
const yEndMin = Number(ctx.yRawValues[yMinIndex]);
|
|
nodeDatumParamsScratch.yStart = 0;
|
|
nodeDatumParamsScratch.yEnd = yEndMax;
|
|
nodeDatumParamsScratch.featherRatio = (positive ? 1 : -1) * sign * (1 - yEndMin / yEndMax);
|
|
}
|
|
nodeDatumParamsScratch.yRange = nodeDatumParamsScratch.yEnd;
|
|
this.upsertNodeDatum(ctx, nodeDatumParamsScratch);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Creates node data for grouped data processing.
|
|
*/
|
|
createNodeDataGrouped(ctx, xPosition, nodeDatumParamsScratch) {
|
|
const processedData = this.processedData;
|
|
const invalidData = processedData.invalidData?.get(this.id);
|
|
const width = ctx.barWidth;
|
|
const yRangeIndex = ctx.isStacked ? this.dataModel.resolveProcessedDataIndexById(this, `yValue-range`) : -1;
|
|
const columnIndex = processedData.columnScopes.findIndex((s) => s.has(this.id));
|
|
const groups = processedData.groups;
|
|
const visibleRange = visibleRangeIndices(1, groups.length, ctx.xAxis.range, (groupIndex) => {
|
|
const group = groups[groupIndex];
|
|
const xValue = group.keys[0];
|
|
return this.xCoordinateRange(xValue);
|
|
});
|
|
const start = visibleRange[0];
|
|
const end2 = visibleRange[1];
|
|
for (let groupIndex = start; groupIndex < end2; groupIndex += 1) {
|
|
const group = groups[groupIndex];
|
|
const aggregation = group.aggregation;
|
|
const datumIndices = group.datumIndices[columnIndex];
|
|
if (datumIndices == null)
|
|
continue;
|
|
for (const relativeDatumIndex of datumIndices) {
|
|
const datumIndex = groupIndex + relativeDatumIndex;
|
|
const x = xPosition(datumIndex);
|
|
if (invalidData?.[datumIndex] === true)
|
|
continue;
|
|
const yRawValue = ctx.yRawValues[datumIndex];
|
|
if (yRawValue == null)
|
|
continue;
|
|
const isPositive = yRawValue >= 0 && !Object.is(yRawValue, -0);
|
|
const yStart = ctx.isStacked ? Number(ctx.yStartValues?.[datumIndex]) : 0;
|
|
const yEnd = ctx.isStacked ? Number(ctx.yEndValues?.[datumIndex]) : yRawValue;
|
|
let yRange = yEnd;
|
|
if (ctx.isStacked) {
|
|
yRange = aggregation[yRangeIndex][isPositive ? 1 : 0];
|
|
}
|
|
nodeDatumParamsScratch.datumIndex = datumIndex;
|
|
nodeDatumParamsScratch.x = x;
|
|
nodeDatumParamsScratch.width = width;
|
|
nodeDatumParamsScratch.yStart = yStart;
|
|
nodeDatumParamsScratch.yEnd = yEnd;
|
|
nodeDatumParamsScratch.yRange = yRange;
|
|
nodeDatumParamsScratch.featherRatio = 0;
|
|
nodeDatumParamsScratch.opacity = 1;
|
|
this.upsertNodeDatum(ctx, nodeDatumParamsScratch);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Creates node data for simple (non-grouped) data processing.
|
|
*/
|
|
createNodeDataSimple(ctx, xPosition, nodeDatumParamsScratch) {
|
|
const invalidData = this.processedData.invalidData?.get(this.id);
|
|
const width = ctx.barWidth;
|
|
const visibleRange = this.visibleRangeIndices("xValue", ctx.xAxis.range);
|
|
let start = visibleRange[0];
|
|
let end2 = visibleRange[1];
|
|
if (this.processedData.input.count < 1e3) {
|
|
start = 0;
|
|
end2 = this.processedData.input.count;
|
|
}
|
|
for (let datumIndex = start; datumIndex < end2; datumIndex += 1) {
|
|
if (invalidData?.[datumIndex] === true)
|
|
continue;
|
|
const yRawValue = ctx.yRawValues[datumIndex];
|
|
if (yRawValue == null)
|
|
continue;
|
|
const x = xPosition(datumIndex);
|
|
const yEnd = Number(yRawValue);
|
|
nodeDatumParamsScratch.datumIndex = datumIndex;
|
|
nodeDatumParamsScratch.x = x;
|
|
nodeDatumParamsScratch.width = width;
|
|
nodeDatumParamsScratch.yStart = 0;
|
|
nodeDatumParamsScratch.yEnd = yEnd;
|
|
nodeDatumParamsScratch.yRange = yEnd;
|
|
nodeDatumParamsScratch.featherRatio = 0;
|
|
nodeDatumParamsScratch.opacity = 1;
|
|
this.upsertNodeDatum(ctx, nodeDatumParamsScratch);
|
|
}
|
|
}
|
|
/**
|
|
* Handles node creation/update - reuses existing nodes when possible for incremental updates.
|
|
* This method decides whether to update existing nodes in-place or create new ones.
|
|
*/
|
|
upsertNodeDatum(ctx, params) {
|
|
const canReuseNode = ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodes.length;
|
|
const needsPhantom = ctx.yFilterValues != null;
|
|
const canReusePhantom = needsPhantom && ctx.canIncrementallyUpdate && ctx.phantomIndex < ctx.phantomNodes.length;
|
|
let nodeData;
|
|
let phantomNodeData;
|
|
if (canReuseNode) {
|
|
nodeData = ctx.nodes[ctx.nodeIndex];
|
|
this.updateNodeDatum(ctx, nodeData, params);
|
|
if (ctx.nodeIndex >= ctx.labels.length) {
|
|
ctx.labels.push(nodeData);
|
|
}
|
|
} else {
|
|
const result = this.createNodeDatum(ctx, params);
|
|
if (result.nodeData) {
|
|
ctx.nodes.push(result.nodeData);
|
|
ctx.labels.push(result.nodeData);
|
|
}
|
|
phantomNodeData = result.phantomNodeData;
|
|
}
|
|
ctx.nodeIndex++;
|
|
if (!needsPhantom) {
|
|
return { nodeData: ctx.nodes[ctx.nodeIndex] };
|
|
}
|
|
if (canReusePhantom) {
|
|
phantomNodeData = ctx.phantomNodes[ctx.phantomIndex];
|
|
this.updateNodeDatum(ctx, phantomNodeData, params);
|
|
} else if (phantomNodeData) {
|
|
ctx.phantomNodes.push(phantomNodeData);
|
|
} else {
|
|
const result = this.createNodeDatum(ctx, params);
|
|
if (result.phantomNodeData) {
|
|
ctx.phantomNodes.push(result.phantomNodeData);
|
|
}
|
|
}
|
|
ctx.phantomIndex++;
|
|
return { nodeData, phantomNodeData };
|
|
}
|
|
// ============================================================================
|
|
// Template Method Hooks (createNodeData flow)
|
|
// ============================================================================
|
|
/**
|
|
* Populates node data by selecting the appropriate strategy based on data type.
|
|
* Creates scratch objects and delegates to strategy-specific methods.
|
|
*/
|
|
populateNodeData(ctx) {
|
|
const xPosition = (index) => this.computeXPosition(ctx, index);
|
|
const nodeDatumParamsScratch = {
|
|
nodeDatumScratch: {
|
|
datum: void 0,
|
|
xValue: void 0,
|
|
yRawValue: 0,
|
|
yFilterValue: void 0,
|
|
labelText: void 0,
|
|
inset: false,
|
|
isPositive: false,
|
|
precomputedBottomY: void 0,
|
|
precomputedIsUpward: void 0
|
|
},
|
|
datumIndex: 0,
|
|
x: 0,
|
|
width: 0,
|
|
yStart: 0,
|
|
yEnd: 0,
|
|
yRange: 0,
|
|
featherRatio: 0,
|
|
opacity: 1
|
|
};
|
|
if (ctx.dataAggregationFilter != null) {
|
|
this.createNodeDataWithAggregation(ctx, xPosition, nodeDatumParamsScratch);
|
|
} else if (this.processedData.type === "grouped") {
|
|
this.createNodeDataGrouped(ctx, xPosition, nodeDatumParamsScratch);
|
|
} else {
|
|
this.createNodeDataSimple(ctx, xPosition, nodeDatumParamsScratch);
|
|
}
|
|
}
|
|
/**
|
|
* Creates the initial result context object.
|
|
* Note: segments is undefined here - it's computed in assembleResult.
|
|
*/
|
|
initializeResult(ctx) {
|
|
return {
|
|
itemId: this.properties.yKey,
|
|
nodeData: ctx.nodes,
|
|
phantomNodeData: ctx.phantomNodes,
|
|
labelData: ctx.labels,
|
|
scales: this.calculateScaling(),
|
|
visible: this.visible || ctx.animationEnabled,
|
|
groupScale: this.getScaling(this.ctx.seriesStateManager.getGroupScale(this)),
|
|
styles: getItemStyles(this.getItemStyle.bind(this)),
|
|
segments: void 0
|
|
};
|
|
}
|
|
/**
|
|
* Finalizes node data by trimming incremental arrays.
|
|
* BarSeries has multiple arrays: nodes, phantomNodes, and labels.
|
|
*/
|
|
finalizeNodeData(ctx) {
|
|
if (ctx.canIncrementallyUpdate) {
|
|
this.trimIncrementalNodeArray(ctx.nodes, ctx.nodeIndex);
|
|
this.trimIncrementalNodeArray(ctx.phantomNodes, ctx.phantomIndex);
|
|
this.trimIncrementalNodeArray(ctx.labels, ctx.nodes.length);
|
|
}
|
|
}
|
|
/**
|
|
* Assembles the final result by computing segments.
|
|
*/
|
|
assembleResult(ctx, result) {
|
|
result.segments = calculateSegments(
|
|
this.properties.segmentation,
|
|
ctx.xAxis,
|
|
ctx.yAxis,
|
|
this.chart.seriesRect,
|
|
this.ctx.scene
|
|
);
|
|
return result;
|
|
}
|
|
nodeFactory() {
|
|
return new BarShape();
|
|
}
|
|
updateSeriesSelections() {
|
|
super.updateSeriesSelections();
|
|
this.phantomSelection = this.updateDatumSelection({
|
|
nodeData: this.contextNodeData?.phantomNodeData ?? [],
|
|
datumSelection: this.phantomSelection
|
|
});
|
|
}
|
|
updateHighlightSelectionItem(opts) {
|
|
const out = super.updateHighlightSelectionItem(opts);
|
|
const highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
const seriesHighlighted = this.isSeriesHighlighted(highlightedDatum);
|
|
const item = seriesHighlighted && highlightedDatum?.datum ? highlightedDatum : void 0;
|
|
this.phantomHighlightSelection = this.updateDatumSelection({
|
|
nodeData: item ? this.getHighlightData(this.contextNodeData?.phantomNodeData ?? [], item) ?? [] : [],
|
|
datumSelection: this.phantomHighlightSelection
|
|
});
|
|
return out;
|
|
}
|
|
updateNodes(itemHighlighted, nodeRefresh) {
|
|
super.updateNodes(itemHighlighted, nodeRefresh);
|
|
this.updateDatumNodes({
|
|
datumSelection: this.phantomSelection,
|
|
isHighlight: false,
|
|
drawingMode: "overlay"
|
|
});
|
|
this.updateDatumNodes({
|
|
datumSelection: this.phantomHighlightSelection,
|
|
isHighlight: true,
|
|
drawingMode: "overlay"
|
|
});
|
|
}
|
|
getHighlightData(nodeData, highlightedItem) {
|
|
const highlightItem = nodeData.find((nodeDatum) => nodeDatum.datum === highlightedItem.datum);
|
|
return highlightItem == null ? void 0 : [{ ...highlightItem }];
|
|
}
|
|
updateDatumSelection(opts) {
|
|
if (!processedDataIsAnimatable(this.processedData)) {
|
|
return opts.datumSelection.update(opts.nodeData);
|
|
}
|
|
return opts.datumSelection.update(opts.nodeData, void 0, this.getDatumId.bind(this));
|
|
}
|
|
makeStylerParams(highlightStateEnum) {
|
|
const { id: seriesId } = this;
|
|
const {
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
stackGroup,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
xKey,
|
|
yKey
|
|
} = this.properties;
|
|
const highlightState = toHighlightString(highlightStateEnum ?? 0 /* None */);
|
|
return {
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
highlightState,
|
|
lineDash,
|
|
lineDashOffset,
|
|
seriesId,
|
|
stackGroup,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
xKey,
|
|
yKey
|
|
};
|
|
}
|
|
makeItemStylerParams(dataModel, processedData, datumIndex, xValue, isHighlight, style) {
|
|
const { id: seriesId } = this;
|
|
const { xKey, yKey, stackGroup } = this.properties;
|
|
const datum = processedData.dataSources.get(seriesId)?.data?.[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValue-raw`, processedData)[datumIndex];
|
|
const xDomain = dataModel.getDomain(this, `xValue`, "key", processedData).domain;
|
|
const yDomain = dataModel.getDomain(this, this.yCumulativeKey(dataModel), "value", processedData).domain;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightStateString = this.getHighlightStateString(activeHighlight, isHighlight, datumIndex);
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
seriesId,
|
|
...datumStylerProperties(xValue, yValue, xKey, yKey, xDomain, yDomain),
|
|
datum,
|
|
xValue,
|
|
yValue,
|
|
stackGroup,
|
|
highlightState: highlightStateString,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
getStyle(ignoreStylerCallback, highlightState) {
|
|
const {
|
|
cornerRadius,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
styler
|
|
} = this.properties;
|
|
let stylerResult = {};
|
|
if (!ignoreStylerCallback && styler) {
|
|
const stylerParams = this.makeStylerParams(highlightState);
|
|
stylerResult = this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
this.cachedCallWithContext(styler, stylerParams) ?? {},
|
|
{ pick: false }
|
|
) ?? {};
|
|
}
|
|
return {
|
|
cornerRadius: stylerResult.cornerRadius ?? cornerRadius,
|
|
fill: stylerResult.fill ?? fill,
|
|
fillOpacity: stylerResult.fillOpacity ?? fillOpacity,
|
|
lineDash: stylerResult.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.lineDashOffset ?? lineDashOffset,
|
|
opacity: 1,
|
|
stroke: stylerResult.stroke ?? stroke,
|
|
strokeOpacity: stylerResult.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.strokeWidth ?? strokeWidth
|
|
};
|
|
}
|
|
getItemStyle(datumIndex, isHighlight, highlightState) {
|
|
const { properties, dataModel, processedData } = this;
|
|
const { itemStyler, simpleItemStyler } = properties;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex, highlightState);
|
|
if (simpleItemStyler && processedData != null && datumIndex != null) {
|
|
const datum = processedData.dataSources.get(this.id)?.data?.[datumIndex];
|
|
const overrides = simpleItemStyler(datum);
|
|
return (0, import_ag_charts_core253.mergeDefaults)(
|
|
overrides,
|
|
highlightStyle,
|
|
this.getStyle(false, highlightState)
|
|
);
|
|
}
|
|
let style = (0, import_ag_charts_core253.mergeDefaults)(highlightStyle, this.getStyle(datumIndex === void 0, highlightState));
|
|
if (itemStyler && dataModel != null && processedData != null && datumIndex != null) {
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const overrides = this.cachedDatumCallback(
|
|
createDatumId(this.getDatumId({ xValue, phantom: false }), isHighlight ? "highlight" : "node"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(
|
|
dataModel,
|
|
processedData,
|
|
datumIndex,
|
|
xValue,
|
|
isHighlight,
|
|
style
|
|
);
|
|
return this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
this.callWithContext(itemStyler, params)
|
|
);
|
|
}
|
|
);
|
|
if (overrides) {
|
|
style = (0, import_ag_charts_core253.mergeDefaults)(overrides, style);
|
|
}
|
|
}
|
|
return style;
|
|
}
|
|
updateDatumStyles(opts) {
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const series = this;
|
|
function applyDatumStyle(node, datum) {
|
|
if (!opts.datumSelection.isGarbage(node)) {
|
|
const highlightState = series.getHighlightState(highlightedDatum, opts.isHighlight, datum.datumIndex);
|
|
datum.style = series.getItemStyle(datum.datumIndex, opts.isHighlight, highlightState);
|
|
}
|
|
}
|
|
opts.datumSelection.each(applyDatumStyle);
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const { shadow } = this.properties;
|
|
const categoryAlongX = this.getCategoryDirection() === import_ag_charts_core253.ChartAxisDirection.X;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const direction = this.getBarDirection();
|
|
const { drawingMode, isHighlight } = opts;
|
|
const series = this;
|
|
const contextStyles = contextNodeData.styles;
|
|
function updateDatumNode(rect2, datum) {
|
|
const style = datum.style ?? contextStyles[series.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex)];
|
|
rect2.setStyleProperties(style, fillBBox);
|
|
const cornerRadius = style.cornerRadius ?? 0;
|
|
const visible = categoryAlongX ? (datum.clipBBox?.width ?? datum.width) > 0 : (datum.clipBBox?.height ?? datum.height) > 0;
|
|
rect2.setStaticProperties(
|
|
drawingMode,
|
|
datum.topLeftCornerRadius ? cornerRadius : 0,
|
|
datum.topRightCornerRadius ? cornerRadius : 0,
|
|
datum.bottomRightCornerRadius ? cornerRadius : 0,
|
|
datum.bottomLeftCornerRadius ? cornerRadius : 0,
|
|
visible,
|
|
datum.crisp,
|
|
shadow,
|
|
direction,
|
|
datum.featherRatio
|
|
);
|
|
}
|
|
opts.datumSelection.each(updateDatumNode);
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const data = this.isLabelEnabled() ? opts.labelData : [];
|
|
return opts.labelSelection.update(data, (text) => {
|
|
text.pointerEvents = 1 /* None */;
|
|
});
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const { isHighlight = false } = opts;
|
|
const params = {
|
|
xKey: this.properties.xKey,
|
|
xName: this.properties.xName ?? this.properties.xKey,
|
|
yKey: this.properties.yKey,
|
|
yName: this.properties.yName ?? this.properties.yKey,
|
|
legendItemName: this.properties.legendItemName ?? this.properties.xName ?? this.properties.xKey
|
|
};
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
opts.labelSelection.each((textNode, datum) => {
|
|
textNode.fillOpacity = this.getHighlightStyle(isHighlight, datum?.datumIndex).opacity ?? 1;
|
|
updateLabelNode(this, textNode, params, this.properties.label, datum.label, isHighlight, activeHighlight);
|
|
});
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, properties } = this;
|
|
const { xKey, xName, yKey, yName, legendItemName, stackGroup, tooltip } = properties;
|
|
const allowNullKeys = properties.allowNullKeys ?? false;
|
|
const xAxis = this.getCategoryAxis();
|
|
const yAxis = this.getValueAxis();
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data?.[datumIndex];
|
|
const xValue = dataModel.resolveKeysById(this, `xValue`, processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValue-raw`, processedData)[datumIndex];
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const format = this.getItemStyle(datumIndex, false);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName, allowNullKeys),
|
|
symbol: this.legendItemSymbol(),
|
|
data: [
|
|
{
|
|
label: yName,
|
|
fallbackLabel: yKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", yValue, datum, yKey, legendItemName),
|
|
missing: isTooltipValueMissing(yValue)
|
|
}
|
|
]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: yName,
|
|
xKey,
|
|
xName,
|
|
yKey,
|
|
yName,
|
|
legendItemName,
|
|
stackGroup,
|
|
...format,
|
|
...this.getModuleTooltipParams()
|
|
}
|
|
);
|
|
}
|
|
legendItemSymbol() {
|
|
const { fill, stroke, strokeWidth, fillOpacity, strokeOpacity, lineDash, lineDashOffset } = this.getStyle(
|
|
false,
|
|
0 /* None */
|
|
);
|
|
return {
|
|
marker: {
|
|
fill: fill ?? "rgba(0, 0, 0, 0)",
|
|
stroke: stroke ?? "rgba(0, 0, 0, 0)",
|
|
fillOpacity,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
const { showInLegend } = this.properties;
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
const { yKey: itemId, yName, legendItemName } = this.properties;
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId,
|
|
seriesId,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId }),
|
|
label: { text: legendItemName ?? yName ?? itemId },
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
resetDatumAnimation(data) {
|
|
resetBarSelectionsDirect([data.datumSelection, this.phantomSelection]);
|
|
}
|
|
animateReadyHighlight(data) {
|
|
resetBarSelectionsDirect([data, this.phantomHighlightSelection]);
|
|
}
|
|
animateEmptyUpdateReady({ datumSelection, labelSelection, annotationSelections }) {
|
|
const { phantomSelection } = this;
|
|
const fns = prepareBarAnimationFunctions(
|
|
collapsedStartingBarPosition(this.isVertical(), this.axes, "normal"),
|
|
"unknown"
|
|
);
|
|
fromToMotion(this.id, "nodes", this.ctx.animationManager, [datumSelection, phantomSelection], fns);
|
|
seriesLabelFadeInAnimation(this, "labels", this.ctx.animationManager, labelSelection);
|
|
seriesLabelFadeInAnimation(this, "annotations", this.ctx.animationManager, ...annotationSelections);
|
|
}
|
|
animateWaitingUpdateReady(data) {
|
|
const { phantomSelection } = this;
|
|
const { datumSelection, labelSelection, annotationSelections, contextData, previousContextData } = data;
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
const dataDiff = calculateDataDiff(
|
|
this.id,
|
|
datumSelection,
|
|
this.getDatumId.bind(this),
|
|
data.contextData,
|
|
previousContextData,
|
|
this.processedData,
|
|
this.processedDataUpdated
|
|
);
|
|
const mode = previousContextData == null ? "fade" : "normal";
|
|
const fns = prepareBarAnimationFunctions(
|
|
collapsedStartingBarPosition(this.isVertical(), this.axes, mode),
|
|
"added"
|
|
);
|
|
fromToMotion(
|
|
this.id,
|
|
"nodes",
|
|
this.ctx.animationManager,
|
|
[datumSelection, phantomSelection],
|
|
fns,
|
|
(_, datum) => this.getDatumId(datum),
|
|
dataDiff
|
|
);
|
|
if (!dataDiff || dataDiff?.changed || !(0, import_ag_charts_core253.areScalingEqual)(contextData.groupScale, previousContextData?.groupScale)) {
|
|
seriesLabelFadeInAnimation(this, "labels", this.ctx.animationManager, labelSelection);
|
|
seriesLabelFadeInAnimation(this, "annotations", this.ctx.animationManager, ...annotationSelections);
|
|
}
|
|
}
|
|
getDatumId(datum) {
|
|
return createDatumId(datum.xValue, datum.phantom);
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.label.enabled;
|
|
}
|
|
computeFocusBounds({ datumIndex }) {
|
|
const datumBox = this.contextNodeData?.nodeData[datumIndex].clipBBox;
|
|
return computeBarFocusBounds(this, datumBox);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.styler != null || this.properties.itemStyler != null || this.properties.simpleItemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
BarSeries.className = "BarSeries";
|
|
BarSeries.type = "bar";
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/barSeriesModule.ts
|
|
var themeTemplate2 = {
|
|
series: {
|
|
direction: "vertical",
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", import_ag_charts_core254.FILL_GRADIENT_LINEAR_DEFAULTS],
|
|
["image", import_ag_charts_core254.FILL_IMAGE_DEFAULTS],
|
|
["pattern", import_ag_charts_core254.FILL_PATTERN_DEFAULTS]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
fillOpacity: 1,
|
|
strokeWidth: { $isUserOption: ["./stroke", 2, 0] },
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
label: {
|
|
...import_ag_charts_core254.LABEL_BOXING_DEFAULTS,
|
|
padding: { $isUserOption: ["./spacing", 0, 8] },
|
|
// compatibility with old `padding` property (now named `spacing`).
|
|
enabled: false,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: {
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $eq: [{ $path: "./placement" }, "outside-start"] },
|
|
{ $eq: [{ $path: "./placement" }, "outside-end"] }
|
|
]
|
|
},
|
|
{ $ref: "textColor" },
|
|
{ $ref: "chartBackgroundColor" }
|
|
]
|
|
},
|
|
placement: "inside-center"
|
|
},
|
|
shadow: {
|
|
enabled: false,
|
|
color: import_ag_charts_core254.DEFAULT_SHADOW_COLOUR,
|
|
xOffset: 3,
|
|
yOffset: 3,
|
|
blur: 5
|
|
},
|
|
highlight: import_ag_charts_core254.MULTI_SERIES_HIGHLIGHT_STYLE,
|
|
segmentation: import_ag_charts_core254.SEGMENTATION_DEFAULTS
|
|
}
|
|
};
|
|
var BarSeriesModule = {
|
|
type: "series",
|
|
name: "bar",
|
|
chartType: "cartesian",
|
|
stackable: true,
|
|
groupable: true,
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: barSeriesOptionsDef,
|
|
predictAxis: predictCartesianNonPrimitiveAxis,
|
|
defaultAxes: import_ag_charts_core254.DIRECTION_SWAP_AXES,
|
|
axisKeys: { [import_ag_charts_core254.ChartAxisDirection.X]: "xKeyAxis", [import_ag_charts_core254.ChartAxisDirection.Y]: "yKeyAxis" },
|
|
axisKeysFlipped: { [import_ag_charts_core254.ChartAxisDirection.X]: "yKeyAxis", [import_ag_charts_core254.ChartAxisDirection.Y]: "xKeyAxis" },
|
|
themeTemplate: themeTemplate2,
|
|
create: (ctx) => new BarSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/bubbleSeriesModule.ts
|
|
var import_ag_charts_core258 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/bubbleSeries.ts
|
|
var import_ag_charts_core257 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/bubbleAggregation.ts
|
|
var import_ag_charts_core255 = require("ag-charts-core");
|
|
var SIZE_QUANTIZATION = 3;
|
|
var FILTER_DATUM_THRESHOLD = 5;
|
|
var FILTER_RANGE_THRESHOLD = 0.05;
|
|
function getPrimaryDatumIndex(context, indices, bounds) {
|
|
const { xValues, yValues, xDomain, yDomain, xNeedsValueOf, yNeedsValueOf } = context;
|
|
const { x0, y0, x1, y1 } = bounds;
|
|
let currentIndex = 0;
|
|
let currentDistanceSquared = Infinity;
|
|
const midX = (x0 + x1) / 2;
|
|
const midY = (y0 + y1) / 2;
|
|
for (const datumIndex of indices) {
|
|
const xValue = xValues[datumIndex];
|
|
const yValue = yValues[datumIndex];
|
|
if (xValue == null || yValue == null)
|
|
continue;
|
|
const xRatio = (0, import_ag_charts_core255.aggregationXRatioForXValue)(xValue, xDomain.min, xDomain.max, xNeedsValueOf);
|
|
const yRatio = (0, import_ag_charts_core255.aggregationXRatioForXValue)(yValue, yDomain.min, yDomain.max, yNeedsValueOf);
|
|
const distanceSquared = (xRatio - midX) ** 2 + (yRatio - midY) ** 2;
|
|
if (distanceSquared < currentDistanceSquared) {
|
|
currentDistanceSquared = distanceSquared;
|
|
currentIndex = datumIndex;
|
|
}
|
|
}
|
|
return currentIndex;
|
|
}
|
|
function countVisibleItems(context, indices, bounds) {
|
|
const { xValues, yValues, xDomain, yDomain, xNeedsValueOf, yNeedsValueOf } = context;
|
|
const { x0, y0, x1, y1 } = bounds;
|
|
let count = 0;
|
|
for (const datumIndex of indices) {
|
|
const xValue = xValues[datumIndex];
|
|
const yValue = yValues[datumIndex];
|
|
if (xValue == null || yValue == null)
|
|
continue;
|
|
const xRatio = (0, import_ag_charts_core255.aggregationXRatioForXValue)(xValue, xDomain.min, xDomain.max, xNeedsValueOf);
|
|
const yRatio = (0, import_ag_charts_core255.aggregationXRatioForXValue)(yValue, yDomain.min, yDomain.max, yNeedsValueOf);
|
|
if (xRatio >= x0 && xRatio <= x1 && yRatio >= y0 && yRatio <= y1) {
|
|
count += 1;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
function quadChildren(context, indices, bounds) {
|
|
const { xValues, yValues, xDomain, yDomain, xNeedsValueOf, yNeedsValueOf } = context;
|
|
const { x0, y0, x1, y1 } = bounds;
|
|
const childBuckets = [
|
|
{ x0: 1, y0: 1, x1: 0, y1: 0, indices: [] },
|
|
{ x0: 1, y0: 1, x1: 0, y1: 0, indices: [] },
|
|
{ x0: 1, y0: 1, x1: 0, y1: 0, indices: [] },
|
|
{ x0: 1, y0: 1, x1: 0, y1: 0, indices: [] }
|
|
];
|
|
const midX = (x0 + x1) / 2;
|
|
const midY = (y0 + y1) / 2;
|
|
for (const datumIndex of indices) {
|
|
const xValue = xValues[datumIndex];
|
|
const yValue = yValues[datumIndex];
|
|
if (xValue == null || yValue == null)
|
|
continue;
|
|
const xRatio = (0, import_ag_charts_core255.aggregationXRatioForXValue)(xValue, xDomain.min, xDomain.max, xNeedsValueOf);
|
|
const yRatio = (0, import_ag_charts_core255.aggregationXRatioForXValue)(yValue, yDomain.min, yDomain.max, yNeedsValueOf);
|
|
const childIndex = (xRatio > midX ? 1 : 0) + (yRatio > midY ? 2 : 0);
|
|
const childBucket = childBuckets[childIndex];
|
|
childBucket.indices.push(datumIndex);
|
|
childBucket.x0 = Math.min(childBucket.x0, xRatio);
|
|
childBucket.y0 = Math.min(childBucket.y0, yRatio);
|
|
childBucket.x1 = Math.max(childBucket.x1, xRatio);
|
|
childBucket.y1 = Math.max(childBucket.y1, yRatio);
|
|
}
|
|
const children = [];
|
|
for (const childBucket of childBuckets) {
|
|
const { indices: childIndices, x0: cx0, x1: cx1, y0: cy0, y1: cy1 } = childBucket;
|
|
if (childIndices.length === 0)
|
|
continue;
|
|
const child = aggregateQuad(context, childIndices, { x0: cx0, y0: cy0, x1: cx1, y1: cy1 });
|
|
children.push(child);
|
|
}
|
|
return children;
|
|
}
|
|
function aggregateQuad(context, indices, bounds) {
|
|
const { x0, y0, x1, y1 } = bounds;
|
|
const terminate = indices.length < FILTER_DATUM_THRESHOLD && x1 - x0 < FILTER_RANGE_THRESHOLD && y1 - y0 < FILTER_RANGE_THRESHOLD || x0 === x1 && y0 === y1;
|
|
let children = terminate ? null : quadChildren(context, indices, bounds);
|
|
if (children?.length === 1) {
|
|
return children[0];
|
|
} else if (children?.length === 0) {
|
|
children = null;
|
|
}
|
|
const scale2 = Math.hypot(x1 - x0, y1 - y0);
|
|
const primaryDatumIndex = getPrimaryDatumIndex(context, indices, bounds);
|
|
return { scale: scale2, x0, y0, x1, y1, indices, primaryDatumIndex, children };
|
|
}
|
|
function computeBubbleAggregation(xDomain, yDomain, xValues, yValues, sizeValues, sizeDomain, options) {
|
|
const [xd0, xd1] = xDomain;
|
|
const [yd0, yd1] = yDomain;
|
|
const [sd0, sd1] = sizeDomain;
|
|
const { xNeedsValueOf, yNeedsValueOf } = options;
|
|
const context = {
|
|
xValues,
|
|
yValues,
|
|
xDomain: { min: xd0, max: xd1 },
|
|
yDomain: { min: yd0, max: yd1 },
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
};
|
|
const filters = [];
|
|
if (sizeValues != null && sd1 > sd0) {
|
|
const sizeIndices = Array.from({ length: SIZE_QUANTIZATION }, () => []);
|
|
for (let datumIndex = 0; datumIndex < sizeValues.length; datumIndex += 1) {
|
|
const sizeValue = sizeValues[datumIndex];
|
|
const sizeRatio = (sizeValue - sd0) / (sd1 - sd0);
|
|
const sizeIndex = Math.trunc(sizeRatio * SIZE_QUANTIZATION);
|
|
if (sizeIndex >= 0 && sizeIndex < SIZE_QUANTIZATION) {
|
|
sizeIndices[sizeIndex].push(datumIndex);
|
|
}
|
|
}
|
|
for (let i = 0; i < sizeIndices.length; i += 1) {
|
|
const indices = sizeIndices[i];
|
|
const node = aggregateQuad(context, indices, { x0: 0, y0: 0, x1: 1, y1: 1 });
|
|
if (node != null) {
|
|
const sizeRatio = i / SIZE_QUANTIZATION;
|
|
filters.push({ sizeRatio, node });
|
|
}
|
|
}
|
|
} else {
|
|
const indices = xValues.map((_, i) => i);
|
|
const node = aggregateQuad(context, indices, { x0: 0, y0: 0, x1: 1, y1: 1 });
|
|
if (node != null) {
|
|
filters.push({ sizeRatio: 0, node });
|
|
}
|
|
}
|
|
return filters.length > 0 ? { xValues, yValues, xd0, xd1, yd0, yd1, filters, xNeedsValueOf, yNeedsValueOf } : void 0;
|
|
}
|
|
function aggregateBubbleData(xScale, yScale, xValues, yValues, sizeValues, xDomainInput, yDomainInput, sizeDomain, xNeedsValueOf, yNeedsValueOf) {
|
|
const [xd0, xd1] = (0, import_ag_charts_core255.aggregationDomain)(xScale, xDomainInput);
|
|
const [yd0, yd1] = (0, import_ag_charts_core255.aggregationDomain)(yScale, yDomainInput);
|
|
return computeBubbleAggregation(
|
|
[xd0, xd1],
|
|
[yd0, yd1],
|
|
xValues,
|
|
yValues,
|
|
sizeValues,
|
|
[sizeDomain[0], sizeDomain[1]],
|
|
{ xNeedsValueOf, yNeedsValueOf }
|
|
);
|
|
}
|
|
function aggregateBubbleDataFromDataModel(xScale, yScale, dataModel, processedData, sizeScale, hasSizeKey, series) {
|
|
const xValues = dataModel.resolveColumnById(series, "xValue", processedData);
|
|
const yValues = dataModel.resolveColumnById(series, "yValue", processedData);
|
|
const sizeValues = hasSizeKey ? dataModel.resolveColumnById(series, "sizeValue", processedData) : void 0;
|
|
const xDomain = dataModel.getDomain(series, "xValue", "value", processedData);
|
|
const yDomain = dataModel.getDomain(series, "yValue", "value", processedData);
|
|
const sizeDomain = hasSizeKey ? sizeScale.domain : [0, 0];
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "yValue", processedData);
|
|
return aggregateBubbleData(
|
|
xScale,
|
|
yScale,
|
|
xValues,
|
|
yValues,
|
|
sizeValues,
|
|
xDomain,
|
|
yDomain,
|
|
sizeDomain,
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
);
|
|
}
|
|
function computeBubbleAggregationCountIndices(dilation, dataAggregation, options, counter, groupedAggregation, singleDatumIndices) {
|
|
const {
|
|
xRange,
|
|
yRange,
|
|
xVisibleRange: [xvr0, xvr1],
|
|
yVisibleRange: [yvr0, yvr1],
|
|
minSize,
|
|
maxSize
|
|
} = options;
|
|
const { xValues, yValues, xd0, xd1, yd0, yd1, xNeedsValueOf, yNeedsValueOf } = dataAggregation;
|
|
const baseScalingFactor = 1 / Math.min(xRange / (xvr1 - xvr0), yRange / (yvr1 - yvr0));
|
|
const context = {
|
|
xValues,
|
|
yValues,
|
|
xDomain: { min: xd0, max: xd1 },
|
|
yDomain: { min: yd0, max: yd1 },
|
|
xNeedsValueOf,
|
|
yNeedsValueOf
|
|
};
|
|
for (const { sizeRatio, node } of dataAggregation.filters) {
|
|
const radius = 0.5 * (minSize + sizeRatio * (maxSize - minSize));
|
|
const baseMinScale = radius * baseScalingFactor;
|
|
const minScale = dilation * baseMinScale;
|
|
const x0 = xvr0 - radius / xRange;
|
|
const x1 = xvr1 + radius / xRange;
|
|
const y0 = yvr0 - radius / yRange;
|
|
const y1 = yvr1 + radius / yRange;
|
|
const queue = [node];
|
|
while (queue.length > 0) {
|
|
const item = queue.pop();
|
|
if (item.x1 < x0 || item.x0 > x1 || item.y1 < y0 || item.y0 > y1) {
|
|
continue;
|
|
}
|
|
if (dilation !== 1 && item.scale <= minScale) {
|
|
if (counter != null) {
|
|
counter.count += 1;
|
|
}
|
|
groupedAggregation?.push({
|
|
datumIndex: item.primaryDatumIndex,
|
|
count: item.indices.length,
|
|
area: (item.x1 - item.x0) * (item.y1 - item.y0),
|
|
dilation: (0, import_ag_charts_core255.clamp)(1, item.scale / baseMinScale, dilation)
|
|
});
|
|
} else if (item.children == null) {
|
|
const { indices } = item;
|
|
if (counter != null) {
|
|
const fullyVisible = item.x0 >= xvr0 && item.x1 <= xvr1 && item.y0 >= yvr0 && item.y1 <= yvr1;
|
|
const itemCount = fullyVisible ? indices.length : countVisibleItems(context, indices, { x0: xvr0, y0: yvr0, x1: xvr1, y1: yvr1 });
|
|
counter.count += itemCount;
|
|
}
|
|
singleDatumIndices?.push(...indices);
|
|
} else {
|
|
queue.push(...item.children);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function computeBubbleAggregationCount(dilation, dataAggregation, options) {
|
|
const counter = { count: 0 };
|
|
computeBubbleAggregationCountIndices(dilation, dataAggregation, options, counter, void 0, void 0);
|
|
return counter.count;
|
|
}
|
|
var MAX_AGGREGATION_DILATION = 100;
|
|
var DILATION_ITERATIONS = 12;
|
|
function computeBubbleAggregationDilation(dataAggregation, aggregationOptions, maxRenderedItems) {
|
|
if (computeBubbleAggregationCount(1, dataAggregation, aggregationOptions) <= maxRenderedItems) {
|
|
return 1;
|
|
}
|
|
let minDilation = 1;
|
|
let maxDilation = 2;
|
|
while (computeBubbleAggregationCount(maxDilation, dataAggregation, aggregationOptions) > maxRenderedItems && maxDilation < MAX_AGGREGATION_DILATION) {
|
|
minDilation *= 2;
|
|
maxDilation *= 2;
|
|
}
|
|
for (let i = 0; i < DILATION_ITERATIONS; i += 1) {
|
|
const dilation = (maxDilation + minDilation) / 2;
|
|
const count = computeBubbleAggregationCount(dilation, dataAggregation, aggregationOptions);
|
|
if (count > maxRenderedItems) {
|
|
minDilation = dilation;
|
|
} else {
|
|
maxDilation = dilation;
|
|
}
|
|
}
|
|
return (minDilation + maxDilation) / 2;
|
|
}
|
|
function computeBubbleAggregationData(dilation, dataAggregation, options) {
|
|
const groupedAggregation = [];
|
|
const singleDatumIndices = [];
|
|
computeBubbleAggregationCountIndices(
|
|
dilation,
|
|
dataAggregation,
|
|
options,
|
|
void 0,
|
|
groupedAggregation,
|
|
singleDatumIndices
|
|
);
|
|
return { groupedAggregation, singleDatumIndices };
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/bubbleSeriesProperties.ts
|
|
var import_ag_charts_core256 = require("ag-charts-core");
|
|
var BubbleSeriesMarker = class extends SeriesMarker {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.maxSize = 30;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property,
|
|
(0, import_ag_charts_core256.SceneChangeDetection)()
|
|
], BubbleSeriesMarker.prototype, "maxSize", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property,
|
|
(0, import_ag_charts_core256.SceneArrayChangeDetection)()
|
|
], BubbleSeriesMarker.prototype, "domain", 2);
|
|
var BubbleSeriesLabel = class extends Label {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.placement = "top";
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesLabel.prototype, "placement", 2);
|
|
var BubbleSeriesProperties = class extends CartesianSeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.label = new BubbleSeriesLabel();
|
|
this.tooltip = makeSeriesTooltip();
|
|
this.maxRenderedItems = Infinity;
|
|
// No validation. Not a part of the options contract.
|
|
this.marker = new BubbleSeriesMarker();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "yKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "sizeKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "labelKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "xFilterKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "yFilterKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "sizeFilterKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "sizeName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "labelName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "title", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.shape")
|
|
], BubbleSeriesProperties.prototype, "shape", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.size")
|
|
], BubbleSeriesProperties.prototype, "size", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.maxSize")
|
|
], BubbleSeriesProperties.prototype, "maxSize", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.domain")
|
|
], BubbleSeriesProperties.prototype, "domain", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.fill")
|
|
], BubbleSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.fillOpacity")
|
|
], BubbleSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.stroke")
|
|
], BubbleSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.strokeWidth")
|
|
], BubbleSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.strokeOpacity")
|
|
], BubbleSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.lineDash")
|
|
], BubbleSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.lineDashOffset")
|
|
], BubbleSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core256.ProxyProperty)("marker.itemStyler")
|
|
], BubbleSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "tooltip", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core256.Property
|
|
], BubbleSeriesProperties.prototype, "maxRenderedItems", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/bubbleSeries.ts
|
|
var BubbleScatterSeriesNodeEvent = class extends CartesianSeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.sizeKey = series.properties.sizeKey;
|
|
}
|
|
};
|
|
var BubbleSeries = class extends CartesianSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
propertyKeys: {
|
|
...DEFAULT_CARTESIAN_DIRECTION_KEYS,
|
|
label: ["labelKey"],
|
|
size: ["sizeKey"]
|
|
},
|
|
propertyNames: {
|
|
...DEFAULT_CARTESIAN_DIRECTION_NAMES,
|
|
label: ["labelName"],
|
|
size: ["sizeName"]
|
|
},
|
|
categoryKey: void 0,
|
|
pickModes: [
|
|
2 /* AXIS_ALIGNED */,
|
|
1 /* NEAREST_NODE */,
|
|
0 /* EXACT_SHAPE_MATCH */
|
|
],
|
|
pathsPerSeries: [],
|
|
datumSelectionGarbageCollection: false,
|
|
animationResetFns: {
|
|
label: resetLabelFn,
|
|
datum: resetMarkerFn
|
|
},
|
|
usesPlacedLabels: true,
|
|
clipFocusBox: false
|
|
});
|
|
this.NodeEvent = BubbleScatterSeriesNodeEvent;
|
|
this.properties = new BubbleSeriesProperties();
|
|
this.dataAggregation = void 0;
|
|
this.sizeScale = new LinearScale();
|
|
this.placedLabelData = [];
|
|
}
|
|
get pickModeAxis() {
|
|
return "main-category";
|
|
}
|
|
get type() {
|
|
return super.type;
|
|
}
|
|
async processData(dataController) {
|
|
if (this.data == null || !this.visible)
|
|
return;
|
|
const xScale = this.axes[import_ag_charts_core257.ChartAxisDirection.X]?.scale;
|
|
const yScale = this.axes[import_ag_charts_core257.ChartAxisDirection.Y]?.scale;
|
|
const { xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const sizeScaleType = this.sizeScale.type;
|
|
const { xKey, yKey, sizeKey, xFilterKey, yFilterKey, sizeFilterKey, labelKey, marker } = this.properties;
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
valueProperty(xKey, xScaleType, { id: `xValue`, allowNullKey }),
|
|
valueProperty(yKey, yScaleType, { id: `yValue`, allowNullKey }),
|
|
...xFilterKey == null ? [] : [valueProperty(xFilterKey, xScaleType, { id: `xFilterValue` })],
|
|
...yFilterKey == null ? [] : [valueProperty(yFilterKey, yScaleType, { id: `yFilterValue` })],
|
|
...sizeFilterKey == null ? [] : [valueProperty(sizeFilterKey, sizeScaleType, { id: `sizeFilterValue` })],
|
|
...sizeKey ? [valueProperty(sizeKey, sizeScaleType, { id: `sizeValue` })] : [],
|
|
...labelKey ? [valueProperty(labelKey, "category", { id: `labelValue` })] : []
|
|
]
|
|
});
|
|
const sizeKeyIdx = sizeKey ? dataModel.resolveProcessedDataIndexById(this, `sizeValue`) : void 0;
|
|
const mutableMarkerDomain = marker.domain ? [marker.domain[0], marker.domain[1]] : void 0;
|
|
this.sizeScale.domain = mutableMarkerDomain ?? (sizeKeyIdx == null ? void 0 : processedData.domain.values[sizeKeyIdx]) ?? [];
|
|
this.dataAggregation = this.aggregateData(dataModel, processedData);
|
|
this.animationState.transition("updateData");
|
|
}
|
|
xCoordinateRange(xValue, pixelSize, index) {
|
|
const { properties, sizeScale } = this;
|
|
const { size, sizeKey } = properties;
|
|
const x = this.axes[import_ag_charts_core257.ChartAxisDirection.X].scale.convert(xValue);
|
|
const sizeValues = sizeKey == null ? void 0 : this.dataModel.resolveColumnById(this, `sizeValue`, this.processedData);
|
|
const sizeValue = sizeValues == null ? size : sizeScale.convert(sizeValues[index]);
|
|
const r = 0.5 * sizeValue * pixelSize;
|
|
return [x - r, x + r];
|
|
}
|
|
yCoordinateRange(yValues, pixelSize, index) {
|
|
const { properties, sizeScale } = this;
|
|
const { size, sizeKey } = properties;
|
|
const y = this.axes[import_ag_charts_core257.ChartAxisDirection.Y].scale.convert(yValues[0]);
|
|
const sizeValues = sizeKey == null ? void 0 : this.dataModel.resolveColumnById(this, `sizeValue`, this.processedData);
|
|
const sizeValue = sizeValues == null ? size : sizeScale.convert(sizeValues[index]);
|
|
const r = 0.5 * sizeValue * pixelSize;
|
|
return [y - r, y + r];
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { dataModel, processedData } = this;
|
|
if (!processedData || !dataModel)
|
|
return { domain: [] };
|
|
const dataValues = {
|
|
[import_ag_charts_core257.ChartAxisDirection.X]: "xValue",
|
|
[import_ag_charts_core257.ChartAxisDirection.Y]: "yValue"
|
|
};
|
|
const id = dataValues[direction];
|
|
const dataDef = dataModel.resolveProcessedDataDefById(this, id);
|
|
const domainData = dataModel.getDomain(this, id, "value", processedData);
|
|
if (dataDef?.def.type === "value" && dataDef?.def.valueType === "category") {
|
|
return { domain: domainData.domain };
|
|
}
|
|
const crossDirection = direction === import_ag_charts_core257.ChartAxisDirection.X ? import_ag_charts_core257.ChartAxisDirection.Y : import_ag_charts_core257.ChartAxisDirection.X;
|
|
const crossId = dataValues[crossDirection];
|
|
const ext = this.domainForClippedRange(direction, [id], crossId);
|
|
return { domain: fixNumericExtent((0, import_ag_charts_core257.extent)(ext)) };
|
|
}
|
|
getSeriesRange(_direction, visibleRange) {
|
|
return this.domainForVisibleRange(import_ag_charts_core257.ChartAxisDirection.Y, ["yValue"], "xValue", visibleRange);
|
|
}
|
|
getVisibleItems(xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
const { dataAggregation, axes } = this;
|
|
const xAxis = axes[import_ag_charts_core257.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core257.ChartAxisDirection.Y];
|
|
if (dataAggregation == null || xAxis == null || yAxis == null) {
|
|
return this.countVisibleItems("xValue", ["yValue"], xVisibleRange, yVisibleRange, minVisibleItems);
|
|
}
|
|
const aggregationOptions = this.aggregationOptions(xAxis, yAxis, xVisibleRange, yVisibleRange ?? [0, 1]);
|
|
return computeBubbleAggregationCount(0, dataAggregation, aggregationOptions);
|
|
}
|
|
aggregateData(dataModel, processedData) {
|
|
if (processedData.type === "grouped")
|
|
return;
|
|
if (processedData.input.count <= this.properties.maxRenderedItems)
|
|
return;
|
|
const xAxis = this.axes[import_ag_charts_core257.ChartAxisDirection.X];
|
|
const yAxis = this.axes[import_ag_charts_core257.ChartAxisDirection.Y];
|
|
if (xAxis == null || yAxis == null)
|
|
return;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
if (!ContinuousScale.is(xScale) || !ContinuousScale.is(yScale))
|
|
return;
|
|
return aggregateBubbleDataFromDataModel(
|
|
xScale.type,
|
|
yScale.type,
|
|
dataModel,
|
|
processedData,
|
|
this.sizeScale,
|
|
this.properties.sizeKey != null,
|
|
this
|
|
);
|
|
}
|
|
aggregationOptions(xAxis, yAxis, xVisibleRange = xAxis.visibleRange, yVisibleRange = yAxis.visibleRange) {
|
|
const { processedData, dataModel } = this;
|
|
const { sizeKey } = this.properties;
|
|
const [markerSize, markerMaxSize] = this.getSizeRange();
|
|
const xRange = Math.abs(xAxis.range[1] - xAxis.range[0]);
|
|
const yRange = Math.abs(yAxis.range[1] - yAxis.range[0]);
|
|
const minSize = Math.max(markerSize, 1);
|
|
const maxSize = sizeKey ? Math.max(markerMaxSize, 1) : minSize;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
if (processedData != null && dataModel != null) {
|
|
if (ContinuousScale.is(xScale)) {
|
|
xVisibleRange = (0, import_ag_charts_core257.rescaleVisibleRange)(
|
|
xVisibleRange,
|
|
xScale.domain.map(import_ag_charts_core257.dateToNumber),
|
|
dataModel.getDomain(this, `xValue`, "value", processedData).domain.map(import_ag_charts_core257.dateToNumber)
|
|
);
|
|
}
|
|
if (ContinuousScale.is(yScale)) {
|
|
yVisibleRange = (0, import_ag_charts_core257.rescaleVisibleRange)(
|
|
yVisibleRange,
|
|
yScale.domain.map(import_ag_charts_core257.dateToNumber),
|
|
dataModel.getDomain(this, `yValue`, "value", processedData).domain.map(import_ag_charts_core257.dateToNumber)
|
|
);
|
|
}
|
|
}
|
|
return { xRange, yRange, minSize, maxSize, xVisibleRange, yVisibleRange };
|
|
}
|
|
/**
|
|
* Creates and returns a context object that caches expensive property lookups
|
|
* and scale conversions. Called once per createNodeData() invocation.
|
|
*/
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData, sizeScale, visible } = this;
|
|
if (!dataModel || !processedData)
|
|
return void 0;
|
|
const rawData = processedData.dataSources.get(this.id)?.data;
|
|
if (rawData == null)
|
|
return void 0;
|
|
const {
|
|
xKey,
|
|
yKey,
|
|
sizeKey,
|
|
xFilterKey,
|
|
yFilterKey,
|
|
sizeFilterKey,
|
|
labelKey,
|
|
xName,
|
|
yName,
|
|
sizeName,
|
|
labelName,
|
|
label,
|
|
legendItemName,
|
|
marker
|
|
} = this.properties;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const canIncrementallyUpdate = processedData.changeDescription != null && this.contextNodeData?.nodeData != null;
|
|
let labelTextDomain;
|
|
if (labelKey) {
|
|
labelTextDomain = [];
|
|
} else if (sizeKey) {
|
|
labelTextDomain = dataModel.getDomain(this, `sizeValue`, "value", processedData).domain;
|
|
} else {
|
|
labelTextDomain = [];
|
|
}
|
|
const xDataValues = dataModel.resolveColumnById(this, `xValue`, processedData);
|
|
return {
|
|
// Axes (from template method parameters)
|
|
xAxis,
|
|
yAxis,
|
|
// Data arrays
|
|
rawData,
|
|
xValues: xDataValues,
|
|
// Base interface field
|
|
xDataValues,
|
|
// BubbleSeries-specific alias
|
|
yDataValues: dataModel.resolveColumnById(this, `yValue`, processedData),
|
|
sizeDataValues: sizeKey == null ? void 0 : dataModel.resolveColumnById(this, `sizeValue`, processedData),
|
|
labelDataValues: labelKey == null ? void 0 : dataModel.resolveColumnById(this, `labelValue`, processedData),
|
|
xFilterDataValues: xFilterKey == null ? void 0 : dataModel.resolveColumnById(this, `xFilterValue`, processedData),
|
|
yFilterDataValues: yFilterKey == null ? void 0 : dataModel.resolveColumnById(this, `yFilterValue`, processedData),
|
|
sizeFilterDataValues: sizeFilterKey == null ? void 0 : dataModel.resolveColumnById(this, `sizeFilterValue`, processedData),
|
|
// Scales
|
|
xScale,
|
|
yScale,
|
|
sizeScale,
|
|
// Computed positioning
|
|
xOffset: (xScale.bandwidth ?? 0) / 2,
|
|
yOffset: (yScale.bandwidth ?? 0) / 2,
|
|
// Property lookups
|
|
xKey,
|
|
yKey,
|
|
sizeKey,
|
|
labelKey,
|
|
xName,
|
|
yName,
|
|
sizeName,
|
|
labelName,
|
|
legendItemName,
|
|
// Label properties
|
|
labelsEnabled: label.enabled,
|
|
labelPlacement: label.placement,
|
|
labelAnchor: Marker.anchor(marker.shape),
|
|
labelTextDomain,
|
|
labelPadding: expandLabelPadding(label),
|
|
labelTextMeasurer: (0, import_ag_charts_core257.cachedTextMeasurer)(label),
|
|
label,
|
|
// Other state
|
|
animationEnabled: !this.ctx.animationManager.isSkipped(),
|
|
visible,
|
|
// Incremental update support
|
|
canIncrementallyUpdate,
|
|
nodes: canIncrementallyUpdate ? this.contextNodeData.nodeData : [],
|
|
nodeIndex: 0
|
|
};
|
|
}
|
|
// ============================================================================
|
|
// Template Method Hooks
|
|
// ============================================================================
|
|
/**
|
|
* Populates the node data array by iterating over visible data.
|
|
* Strategy selection happens inside: simple or aggregation path.
|
|
*/
|
|
populateNodeData(ctx) {
|
|
this.sizeScale.range = this.getSizeRange();
|
|
const scratch = {
|
|
datum: void 0,
|
|
xDatum: void 0,
|
|
yDatum: void 0,
|
|
sizeValue: void 0,
|
|
x: 0,
|
|
y: 0,
|
|
selected: void 0,
|
|
nodeLabel: { text: "", width: 0, height: 0 },
|
|
markerSize: 0,
|
|
count: 1,
|
|
dilation: 1,
|
|
area: 0
|
|
};
|
|
const { dataAggregation } = this;
|
|
if (dataAggregation == null) {
|
|
this.createNodeDataSimple(ctx, scratch);
|
|
} else {
|
|
this.createNodeDataWithAggregation(ctx, scratch, ctx.xAxis, ctx.yAxis, dataAggregation);
|
|
}
|
|
}
|
|
/**
|
|
* Initializes the result context object with default values.
|
|
* Called before populate phase to allow early return for invisible series.
|
|
*/
|
|
initializeResult(ctx) {
|
|
const { marker } = this.properties;
|
|
return {
|
|
itemId: ctx.yKey,
|
|
nodeData: ctx.nodes,
|
|
labelData: ctx.labelsEnabled ? ctx.nodes : [],
|
|
scales: this.calculateScaling(),
|
|
visible: this.visible || ctx.animationEnabled,
|
|
styles: getMarkerStyles(this, this.properties, marker)
|
|
};
|
|
}
|
|
/**
|
|
* Validates datum state and upserts node - centralizes duplicated upsert pattern.
|
|
*/
|
|
upsertBubbleNodeDatum(ctx, scratch, datumIndex) {
|
|
if (!this.prepareNodeDatumState(ctx, scratch, datumIndex))
|
|
return;
|
|
upsertNodeDatum(
|
|
ctx,
|
|
{ scratch, datumIndex },
|
|
(c, p) => {
|
|
const node = this.createSkeletonNodeDatum(c, p.scratch, p.datumIndex);
|
|
this.updateNodeDatum(c, node, p.scratch, p.datumIndex);
|
|
return node;
|
|
},
|
|
(c, n, p) => this.updateNodeDatum(c, n, p.scratch, p.datumIndex)
|
|
);
|
|
}
|
|
/**
|
|
* Simple iteration path for ungrouped data without aggregation.
|
|
*/
|
|
createNodeDataSimple(ctx, scratch) {
|
|
const dataLength = ctx.rawData.length;
|
|
for (let datumIndex = 0; datumIndex < dataLength; datumIndex++) {
|
|
scratch.count = 1;
|
|
scratch.dilation = 1;
|
|
scratch.area = 0;
|
|
this.upsertBubbleNodeDatum(ctx, scratch, datumIndex);
|
|
}
|
|
}
|
|
/**
|
|
* Aggregation path for large datasets using quadtree-based 2D spatial aggregation.
|
|
*/
|
|
createNodeDataWithAggregation(ctx, scratch, xAxis, yAxis, dataAggregation) {
|
|
const { maxRenderedItems } = this.properties;
|
|
const aggregationOptions = this.aggregationOptions(xAxis, yAxis);
|
|
const aggregationDilation = computeBubbleAggregationDilation(
|
|
dataAggregation,
|
|
aggregationOptions,
|
|
maxRenderedItems
|
|
);
|
|
const { groupedAggregation, singleDatumIndices } = computeBubbleAggregationData(
|
|
aggregationDilation,
|
|
dataAggregation,
|
|
aggregationOptions
|
|
);
|
|
for (const { datumIndex, count, dilation, area: area2 } of groupedAggregation) {
|
|
scratch.count = count;
|
|
scratch.dilation = dilation;
|
|
scratch.area = area2;
|
|
this.upsertBubbleNodeDatum(ctx, scratch, datumIndex);
|
|
}
|
|
for (const datumIndex of singleDatumIndices) {
|
|
scratch.count = 1;
|
|
scratch.dilation = 1;
|
|
scratch.area = 0;
|
|
this.upsertBubbleNodeDatum(ctx, scratch, datumIndex);
|
|
}
|
|
}
|
|
/**
|
|
* Validates and prepares state needed for node creation/update.
|
|
* Returns undefined if datum should be skipped (invalid data).
|
|
*/
|
|
prepareNodeDatumState(ctx, scratch, datumIndex) {
|
|
const datum = ctx.rawData[datumIndex];
|
|
const xDatum = ctx.xDataValues[datumIndex];
|
|
const yDatum = ctx.yDataValues[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if ((xDatum === void 0 || yDatum === void 0) && !allowNullKeys)
|
|
return void 0;
|
|
const sizeValue = ctx.sizeDataValues?.[datumIndex];
|
|
const x = ctx.xScale.convert(xDatum) + ctx.xOffset;
|
|
const y = ctx.yScale.convert(yDatum) + ctx.yOffset;
|
|
if (!Number.isFinite(x) || !Number.isFinite(y))
|
|
return void 0;
|
|
let selected;
|
|
if (ctx.xFilterDataValues != null && ctx.yFilterDataValues != null) {
|
|
selected = ctx.xFilterDataValues[datumIndex] === xDatum && ctx.yFilterDataValues[datumIndex] === yDatum;
|
|
if (ctx.sizeFilterDataValues != null) {
|
|
selected && (selected = ctx.sizeFilterDataValues[datumIndex] === sizeValue);
|
|
}
|
|
}
|
|
let nodeLabel;
|
|
if (ctx.labelsEnabled) {
|
|
nodeLabel = this.computeLabel(ctx, datum, yDatum, sizeValue, datumIndex);
|
|
} else {
|
|
nodeLabel = { text: "", width: 0, height: 0 };
|
|
}
|
|
const markerSize = sizeValue == null ? ctx.sizeScale.range[0] : ctx.sizeScale.convert(sizeValue);
|
|
scratch.datum = datum;
|
|
scratch.xDatum = xDatum;
|
|
scratch.yDatum = yDatum;
|
|
scratch.sizeValue = sizeValue;
|
|
scratch.x = x;
|
|
scratch.y = y;
|
|
scratch.selected = selected;
|
|
scratch.nodeLabel = nodeLabel;
|
|
scratch.markerSize = markerSize;
|
|
return scratch;
|
|
}
|
|
/**
|
|
* Computes label text and measurements for a datum.
|
|
* Separated to enable skipping when labels are disabled.
|
|
*/
|
|
computeLabel(ctx, datum, yDatum, sizeValue, datumIndex) {
|
|
let labelTextValue;
|
|
let labelTextKey;
|
|
let labelTextProperty;
|
|
if (ctx.labelKey && ctx.labelDataValues) {
|
|
labelTextValue = ctx.labelDataValues[datumIndex];
|
|
labelTextKey = ctx.labelKey;
|
|
labelTextProperty = "label";
|
|
} else if (ctx.sizeKey) {
|
|
labelTextValue = sizeValue;
|
|
labelTextKey = ctx.sizeKey;
|
|
labelTextProperty = "size";
|
|
} else {
|
|
labelTextValue = yDatum;
|
|
labelTextKey = ctx.yKey;
|
|
labelTextProperty = "y";
|
|
}
|
|
const labelText = this.getLabelText(
|
|
labelTextValue,
|
|
datum,
|
|
labelTextKey,
|
|
labelTextProperty,
|
|
ctx.labelTextDomain,
|
|
ctx.label,
|
|
{
|
|
value: labelTextValue,
|
|
datum,
|
|
xKey: ctx.xKey,
|
|
yKey: ctx.yKey,
|
|
// sizeKey may be undefined for ScatterSeries (which extends BubbleSeries)
|
|
sizeKey: ctx.sizeKey,
|
|
labelKey: ctx.labelKey,
|
|
xName: ctx.xName,
|
|
yName: ctx.yName,
|
|
sizeName: ctx.sizeName,
|
|
labelName: ctx.labelName,
|
|
legendItemName: ctx.legendItemName
|
|
}
|
|
);
|
|
let { width, height } = (0, import_ag_charts_core257.isArray)(labelText) ? (0, import_ag_charts_core257.measureTextSegments)(labelText, ctx.label) : ctx.labelTextMeasurer.measureLines(String(labelText));
|
|
width += ctx.labelPadding.left + ctx.labelPadding.right;
|
|
height += ctx.labelPadding.bottom + ctx.labelPadding.top;
|
|
return { text: labelText, width, height };
|
|
}
|
|
/**
|
|
* Creates a minimal skeleton node - actual values set by updateNodeDatum.
|
|
*/
|
|
createSkeletonNodeDatum(ctx, _scratch, _datumIndex) {
|
|
return {
|
|
series: this,
|
|
yKey: ctx.yKey,
|
|
xKey: ctx.xKey,
|
|
datum: void 0,
|
|
datumIndex: 0,
|
|
xValue: void 0,
|
|
yValue: void 0,
|
|
sizeValue: void 0,
|
|
capDefaults: { lengthRatioMultiplier: this.properties.marker.getDiameter(), lengthMax: Infinity },
|
|
point: { x: 0, y: 0, size: 0 },
|
|
midPoint: { x: 0, y: 0 },
|
|
label: { text: "", width: 0, height: 0 },
|
|
anchor: ctx.labelAnchor,
|
|
placement: ctx.labelPlacement,
|
|
count: 1,
|
|
dilation: 1,
|
|
area: 0,
|
|
selected: void 0
|
|
};
|
|
}
|
|
/**
|
|
* Updates node properties in-place.
|
|
* Shared by both create (skeleton + update) and incremental update paths.
|
|
*/
|
|
updateNodeDatum(ctx, node, scratch, datumIndex) {
|
|
const mutableNode = node;
|
|
const { x, y, markerSize, dilation } = scratch;
|
|
mutableNode.datum = scratch.datum;
|
|
mutableNode.datumIndex = datumIndex;
|
|
mutableNode.xValue = scratch.xDatum;
|
|
mutableNode.yValue = scratch.yDatum;
|
|
mutableNode.sizeValue = scratch.sizeValue;
|
|
mutableNode.selected = scratch.selected;
|
|
mutableNode.count = scratch.count;
|
|
mutableNode.dilation = scratch.dilation;
|
|
mutableNode.area = scratch.area;
|
|
mutableNode.label = scratch.nodeLabel;
|
|
mutableNode.anchor = ctx.labelAnchor;
|
|
mutableNode.placement = ctx.labelPlacement;
|
|
const mutablePoint = mutableNode.point;
|
|
mutablePoint.x = x;
|
|
mutablePoint.y = y;
|
|
mutablePoint.size = Math.sqrt(dilation) * markerSize;
|
|
const mutableMidPoint = mutableNode.midPoint;
|
|
mutableMidPoint.x = x;
|
|
mutableMidPoint.y = y;
|
|
}
|
|
isPathOrSelectionDirty() {
|
|
return this.properties.marker.isDirty();
|
|
}
|
|
getLabelData() {
|
|
if (!this.isLabelEnabled())
|
|
return [];
|
|
return this.contextNodeData?.labelData ?? [];
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const { nodeData, datumSelection } = opts;
|
|
if (this.properties.marker.isDirty()) {
|
|
datumSelection.clear();
|
|
datumSelection.cleanup();
|
|
}
|
|
if (!processedDataIsAnimatable(this.processedData)) {
|
|
return datumSelection.update(nodeData);
|
|
}
|
|
const { sizeKey } = this.properties;
|
|
let getId;
|
|
if (sizeKey) {
|
|
getId = (datum) => createDatumId(datum.xValue, datum.yValue, datum.sizeValue, (0, import_ag_charts_core257.toPlainText)(datum.label.text));
|
|
}
|
|
return datumSelection.update(nodeData, void 0, getId);
|
|
}
|
|
updateDatumStyles(opts) {
|
|
const { datumSelection, isHighlight } = opts;
|
|
const { xKey, yKey, sizeKey, labelKey, marker } = this.properties;
|
|
const params = { xKey, yKey, sizeKey, labelKey };
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
datumSelection.each((node, datum) => {
|
|
if (!datumSelection.isGarbage(node)) {
|
|
const highlightState = this.getHighlightState(highlightedDatum, opts.isHighlight, datum.datumIndex);
|
|
const stylerStyle = this.getStyle(highlightState);
|
|
datum.style = this.getMarkerStyle(
|
|
marker,
|
|
datum,
|
|
params,
|
|
{
|
|
isHighlight,
|
|
highlightState,
|
|
resolveMarkerSubPath: []
|
|
},
|
|
stylerStyle
|
|
);
|
|
}
|
|
});
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData)
|
|
return;
|
|
const { datumSelection, isHighlight, drawingMode } = opts;
|
|
this.sizeScale.range = this.getSizeRange();
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const aggregated = this.dataAggregation != null;
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
datumSelection.each((node, datum, index) => {
|
|
const {
|
|
point: { size },
|
|
count,
|
|
area: area2,
|
|
dilation
|
|
} = datum;
|
|
const state = this.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex);
|
|
const style = { ...datum.style ?? contextNodeData.styles[state] };
|
|
style.size = size;
|
|
if (dilation > 1) {
|
|
const fillOpacity = style.fillOpacity ?? 0;
|
|
const opacityScale = 0.269669 + 683e-6 * count + -37.534348 * area2 + 4449e-6 * count * area2 + -0 * count ** 2 + 44.428603 * area2 ** 2;
|
|
style.fillOpacity = (0, import_ag_charts_core257.clamp)(fillOpacity / dilation, fillOpacity / 0.1 * opacityScale, 1);
|
|
}
|
|
this.applyMarkerStyle(style, node, datum.point, fillBBox, { selected: datum.selected });
|
|
node.drawingMode = this.resolveMarkerDrawingModeForState(drawingMode, style);
|
|
node.zIndex = aggregated ? [-count, index] : 0;
|
|
});
|
|
if (!isHighlight) {
|
|
this.properties.marker.markClean();
|
|
}
|
|
}
|
|
updatePlacedLabelData(labelData) {
|
|
this.placedLabelData = labelData;
|
|
this.labelSelection.update(
|
|
labelData.map((v) => ({
|
|
...v.datum,
|
|
point: {
|
|
x: v.x,
|
|
y: v.y,
|
|
size: v.datum.point.size
|
|
}
|
|
})),
|
|
(text) => {
|
|
text.pointerEvents = 1 /* None */;
|
|
}
|
|
);
|
|
this.updateLabelNodes({ labelSelection: this.labelSelection });
|
|
this.updateHighlightLabelSelection();
|
|
}
|
|
updateHighlightLabelSelection() {
|
|
const highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
const highlightItem = this.isSeriesHighlighted(highlightedDatum) && highlightedDatum?.datum ? highlightedDatum : void 0;
|
|
const highlightLabelData = highlightItem == null ? [] : this.placedLabelData.filter((label) => label.datum.datumIndex === highlightItem.datumIndex).map((label) => ({
|
|
...label.datum,
|
|
point: {
|
|
x: label.x,
|
|
y: label.y,
|
|
size: label.datum.point.size
|
|
}
|
|
}));
|
|
this.highlightLabelSelection = this.updateLabelSelection({
|
|
labelData: highlightLabelData,
|
|
labelSelection: this.highlightLabelSelection
|
|
}) ?? this.highlightLabelSelection;
|
|
this.highlightLabelGroup.visible = highlightLabelData.length > 0;
|
|
this.highlightLabelGroup.batchedUpdate(() => {
|
|
this.updateLabelNodes({ labelSelection: this.highlightLabelSelection, isHighlight: true });
|
|
});
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const { isHighlight = false } = opts;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const params = this.makeLabelFormatterParams();
|
|
opts.labelSelection.each((text, datum) => {
|
|
const style = getLabelStyles(this, datum, params, this.properties.label, isHighlight, activeHighlight);
|
|
text.text = datum.label.text;
|
|
text.fill = style.color;
|
|
text.x = datum.point?.x ?? 0;
|
|
text.y = datum.point?.y ?? 0;
|
|
text.fontStyle = style.fontStyle;
|
|
text.fontWeight = style.fontWeight;
|
|
text.fontSize = style.fontSize;
|
|
text.fontFamily = style.fontFamily;
|
|
text.textBaseline = "top";
|
|
text.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex).opacity ?? 1;
|
|
text.setBoxing(style);
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const { labelData, labelSelection } = opts;
|
|
return labelSelection.update(labelData, (text) => {
|
|
text.pointerEvents = 1 /* None */;
|
|
});
|
|
}
|
|
makeStylerParams(highlightStateEnum) {
|
|
const {
|
|
id: seriesId,
|
|
properties: {
|
|
size,
|
|
maxSize,
|
|
shape,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
xKey,
|
|
yKey,
|
|
sizeKey,
|
|
labelKey
|
|
}
|
|
} = this;
|
|
const highlightState = toHighlightString(highlightStateEnum ?? 0 /* None */);
|
|
if (this.type === "bubble") {
|
|
return {
|
|
highlightState,
|
|
size,
|
|
maxSize,
|
|
shape,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
seriesId,
|
|
sizeKey,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
xKey,
|
|
yKey,
|
|
labelKey
|
|
};
|
|
} else if (this.type === "scatter") {
|
|
return {
|
|
highlightState,
|
|
size,
|
|
shape,
|
|
fill,
|
|
fillOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
seriesId,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
xKey,
|
|
yKey,
|
|
labelKey
|
|
};
|
|
} else {
|
|
return this.type;
|
|
}
|
|
}
|
|
makeLabelFormatterParams() {
|
|
const { xKey, xName, yKey, yName, sizeKey, sizeName, labelKey, labelName, legendItemName } = this.properties;
|
|
return {
|
|
xKey,
|
|
xName,
|
|
yKey,
|
|
yName,
|
|
sizeKey,
|
|
sizeName,
|
|
labelKey,
|
|
labelName,
|
|
legendItemName
|
|
};
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, axes, properties, ctx } = this;
|
|
const { formatManager } = ctx;
|
|
const {
|
|
xKey,
|
|
xName,
|
|
yKey,
|
|
yName,
|
|
sizeKey,
|
|
sizeName,
|
|
labelKey,
|
|
labelName,
|
|
title,
|
|
tooltip,
|
|
marker,
|
|
legendItemName
|
|
} = properties;
|
|
const xAxis = axes[import_ag_charts_core257.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core257.ChartAxisDirection.Y];
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data?.[datumIndex];
|
|
const xValue = dataModel.resolveColumnById(this, `xValue`, processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValue`, processedData)[datumIndex];
|
|
const allowNullKeys = this.properties.allowNullKeys ?? false;
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const data = [];
|
|
if (this.isLabelEnabled() && labelKey != null) {
|
|
const value = dataModel.resolveColumnById(this, `labelValue`, processedData)[datumIndex];
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "category",
|
|
value,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: labelKey,
|
|
source: "tooltip",
|
|
property: "label",
|
|
domain: [],
|
|
boundSeries: this.getFormatterContext("label")
|
|
});
|
|
data.push({ label: labelName, fallbackLabel: labelKey, value: content ?? (0, import_ag_charts_core257.formatValue)(value) });
|
|
}
|
|
data.push(
|
|
{
|
|
label: xName,
|
|
fallbackLabel: xKey,
|
|
value: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName, allowNullKeys),
|
|
missing: isTooltipValueMissing(xValue, allowNullKeys)
|
|
},
|
|
{
|
|
label: yName,
|
|
fallbackLabel: yKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", yValue, datum, yKey, legendItemName, allowNullKeys),
|
|
missing: isTooltipValueMissing(yValue, allowNullKeys)
|
|
}
|
|
);
|
|
if (sizeKey != null) {
|
|
const value = dataModel.resolveColumnById(this, `sizeValue`, processedData)[datumIndex];
|
|
if (value != null) {
|
|
const domain = dataModel.getDomain(this, `sizeValue`, "value", processedData).domain;
|
|
const content = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value,
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key: sizeKey,
|
|
source: "tooltip",
|
|
property: "size",
|
|
boundSeries: this.getFormatterContext("size"),
|
|
domain,
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
});
|
|
data.push({ label: sizeName, fallbackLabel: sizeKey, value: content ?? (0, import_ag_charts_core257.formatValue)(value) });
|
|
}
|
|
}
|
|
const activeStyle = this.getMarkerStyle(
|
|
marker,
|
|
{ datum, datumIndex },
|
|
{ xKey, yKey, sizeKey, labelKey },
|
|
{ resolveMarkerSubPath: [] }
|
|
);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
title,
|
|
symbol: this.legendItemSymbol(),
|
|
data
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: yKey,
|
|
xKey,
|
|
xName,
|
|
yKey,
|
|
yName,
|
|
sizeKey,
|
|
sizeName,
|
|
labelKey,
|
|
labelName,
|
|
legendItemName,
|
|
...activeStyle,
|
|
...this.getModuleTooltipParams()
|
|
}
|
|
);
|
|
}
|
|
legendItemSymbol() {
|
|
const style = this.getStyle();
|
|
const marker = this.getMarkerStyle(
|
|
this.properties.marker,
|
|
{},
|
|
void 0,
|
|
{
|
|
isHighlight: false,
|
|
checkForHighlight: false,
|
|
resolveMarkerSubPath: []
|
|
},
|
|
style
|
|
);
|
|
return {
|
|
marker
|
|
};
|
|
}
|
|
getLegendData() {
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
const { yKey: itemId, yName, legendItemName, title, showInLegend } = this.properties;
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId,
|
|
seriesId,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId }),
|
|
label: {
|
|
text: legendItemName ?? title ?? yName ?? itemId
|
|
},
|
|
symbol: this.legendItemSymbol(),
|
|
legendItemName,
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
animateEmptyUpdateReady({ datumSelection, labelSelection }) {
|
|
markerScaleInAnimation(this, this.ctx.animationManager, datumSelection);
|
|
seriesLabelFadeInAnimation(this, "labels", this.ctx.animationManager, labelSelection);
|
|
}
|
|
resetDatumAnimation(data) {
|
|
resetMarkerSelectionsDirect([data.datumSelection]);
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.label.enabled;
|
|
}
|
|
nodeFactory() {
|
|
return new Marker();
|
|
}
|
|
getStyle(highlightState) {
|
|
const { properties } = this;
|
|
let stylerResult = {};
|
|
if (properties.styler) {
|
|
const stylerParams = this.makeStylerParams(highlightState);
|
|
const cbResult = this.cachedCallWithContext(properties.styler, stylerParams) ?? {};
|
|
const resolved = this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
cbResult,
|
|
{ pick: false }
|
|
);
|
|
stylerResult = resolved ?? {};
|
|
}
|
|
return {
|
|
fill: stylerResult.fill ?? properties.fill,
|
|
fillOpacity: stylerResult.fillOpacity ?? properties.fillOpacity,
|
|
lineDash: stylerResult.lineDash ?? properties.lineDash,
|
|
lineDashOffset: stylerResult.lineDashOffset ?? properties.lineDashOffset,
|
|
shape: stylerResult.shape ?? properties.shape,
|
|
size: stylerResult.size ?? properties.size,
|
|
maxSize: stylerResult.maxSize ?? properties.maxSize,
|
|
stroke: stylerResult.stroke ?? properties.stroke,
|
|
strokeOpacity: stylerResult.strokeOpacity ?? properties.strokeOpacity,
|
|
strokeWidth: stylerResult.strokeWidth ?? properties.strokeWidth
|
|
};
|
|
}
|
|
getSizeRange() {
|
|
const { size, maxSize } = this.getStyle();
|
|
return [size, maxSize];
|
|
}
|
|
getFormattedMarkerStyle(datum) {
|
|
const { xKey, yKey, sizeKey, labelKey, marker } = this.properties;
|
|
return this.getMarkerStyle(marker, datum, { xKey, yKey, sizeKey, labelKey }, { resolveMarkerSubPath: [] });
|
|
}
|
|
computeFocusBounds(opts) {
|
|
return computeMarkerFocusBounds(this, opts);
|
|
}
|
|
hasItemStylers() {
|
|
const { styler, itemStyler, marker, label } = this.properties;
|
|
return !!(styler ?? itemStyler ?? marker.itemStyler ?? label.itemStyler);
|
|
}
|
|
initQuadTree(quadtree) {
|
|
addHitTestersToQuadtree(quadtree, this.datumNodesIter());
|
|
}
|
|
pickNodeDataClosestDatum(point) {
|
|
return findQuadtreeMatch(this, point);
|
|
}
|
|
};
|
|
BubbleSeries.className = "BubbleSeries";
|
|
BubbleSeries.type = "bubble";
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/bubbleSeriesModule.ts
|
|
var themeTemplate3 = {
|
|
series: {
|
|
shape: "circle",
|
|
size: 7,
|
|
maxSize: 30,
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", import_ag_charts_core258.FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS],
|
|
["image", import_ag_charts_core258.FILL_IMAGE_DEFAULTS],
|
|
["pattern", import_ag_charts_core258.FILL_PATTERN_DEFAULTS]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
fillOpacity: 0.8,
|
|
maxRenderedItems: 2e3,
|
|
label: {
|
|
...import_ag_charts_core258.LABEL_BOXING_DEFAULTS,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
tooltip: {
|
|
range: {
|
|
$if: [
|
|
{ $eq: [{ $path: ["/tooltip/range", "nearest"] }, "area"] },
|
|
"nearest",
|
|
{ $path: ["/tooltip/range", "nearest"] }
|
|
]
|
|
},
|
|
position: {
|
|
anchorTo: { $path: ["/tooltip/position/anchorTo", "node"] }
|
|
}
|
|
},
|
|
highlight: import_ag_charts_core258.MULTI_SERIES_HIGHLIGHT_STYLE
|
|
}
|
|
};
|
|
var BubbleSeriesModule = {
|
|
type: "series",
|
|
name: "bubble",
|
|
chartType: "cartesian",
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: bubbleSeriesOptionsDef,
|
|
predictAxis: predictCartesianAxis,
|
|
defaultAxes: {
|
|
x: {
|
|
type: import_ag_charts_core258.CARTESIAN_AXIS_TYPE.NUMBER,
|
|
position: import_ag_charts_core258.CARTESIAN_POSITION.BOTTOM
|
|
},
|
|
y: {
|
|
type: import_ag_charts_core258.CARTESIAN_AXIS_TYPE.NUMBER,
|
|
position: import_ag_charts_core258.CARTESIAN_POSITION.LEFT
|
|
}
|
|
},
|
|
axisKeys: { [import_ag_charts_core258.ChartAxisDirection.X]: "xKeyAxis", [import_ag_charts_core258.ChartAxisDirection.Y]: "yKeyAxis" },
|
|
themeTemplate: themeTemplate3,
|
|
create: (ctx) => new BubbleSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/histogramSeriesModule.ts
|
|
var import_ag_charts_core261 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/histogramSeries.ts
|
|
var import_ag_charts_core260 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/histogramSeriesProperties.ts
|
|
var import_ag_charts_core259 = require("ag-charts-core");
|
|
var HistogramSeriesProperties = class extends CartesianSeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fillOpacity = 1;
|
|
this.strokeWidth = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.cornerRadius = 0;
|
|
this.areaPlot = false;
|
|
this.aggregation = "sum";
|
|
this.shadow = new DropShadow();
|
|
this.label = new Label();
|
|
this.tooltip = makeSeriesTooltip();
|
|
}
|
|
getStyle() {
|
|
const { fill, fillOpacity, stroke, strokeWidth, strokeOpacity, lineDash, lineDashOffset, cornerRadius } = this;
|
|
return {
|
|
fill,
|
|
fillOpacity,
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
cornerRadius,
|
|
opacity: 1
|
|
};
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "yKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "areaPlot", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "bins", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "aggregation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "binCount", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "shadow", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core259.Property
|
|
], HistogramSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/histogramSeries.ts
|
|
var defaultBinCount = 10;
|
|
var HistogramSeries = class extends CartesianSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
propertyKeys: DEFAULT_CARTESIAN_DIRECTION_KEYS,
|
|
propertyNames: DEFAULT_CARTESIAN_DIRECTION_NAMES,
|
|
categoryKey: void 0,
|
|
pickModes: [1 /* NEAREST_NODE */, 0 /* EXACT_SHAPE_MATCH */],
|
|
datumSelectionGarbageCollection: true,
|
|
animationAlwaysPopulateNodeData: true,
|
|
alwaysClip: true,
|
|
animationResetFns: {
|
|
datum: resetBarSelectionsFn,
|
|
label: resetLabelFn
|
|
}
|
|
});
|
|
this.properties = new HistogramSeriesProperties();
|
|
this.calculatedBins = [];
|
|
}
|
|
get hasData() {
|
|
return this.calculatedBins.length > 0;
|
|
}
|
|
// During processData phase, used to unify different ways of the user specifying
|
|
// the bins. Returns bins in format[[min1, max1], [min2, max2], ... ].
|
|
deriveBins(xDomain) {
|
|
const binStarts = (0, import_ag_charts_core260.createTicks)(xDomain[0], xDomain[1], defaultBinCount).ticks;
|
|
const binSize = (0, import_ag_charts_core260.tickStep)(xDomain[0], xDomain[1], defaultBinCount);
|
|
const [firstBinEnd] = binStarts;
|
|
const expandStartToBin = (n) => [n, n + binSize];
|
|
return [[firstBinEnd - binSize, firstBinEnd], ...binStarts.map(expandStartToBin)];
|
|
}
|
|
calculateNiceBins(domain, binCount) {
|
|
const startGuess = Math.floor(domain[0]);
|
|
const stop = domain[1];
|
|
const segments = binCount || 1;
|
|
const { start, binSize } = this.calculateNiceStart(startGuess, stop, segments);
|
|
return this.getBins(start, stop, binSize, segments);
|
|
}
|
|
getBins(start, stop, step, count) {
|
|
const bins = [];
|
|
const precision = this.calculatePrecision(step);
|
|
for (let i = 0; i < count; i++) {
|
|
const a = Math.round((start + i * step) * precision) / precision;
|
|
let b = Math.round((start + (i + 1) * step) * precision) / precision;
|
|
if (i === count - 1) {
|
|
b = Math.max(b, stop);
|
|
}
|
|
bins[i] = [a, b];
|
|
}
|
|
return bins;
|
|
}
|
|
calculatePrecision(step) {
|
|
let precision = 10;
|
|
if (Number.isFinite(step) && step > 0) {
|
|
while (step < 1) {
|
|
precision *= 10;
|
|
step *= 10;
|
|
}
|
|
}
|
|
return precision;
|
|
}
|
|
calculateNiceStart(a, b, segments) {
|
|
const binSize = Math.abs(b - a) / segments;
|
|
const order = Math.floor(Math.log10(binSize));
|
|
const magnitude = Math.pow(10, order);
|
|
const start = Math.floor(a / magnitude) * magnitude;
|
|
return {
|
|
start,
|
|
binSize
|
|
};
|
|
}
|
|
async processData(dataController) {
|
|
const { visible } = this;
|
|
const { xKey, yKey, areaPlot, aggregation } = this.properties;
|
|
const xScale = this.axes[import_ag_charts_core260.ChartAxisDirection.X]?.scale;
|
|
const yScale = this.axes[import_ag_charts_core260.ChartAxisDirection.Y]?.scale;
|
|
const { xScaleType, yScaleType } = this.getScaleInformation({ yScale, xScale });
|
|
const visibleProps = visible ? {} : { forceValue: 0 };
|
|
const props = [keyProperty(xKey, xScaleType), SORT_DOMAIN_GROUPS];
|
|
if (yKey) {
|
|
let aggProp = groupCount("groupAgg", { visible });
|
|
if (aggregation === "count") {
|
|
} else if (aggregation === "sum") {
|
|
aggProp = groupSum("groupAgg", { visible });
|
|
} else if (aggregation === "mean") {
|
|
aggProp = groupAverage("groupAgg", { visible });
|
|
}
|
|
if (areaPlot) {
|
|
aggProp = area("groupAgg", aggProp);
|
|
}
|
|
props.push(valueProperty(yKey, yScaleType, { invalidValue: void 0, ...visibleProps }), aggProp);
|
|
} else {
|
|
props.push(rowCountProperty("count"));
|
|
let aggProp = groupCount("groupAgg", { visible });
|
|
if (areaPlot) {
|
|
aggProp = area("groupAgg", aggProp);
|
|
}
|
|
props.push(aggProp);
|
|
}
|
|
let calculatedBinDomains = [];
|
|
const groupByFn = (dataSet) => {
|
|
const xExtent = fixNumericExtent(dataSet.domain.keys[0]);
|
|
if (xExtent.length === 0) {
|
|
dataSet.domain.groups = [];
|
|
return () => [];
|
|
}
|
|
const bins = (0, import_ag_charts_core260.isNumber)(this.properties.binCount) ? this.calculateNiceBins(xExtent, this.properties.binCount) : this.properties.bins ?? this.deriveBins(xExtent);
|
|
const binCount = bins.length;
|
|
calculatedBinDomains = [...bins];
|
|
return (keys) => {
|
|
let xValue = keys[0];
|
|
if ((0, import_ag_charts_core260.isDate)(xValue)) {
|
|
xValue = xValue.getTime();
|
|
}
|
|
if (!(0, import_ag_charts_core260.isNumber)(xValue))
|
|
return [];
|
|
for (let i = 0; i < binCount; i++) {
|
|
const nextBin = bins[i];
|
|
if (xValue >= nextBin[0] && xValue < nextBin[1]) {
|
|
return nextBin;
|
|
}
|
|
if (i === binCount - 1 && xValue <= nextBin[1]) {
|
|
return nextBin;
|
|
}
|
|
}
|
|
return [];
|
|
};
|
|
};
|
|
const { dataModel, processedData: p } = await this.requestDataModel(dataController, this.data, {
|
|
props,
|
|
groupByFn
|
|
});
|
|
const processedData = p;
|
|
const groups = /* @__PURE__ */ new Map();
|
|
for (const [groupIndex, group] of processedData.groups.entries()) {
|
|
const domain = group.keys;
|
|
groups.set(createDatumId(...domain), { group, groupIndex });
|
|
}
|
|
this.calculatedBins = calculatedBinDomains.map((domain) => {
|
|
const g = groups.get(createDatumId(...domain));
|
|
if (g) {
|
|
const { group, groupIndex } = g;
|
|
const [[negativeAgg, positiveAgg] = [0, 0]] = group.aggregation;
|
|
const datum = [...dataModel.forEachDatum(this, processedData, group, groupIndex)];
|
|
const frequency = this.frequency(group);
|
|
const total = negativeAgg + positiveAgg;
|
|
return { domain, datum, groupIndex, frequency, total };
|
|
} else {
|
|
return { domain, datum: [], groupIndex: -1, frequency: 0, total: 0 };
|
|
}
|
|
});
|
|
this.animationState.transition("updateData");
|
|
}
|
|
xCoordinateRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
yCoordinateRange() {
|
|
return [Number.NaN, Number.NaN];
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { processedData, dataModel } = this;
|
|
if (!processedData || !dataModel || !this.calculatedBins.length)
|
|
return { domain: [] };
|
|
const yDomain = dataModel.getDomain(this, `groupAgg`, "aggregate", processedData).domain;
|
|
const xDomainMin = this.calculatedBins[0].domain[0];
|
|
const xDomainMax = this.calculatedBins[(this.calculatedBins?.length ?? 0) - 1].domain[1];
|
|
if (direction === import_ag_charts_core260.ChartAxisDirection.X) {
|
|
return { domain: fixNumericExtent([xDomainMin, xDomainMax]) };
|
|
}
|
|
return { domain: fixNumericExtent(yDomain) };
|
|
}
|
|
getSeriesRange(_direction, [r0, r1]) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || processedData?.type !== "grouped")
|
|
return [Number.NaN, Number.NaN];
|
|
const xScale = this.axes[import_ag_charts_core260.ChartAxisDirection.X].scale;
|
|
const yMin = 0;
|
|
let yMax = -Infinity;
|
|
for (const { keys, aggregation } of processedData.groups) {
|
|
const [[negativeAgg, positiveAgg] = [0, 0]] = aggregation;
|
|
const [xDomainMin, xDomainMax] = keys;
|
|
const [x0, x1] = (0, import_ag_charts_core260.findMinMax)([xScale.convert(xDomainMin), xScale.convert(xDomainMax)]);
|
|
if (x1 >= r0 && x0 <= r1) {
|
|
const total = negativeAgg + positiveAgg;
|
|
yMax = Math.max(yMax, total);
|
|
}
|
|
}
|
|
if (yMin > yMax)
|
|
return [Number.NaN, Number.NaN];
|
|
return [yMin, yMax];
|
|
}
|
|
frequency(group) {
|
|
return group.datumIndices.reduce((acc, datumIndices) => acc + datumIndices.length, 0);
|
|
}
|
|
/**
|
|
* Creates the shared context for datum creation.
|
|
* Caches expensive lookups and computations that are constant across all datums.
|
|
*
|
|
* Note: rawData and xValues are empty arrays because HistogramSeries
|
|
* iterates over calculatedBins rather than raw data.
|
|
*/
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { xKey, yKey, xName, yName, label } = this.properties;
|
|
const { contextNodeData, processedData } = this;
|
|
const canIncrementallyUpdate = contextNodeData?.nodeData != null && processedData?.changeDescription != null;
|
|
return {
|
|
// Axes (from template method parameters)
|
|
xAxis,
|
|
yAxis,
|
|
// Scales
|
|
xScale: xAxis.scale,
|
|
yScale: yAxis.scale,
|
|
yAxisReversed: yAxis.isReversed(),
|
|
// Data source (empty arrays - histogram uses calculatedBins instead)
|
|
rawData: [],
|
|
xValues: [],
|
|
// Property lookups
|
|
xKey,
|
|
yKey,
|
|
xName,
|
|
yName,
|
|
label,
|
|
// Animation flag
|
|
animationEnabled: !this.ctx.animationManager.isSkipped(),
|
|
// Incremental update support
|
|
canIncrementallyUpdate,
|
|
nodes: canIncrementallyUpdate ? contextNodeData.nodeData : [],
|
|
nodeIndex: 0
|
|
};
|
|
}
|
|
/**
|
|
* Creates label data for a histogram bin if labels are enabled.
|
|
*/
|
|
createLabelData(ctx, bin, x, y, w, h) {
|
|
const { label, yKey, xKey, xName, yName } = ctx;
|
|
const { total, datum } = bin;
|
|
if (!label.enabled || total === 0) {
|
|
return void 0;
|
|
}
|
|
return {
|
|
x: x + w / 2,
|
|
y: y + h / 2,
|
|
text: this.getLabelText(total, datum, yKey, "y", [], label, {
|
|
value: total,
|
|
datum,
|
|
xKey,
|
|
yKey,
|
|
xName,
|
|
yName
|
|
})
|
|
};
|
|
}
|
|
/**
|
|
* Creates a skeleton HistogramNodeDatum with minimal required fields.
|
|
* The node will be populated by updateNodeDatum.
|
|
*/
|
|
createSkeletonNodeDatum(ctx, bin) {
|
|
const { xKey, yKey } = ctx;
|
|
const { domain, datum, groupIndex, frequency, total } = bin;
|
|
return {
|
|
series: this,
|
|
datumIndex: groupIndex,
|
|
datum,
|
|
aggregatedValue: total,
|
|
frequency,
|
|
domain,
|
|
yKey,
|
|
xKey,
|
|
x: 0,
|
|
y: 0,
|
|
xValue: 0,
|
|
yValue: 0,
|
|
width: 0,
|
|
height: 0,
|
|
midPoint: { x: 0, y: 0 },
|
|
topLeftCornerRadius: false,
|
|
topRightCornerRadius: false,
|
|
bottomRightCornerRadius: false,
|
|
bottomLeftCornerRadius: false,
|
|
label: void 0,
|
|
crisp: true
|
|
};
|
|
}
|
|
/**
|
|
* Updates an existing HistogramNodeDatum in-place.
|
|
* This is more efficient than recreating the entire node when only data values change.
|
|
*/
|
|
updateNodeDatum(ctx, node, bin) {
|
|
const { xScale, yScale, yAxisReversed } = ctx;
|
|
const { domain, datum, groupIndex, frequency, total } = bin;
|
|
const mutableNode = node;
|
|
const [xDomainMin, xDomainMax] = domain;
|
|
const xMinPx = xScale.convert(xDomainMin);
|
|
const xMaxPx = xScale.convert(xDomainMax);
|
|
const yZeroPx = yScale.convert(0);
|
|
const yMaxPx = yScale.convert(total);
|
|
const w = Math.abs(xMaxPx - xMinPx);
|
|
const h = Math.abs(yMaxPx - yZeroPx);
|
|
const x = Math.min(xMinPx, xMaxPx);
|
|
const y = Math.min(yZeroPx, yMaxPx);
|
|
mutableNode.datumIndex = groupIndex;
|
|
mutableNode.datum = datum;
|
|
mutableNode.aggregatedValue = total;
|
|
mutableNode.frequency = frequency;
|
|
mutableNode.domain = domain;
|
|
mutableNode.x = x;
|
|
mutableNode.y = y;
|
|
mutableNode.xValue = xMinPx;
|
|
mutableNode.yValue = yMaxPx;
|
|
mutableNode.width = w;
|
|
mutableNode.height = h;
|
|
if (mutableNode.midPoint) {
|
|
mutableNode.midPoint.x = x + w / 2;
|
|
mutableNode.midPoint.y = y + h / 2;
|
|
} else {
|
|
mutableNode.midPoint = { x: x + w / 2, y: y + h / 2 };
|
|
}
|
|
mutableNode.topLeftCornerRadius = !yAxisReversed;
|
|
mutableNode.topRightCornerRadius = !yAxisReversed;
|
|
mutableNode.bottomRightCornerRadius = yAxisReversed;
|
|
mutableNode.bottomLeftCornerRadius = yAxisReversed;
|
|
mutableNode.label = this.createLabelData(ctx, bin, x, y, w, h);
|
|
}
|
|
/**
|
|
* Creates a HistogramNodeDatum for a single bin.
|
|
* Creates a skeleton node and uses updateNodeDatum to populate it.
|
|
*/
|
|
createNodeDatum(ctx, bin) {
|
|
const node = this.createSkeletonNodeDatum(ctx, bin);
|
|
this.updateNodeDatum(ctx, node, bin);
|
|
return node;
|
|
}
|
|
/**
|
|
* Template method hook: Iterates over calculated bins and creates/updates node datums.
|
|
*/
|
|
populateNodeData(ctx) {
|
|
const { processedData } = this;
|
|
if (processedData?.type !== "grouped") {
|
|
return;
|
|
}
|
|
for (const bin of this.calculatedBins) {
|
|
upsertNodeDatum(
|
|
ctx,
|
|
bin,
|
|
(c, b) => this.createNodeDatum(c, b),
|
|
(c, n, b) => this.updateNodeDatum(c, n, b)
|
|
);
|
|
}
|
|
}
|
|
/**
|
|
* Template method hook: Creates the result object shell.
|
|
*/
|
|
initializeResult(ctx) {
|
|
return {
|
|
itemId: this.properties.yKey ?? this.id,
|
|
nodeData: ctx.nodes,
|
|
labelData: ctx.nodes,
|
|
scales: this.calculateScaling(),
|
|
animationValid: true,
|
|
visible: this.visible || ctx.animationEnabled,
|
|
styles: getItemStyles(this.getItemStyle.bind(this))
|
|
};
|
|
}
|
|
/**
|
|
* Template method hook: Trims arrays and sorts nodes for keyboard navigation.
|
|
*/
|
|
finalizeNodeData(ctx) {
|
|
super.finalizeNodeData(ctx);
|
|
ctx.nodes.sort((a, b) => a.x - b.x);
|
|
}
|
|
nodeFactory() {
|
|
return new Rect();
|
|
}
|
|
updateDatumSelection(opts) {
|
|
const { nodeData, datumSelection } = opts;
|
|
if (!processedDataIsAnimatable(this.processedData)) {
|
|
return datumSelection.update(nodeData);
|
|
}
|
|
return datumSelection.update(
|
|
nodeData,
|
|
void 0,
|
|
(datum) => createDatumId(...datum.domain)
|
|
);
|
|
}
|
|
getItemStyle(datumIndex, isHighlight, highlightState) {
|
|
const { properties } = this;
|
|
const highlightStyle = this.getHighlightStyle(isHighlight, datumIndex, highlightState);
|
|
return (0, import_ag_charts_core260.mergeDefaults)(highlightStyle, properties.getStyle());
|
|
}
|
|
updateDatumStyles(opts) {
|
|
const { datumSelection, isHighlight } = opts;
|
|
datumSelection.each((node, datum) => {
|
|
if (!datumSelection.isGarbage(node)) {
|
|
datum.style = this.getItemStyle(datum.datumIndex, isHighlight);
|
|
}
|
|
});
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const { shadow } = this.properties;
|
|
const fillBBox = this.getShapeFillBBox();
|
|
opts.datumSelection.each((rect2, datum) => {
|
|
const style = datum.style ?? contextNodeData.styles[this.getHighlightState(highlightedDatum, opts.isHighlight, datum.datumIndex)];
|
|
const { cornerRadius = 0 } = style;
|
|
const { topLeftCornerRadius, topRightCornerRadius, bottomRightCornerRadius, bottomLeftCornerRadius } = datum;
|
|
rect2.setStyleProperties(style, fillBBox);
|
|
rect2.topLeftCornerRadius = topLeftCornerRadius ? cornerRadius : 0;
|
|
rect2.topRightCornerRadius = topRightCornerRadius ? cornerRadius : 0;
|
|
rect2.bottomRightCornerRadius = bottomRightCornerRadius ? cornerRadius : 0;
|
|
rect2.bottomLeftCornerRadius = bottomLeftCornerRadius ? cornerRadius : 0;
|
|
rect2.crisp = datum.crisp;
|
|
rect2.fillShadow = shadow;
|
|
});
|
|
}
|
|
updateLabelSelection(opts) {
|
|
const { labelData, labelSelection } = opts;
|
|
return labelSelection.update(labelData, (text) => {
|
|
text.pointerEvents = 1 /* None */;
|
|
text.textAlign = "center";
|
|
text.textBaseline = "middle";
|
|
});
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const labelEnabled = this.isLabelEnabled();
|
|
const { isHighlight = false } = opts;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
opts.labelSelection.each((text, datum) => {
|
|
const style = getLabelStyles(
|
|
this,
|
|
datum,
|
|
this.properties,
|
|
this.properties.label,
|
|
isHighlight,
|
|
activeHighlight
|
|
);
|
|
const { enabled, fontStyle, fontWeight: fontWeight2, fontSize, fontFamily, color: color8 } = style;
|
|
if (enabled && labelEnabled && datum?.label) {
|
|
text.text = datum.label.text;
|
|
text.x = datum.label.x;
|
|
text.y = datum.label.y;
|
|
text.fontStyle = fontStyle;
|
|
text.fontWeight = fontWeight2;
|
|
text.fontFamily = fontFamily;
|
|
text.fontSize = fontSize;
|
|
text.fill = color8;
|
|
text.visible = true;
|
|
text.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex).opacity ?? 1;
|
|
text.setBoxing(style);
|
|
} else {
|
|
text.visible = false;
|
|
}
|
|
});
|
|
}
|
|
initQuadTree(quadtree) {
|
|
const { value: childNode } = this.contentGroup.children().next();
|
|
if (childNode instanceof Group) {
|
|
addHitTestersToQuadtree(quadtree, childNode.children());
|
|
}
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
return findQuadtreeMatch(this, point);
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const {
|
|
id: seriesId,
|
|
dataModel,
|
|
processedData,
|
|
axes,
|
|
properties,
|
|
ctx: { localeManager }
|
|
} = this;
|
|
const { xKey, xName, yKey, yName, tooltip, legendItemName } = properties;
|
|
const xAxis = axes[import_ag_charts_core260.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core260.ChartAxisDirection.Y];
|
|
if (!dataModel || processedData?.type !== "grouped" || !xAxis || !yAxis) {
|
|
return;
|
|
}
|
|
const group = processedData.groups[datumIndex];
|
|
const { aggregation, keys } = group;
|
|
const [[negativeAgg, positiveAgg] = [0, 0]] = aggregation;
|
|
const frequency = this.frequency(group);
|
|
const domain = keys;
|
|
const [rangeMin, rangeMax] = domain;
|
|
const aggregatedValue = negativeAgg + positiveAgg;
|
|
const datum = {
|
|
data: [...dataModel.forEachDatum(this, processedData, group, datumIndex)],
|
|
aggregatedValue,
|
|
frequency,
|
|
domain
|
|
};
|
|
const data = [
|
|
{
|
|
label: xName,
|
|
fallbackLabel: xKey,
|
|
value: `${this.getAxisValueText(xAxis, "tooltip", rangeMin, datum, xKey, legendItemName)} - ${this.getAxisValueText(xAxis, "tooltip", rangeMax, datum, xKey, legendItemName)}`
|
|
},
|
|
{
|
|
label: localeManager.t("seriesHistogramTooltipFrequency"),
|
|
value: this.getAxisValueText(yAxis, "tooltip", frequency, datum, yKey, legendItemName)
|
|
}
|
|
];
|
|
if (yKey != null) {
|
|
let label;
|
|
switch (properties.aggregation) {
|
|
case "sum":
|
|
label = localeManager.t("seriesHistogramTooltipSum", { yName: yName ?? yKey });
|
|
break;
|
|
case "mean":
|
|
label = localeManager.t("seriesHistogramTooltipMean", { yName: yName ?? yKey });
|
|
break;
|
|
case "count":
|
|
label = localeManager.t("seriesHistogramTooltipCount", { yName: yName ?? yKey });
|
|
break;
|
|
}
|
|
data.push({
|
|
label,
|
|
value: this.getAxisValueText(yAxis, "tooltip", aggregatedValue, datum, yKey, legendItemName)
|
|
});
|
|
}
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
symbol: this.legendItemSymbol(),
|
|
data
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: yName,
|
|
xKey,
|
|
// HistogramSeries is an outlier since it's callbacks don't use TDatum.
|
|
xName,
|
|
yKey,
|
|
// HistogramSeries is an outlier since it's callbacks don't use TDatum.
|
|
yName,
|
|
xRange: [rangeMin, rangeMax],
|
|
frequency,
|
|
...this.getItemStyle(datumIndex, false)
|
|
}
|
|
);
|
|
}
|
|
legendItemSymbol() {
|
|
const { fill, fillOpacity, stroke, strokeWidth, strokeOpacity, lineDash, lineDashOffset } = this.properties;
|
|
return {
|
|
marker: {
|
|
fill: (0, import_ag_charts_core260.deepClone)(fill) ?? "rgba(0, 0, 0, 0)",
|
|
stroke: stroke ?? "rgba(0, 0, 0, 0)",
|
|
fillOpacity,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
const { xKey: itemId, yName, showInLegend } = this.properties;
|
|
return [
|
|
{
|
|
legendType: "category",
|
|
id: seriesId,
|
|
itemId,
|
|
seriesId,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId }),
|
|
label: {
|
|
text: yName ?? itemId ?? "Frequency"
|
|
},
|
|
symbol: this.legendItemSymbol(),
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
resetDatumAnimation(data) {
|
|
resetBarSelectionsDirect([data.datumSelection]);
|
|
}
|
|
animateEmptyUpdateReady({ datumSelection, labelSelection }) {
|
|
const fns = prepareBarAnimationFunctions(collapsedStartingBarPosition(true, this.axes, "normal"), "unknown");
|
|
fromToMotion(this.id, "datums", this.ctx.animationManager, [datumSelection], fns);
|
|
seriesLabelFadeInAnimation(this, "labels", this.ctx.animationManager, labelSelection);
|
|
}
|
|
animateWaitingUpdateReady(data) {
|
|
const fns = prepareBarAnimationFunctions(collapsedStartingBarPosition(true, this.axes, "normal"), "added");
|
|
const dataDiff = {
|
|
changed: true,
|
|
added: /* @__PURE__ */ new Set(),
|
|
updated: /* @__PURE__ */ new Set(),
|
|
removed: /* @__PURE__ */ new Set(),
|
|
moved: /* @__PURE__ */ new Set()
|
|
};
|
|
fromToMotion(
|
|
this.id,
|
|
"datums",
|
|
this.ctx.animationManager,
|
|
[data.datumSelection],
|
|
fns,
|
|
(_, datum) => createDatumId(...datum.domain),
|
|
dataDiff
|
|
);
|
|
if (dataDiff?.changed) {
|
|
seriesLabelFadeInAnimation(this, "labels", this.ctx.animationManager, data.labelSelection);
|
|
}
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.label.enabled;
|
|
}
|
|
computeFocusBounds({ datumIndex }) {
|
|
return computeBarFocusBounds(this, this.contextNodeData?.nodeData[datumIndex]);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
HistogramSeries.className = "HistogramSeries";
|
|
HistogramSeries.type = "histogram";
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/histogramSeriesModule.ts
|
|
var themeTemplate4 = {
|
|
series: {
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", import_ag_charts_core261.FILL_GRADIENT_LINEAR_DEFAULTS],
|
|
["image", import_ag_charts_core261.FILL_IMAGE_DEFAULTS],
|
|
["pattern", import_ag_charts_core261.FILL_PATTERN_DEFAULTS]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
strokeWidth: 1,
|
|
fillOpacity: 1,
|
|
strokeOpacity: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
label: {
|
|
...import_ag_charts_core261.LABEL_BOXING_DEFAULTS,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "chartBackgroundColor" }
|
|
},
|
|
shadow: {
|
|
enabled: false,
|
|
color: import_ag_charts_core261.DEFAULT_SHADOW_COLOUR,
|
|
xOffset: 3,
|
|
yOffset: 3,
|
|
blur: 5
|
|
},
|
|
highlight: import_ag_charts_core261.MULTI_SERIES_HIGHLIGHT_STYLE
|
|
}
|
|
};
|
|
var HistogramSeriesModule = {
|
|
type: "series",
|
|
name: "histogram",
|
|
chartType: "cartesian",
|
|
// enterprise: true,
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: histogramSeriesOptionsDef,
|
|
predictAxis: predictCartesianNonPrimitiveAxis,
|
|
defaultAxes: {
|
|
x: {
|
|
type: import_ag_charts_core261.CARTESIAN_AXIS_TYPE.NUMBER,
|
|
position: import_ag_charts_core261.CARTESIAN_POSITION.BOTTOM
|
|
},
|
|
y: {
|
|
type: import_ag_charts_core261.CARTESIAN_AXIS_TYPE.NUMBER,
|
|
position: import_ag_charts_core261.CARTESIAN_POSITION.LEFT
|
|
}
|
|
},
|
|
axisKeys: { [import_ag_charts_core261.ChartAxisDirection.X]: "xKeyAxis", [import_ag_charts_core261.ChartAxisDirection.Y]: "yKeyAxis" },
|
|
themeTemplate: themeTemplate4,
|
|
create: (ctx) => new HistogramSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineSeriesModule.ts
|
|
var import_ag_charts_core265 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineSeries.ts
|
|
var import_ag_charts_core264 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineAggregation.ts
|
|
var import_ag_charts_core262 = require("ag-charts-core");
|
|
var MAX_POINTS2 = 10;
|
|
function isIndexInAggregation(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf, xValuesLength) {
|
|
const xValue = xValues[datumIndex];
|
|
if (xValue === void 0)
|
|
return false;
|
|
const xRatio = Number.isFinite(d0) ? (0, import_ag_charts_core262.aggregationXRatioForXValue)(xValue, d0, d1, xNeedsValueOf) : (0, import_ag_charts_core262.aggregationXRatioForDatumIndex)(datumIndex, xValuesLength);
|
|
const aggIndex = (0, import_ag_charts_core262.aggregationIndexForXRatio)(xRatio, maxRange);
|
|
return datumIndex === indexData[aggIndex + import_ag_charts_core262.AGGREGATION_INDEX_X_MIN] || datumIndex === indexData[aggIndex + import_ag_charts_core262.AGGREGATION_INDEX_X_MAX] || datumIndex === indexData[aggIndex + import_ag_charts_core262.AGGREGATION_INDEX_Y_MIN] || datumIndex === indexData[aggIndex + import_ag_charts_core262.AGGREGATION_INDEX_Y_MAX];
|
|
}
|
|
function buildIndicesFromAggregation2(xValues, d0, d1, indexData, maxRange, xNeedsValueOf, xValuesLength, reuseArray) {
|
|
let count = 0;
|
|
for (let datumIndex = 0; datumIndex < xValuesLength; datumIndex++) {
|
|
if (isIndexInAggregation(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf, xValuesLength)) {
|
|
count++;
|
|
}
|
|
}
|
|
const indices = reuseArray?.length === count ? reuseArray : new Uint32Array(count);
|
|
let idx = 0;
|
|
for (let datumIndex = 0; datumIndex < xValuesLength; datumIndex++) {
|
|
if (isIndexInAggregation(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf, xValuesLength)) {
|
|
indices[idx++] = datumIndex;
|
|
}
|
|
}
|
|
return indices;
|
|
}
|
|
function filterIndicesFromPrevious(prevIndices, xValues, d0, d1, indexData, maxRange, xNeedsValueOf, xValuesLength, reuseArray) {
|
|
let count = 0;
|
|
for (const datumIndex of prevIndices) {
|
|
if (isIndexInAggregation(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf, xValuesLength)) {
|
|
count++;
|
|
}
|
|
}
|
|
const indices = reuseArray?.length === count ? reuseArray : new Uint32Array(count);
|
|
let idx = 0;
|
|
for (const datumIndex of prevIndices) {
|
|
if (isIndexInAggregation(xValues, d0, d1, indexData, maxRange, datumIndex, xNeedsValueOf, xValuesLength)) {
|
|
indices[idx++] = datumIndex;
|
|
}
|
|
}
|
|
return indices;
|
|
}
|
|
function computeLineAggregation(domain, xValues, yValues, options) {
|
|
const xValuesLength = xValues.length;
|
|
if (xValuesLength < import_ag_charts_core262.AGGREGATION_THRESHOLD)
|
|
return;
|
|
const [d0, d1] = domain;
|
|
const { xNeedsValueOf, yNeedsValueOf, existingFilters } = options;
|
|
let maxRange = (0, import_ag_charts_core262.aggregationRangeFittingPoints)(xValues, d0, d1, { xNeedsValueOf });
|
|
const existingFilter = existingFilters?.find((f) => f.maxRange === maxRange);
|
|
let { indexData, valueData } = (0, import_ag_charts_core262.createAggregationIndices)(xValues, yValues, yValues, d0, d1, maxRange, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
reuseIndexData: existingFilter?.indexData,
|
|
reuseValueData: existingFilter?.valueData
|
|
});
|
|
let indices = buildIndicesFromAggregation2(
|
|
xValues,
|
|
d0,
|
|
d1,
|
|
indexData,
|
|
maxRange,
|
|
xNeedsValueOf,
|
|
xValuesLength,
|
|
existingFilter?.indices
|
|
);
|
|
const filters = [{ maxRange, indices, indexData, valueData }];
|
|
while (indices.length > MAX_POINTS2 && maxRange > 64) {
|
|
const currentMaxRange = maxRange;
|
|
const nextMaxRange = Math.trunc(currentMaxRange / 2);
|
|
const nextExistingFilter = existingFilters?.find((f) => f.maxRange === nextMaxRange);
|
|
const compacted = (0, import_ag_charts_core262.compactAggregationIndices)(indexData, valueData, currentMaxRange, {
|
|
reuseIndexData: nextExistingFilter?.indexData,
|
|
reuseValueData: nextExistingFilter?.valueData
|
|
});
|
|
maxRange = compacted.maxRange;
|
|
indexData = compacted.indexData;
|
|
valueData = compacted.valueData;
|
|
indices = filterIndicesFromPrevious(
|
|
indices,
|
|
xValues,
|
|
d0,
|
|
d1,
|
|
indexData,
|
|
maxRange,
|
|
xNeedsValueOf,
|
|
xValuesLength,
|
|
nextExistingFilter?.indices
|
|
);
|
|
filters.push({ maxRange, indices, indexData, valueData });
|
|
}
|
|
filters.reverse();
|
|
return filters;
|
|
}
|
|
function computeLineAggregationPartial(domain, xValues, yValues, options) {
|
|
const xValuesLength = xValues.length;
|
|
if (xValuesLength < import_ag_charts_core262.AGGREGATION_THRESHOLD)
|
|
return;
|
|
const [d0, d1] = domain;
|
|
const { xNeedsValueOf, yNeedsValueOf, targetRange, existingFilters } = options;
|
|
const finestMaxRange = (0, import_ag_charts_core262.aggregationRangeFittingPoints)(xValues, d0, d1, { xNeedsValueOf });
|
|
const targetMaxRange = Math.min(finestMaxRange, (0, import_ag_charts_core262.nextPowerOf2)(Math.max(targetRange, import_ag_charts_core262.AGGREGATION_MIN_RANGE)));
|
|
const existingFilter = existingFilters?.find((f) => f.maxRange === targetMaxRange);
|
|
const { indexData, valueData } = (0, import_ag_charts_core262.createAggregationIndices)(xValues, yValues, yValues, d0, d1, targetMaxRange, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
reuseIndexData: existingFilter?.indexData,
|
|
reuseValueData: existingFilter?.valueData
|
|
});
|
|
const indices = buildIndicesFromAggregation2(
|
|
xValues,
|
|
d0,
|
|
d1,
|
|
indexData,
|
|
targetMaxRange,
|
|
xNeedsValueOf,
|
|
xValuesLength,
|
|
existingFilter?.indices
|
|
);
|
|
const immediateLevel = {
|
|
maxRange: targetMaxRange,
|
|
indices,
|
|
indexData,
|
|
valueData
|
|
};
|
|
function computeRemaining() {
|
|
const allLevels = computeLineAggregation([d0, d1], xValues, yValues, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
return allLevels?.filter((level) => level.maxRange !== targetMaxRange) ?? [];
|
|
}
|
|
return { immediate: [immediateLevel], computeRemaining };
|
|
}
|
|
function aggregateLineData(scale2, xValues, yValues, domainInput, xNeedsValueOf, yNeedsValueOf) {
|
|
const [d0, d1] = (0, import_ag_charts_core262.aggregationDomain)(scale2, domainInput);
|
|
return computeLineAggregation([d0, d1], xValues, yValues, { xNeedsValueOf, yNeedsValueOf });
|
|
}
|
|
var memoizedAggregateLineData = (0, import_ag_charts_core262.simpleMemorize2)(aggregateLineData);
|
|
function aggregateLineDataFromDataModel(scale2, dataModel, processedData, yKey, series, existingFilters) {
|
|
const xValues = dataModel.resolveColumnById(series, "xValue", processedData);
|
|
const yValues = dataModel.resolveColumnById(series, yKey, processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "value", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, yKey, processedData);
|
|
if (existingFilters) {
|
|
const [d0, d1] = (0, import_ag_charts_core262.aggregationDomain)(scale2, domainInput);
|
|
return computeLineAggregation([d0, d1], xValues, yValues, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
existingFilters
|
|
});
|
|
}
|
|
return memoizedAggregateLineData(scale2, xValues, yValues, domainInput, xNeedsValueOf, yNeedsValueOf);
|
|
}
|
|
function aggregateLineDataFromDataModelPartial(scale2, dataModel, processedData, yKey, series, targetRange, existingFilters) {
|
|
const xValues = dataModel.resolveColumnById(series, "xValue", processedData);
|
|
const yValues = dataModel.resolveColumnById(series, yKey, processedData);
|
|
const domainInput = dataModel.getDomain(series, "xValue", "value", processedData);
|
|
const xNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, "xValue", processedData);
|
|
const yNeedsValueOf = dataModel.resolveColumnNeedsValueOf(series, yKey, processedData);
|
|
const [d0, d1] = (0, import_ag_charts_core262.aggregationDomain)(scale2, domainInput);
|
|
return computeLineAggregationPartial([d0, d1], xValues, yValues, {
|
|
xNeedsValueOf,
|
|
yNeedsValueOf,
|
|
targetRange,
|
|
existingFilters
|
|
});
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineSeriesProperties.ts
|
|
var import_ag_charts_core263 = require("ag-charts-core");
|
|
var LineSeriesProperties = class extends CartesianSeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.stroke = "#874349";
|
|
this.strokeWidth = 2;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.interpolation = new import_ag_charts_core263.InterpolationProperties();
|
|
this.marker = new SeriesMarker();
|
|
this.label = new Label();
|
|
this.tooltip = makeSeriesTooltip();
|
|
this.connectMissingData = false;
|
|
this.sparklineMode = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "xKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "yKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "xName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "yName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "yFilterKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "stackGroup", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "normalizedTo", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "title", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "stroke", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "interpolation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "styler", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "marker", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "label", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "tooltip", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "connectMissingData", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core263.Property
|
|
], LineSeriesProperties.prototype, "sparklineMode", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineSeries.ts
|
|
var CROSS_FILTER_LINE_STROKE_OPACITY_FACTOR = 0.25;
|
|
var LineSeries = class extends CartesianSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
propertyKeys: DEFAULT_CARTESIAN_DIRECTION_KEYS,
|
|
propertyNames: DEFAULT_CARTESIAN_DIRECTION_NAMES,
|
|
categoryKey: "xValue",
|
|
pickModes: [
|
|
2 /* AXIS_ALIGNED */,
|
|
1 /* NEAREST_NODE */,
|
|
0 /* EXACT_SHAPE_MATCH */
|
|
],
|
|
datumSelectionGarbageCollection: false,
|
|
segmentedDataNodes: false,
|
|
animationResetFns: {
|
|
path: buildResetPathFn({ getVisible: () => this.visible, getOpacity: () => this.getOpacity() }),
|
|
label: resetLabelFn,
|
|
datum: (node, datum) => ({ ...resetMarkerFn(node), ...resetMarkerPositionFn(node, datum) })
|
|
},
|
|
clipFocusBox: false
|
|
});
|
|
this.properties = new LineSeriesProperties();
|
|
this.aggregationManager = new AggregationManager();
|
|
}
|
|
get pickModeAxis() {
|
|
return this.properties.sparklineMode ? "main" : "main-category";
|
|
}
|
|
isNormalized() {
|
|
return this.properties.normalizedTo != null;
|
|
}
|
|
renderToOffscreenCanvas() {
|
|
const hasMarkers = (this.contextNodeData?.nodeData?.length ?? 0) > 0;
|
|
return hasMarkers && this.getDrawingMode(false) === "cutout" || super.renderToOffscreenCanvas();
|
|
}
|
|
async processData(dataController) {
|
|
if (this.data == null)
|
|
return;
|
|
const { data, visible, seriesGrouping: { groupIndex = this.id, stackCount = 0 } = {} } = this;
|
|
const { xKey, yKey, yFilterKey, connectMissingData, normalizedTo } = this.properties;
|
|
const xScale = this.axes[import_ag_charts_core264.ChartAxisDirection.X]?.scale;
|
|
const yScale = this.axes[import_ag_charts_core264.ChartAxisDirection.Y]?.scale;
|
|
const { isContinuousX, xScaleType, yScaleType } = this.getScaleInformation({ xScale, yScale });
|
|
const stacked = stackCount > 1 || normalizedTo != null;
|
|
const common = { invalidValue: null };
|
|
if (connectMissingData && stacked) {
|
|
common.invalidValue = 0;
|
|
}
|
|
if (stacked && !visible) {
|
|
common.forceValue = 0;
|
|
}
|
|
const idMap = {
|
|
value: `area-stack-${groupIndex}-yValue`,
|
|
marker: `area-stack-${groupIndex}-yValues-marker`
|
|
};
|
|
const props = [];
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
if (!isContinuousX || stacked) {
|
|
props.push(keyProperty(xKey, xScaleType, { id: "xKey", allowNullKey }));
|
|
}
|
|
props.push(
|
|
valueProperty(xKey, xScaleType, { id: "xValue", allowNullKey }),
|
|
valueProperty(yKey, yScaleType, {
|
|
id: `yValueRaw`,
|
|
...common,
|
|
invalidValue: void 0
|
|
})
|
|
);
|
|
if (yFilterKey != null) {
|
|
props.push(valueProperty(yFilterKey, yScaleType, { id: "yFilterRaw" }));
|
|
}
|
|
if (stacked) {
|
|
props.push(
|
|
...groupAccumulativeValueProperty(
|
|
yKey,
|
|
"normal",
|
|
{ id: `yValueCumulative`, ...common, groupId: idMap.marker },
|
|
yScaleType
|
|
)
|
|
);
|
|
}
|
|
if ((0, import_ag_charts_core264.isDefined)(normalizedTo)) {
|
|
props.push(
|
|
valueProperty(yKey, yScaleType, { id: `yValue`, ...common, groupId: idMap.value }),
|
|
normaliseGroupTo(Object.values(idMap), normalizedTo)
|
|
);
|
|
}
|
|
if (this.needsDataModelDiff()) {
|
|
props.push(animationValidation(isContinuousX ? ["xValue"] : void 0));
|
|
if (this.processedData) {
|
|
props.push(diff(this.id, this.processedData));
|
|
}
|
|
}
|
|
const { dataModel, processedData } = await this.requestDataModel(dataController, data, {
|
|
props,
|
|
groupByKeys: stacked,
|
|
groupByData: !stacked
|
|
});
|
|
this.aggregateData(dataModel, processedData);
|
|
this.animationState.transition("updateData");
|
|
}
|
|
yValueKey() {
|
|
return this.isNormalized() ? "yValue" : "yValueRaw";
|
|
}
|
|
yCumulativeKey(processData) {
|
|
return processData.type === "grouped" ? "yValueCumulative" : this.yValueKey();
|
|
}
|
|
xCoordinateRange(xValue, pixelSize) {
|
|
const { marker } = this.properties;
|
|
const x = this.axes[import_ag_charts_core264.ChartAxisDirection.X].scale.convert(xValue);
|
|
const r = marker.enabled ? 0.5 * marker.size * pixelSize : 0;
|
|
return [x - r, x + r];
|
|
}
|
|
yCoordinateRange(yValues, pixelSize) {
|
|
const { marker } = this.properties;
|
|
const y = this.axes[import_ag_charts_core264.ChartAxisDirection.Y].scale.convert(yValues[0]);
|
|
const r = marker.enabled ? 0.5 * marker.size * pixelSize : 0;
|
|
return [y - r, y + r];
|
|
}
|
|
getSeriesDomain(direction) {
|
|
const { dataModel, processedData, axes } = this;
|
|
if (!dataModel || !processedData)
|
|
return { domain: [] };
|
|
const yAxis = axes[import_ag_charts_core264.ChartAxisDirection.Y];
|
|
if (direction === import_ag_charts_core264.ChartAxisDirection.X) {
|
|
const xDef = dataModel.resolveProcessedDataDefById(this, `xValue`);
|
|
const xDomain = dataModel.getDomain(this, `xValue`, "value", processedData);
|
|
if (xDef?.def.type === "value" && xDef.def.valueType === "category") {
|
|
const sortMetadata = dataModel.getKeySortMetadata(this, "xValue", processedData);
|
|
return { domain: xDomain.domain, sortMetadata };
|
|
}
|
|
return { domain: fixNumericExtent((0, import_ag_charts_core264.extent)(xDomain.domain)) };
|
|
}
|
|
const yExtent = this.domainForClippedRange(
|
|
import_ag_charts_core264.ChartAxisDirection.Y,
|
|
[this.yCumulativeKey(processedData)],
|
|
"xValue"
|
|
);
|
|
if (this.isNormalized() && yAxis instanceof NumberAxis && !(yAxis instanceof LogAxis)) {
|
|
const fixedYExtent = Number.isFinite(yExtent[1] - yExtent[0]) ? [Math.min(yExtent[0], 0), Math.max(yExtent[1], 0)] : [];
|
|
return { domain: fixNumericExtent(fixedYExtent) };
|
|
} else {
|
|
return { domain: fixNumericExtent(yExtent) };
|
|
}
|
|
}
|
|
getSeriesRange(_direction, visibleRange) {
|
|
return this.domainForVisibleRange(
|
|
import_ag_charts_core264.ChartAxisDirection.Y,
|
|
[this.yCumulativeKey(this.processedData)],
|
|
"xValue",
|
|
visibleRange
|
|
);
|
|
}
|
|
getZoomRangeFittingItems(xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
return this.zoomFittingVisibleItems(
|
|
"xValue",
|
|
[this.yCumulativeKey(this.processedData)],
|
|
xVisibleRange,
|
|
yVisibleRange,
|
|
minVisibleItems
|
|
);
|
|
}
|
|
getVisibleItems(xVisibleRange, yVisibleRange, minVisibleItems) {
|
|
return this.countVisibleItems(
|
|
"xValue",
|
|
[this.yCumulativeKey(this.processedData)],
|
|
xVisibleRange,
|
|
yVisibleRange,
|
|
minVisibleItems
|
|
);
|
|
}
|
|
aggregateData(dataModel, processedData) {
|
|
this.aggregationManager.markStale(processedData.input.count);
|
|
if (processedData.type !== "ungrouped")
|
|
return;
|
|
if (processedDataIsAnimatable(processedData))
|
|
return;
|
|
const xAxis = this.axes[import_ag_charts_core264.ChartAxisDirection.X];
|
|
if (xAxis == null)
|
|
return;
|
|
const targetRange = this.estimateTargetRange();
|
|
this.aggregationManager.aggregate({
|
|
computePartial: (existingFilters) => aggregateLineDataFromDataModelPartial(
|
|
xAxis.scale.type,
|
|
dataModel,
|
|
processedData,
|
|
this.yCumulativeKey(processedData),
|
|
this,
|
|
targetRange,
|
|
existingFilters
|
|
),
|
|
computeFull: (existingFilters) => aggregateLineDataFromDataModel(
|
|
xAxis.scale.type,
|
|
dataModel,
|
|
processedData,
|
|
this.yCumulativeKey(processedData),
|
|
this,
|
|
existingFilters
|
|
),
|
|
targetRange
|
|
});
|
|
const filters = this.aggregationManager.filters;
|
|
if (filters && filters.length > 0) {
|
|
import_ag_charts_core264.DebugMetrics.record(
|
|
`${this.type}:aggregation`,
|
|
filters.map((f) => f.maxRange)
|
|
);
|
|
}
|
|
}
|
|
estimateTargetRange() {
|
|
const xAxis = this.axes[import_ag_charts_core264.ChartAxisDirection.X];
|
|
if (xAxis?.scale?.range) {
|
|
const [r0, r1] = xAxis.scale.range;
|
|
return Math.abs(r1 - r0);
|
|
}
|
|
return this.ctx.scene?.canvas?.width ?? 800;
|
|
}
|
|
/**
|
|
* Creates the context object for efficient node datum creation.
|
|
* Caches expensive-to-compute values that are reused across all datum iterations
|
|
* to minimize memory allocations. Only caches values that are expensive to
|
|
* compute - cheap property lookups use `this` directly.
|
|
*/
|
|
createNodeDatumContext(xAxis, yAxis) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData)
|
|
return void 0;
|
|
const xScale = xAxis.scale;
|
|
const yScale = yAxis.scale;
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
const [r0, r1] = xScale.range;
|
|
const range4 = Math.abs(r1 - r0);
|
|
this.aggregationManager.ensureLevelForRange(range4);
|
|
const dataAggregationFilter = this.aggregationManager.getFilterForRange(range4);
|
|
const canIncrementallyUpdate = this.canIncrementallyUpdateNodes(dataAggregationFilter != null);
|
|
return {
|
|
xAxis,
|
|
yAxis,
|
|
rawData,
|
|
xValues: dataModel.resolveColumnById(this, "xValue", processedData),
|
|
yRawValues: dataModel.resolveColumnById(this, "yValueRaw", processedData),
|
|
yCumulativeValues: dataModel.resolveColumnById(this, this.yCumulativeKey(processedData), processedData),
|
|
selectionValues: this.properties.yFilterKey ? dataModel.resolveColumnById(this, "yFilterRaw", processedData) : void 0,
|
|
xScale,
|
|
yScale,
|
|
xOffset: (xScale.bandwidth ?? 0) / 2,
|
|
yOffset: (yScale.bandwidth ?? 0) / 2,
|
|
size: this.properties.marker.enabled ? this.properties.marker.size : 0,
|
|
yDomain: this.getSeriesDomain(import_ag_charts_core264.ChartAxisDirection.Y).domain,
|
|
labelsEnabled: this.properties.label.enabled,
|
|
animationEnabled: !this.ctx.animationManager.isSkipped(),
|
|
canIncrementallyUpdate,
|
|
dataAggregationFilter,
|
|
range: range4,
|
|
xKey: this.properties.xKey,
|
|
yKey: this.properties.yKey,
|
|
xName: this.properties.xName,
|
|
yName: this.properties.yName,
|
|
legendItemName: this.properties.legendItemName,
|
|
connectMissingData: this.properties.connectMissingData,
|
|
capDefaults: {
|
|
lengthRatioMultiplier: this.properties.marker.getDiameter(),
|
|
lengthMax: Infinity
|
|
},
|
|
nodes: canIncrementallyUpdate ? this.contextNodeData.nodeData : [],
|
|
spanPoints: [],
|
|
nodeIndex: 0
|
|
};
|
|
}
|
|
/**
|
|
* Processes a single datum and updates the context's nodes and spanPoints arrays.
|
|
* Uses the scratch object to avoid per-iteration allocations.
|
|
*/
|
|
handleDatum(ctx, scratch, datumIndex) {
|
|
scratch.datum = ctx.rawData[datumIndex];
|
|
scratch.xDatum = ctx.xValues[datumIndex];
|
|
scratch.yDatum = ctx.yRawValues[datumIndex];
|
|
scratch.yCumulative = ctx.yCumulativeValues[datumIndex];
|
|
scratch.selected = ctx.selectionValues?.[datumIndex];
|
|
scratch.x = ctx.xScale.convert(scratch.xDatum) + ctx.xOffset;
|
|
scratch.y = ctx.yScale.convert(scratch.yCumulative) + ctx.yOffset;
|
|
if (!Number.isFinite(scratch.x))
|
|
return;
|
|
if (scratch.yDatum != null) {
|
|
const labelText = ctx.labelsEnabled ? this.getLabelText(
|
|
scratch.yDatum,
|
|
scratch.datum,
|
|
ctx.yKey,
|
|
"y",
|
|
ctx.yDomain,
|
|
this.properties.label,
|
|
{
|
|
value: scratch.yDatum,
|
|
datum: scratch.datum,
|
|
xKey: ctx.xKey,
|
|
yKey: ctx.yKey,
|
|
xName: ctx.xName,
|
|
yName: ctx.yName,
|
|
legendItemName: ctx.legendItemName
|
|
}
|
|
) : void 0;
|
|
const canReuseNode = ctx.canIncrementallyUpdate && ctx.nodeIndex < ctx.nodes.length;
|
|
if (canReuseNode) {
|
|
const existingNode = ctx.nodes[ctx.nodeIndex];
|
|
existingNode.datum = scratch.datum;
|
|
existingNode.datumIndex = datumIndex;
|
|
existingNode.point = { x: scratch.x, y: scratch.y, size: ctx.size };
|
|
existingNode.midPoint = { x: scratch.x, y: scratch.y };
|
|
existingNode.cumulativeValue = scratch.yCumulative;
|
|
existingNode.yValue = scratch.yDatum;
|
|
existingNode.xValue = scratch.xDatum;
|
|
existingNode.labelText = labelText;
|
|
existingNode.selected = scratch.selected;
|
|
} else {
|
|
ctx.nodes.push({
|
|
series: this,
|
|
datum: scratch.datum,
|
|
datumIndex,
|
|
yKey: ctx.yKey,
|
|
xKey: ctx.xKey,
|
|
point: { x: scratch.x, y: scratch.y, size: ctx.size },
|
|
midPoint: { x: scratch.x, y: scratch.y },
|
|
cumulativeValue: scratch.yCumulative,
|
|
yValue: scratch.yDatum,
|
|
xValue: scratch.xDatum,
|
|
capDefaults: ctx.capDefaults,
|
|
labelText,
|
|
selected: scratch.selected
|
|
});
|
|
}
|
|
ctx.nodeIndex++;
|
|
}
|
|
this.updateSpanPoints(ctx, scratch);
|
|
}
|
|
/**
|
|
* Updates span points array based on current scratch values.
|
|
*/
|
|
updateSpanPoints(ctx, scratch) {
|
|
const currentSpanPoints = ctx.spanPoints.at(-1);
|
|
if (scratch.yDatum != null) {
|
|
const spanPoint = {
|
|
point: { x: scratch.x, y: scratch.y },
|
|
xDatum: scratch.xDatum,
|
|
yDatum: scratch.yCumulative
|
|
};
|
|
if (Array.isArray(currentSpanPoints)) {
|
|
currentSpanPoints.push(spanPoint);
|
|
} else if (currentSpanPoints == null) {
|
|
ctx.spanPoints.push([spanPoint]);
|
|
} else {
|
|
currentSpanPoints.skip += 1;
|
|
ctx.spanPoints.push([spanPoint]);
|
|
}
|
|
} else if (!ctx.connectMissingData) {
|
|
if (Array.isArray(currentSpanPoints) || currentSpanPoints == null) {
|
|
ctx.spanPoints.push({ skip: 0 });
|
|
} else {
|
|
currentSpanPoints.skip += 1;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Populates node data by iterating over the visible range.
|
|
*/
|
|
populateNodeData(ctx) {
|
|
const scratch = {
|
|
datum: void 0,
|
|
xDatum: void 0,
|
|
yDatum: void 0,
|
|
yCumulative: 0,
|
|
selected: void 0,
|
|
x: 0,
|
|
y: 0
|
|
};
|
|
const indices = ctx.dataAggregationFilter?.indices;
|
|
let [start, end2] = this.visibleRangeIndices("xValue", ctx.xAxis.range, indices);
|
|
start = Math.max(start - 1, 0);
|
|
end2 = Math.min(end2 + 1, indices?.length ?? ctx.xValues.length);
|
|
if (this.processedData.input.count < 1e3) {
|
|
start = 0;
|
|
end2 = this.processedData.input.count;
|
|
}
|
|
for (let i = start; i < end2; i += 1) {
|
|
this.handleDatum(ctx, scratch, indices?.[i] ?? i);
|
|
}
|
|
}
|
|
/**
|
|
* Creates the initial result context object.
|
|
* Note: strokeData and segments are computed in assembleResult, but we need valid defaults
|
|
* for the early return case (when !this.visible).
|
|
*/
|
|
initializeResult(ctx) {
|
|
return {
|
|
itemId: ctx.yKey,
|
|
nodeData: ctx.nodes,
|
|
labelData: ctx.nodes,
|
|
strokeData: { itemId: ctx.yKey, spans: [] },
|
|
// Default for early return
|
|
scales: this.calculateScaling(),
|
|
visible: this.visible,
|
|
crossFiltering: false,
|
|
styles: getMarkerStyles(this, this.properties, this.properties.marker),
|
|
segments: void 0
|
|
};
|
|
}
|
|
/**
|
|
* Assembles the final result by computing strokeData, crossFiltering, and segments.
|
|
*/
|
|
assembleResult(ctx, result) {
|
|
const strokeSpans = ctx.spanPoints.flatMap((p) => {
|
|
return Array.isArray(p) ? interpolatePoints(p, this.properties.interpolation) : [];
|
|
});
|
|
result.strokeData = { itemId: ctx.yKey, spans: strokeSpans };
|
|
result.crossFiltering = ctx.selectionValues?.some((selectionValue, index) => selectionValue === ctx.yRawValues[index]) ?? false;
|
|
result.segments = calculateSegments(
|
|
this.properties.segmentation,
|
|
ctx.xAxis,
|
|
ctx.yAxis,
|
|
this.chart.seriesRect,
|
|
this.ctx.scene,
|
|
false
|
|
);
|
|
return result;
|
|
}
|
|
isPathOrSelectionDirty() {
|
|
return this.properties.marker.isDirty();
|
|
}
|
|
updatePathNodes(opts) {
|
|
const {
|
|
paths: [lineNode],
|
|
visible,
|
|
animationEnabled
|
|
} = opts;
|
|
const crossFiltering = this.contextNodeData?.crossFiltering === true;
|
|
const merged = (0, import_ag_charts_core264.mergeDefaults)(this.getHighlightStyle(), this.getStyle());
|
|
const { strokeWidth, stroke, strokeOpacity, lineDash, lineDashOffset, opacity } = merged;
|
|
const segments = this.contextNodeData?.segments;
|
|
lineNode.setProperties({
|
|
segments,
|
|
fill: void 0,
|
|
lineJoin: "round",
|
|
pointerEvents: 1 /* None */,
|
|
opacity,
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity: strokeOpacity * (crossFiltering ? CROSS_FILTER_LINE_STROKE_OPACITY_FACTOR : 1),
|
|
lineDash,
|
|
lineDashOffset
|
|
});
|
|
lineNode.datum = segments;
|
|
if (!animationEnabled) {
|
|
lineNode.visible = visible;
|
|
}
|
|
updateClipPath(this, lineNode);
|
|
}
|
|
updateDatumSelection(opts) {
|
|
let { nodeData } = opts;
|
|
const { datumSelection } = opts;
|
|
const { contextNodeData, processedData, axes, properties } = this;
|
|
const { marker } = properties;
|
|
const markersEnabled = contextNodeData?.crossFiltering === true || markerEnabled(processedData.input.count, axes[import_ag_charts_core264.ChartAxisDirection.X].scale, marker);
|
|
nodeData = markersEnabled ? nodeData : [];
|
|
if (marker.isDirty()) {
|
|
datumSelection.clear();
|
|
datumSelection.cleanup();
|
|
}
|
|
if (!processedDataIsAnimatable(this.processedData)) {
|
|
return datumSelection.update(nodeData);
|
|
}
|
|
return datumSelection.update(nodeData, void 0, (datum) => createDatumId(datum.xValue));
|
|
}
|
|
updateDatumStyles(opts) {
|
|
const { datumSelection, isHighlight } = opts;
|
|
const { marker } = this.properties;
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
datumSelection.each((node, datum) => {
|
|
if (!datumSelection.isGarbage(node)) {
|
|
const highlightState = this.getHighlightState(highlightedDatum, opts.isHighlight, datum.datumIndex);
|
|
const stylerStyle = this.getStyle(highlightState);
|
|
const { stroke, strokeWidth, strokeOpacity } = stylerStyle;
|
|
const params = this.makeItemStylerParams(
|
|
this.dataModel,
|
|
this.processedData,
|
|
datum.datumIndex,
|
|
stylerStyle.marker
|
|
);
|
|
datum.style = this.getMarkerStyle(
|
|
marker,
|
|
datum,
|
|
params,
|
|
{ isHighlight, highlightState },
|
|
stylerStyle.marker,
|
|
{
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity
|
|
}
|
|
);
|
|
}
|
|
});
|
|
}
|
|
updateDatumNodes(opts) {
|
|
const { contextNodeData } = this;
|
|
if (!contextNodeData) {
|
|
return;
|
|
}
|
|
const { datumSelection, isHighlight } = opts;
|
|
const applyTranslation = this.ctx.animationManager.isSkipped();
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const drawingMode = this.getDrawingMode(isHighlight, opts.drawingMode);
|
|
datumSelection.each((node, datum) => {
|
|
const state = this.getHighlightState(highlightedDatum, isHighlight, datum.datumIndex);
|
|
const style = datum.style ?? contextNodeData.styles[state];
|
|
this.applyMarkerStyle(style, node, datum.point, fillBBox, {
|
|
applyTranslation,
|
|
selected: datum.selected
|
|
});
|
|
node.drawingMode = this.resolveMarkerDrawingModeForState(drawingMode, style);
|
|
});
|
|
if (!isHighlight) {
|
|
this.properties.marker.markClean();
|
|
}
|
|
}
|
|
updateLabelSelection(opts) {
|
|
return opts.labelSelection.update(this.isLabelEnabled() ? opts.labelData : []);
|
|
}
|
|
updateLabelNodes(opts) {
|
|
const { isHighlight = false } = opts;
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
const params = this.makeLabelFormatterParams();
|
|
opts.labelSelection.each((text, datum) => {
|
|
const style = getLabelStyles(this, datum, params, this.properties.label, isHighlight, activeHighlight);
|
|
const { enabled, fontStyle, fontWeight: fontWeight2, fontSize, fontFamily, color: color8 } = style;
|
|
if (enabled && datum?.labelText) {
|
|
text.fontStyle = fontStyle;
|
|
text.fontWeight = fontWeight2;
|
|
text.fontSize = fontSize;
|
|
text.fontFamily = fontFamily;
|
|
text.textAlign = "center";
|
|
text.textBaseline = "bottom";
|
|
text.text = datum.labelText;
|
|
text.x = datum.point.x;
|
|
text.y = datum.point.y - 10;
|
|
text.fill = color8;
|
|
text.visible = true;
|
|
text.fillOpacity = this.getHighlightStyle(isHighlight, datum.datumIndex).opacity ?? 1;
|
|
text.setBoxing(style);
|
|
} else {
|
|
text.visible = false;
|
|
}
|
|
});
|
|
}
|
|
makeStylerParams(highlightStateEnum) {
|
|
const { id: seriesId } = this;
|
|
const { marker, lineDash, lineDashOffset, stroke, strokeOpacity, strokeWidth, xKey, yKey } = this.properties;
|
|
const highlightState = toHighlightString(highlightStateEnum ?? 0 /* None */);
|
|
return {
|
|
marker: {
|
|
fill: marker.fill,
|
|
fillOpacity: marker.fillOpacity,
|
|
size: marker.size,
|
|
shape: marker.shape,
|
|
stroke: marker.stroke,
|
|
strokeOpacity: marker.strokeOpacity,
|
|
strokeWidth: marker.strokeWidth,
|
|
lineDash: marker.lineDash,
|
|
lineDashOffset: marker.lineDashOffset
|
|
},
|
|
highlightState,
|
|
lineDash,
|
|
lineDashOffset,
|
|
seriesId,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
xKey,
|
|
yKey
|
|
};
|
|
}
|
|
makeItemStylerParams(dataModel, processedData, datumIndex, style) {
|
|
const { xKey, yKey } = this.properties;
|
|
const xValue = dataModel.resolveColumnById(this, `xValue`, processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValueRaw`, processedData)[datumIndex];
|
|
const xDomain = dataModel.getDomain(this, `xValue`, "key", processedData).domain;
|
|
const yDomain = dataModel.getDomain(this, this.yCumulativeKey(processedData), "value", processedData).domain;
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
...datumStylerProperties(xValue, yValue, xKey, yKey, xDomain, yDomain),
|
|
xValue,
|
|
yValue,
|
|
...style,
|
|
fill
|
|
};
|
|
}
|
|
makeLabelFormatterParams() {
|
|
const { xKey, xName, yKey, yName, legendItemName } = this.properties;
|
|
return { xKey, xName, yKey, yName, legendItemName };
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const { id: seriesId, dataModel, processedData, axes, properties } = this;
|
|
const { xKey, xName, yKey, yName, tooltip, legendItemName } = properties;
|
|
const allowNullKeys = properties.allowNullKeys ?? false;
|
|
const xAxis = axes[import_ag_charts_core264.ChartAxisDirection.X];
|
|
const yAxis = axes[import_ag_charts_core264.ChartAxisDirection.Y];
|
|
if (!dataModel || !processedData || !xAxis || !yAxis)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data?.[datumIndex];
|
|
const xValue = dataModel.resolveColumnById(this, `xValue`, processedData)[datumIndex];
|
|
const yValue = dataModel.resolveColumnById(this, `yValueRaw`, processedData)[datumIndex];
|
|
if (xValue === void 0 && !allowNullKeys)
|
|
return;
|
|
const stylerStyle = this.getStyle();
|
|
const params = this.makeItemStylerParams(dataModel, processedData, datumIndex, stylerStyle.marker);
|
|
const format = this.getMarkerStyle(
|
|
this.properties.marker,
|
|
{ datumIndex, datum },
|
|
params,
|
|
{ isHighlight: false },
|
|
stylerStyle.marker
|
|
);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
heading: this.getAxisValueText(xAxis, "tooltip", xValue, datum, xKey, legendItemName, allowNullKeys),
|
|
symbol: this.legendItemSymbol(),
|
|
data: [
|
|
{
|
|
label: yName,
|
|
fallbackLabel: yKey,
|
|
value: this.getAxisValueText(yAxis, "tooltip", yValue, datum, yKey, legendItemName),
|
|
missing: isTooltipValueMissing(yValue)
|
|
}
|
|
]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: yName,
|
|
xKey,
|
|
xName,
|
|
yKey,
|
|
yName,
|
|
...format,
|
|
...this.getModuleTooltipParams()
|
|
}
|
|
);
|
|
}
|
|
legendItemSymbol() {
|
|
const { stroke, strokeOpacity, strokeWidth, lineDash, marker } = this.getStyle();
|
|
const markerStyle = this.getMarkerStyle(
|
|
this.properties.marker,
|
|
{},
|
|
void 0,
|
|
{
|
|
isHighlight: false,
|
|
checkForHighlight: false
|
|
},
|
|
{
|
|
size: marker.size,
|
|
shape: marker.shape,
|
|
fill: marker.fill,
|
|
fillOpacity: marker.fillOpacity,
|
|
stroke: marker.stroke,
|
|
strokeOpacity: marker.strokeOpacity,
|
|
strokeWidth: marker.strokeWidth,
|
|
lineDash: marker.lineDash,
|
|
lineDashOffset: marker.lineDashOffset
|
|
}
|
|
);
|
|
return {
|
|
marker: {
|
|
...markerStyle,
|
|
enabled: this.properties.marker.enabled
|
|
},
|
|
line: {
|
|
enabled: true,
|
|
stroke,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
if (legendType !== "category") {
|
|
return [];
|
|
}
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
const { yKey: itemId, yName, title, legendItemName, showInLegend } = this.properties;
|
|
return [
|
|
{
|
|
legendType,
|
|
id: seriesId,
|
|
itemId,
|
|
legendItemName,
|
|
seriesId,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId }),
|
|
label: {
|
|
text: legendItemName ?? title ?? yName ?? itemId
|
|
},
|
|
symbol: this.legendItemSymbol(),
|
|
hideInLegend: !showInLegend
|
|
}
|
|
];
|
|
}
|
|
updatePaths(opts) {
|
|
this.updateLinePaths(opts.paths, opts.contextData);
|
|
}
|
|
updateLinePaths(paths, contextData) {
|
|
const spans = contextData.strokeData.spans;
|
|
const [lineNode] = paths;
|
|
lineNode.path.clear();
|
|
plotLinePathStroke(lineNode, spans);
|
|
lineNode.markDirty("LineSeries");
|
|
}
|
|
resetDatumAnimation(data) {
|
|
resetMarkerSelectionsDirect([data.datumSelection]);
|
|
}
|
|
animateEmptyUpdateReady(animationData) {
|
|
const { datumSelection, labelSelection, annotationSelections, contextData, paths } = animationData;
|
|
const { animationManager } = this.ctx;
|
|
this.updateLinePaths(paths, contextData);
|
|
pathSwipeInAnimation(this, animationManager, ...paths);
|
|
resetMotion([datumSelection], resetMarkerPositionFn);
|
|
markerSwipeScaleInAnimation(
|
|
this,
|
|
animationManager,
|
|
{ ...this.getAnimationDrawingModes(), phase: "initial" },
|
|
datumSelection
|
|
);
|
|
seriesLabelFadeInAnimation(this, "labels", animationManager, labelSelection);
|
|
seriesLabelFadeInAnimation(this, "annotations", animationManager, ...annotationSelections);
|
|
}
|
|
animateReadyResize(animationData) {
|
|
const { contextData, paths } = animationData;
|
|
this.updateLinePaths(paths, contextData);
|
|
super.animateReadyResize(animationData);
|
|
}
|
|
animateWaitingUpdateReady(animationData) {
|
|
const { animationManager } = this.ctx;
|
|
const {
|
|
datumSelection,
|
|
labelSelection: labelSelections,
|
|
annotationSelections,
|
|
contextData,
|
|
paths,
|
|
previousContextData
|
|
} = animationData;
|
|
const [path] = paths;
|
|
if (contextData.visible === false && previousContextData?.visible === false)
|
|
return;
|
|
this.resetDatumAnimation(animationData);
|
|
this.resetLabelAnimation(animationData);
|
|
const update = () => {
|
|
this.resetPathAnimation(animationData);
|
|
this.updateLinePaths(paths, contextData);
|
|
};
|
|
const skip = () => {
|
|
animationManager.skipCurrentBatch();
|
|
update();
|
|
};
|
|
if (contextData == null || previousContextData == null) {
|
|
update();
|
|
markerFadeInAnimation(this, animationManager, "added", this.getAnimationDrawingModes(), datumSelection);
|
|
staticFromToMotion(
|
|
this.id,
|
|
"path_properties",
|
|
animationManager,
|
|
[path],
|
|
{ opacity: 0 },
|
|
{ opacity: this.getOpacity() },
|
|
{ phase: "add" }
|
|
);
|
|
seriesLabelFadeInAnimation(this, "labels", animationManager, labelSelections);
|
|
seriesLabelFadeInAnimation(this, "annotations", animationManager, ...annotationSelections);
|
|
return;
|
|
}
|
|
if (contextData.crossFiltering !== previousContextData.crossFiltering) {
|
|
skip();
|
|
return;
|
|
}
|
|
const fns = prepareLinePathAnimation(
|
|
contextData,
|
|
previousContextData,
|
|
this.processedData?.reduced?.diff?.[this.id],
|
|
this.getOpacity()
|
|
);
|
|
if (fns === void 0) {
|
|
skip();
|
|
return;
|
|
} else if (fns.status === "no-op") {
|
|
return;
|
|
}
|
|
fromToMotion(this.id, "path_properties", animationManager, [path], fns.stroke.pathProperties);
|
|
if (fns.status === "added") {
|
|
this.updateLinePaths(paths, contextData);
|
|
} else if (fns.status === "removed") {
|
|
this.updateLinePaths(paths, previousContextData);
|
|
} else {
|
|
pathMotion(this.id, "path_update", animationManager, [path], fns.stroke.path);
|
|
}
|
|
if (fns.hasMotion) {
|
|
markerFadeInAnimation(this, animationManager, void 0, this.getAnimationDrawingModes(), datumSelection);
|
|
seriesLabelFadeInAnimation(this, "labels", animationManager, labelSelections);
|
|
seriesLabelFadeInAnimation(this, "annotations", animationManager, ...annotationSelections);
|
|
}
|
|
this.ctx.animationManager.animate({
|
|
id: this.id,
|
|
groupId: "reset_after_animation",
|
|
phase: "trailing",
|
|
from: {},
|
|
to: {},
|
|
onComplete: () => this.updateLinePaths(paths, contextData)
|
|
});
|
|
}
|
|
isLabelEnabled() {
|
|
return this.properties.label.enabled;
|
|
}
|
|
getBandScalePadding() {
|
|
return { inner: 1, outer: 0.1 };
|
|
}
|
|
nodeFactory() {
|
|
return new Marker();
|
|
}
|
|
getStyle(highlightState) {
|
|
const { styler, marker, lineDash, lineDashOffset, stroke, strokeOpacity, strokeWidth } = this.properties;
|
|
const { size, shape, fill = "transparent", fillOpacity } = marker;
|
|
let stylerResult = {};
|
|
if (styler) {
|
|
const stylerParams = this.makeStylerParams(highlightState);
|
|
const cbResult = this.cachedCallWithContext(styler, stylerParams) ?? {};
|
|
const resolved = this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
cbResult,
|
|
{ pick: false }
|
|
);
|
|
stylerResult = resolved ?? {};
|
|
}
|
|
stylerResult.marker ?? (stylerResult.marker = {});
|
|
return {
|
|
lineDash: stylerResult.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.lineDashOffset ?? lineDashOffset,
|
|
stroke: stylerResult.stroke ?? stroke,
|
|
strokeOpacity: stylerResult.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.strokeWidth ?? strokeWidth,
|
|
marker: {
|
|
fill: stylerResult.marker.fill ?? fill,
|
|
fillOpacity: stylerResult.marker.fillOpacity ?? fillOpacity,
|
|
shape: stylerResult.marker.shape ?? shape,
|
|
size: stylerResult.marker.size ?? size,
|
|
lineDash: stylerResult.marker.lineDash ?? marker.lineDash ?? lineDash,
|
|
lineDashOffset: stylerResult.marker.lineDashOffset ?? marker.lineDashOffset ?? lineDashOffset,
|
|
stroke: stylerResult.marker.stroke ?? marker.stroke ?? stroke,
|
|
strokeOpacity: stylerResult.marker.strokeOpacity ?? marker.strokeOpacity ?? strokeOpacity,
|
|
strokeWidth: stylerResult.marker.strokeWidth ?? marker.strokeWidth ?? strokeWidth
|
|
}
|
|
};
|
|
}
|
|
getFormattedMarkerStyle(datum) {
|
|
const stylerStyle = this.getStyle();
|
|
const params = this.makeItemStylerParams(
|
|
this.dataModel,
|
|
this.processedData,
|
|
datum.datumIndex,
|
|
stylerStyle.marker
|
|
);
|
|
return this.getMarkerStyle(
|
|
this.properties.marker,
|
|
datum,
|
|
params,
|
|
{ isHighlight: true },
|
|
void 0,
|
|
stylerStyle
|
|
);
|
|
}
|
|
computeFocusBounds(opts) {
|
|
return computeMarkerFocusBounds(this, opts);
|
|
}
|
|
hasItemStylers() {
|
|
return this.properties.styler != null || this.properties.marker.itemStyler != null || this.properties.label.itemStyler != null;
|
|
}
|
|
};
|
|
LineSeries.className = "LineSeries";
|
|
LineSeries.type = "line";
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/lineSeriesModule.ts
|
|
var themeTemplate5 = {
|
|
series: {
|
|
stroke: import_ag_charts_core265.SAFE_STROKE_FILL_OPERATION,
|
|
strokeWidth: 2,
|
|
strokeOpacity: 1,
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
interpolation: {
|
|
type: "linear"
|
|
},
|
|
marker: {
|
|
shape: "circle",
|
|
size: 7,
|
|
strokeWidth: { $isUserOption: ["./stroke", 1, 0] },
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", import_ag_charts_core265.FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS],
|
|
["image", import_ag_charts_core265.FILL_IMAGE_DEFAULTS],
|
|
["pattern", import_ag_charts_core265.FILL_PATTERN_DEFAULTS]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" }
|
|
},
|
|
label: {
|
|
...import_ag_charts_core265.LABEL_BOXING_DEFAULTS,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
tooltip: {
|
|
range: {
|
|
$if: [
|
|
{ $eq: [{ $path: ["/tooltip/range", "nearest"] }, "area"] },
|
|
"nearest",
|
|
{ $path: ["/tooltip/range", "nearest"] }
|
|
]
|
|
},
|
|
position: {
|
|
anchorTo: { $path: ["/tooltip/position/anchorTo", "node"] }
|
|
}
|
|
},
|
|
highlight: import_ag_charts_core265.MARKER_SERIES_HIGHLIGHT_STYLE,
|
|
segmentation: import_ag_charts_core265.SEGMENTATION_DEFAULTS
|
|
}
|
|
};
|
|
var LineSeriesModule = {
|
|
type: "series",
|
|
name: "line",
|
|
chartType: "cartesian",
|
|
stackable: true,
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: lineSeriesOptionsDef,
|
|
predictAxis: predictCartesianNonPrimitiveAxis,
|
|
defaultAxes: {
|
|
y: {
|
|
type: import_ag_charts_core265.CARTESIAN_AXIS_TYPE.NUMBER,
|
|
position: import_ag_charts_core265.CARTESIAN_POSITION.LEFT
|
|
},
|
|
x: {
|
|
type: import_ag_charts_core265.CARTESIAN_AXIS_TYPE.CATEGORY,
|
|
position: import_ag_charts_core265.CARTESIAN_POSITION.BOTTOM
|
|
}
|
|
},
|
|
axisKeys: { [import_ag_charts_core265.ChartAxisDirection.X]: "xKeyAxis", [import_ag_charts_core265.ChartAxisDirection.Y]: "yKeyAxis" },
|
|
themeTemplate: themeTemplate5,
|
|
create: (ctx) => new LineSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/scatterSeriesModule.ts
|
|
var import_ag_charts_core266 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/scatterSeries.ts
|
|
var ScatterSeries = class extends BubbleSeries {
|
|
};
|
|
ScatterSeries.className = "ScatterSeries";
|
|
ScatterSeries.type = "scatter";
|
|
|
|
// packages/ag-charts-community/src/chart/series/cartesian/scatterSeriesModule.ts
|
|
var themeTemplate6 = {
|
|
series: {
|
|
shape: "circle",
|
|
size: 7,
|
|
fill: {
|
|
$applySwitch: [
|
|
{ $path: "type" },
|
|
{ $palette: "fill" },
|
|
["gradient", import_ag_charts_core266.FILL_GRADIENT_RADIAL_REVERSED_DEFAULTS],
|
|
["image", import_ag_charts_core266.FILL_IMAGE_DEFAULTS],
|
|
["pattern", import_ag_charts_core266.FILL_PATTERN_DEFAULTS]
|
|
]
|
|
},
|
|
stroke: { $palette: "stroke" },
|
|
fillOpacity: 0.8,
|
|
maxRenderedItems: 2e3,
|
|
label: {
|
|
...import_ag_charts_core266.LABEL_BOXING_DEFAULTS,
|
|
enabled: false,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" }
|
|
},
|
|
tooltip: {
|
|
range: {
|
|
$if: [
|
|
{ $eq: [{ $path: ["/tooltip/range", "nearest"] }, "area"] },
|
|
"nearest",
|
|
{ $path: ["/tooltip/range", "nearest"] }
|
|
]
|
|
},
|
|
position: {
|
|
anchorTo: { $path: ["/tooltip/position/anchorTo", "node"] }
|
|
}
|
|
},
|
|
highlight: import_ag_charts_core266.MULTI_SERIES_HIGHLIGHT_STYLE
|
|
}
|
|
};
|
|
var ScatterSeriesModule = {
|
|
type: "series",
|
|
name: "scatter",
|
|
chartType: "cartesian",
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: scatterSeriesOptionsDef,
|
|
predictAxis: predictCartesianAxis,
|
|
defaultAxes: {
|
|
x: {
|
|
type: import_ag_charts_core266.CARTESIAN_AXIS_TYPE.NUMBER,
|
|
position: import_ag_charts_core266.CARTESIAN_POSITION.BOTTOM
|
|
},
|
|
y: {
|
|
type: import_ag_charts_core266.CARTESIAN_AXIS_TYPE.NUMBER,
|
|
position: import_ag_charts_core266.CARTESIAN_POSITION.LEFT
|
|
}
|
|
},
|
|
axisKeys: { [import_ag_charts_core266.ChartAxisDirection.X]: "xKeyAxis", [import_ag_charts_core266.ChartAxisDirection.Y]: "yKeyAxis" },
|
|
themeTemplate: themeTemplate6,
|
|
create: (ctx) => new ScatterSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/donutSeries.ts
|
|
var import_ag_charts_core269 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/donutSeriesProperties.ts
|
|
var import_ag_charts_core267 = require("ag-charts-core");
|
|
var DonutTitle = class extends Caption {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.showInLegend = false;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutTitle.prototype, "showInLegend", 2);
|
|
var DonutInnerLabel = class extends Label {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.spacing = 2;
|
|
}
|
|
set(properties, _reset) {
|
|
return super.set(properties);
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutInnerLabel.prototype, "text", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutInnerLabel.prototype, "spacing", 2);
|
|
var DonutInnerCircle = class extends import_ag_charts_core267.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.fill = "transparent";
|
|
this.fillOpacity = 1;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutInnerCircle.prototype, "fill", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutInnerCircle.prototype, "fillOpacity", 2);
|
|
var DonutSeriesCalloutLabel = class extends Label {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.offset = 3;
|
|
this.minAngle = 0;
|
|
this.minSpacing = 4;
|
|
this.maxCollisionOffset = 50;
|
|
this.avoidCollisions = true;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesCalloutLabel.prototype, "offset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesCalloutLabel.prototype, "minAngle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesCalloutLabel.prototype, "minSpacing", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesCalloutLabel.prototype, "maxCollisionOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesCalloutLabel.prototype, "avoidCollisions", 2);
|
|
var DonutSeriesSectorLabel = class extends Label {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.positionOffset = 0;
|
|
this.positionRatio = 0.5;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesSectorLabel.prototype, "positionOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesSectorLabel.prototype, "positionRatio", 2);
|
|
var DonutSeriesCalloutLine = class extends import_ag_charts_core267.BaseProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.length = 10;
|
|
this.strokeWidth = 1;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesCalloutLine.prototype, "colors", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesCalloutLine.prototype, "length", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesCalloutLine.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesCalloutLine.prototype, "itemStyler", 2);
|
|
var DonutSeriesProperties = class extends SeriesProperties {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.defaultColorRange = [];
|
|
this.defaultPatternFills = [];
|
|
this.fills = Object.values(DEFAULT_FILLS);
|
|
this.strokes = Object.values(DEFAULT_STROKES);
|
|
this.fillOpacity = 1;
|
|
this.strokeOpacity = 1;
|
|
this.lineDash = [0];
|
|
this.lineDashOffset = 0;
|
|
this.cornerRadius = 0;
|
|
this.rotation = 0;
|
|
this.outerRadiusOffset = 0;
|
|
this.outerRadiusRatio = 1;
|
|
this.strokeWidth = 1;
|
|
this.sectorSpacing = 0;
|
|
this.hideZeroValueSectorsInLegend = false;
|
|
this.innerLabels = new import_ag_charts_core267.PropertiesArray(DonutInnerLabel);
|
|
this.title = new DonutTitle();
|
|
this.innerCircle = new DonutInnerCircle();
|
|
this.shadow = new DropShadow();
|
|
this.calloutLabel = new DonutSeriesCalloutLabel();
|
|
this.sectorLabel = new DonutSeriesSectorLabel();
|
|
this.calloutLine = new DonutSeriesCalloutLine();
|
|
this.tooltip = makeSeriesTooltip();
|
|
}
|
|
};
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "angleKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "angleName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "angleFilterKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "radiusKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "radiusName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "radiusMin", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "radiusMax", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "calloutLabelKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "calloutLabelName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "sectorLabelKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "sectorLabelName", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "legendItemKey", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "defaultColorRange", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "defaultPatternFills", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "fills", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "strokes", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "fillOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "strokeOpacity", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "lineDash", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "lineDashOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "cornerRadius", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "itemStyler", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "rotation", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "outerRadiusOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "outerRadiusRatio", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "innerRadiusOffset", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "innerRadiusRatio", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "strokeWidth", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "sectorSpacing", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "hideZeroValueSectorsInLegend", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "innerLabels", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "title", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "innerCircle", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "shadow", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "calloutLabel", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "sectorLabel", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "calloutLine", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core267.Property
|
|
], DonutSeriesProperties.prototype, "tooltip", 2);
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/pieUtil.ts
|
|
var import_ag_charts_core268 = require("ag-charts-core");
|
|
function preparePieSeriesAnimationFunctions(initialLoad, rotationDegrees, scaleFn, oldScaleFn) {
|
|
const scale2 = [scaleFn.convert(0), scaleFn.convert(1)];
|
|
const oldScale = [oldScaleFn.convert(0), oldScaleFn.convert(1)];
|
|
const rotation = Math.PI / -2 + (0, import_ag_charts_core268.toRadians)(rotationDegrees);
|
|
const phase = initialLoad ? "initial" : "update";
|
|
const scaleToNewRadius = ({ radius }) => {
|
|
return { innerRadius: scale2[0], outerRadius: scale2[0] + (scale2[1] - scale2[0]) * radius };
|
|
};
|
|
const scaleToOldRadius = ({ radius }) => {
|
|
return { innerRadius: oldScale[0], outerRadius: oldScale[0] + (oldScale[1] - oldScale[0]) * radius };
|
|
};
|
|
const fromFn = (sect, datum, status, { prevFromProps }) => {
|
|
let { startAngle, endAngle, innerRadius, outerRadius } = sect;
|
|
let { fill, stroke } = datum.sectorFormat;
|
|
if (status === "updated" && sect.previousDatum == null) {
|
|
status = "added";
|
|
}
|
|
if (status === "unknown" || status === "added" && !prevFromProps) {
|
|
startAngle = rotation;
|
|
endAngle = rotation;
|
|
innerRadius = datum.innerRadius;
|
|
outerRadius = datum.outerRadius;
|
|
} else if (status === "added" && prevFromProps) {
|
|
startAngle = prevFromProps.endAngle ?? rotation;
|
|
endAngle = prevFromProps.endAngle ?? rotation;
|
|
innerRadius = prevFromProps.innerRadius ?? datum.innerRadius;
|
|
outerRadius = prevFromProps.outerRadius ?? datum.outerRadius;
|
|
}
|
|
if (status === "added" && !initialLoad) {
|
|
const radii = scaleToOldRadius(datum);
|
|
innerRadius = radii.innerRadius;
|
|
outerRadius = radii.outerRadius;
|
|
}
|
|
if (status === "updated") {
|
|
fill = sect.fill ?? fill;
|
|
stroke = (typeof sect.stroke === "string" ? sect.stroke : void 0) ?? stroke;
|
|
}
|
|
const animatableFill = typeof fill === "string" ? { fill } : {};
|
|
return { startAngle, endAngle, innerRadius, outerRadius, stroke, phase, ...animatableFill };
|
|
};
|
|
const toFn = (_sect, datum, status, { prevLive }) => {
|
|
let { startAngle, endAngle, innerRadius, outerRadius } = datum;
|
|
const { stroke, fill } = datum.sectorFormat;
|
|
if (status === "removed" && prevLive) {
|
|
startAngle = prevLive.datum?.endAngle;
|
|
endAngle = prevLive.datum?.endAngle;
|
|
} else if (status === "removed" && !prevLive) {
|
|
startAngle = rotation;
|
|
endAngle = rotation;
|
|
}
|
|
if (status === "removed") {
|
|
const radii = scaleToNewRadius(datum);
|
|
innerRadius = radii.innerRadius;
|
|
outerRadius = radii.outerRadius;
|
|
}
|
|
const animatableFill = typeof fill === "string" ? { fill } : {};
|
|
return { startAngle, endAngle, outerRadius, innerRadius, stroke, ...animatableFill };
|
|
};
|
|
const innerCircleFromFn = (node, _) => {
|
|
return { size: node.previousDatum?.radius ?? node.size ?? 0, phase };
|
|
};
|
|
const innerCircleToFn = (_, datum) => {
|
|
return { size: datum.radius ?? 0 };
|
|
};
|
|
return { nodes: { toFn, fromFn }, innerCircle: { fromFn: innerCircleFromFn, toFn: innerCircleToFn } };
|
|
}
|
|
function resetPieSelectionsFn(_node, datum) {
|
|
return {
|
|
startAngle: datum.startAngle,
|
|
endAngle: datum.endAngle,
|
|
innerRadius: datum.innerRadius,
|
|
outerRadius: datum.outerRadius,
|
|
stroke: datum.sectorFormat.stroke
|
|
};
|
|
}
|
|
function pickByMatchingAngle(series, point) {
|
|
const dy = point.y - series.centerY;
|
|
const dx = point.x - series.centerX;
|
|
const angle = Math.atan2(dy, dx);
|
|
const sectors = series.getItemNodes();
|
|
for (const sector of sectors) {
|
|
if (sector.datum.missing === true)
|
|
continue;
|
|
if ((0, import_ag_charts_core268.isBetweenAngles)(angle, sector.startAngle, sector.endAngle)) {
|
|
const radius = Math.hypot(dx, dy);
|
|
let distance = 0;
|
|
if (radius < sector.innerRadius) {
|
|
distance = sector.innerRadius - radius;
|
|
} else if (radius > sector.outerRadius) {
|
|
distance = radius - sector.outerRadius;
|
|
}
|
|
return { datum: sector.datum, distance };
|
|
}
|
|
}
|
|
return void 0;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/donutSeries.ts
|
|
var PieDonutSeriesNodeEvent = class extends SeriesNodeEvent {
|
|
constructor(type, nativeEvent, datum, series) {
|
|
super(type, nativeEvent, datum, series);
|
|
this.angleKey = series.properties.angleKey;
|
|
this.radiusKey = series.properties.radiusKey;
|
|
this.calloutLabelKey = series.properties.calloutLabelKey;
|
|
this.sectorLabelKey = series.properties.sectorLabelKey;
|
|
}
|
|
};
|
|
var DonutSeries = class extends PolarSeries {
|
|
constructor(moduleCtx) {
|
|
super({
|
|
moduleCtx,
|
|
categoryKey: void 0,
|
|
propertyKeys: {
|
|
...DEFAULT_POLAR_DIRECTION_KEYS,
|
|
sectorLabel: ["sectorLabelKey"],
|
|
calloutLabel: ["calloutLabelKey"]
|
|
},
|
|
propertyNames: {
|
|
...DEFAULT_POLAR_DIRECTION_NAMES,
|
|
sectorLabel: ["sectorLabelName"],
|
|
calloutLabel: ["calloutLabelName"]
|
|
},
|
|
pickModes: [1 /* NEAREST_NODE */, 0 /* EXACT_SHAPE_MATCH */],
|
|
animationResetFns: { item: resetPieSelectionsFn, label: resetLabelFn }
|
|
});
|
|
this.properties = new DonutSeriesProperties();
|
|
this.phantomNodeData = void 0;
|
|
this.backgroundGroup = new TranslatableGroup({
|
|
name: `${this.id}-background`,
|
|
zIndex: import_ag_charts_core269.PolarZIndexMap.BACKGROUND
|
|
});
|
|
this.noVisibleData = false;
|
|
this.previousRadiusScale = new LinearScale();
|
|
this.radiusScale = new LinearScale();
|
|
this.phantomGroup = this.contentGroup.appendChild(new Group({ name: "phantom", zIndex: -1 }));
|
|
this.phantomSelection = Selection.select(
|
|
this.phantomGroup,
|
|
() => this.nodeFactory(),
|
|
false
|
|
);
|
|
this.phantomHighlightGroup = this.highlightGroup.appendChild(new Group({ name: "phantom", zIndex: -1 }));
|
|
this.phantomHighlightSelection = Selection.select(
|
|
this.phantomHighlightGroup,
|
|
() => this.nodeFactory(),
|
|
false
|
|
);
|
|
this.calloutLabelGroup = this.contentGroup.appendChild(new Group({ name: "pieCalloutLabels" }));
|
|
this.calloutLabelSelection = new Selection(
|
|
this.calloutLabelGroup,
|
|
Group
|
|
);
|
|
// AG-6193 If the sum of all datums is 0, then we'll draw 1 or 2 rings to represent the empty series.
|
|
this.zerosumRingsGroup = this.backgroundGroup.appendChild(new Group({ name: `${this.id}-zerosumRings` }));
|
|
this.zerosumOuterRing = this.zerosumRingsGroup.appendChild(new Marker({ shape: "circle" }));
|
|
this.zerosumInnerRing = this.zerosumRingsGroup.appendChild(new Marker({ shape: "circle" }));
|
|
this.innerLabelsGroup = this.contentGroup.appendChild(new Group({ name: "innerLabels" }));
|
|
this.innerCircleGroup = this.backgroundGroup.appendChild(new Group({ name: `${this.id}-innerCircle` }));
|
|
this.innerLabelsSelection = Selection.select(this.innerLabelsGroup, Text);
|
|
this.innerCircleSelection = Selection.select(
|
|
this.innerCircleGroup,
|
|
() => new Marker({ shape: "circle" })
|
|
);
|
|
this.surroundingRadius = void 0;
|
|
this.NodeEvent = PieDonutSeriesNodeEvent;
|
|
this.angleScale = new LinearScale();
|
|
this.angleScale.domain = [0, 1];
|
|
this.angleScale.range = [-Math.PI, Math.PI].map((angle) => angle + Math.PI / 2);
|
|
this.phantomGroup.opacity = 0.2;
|
|
this.phantomHighlightGroup.opacity = 0.2;
|
|
this.innerLabelsGroup.pointerEvents = 1 /* None */;
|
|
}
|
|
get calloutNodeData() {
|
|
return this.phantomNodeData ?? this.nodeData;
|
|
}
|
|
attachSeries(seriesContentNode, seriesNode, annotationNode) {
|
|
super.attachSeries(seriesContentNode, seriesNode, annotationNode);
|
|
seriesContentNode?.appendChild(this.backgroundGroup);
|
|
}
|
|
detachSeries(seriesContentNode, seriesNode, annotationNode) {
|
|
super.detachSeries(seriesContentNode, seriesNode, annotationNode);
|
|
this.backgroundGroup.remove();
|
|
}
|
|
setZIndex(zIndex) {
|
|
super.setZIndex(zIndex);
|
|
this.backgroundGroup.zIndex = [import_ag_charts_core269.PolarZIndexMap.BACKGROUND, zIndex];
|
|
}
|
|
nodeFactory() {
|
|
const sector = new Sector();
|
|
sector.miterLimit = 1e9;
|
|
return sector;
|
|
}
|
|
getSeriesDomain(direction) {
|
|
if (direction === import_ag_charts_core269.ChartAxisDirection.Angle) {
|
|
return { domain: this.angleScale.domain };
|
|
} else {
|
|
return { domain: this.radiusScale.domain };
|
|
}
|
|
}
|
|
async processData(dataController) {
|
|
if (this.data == null)
|
|
return;
|
|
const {
|
|
visible,
|
|
id: seriesId,
|
|
ctx: { legendManager }
|
|
} = this;
|
|
const { angleKey, angleFilterKey, radiusKey, calloutLabelKey, sectorLabelKey, legendItemKey } = this.properties;
|
|
const processor = () => (value, index) => {
|
|
if (visible && legendManager.getItemEnabled({ seriesId, itemId: index })) {
|
|
return value;
|
|
}
|
|
return 0;
|
|
};
|
|
const animationEnabled = !this.ctx.animationManager.isSkipped();
|
|
const allowNullKey = this.properties.allowNullKeys ?? false;
|
|
const extraKeyProps = [];
|
|
const extraProps = [];
|
|
if (legendItemKey) {
|
|
extraKeyProps.push(keyProperty(legendItemKey, "category", { id: `legendItemKey`, allowNullKey }));
|
|
} else if (calloutLabelKey) {
|
|
extraKeyProps.push(keyProperty(calloutLabelKey, "category", { id: `calloutLabelKey`, allowNullKey }));
|
|
} else if (sectorLabelKey) {
|
|
extraKeyProps.push(keyProperty(sectorLabelKey, "category", { id: `sectorLabelKey`, allowNullKey }));
|
|
}
|
|
const radiusScaleType = this.radiusScale.type;
|
|
const angleScaleType = this.angleScale.type;
|
|
if (radiusKey) {
|
|
extraProps.push(
|
|
rangedValueProperty(radiusKey, {
|
|
id: "radiusValue",
|
|
min: this.properties.radiusMin ?? 0,
|
|
max: this.properties.radiusMax,
|
|
missingValue: this.properties.radiusMax ?? 1,
|
|
processor
|
|
}),
|
|
valueProperty(radiusKey, radiusScaleType, { id: `radiusRaw`, processor }),
|
|
// Raw value pass-through.
|
|
normalisePropertyTo("radiusValue", [0, 1], 1, this.properties.radiusMin ?? 0, this.properties.radiusMax)
|
|
);
|
|
}
|
|
if (calloutLabelKey) {
|
|
extraProps.push(valueProperty(calloutLabelKey, "category", { id: `calloutLabelValue`, allowNullKey }));
|
|
}
|
|
if (sectorLabelKey) {
|
|
extraProps.push(valueProperty(sectorLabelKey, "category", { id: `sectorLabelValue`, allowNullKey }));
|
|
}
|
|
if (legendItemKey) {
|
|
extraProps.push(valueProperty(legendItemKey, "category", { id: `legendItemValue`, allowNullKey }));
|
|
}
|
|
if (angleFilterKey) {
|
|
extraProps.push(
|
|
accumulativeValueProperty(angleFilterKey, angleScaleType, {
|
|
id: `angleFilterValue`,
|
|
onlyPositive: true,
|
|
invalidValue: 0,
|
|
processor
|
|
}),
|
|
valueProperty(angleFilterKey, angleScaleType, { id: `angleFilterRaw` }),
|
|
normalisePropertyTo("angleFilterValue", [0, 1], 0, 0)
|
|
);
|
|
}
|
|
if (animationEnabled && this.processedData?.reduced?.animationValidation?.uniqueKeys && extraKeyProps.length > 0) {
|
|
extraProps.push(diff(this.id, this.processedData));
|
|
}
|
|
extraProps.push(animationValidation());
|
|
await this.requestDataModel(dataController, this.data, {
|
|
props: [
|
|
...extraKeyProps,
|
|
accumulativeValueProperty(angleKey, angleScaleType, {
|
|
id: `angleValue`,
|
|
onlyPositive: true,
|
|
invalidValue: 0,
|
|
processor
|
|
}),
|
|
valueProperty(angleKey, angleScaleType, { id: `angleRaw` }),
|
|
// Raw value pass-through.
|
|
normalisePropertyTo("angleValue", [0, 1], 0, 0),
|
|
...extraProps
|
|
]
|
|
});
|
|
for (const valueDef of this.processedData?.defs?.values ?? []) {
|
|
const { id, missing, property } = valueDef;
|
|
const missCount = getMissCount(this, missing);
|
|
if (id !== "angleRaw" && missCount > 0) {
|
|
import_ag_charts_core269.Logger.warnOnce(
|
|
`no value was found for the key '${String(property)}' on ${missCount} data element${missCount > 1 ? "s" : ""}`
|
|
);
|
|
}
|
|
}
|
|
this.animationState.transition("updateData");
|
|
}
|
|
maybeRefreshNodeData() {
|
|
if (!this.nodeDataRefresh)
|
|
return;
|
|
const { nodeData = [], phantomNodeData } = this.createNodeData() ?? {};
|
|
this.nodeData = nodeData;
|
|
this.phantomNodeData = phantomNodeData;
|
|
if (nodeData.length > 0) {
|
|
import_ag_charts_core269.DebugMetrics.record(`${this.type}:nodeData`, nodeData.length);
|
|
}
|
|
this.nodeDataRefresh = false;
|
|
}
|
|
getProcessedDataValues(dataModel, processedData) {
|
|
const angleValues = dataModel.resolveColumnById(this, `angleValue`, processedData);
|
|
const angleRawValues = dataModel.resolveColumnById(this, `angleRaw`, processedData);
|
|
const angleFilterValues = this.properties.angleFilterKey == null ? void 0 : dataModel.resolveColumnById(this, `angleFilterValue`, processedData);
|
|
const angleFilterRawValues = this.properties.angleFilterKey == null ? void 0 : dataModel.resolveColumnById(this, `angleFilterRaw`, processedData);
|
|
const radiusValues = this.properties.radiusKey ? dataModel.resolveColumnById(this, `radiusValue`, processedData) : void 0;
|
|
const radiusRawValues = this.properties.radiusKey ? dataModel.resolveColumnById(this, `radiusRaw`, processedData) : void 0;
|
|
const calloutLabelValues = this.properties.calloutLabelKey ? dataModel.resolveColumnById(this, `calloutLabelValue`, processedData) : void 0;
|
|
const sectorLabelValues = this.properties.sectorLabelKey ? dataModel.resolveColumnById(this, `sectorLabelValue`, processedData) : void 0;
|
|
const legendItemValues = this.properties.legendItemKey ? dataModel.resolveColumnById(this, `legendItemValue`, processedData) : void 0;
|
|
return {
|
|
angleValues,
|
|
angleRawValues,
|
|
angleFilterValues,
|
|
angleFilterRawValues,
|
|
radiusValues,
|
|
radiusRawValues,
|
|
calloutLabelValues,
|
|
sectorLabelValues,
|
|
legendItemValues
|
|
};
|
|
}
|
|
createNodeData() {
|
|
const {
|
|
id: seriesId,
|
|
processedData,
|
|
dataModel,
|
|
angleScale,
|
|
ctx: { legendManager },
|
|
visible
|
|
} = this;
|
|
const { rotation, innerRadiusRatio } = this.properties;
|
|
if (!dataModel || processedData?.type !== "ungrouped")
|
|
return;
|
|
const processedDataValues = this.getProcessedDataValues(dataModel, processedData);
|
|
const {
|
|
angleValues,
|
|
angleRawValues,
|
|
angleFilterValues,
|
|
angleFilterRawValues,
|
|
radiusValues,
|
|
radiusRawValues,
|
|
legendItemValues
|
|
} = processedDataValues;
|
|
const useFilterAngles = angleFilterRawValues?.some((filterRawValue, index) => {
|
|
return filterRawValue > angleRawValues[index];
|
|
}) ?? false;
|
|
let currentStart = 0;
|
|
let sum = 0;
|
|
const nodes = [];
|
|
const phantomNodes = angleFilterRawValues == null ? void 0 : [];
|
|
const rawData = processedData.dataSources.get(this.id)?.data ?? [];
|
|
const invalidData = processedData.invalidData?.get(this.id);
|
|
for (const [datumIndex, datum] of rawData.entries()) {
|
|
if (invalidData?.[datumIndex] === true)
|
|
continue;
|
|
const currentValue = useFilterAngles ? angleFilterValues[datumIndex] : angleValues[datumIndex];
|
|
const crossFilterScale = angleFilterRawValues != null && !useFilterAngles ? Math.sqrt(angleFilterRawValues[datumIndex] / angleRawValues[datumIndex]) : 1;
|
|
const startAngle = angleScale.convert(currentStart) + (0, import_ag_charts_core269.toRadians)(rotation);
|
|
currentStart = currentValue;
|
|
sum += currentValue;
|
|
const endAngle = angleScale.convert(currentStart) + (0, import_ag_charts_core269.toRadians)(rotation);
|
|
const span = Math.abs(endAngle - startAngle);
|
|
const midAngle = startAngle + span / 2;
|
|
const angleValue = angleRawValues[datumIndex];
|
|
const radiusRaw = radiusValues?.[datumIndex] ?? 1;
|
|
const radius = radiusRaw * crossFilterScale;
|
|
const radiusValue = radiusRawValues?.[datumIndex];
|
|
const legendItemValue = legendItemValues?.[datumIndex];
|
|
const nodeLabels = this.getLabels(datumIndex, datum, midAngle, span, processedDataValues);
|
|
const sectorFormat = this.getItemStyle({ datum, datumIndex }, false);
|
|
const node = {
|
|
series: this,
|
|
datum,
|
|
datumIndex,
|
|
angleValue,
|
|
midAngle,
|
|
midCos: Math.cos(midAngle),
|
|
midSin: Math.sin(midAngle),
|
|
startAngle,
|
|
endAngle,
|
|
radius,
|
|
innerRadius: Math.max(this.radiusScale.convert(0), 0),
|
|
outerRadius: Math.max(this.radiusScale.convert(radius), 0),
|
|
sectorFormat,
|
|
radiusValue,
|
|
legendItemValue,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId: datumIndex }),
|
|
focusable: true,
|
|
...nodeLabels
|
|
};
|
|
nodes.push(node);
|
|
if (phantomNodes != null) {
|
|
phantomNodes.push({
|
|
...node,
|
|
radius: 1,
|
|
innerRadius: Math.max(this.radiusScale.convert(0), 0),
|
|
outerRadius: Math.max(this.radiusScale.convert(1), 0),
|
|
focusable: false
|
|
});
|
|
}
|
|
}
|
|
this.zerosumOuterRing.visible = sum === 0;
|
|
this.zerosumInnerRing.visible = sum === 0 && innerRadiusRatio != null && innerRadiusRatio !== 1 && innerRadiusRatio > 0;
|
|
return {
|
|
itemId: seriesId,
|
|
nodeData: nodes,
|
|
labelData: nodes,
|
|
phantomNodeData: phantomNodes
|
|
};
|
|
}
|
|
getLabelContent(datumIndex, datum, values) {
|
|
const { id: seriesId, ctx, properties } = this;
|
|
const { formatManager } = ctx;
|
|
const { calloutLabel, sectorLabel, calloutLabelKey, sectorLabelKey, legendItemKey } = properties;
|
|
const allowNullKeys = properties.allowNullKeys ?? false;
|
|
const calloutLabelValue = values.calloutLabelValues?.[datumIndex];
|
|
const sectorLabelValue = values.sectorLabelValues?.[datumIndex];
|
|
const legendItemValue = values.legendItemValues?.[datumIndex];
|
|
const labelFormatterParams = {
|
|
datum,
|
|
angleKey: this.properties.angleKey,
|
|
angleName: this.properties.angleName,
|
|
radiusKey: this.properties.radiusKey,
|
|
radiusName: this.properties.radiusName,
|
|
calloutLabelKey: this.properties.calloutLabelKey,
|
|
calloutLabelName: this.properties.calloutLabelName,
|
|
sectorLabelKey: this.properties.sectorLabelKey,
|
|
sectorLabelName: this.properties.sectorLabelName,
|
|
legendItemKey: this.properties.legendItemKey
|
|
};
|
|
const result = {
|
|
callout: void 0,
|
|
sector: void 0,
|
|
legendItem: void 0
|
|
};
|
|
if (calloutLabelKey) {
|
|
result.callout = this.getLabelText(
|
|
calloutLabelValue,
|
|
datum,
|
|
calloutLabelKey,
|
|
"calloutLabel",
|
|
[],
|
|
calloutLabel,
|
|
{ ...labelFormatterParams, value: calloutLabelValue },
|
|
allowNullKeys
|
|
);
|
|
}
|
|
if (sectorLabelKey) {
|
|
result.sector = this.getLabelText(
|
|
sectorLabelValue,
|
|
datum,
|
|
sectorLabelKey,
|
|
"sectorLabel",
|
|
[],
|
|
sectorLabel,
|
|
{ ...labelFormatterParams, value: sectorLabelValue },
|
|
allowNullKeys
|
|
);
|
|
}
|
|
if (legendItemKey != null && (legendItemValue != null || allowNullKeys)) {
|
|
const legendItemDisplay = legendItemValue ?? "";
|
|
result.legendItem = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "category",
|
|
value: allowNullKeys ? legendItemValue : legendItemDisplay,
|
|
datum,
|
|
seriesId,
|
|
legendItemName: void 0,
|
|
key: legendItemKey,
|
|
source: "legend-label",
|
|
property: "legendItem",
|
|
domain: [],
|
|
boundSeries: this.getFormatterContext("legendItem")
|
|
}) ?? legendItemDisplay;
|
|
}
|
|
return result;
|
|
}
|
|
getLabels(datumIndex, datum, midAngle, span, values) {
|
|
const { properties } = this;
|
|
const { calloutLabel, sectorLabel, legendItemKey } = properties;
|
|
const formats = this.getLabelContent(datumIndex, datum, values);
|
|
const result = {};
|
|
if (calloutLabel.enabled && formats.callout && span >= (0, import_ag_charts_core269.toRadians)(calloutLabel.minAngle)) {
|
|
result.calloutLabel = {
|
|
...this.getTextAlignment(midAngle),
|
|
text: formats.callout,
|
|
hidden: false,
|
|
collisionTextAlign: void 0,
|
|
collisionOffsetY: 0,
|
|
box: void 0
|
|
};
|
|
}
|
|
if (sectorLabel.enabled && formats.sector) {
|
|
result.sectorLabel = { text: formats.sector };
|
|
}
|
|
if (legendItemKey && formats.legendItem) {
|
|
result.legendItem = { key: legendItemKey, text: formats.legendItem };
|
|
}
|
|
return result;
|
|
}
|
|
getTextAlignment(midAngle) {
|
|
const quadrantTextOpts = [
|
|
{ textAlign: "center", textBaseline: "bottom" },
|
|
{ textAlign: "left", textBaseline: "middle" },
|
|
{ textAlign: "center", textBaseline: "top" },
|
|
{ textAlign: "right", textBaseline: "middle" }
|
|
];
|
|
const midAngle180 = (0, import_ag_charts_core269.normalizeAngle180)(midAngle);
|
|
const quadrantStart = -0.75 * Math.PI;
|
|
const quadrantOffset = midAngle180 - quadrantStart;
|
|
const quadrant = Math.floor(quadrantOffset / (Math.PI / 2));
|
|
const quadrantIndex = (0, import_ag_charts_core269.modulus)(quadrant, quadrantTextOpts.length);
|
|
return quadrantTextOpts[quadrantIndex];
|
|
}
|
|
getFillParams(fill, innerRadius, outerRadius) {
|
|
if (!(0, import_ag_charts_core269.isGradientFill)(fill) || fill.bounds === "item")
|
|
return;
|
|
return {
|
|
centerX: 0,
|
|
centerY: 0,
|
|
innerRadius,
|
|
outerRadius
|
|
};
|
|
}
|
|
getItemStyle({ datum, datumIndex }, isHighlight, highlightState, legendItemValues) {
|
|
const { fills, strokes, itemStyler } = this.properties;
|
|
const defaultStroke = strokes[datumIndex];
|
|
const defaultFill = fills[datumIndex];
|
|
const {
|
|
fill,
|
|
fillOpacity,
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
cornerRadius,
|
|
opacity
|
|
} = (0, import_ag_charts_core269.mergeDefaults)(
|
|
this.getHighlightStyle(isHighlight, datumIndex, highlightState, legendItemValues),
|
|
{ fill: defaultFill, stroke: defaultStroke },
|
|
this.properties
|
|
);
|
|
let overrides;
|
|
if (itemStyler) {
|
|
overrides = this.cachedDatumCallback(
|
|
this.getDatumId(datumIndex) + (isHighlight ? "-highlight" : "-hide"),
|
|
() => {
|
|
const params = this.makeItemStylerParams(datum, datumIndex, isHighlight, {
|
|
fill,
|
|
fillOpacity,
|
|
stroke,
|
|
strokeWidth,
|
|
strokeOpacity,
|
|
lineDash,
|
|
lineDashOffset,
|
|
cornerRadius
|
|
});
|
|
return this.ctx.optionsGraphService.resolvePartial(
|
|
["series", `${this.declarationOrder}`],
|
|
this.callWithContext(itemStyler, params),
|
|
{ proxyPaths: { fill: ["fills", `${datumIndex}`], stroke: ["strokes", `${datumIndex}`] } }
|
|
);
|
|
}
|
|
);
|
|
}
|
|
return {
|
|
fill: overrides?.fill ?? fill,
|
|
fillOpacity: overrides?.fillOpacity ?? fillOpacity,
|
|
stroke: overrides?.stroke ?? stroke,
|
|
strokeWidth: overrides?.strokeWidth ?? strokeWidth,
|
|
strokeOpacity: overrides?.strokeOpacity ?? strokeOpacity,
|
|
lineDash: overrides?.lineDash ?? lineDash,
|
|
lineDashOffset: overrides?.lineDashOffset ?? lineDashOffset,
|
|
cornerRadius: overrides?.cornerRadius ?? cornerRadius,
|
|
opacity
|
|
};
|
|
}
|
|
makeItemStylerParams(datum, datumIndex, isHighlight, style) {
|
|
const { angleKey, radiusKey, calloutLabelKey, sectorLabelKey, legendItemKey } = this.properties;
|
|
const fill = this.filterItemStylerFillParams(style.fill) ?? style.fill;
|
|
return {
|
|
datum,
|
|
angleKey,
|
|
radiusKey,
|
|
calloutLabelKey,
|
|
sectorLabelKey,
|
|
legendItemKey,
|
|
...style,
|
|
fill,
|
|
highlightState: this.getHighlightStateString(
|
|
this.ctx.highlightManager?.getActiveHighlight(),
|
|
isHighlight,
|
|
datumIndex
|
|
),
|
|
seriesId: this.id
|
|
};
|
|
}
|
|
getCalloutLineStyle(nodeDatum, highlighted) {
|
|
const { properties } = this;
|
|
let itemStylerResult = {};
|
|
if (properties.calloutLine.itemStyler) {
|
|
const highlightState = this.getHighlightStateString(
|
|
this.ctx.highlightManager?.getActiveHighlight(),
|
|
highlighted,
|
|
nodeDatum.datumIndex
|
|
);
|
|
const params = {
|
|
angleKey: properties.angleKey,
|
|
angleName: properties.angleName ?? properties.angleKey,
|
|
calloutLabelKey: properties.calloutLabelKey,
|
|
calloutLabelName: properties.calloutLabelName ?? properties.calloutLabelKey,
|
|
datum: nodeDatum.datum,
|
|
highlightState,
|
|
legendItemKey: properties.legendItemKey,
|
|
radiusKey: properties.radiusKey,
|
|
radiusName: properties.radiusName ?? properties.radiusKey,
|
|
sectorLabelKey: properties.sectorLabelKey,
|
|
sectorLabelName: properties.sectorLabelName ?? properties.sectorLabelKey,
|
|
seriesId: this.id
|
|
};
|
|
itemStylerResult = this.cachedCallWithContext(properties.calloutLine.itemStyler, params) ?? {};
|
|
}
|
|
return {
|
|
length: itemStylerResult.length ?? properties.calloutLine.length,
|
|
strokeWidth: itemStylerResult.strokeWidth ?? properties.calloutLine.strokeWidth,
|
|
color: itemStylerResult.color,
|
|
colors: properties.calloutLine.colors
|
|
};
|
|
}
|
|
getInnerRadius() {
|
|
const { radius } = this;
|
|
const { innerRadiusRatio = 1, innerRadiusOffset = 0 } = this.properties;
|
|
const innerRadius = radius * innerRadiusRatio + innerRadiusOffset;
|
|
if (innerRadius === radius || innerRadius < 0) {
|
|
return 0;
|
|
}
|
|
return innerRadius;
|
|
}
|
|
getOuterRadius() {
|
|
const { outerRadiusRatio, outerRadiusOffset } = this.properties;
|
|
return Math.max(this.radius * outerRadiusRatio + outerRadiusOffset, 0);
|
|
}
|
|
updateRadiusScale(resize) {
|
|
const newRange = [this.getInnerRadius(), this.getOuterRadius()];
|
|
this.radiusScale.range = newRange;
|
|
if (resize) {
|
|
this.previousRadiusScale.range = newRange;
|
|
}
|
|
const setRadii = (d) => ({
|
|
...d,
|
|
innerRadius: Math.max(this.radiusScale.convert(0), 0),
|
|
outerRadius: Math.max(this.radiusScale.convert(d.radius), 0)
|
|
});
|
|
this.nodeData = this.nodeData.map(setRadii);
|
|
this.phantomNodeData = this.phantomNodeData?.map(setRadii);
|
|
}
|
|
getTitleTranslationY() {
|
|
const outerRadius = Math.max(0, this.radiusScale.range[1]);
|
|
if (outerRadius === 0) {
|
|
return Number.NaN;
|
|
}
|
|
const spacing = this.properties.title?.spacing ?? 0;
|
|
const titleOffset = 2 + spacing;
|
|
const dy = Math.max(0, -outerRadius);
|
|
return -outerRadius - titleOffset - dy;
|
|
}
|
|
update({ seriesRect }) {
|
|
const { title } = this.properties;
|
|
const newNodeDataDependencies = {
|
|
seriesRectWidth: seriesRect?.width,
|
|
seriesRectHeight: seriesRect?.height
|
|
};
|
|
const resize = (0, import_ag_charts_core269.jsonDiff)(this.nodeDataDependencies, newNodeDataDependencies) != null;
|
|
if (resize) {
|
|
this._nodeDataDependencies = newNodeDataDependencies;
|
|
}
|
|
this.maybeRefreshNodeData();
|
|
this.updateTitleNodes();
|
|
this.updateRadiusScale(resize);
|
|
this.contentGroup.translationX = this.centerX;
|
|
this.contentGroup.translationY = this.centerY;
|
|
this.highlightGroup.translationX = this.centerX;
|
|
this.highlightGroup.translationY = this.centerY;
|
|
this.backgroundGroup.translationX = this.centerX;
|
|
this.backgroundGroup.translationY = this.centerY;
|
|
if (this.labelGroup) {
|
|
this.labelGroup.translationX = this.centerX;
|
|
this.labelGroup.translationY = this.centerY;
|
|
}
|
|
if (title) {
|
|
const dy = this.getTitleTranslationY();
|
|
title.node.y = Number.isFinite(dy) ? dy : 0;
|
|
const titleBox = title.node.getBBox();
|
|
title.node.visible = title.enabled && Number.isFinite(dy) && !this.bboxIntersectsSurroundingSeries(titleBox);
|
|
}
|
|
for (const circle of [this.zerosumInnerRing, this.zerosumOuterRing]) {
|
|
circle.fillOpacity = 0;
|
|
circle.stroke = this.properties.calloutLabel.color;
|
|
circle.strokeWidth = 1;
|
|
circle.strokeOpacity = 1;
|
|
}
|
|
this.updateNodeMidPoint();
|
|
this.updateSelections();
|
|
this.updateNodes(seriesRect);
|
|
}
|
|
updateTitleNodes() {
|
|
const { oldTitle } = this;
|
|
const { title } = this.properties;
|
|
if (oldTitle !== title) {
|
|
if (oldTitle) {
|
|
oldTitle.node.remove();
|
|
}
|
|
if (title) {
|
|
title.node.textBaseline = "bottom";
|
|
this.labelGroup?.appendChild(title.node);
|
|
}
|
|
this.oldTitle = title;
|
|
}
|
|
}
|
|
updateNodeMidPoint() {
|
|
const setMidPoint = (d) => {
|
|
const radius = d.innerRadius + (d.outerRadius - d.innerRadius) / 2;
|
|
d.midPoint = {
|
|
x: d.midCos * Math.max(0, radius),
|
|
y: d.midSin * Math.max(0, radius)
|
|
};
|
|
};
|
|
for (const datum of this.nodeData) {
|
|
setMidPoint(datum);
|
|
}
|
|
if (this.phantomNodeData) {
|
|
for (const datum of this.phantomNodeData) {
|
|
setMidPoint(datum);
|
|
}
|
|
}
|
|
}
|
|
updateSelections() {
|
|
this.updateGroupSelection();
|
|
this.updateInnerCircleSelection();
|
|
}
|
|
updateGroupSelection() {
|
|
const {
|
|
itemSelection,
|
|
highlightSelection,
|
|
phantomSelection,
|
|
phantomHighlightSelection,
|
|
calloutLabelSelection,
|
|
labelSelection,
|
|
highlightLabelSelection,
|
|
innerLabelsSelection
|
|
} = this;
|
|
const highlightedNodeData = this.nodeData.map((datum) => ({
|
|
...datum,
|
|
// Allow mutable sectorFormat, so formatted sector styles can be updated and varied
|
|
// between normal and highlighted cases.
|
|
sectorFormat: { ...datum.sectorFormat }
|
|
}));
|
|
const phantomHighlightedNodeData = this.phantomNodeData?.map((datum) => ({
|
|
...datum,
|
|
// Allow mutable sectorFormat, so formatted sector styles can be updated and varied
|
|
// between normal and highlighted cases.
|
|
sectorFormat: { ...datum.sectorFormat }
|
|
}));
|
|
const update = (selection, nodeData) => {
|
|
selection.update(nodeData, void 0, (datum) => this.getDatumId(datum.datumIndex));
|
|
if (this.ctx.animationManager.isSkipped()) {
|
|
selection.cleanup();
|
|
}
|
|
};
|
|
update(itemSelection, this.nodeData);
|
|
update(highlightSelection, highlightedNodeData);
|
|
update(phantomSelection, this.phantomNodeData ?? []);
|
|
update(phantomHighlightSelection, phantomHighlightedNodeData ?? []);
|
|
calloutLabelSelection.update(this.calloutNodeData, (group) => {
|
|
const line = new Line();
|
|
line.tag = 0 /* CalloutLine */;
|
|
line.pointerEvents = 1 /* None */;
|
|
group.appendChild(line);
|
|
const text = new Text();
|
|
text.tag = 1 /* CalloutLabel */;
|
|
text.pointerEvents = 1 /* None */;
|
|
group.appendChild(text);
|
|
});
|
|
labelSelection.update(this.nodeData);
|
|
highlightLabelSelection.update(highlightedNodeData);
|
|
innerLabelsSelection.update(this.properties.innerLabels, (node) => {
|
|
node.pointerEvents = 1 /* None */;
|
|
});
|
|
}
|
|
updateInnerCircleSelection() {
|
|
const { innerCircle } = this.properties;
|
|
let radius = 0;
|
|
const innerRadius = this.getInnerRadius();
|
|
if (innerRadius > 0) {
|
|
const circleRadius = Math.min(innerRadius, this.getOuterRadius());
|
|
const antiAliasingPadding = 1;
|
|
radius = Math.ceil(circleRadius * 2 + antiAliasingPadding);
|
|
}
|
|
const datums = innerCircle ? [{ radius }] : [];
|
|
this.innerCircleSelection.update(datums);
|
|
}
|
|
updateNodes(seriesRect) {
|
|
const highlightedDatum = this.ctx.highlightManager.getActiveHighlight();
|
|
const { visible, dataModel, processedData } = this;
|
|
this.backgroundGroup.visible = visible;
|
|
this.contentGroup.visible = visible;
|
|
if (!dataModel || !processedData)
|
|
return;
|
|
const { legendItemValues } = this.getProcessedDataValues(dataModel, processedData);
|
|
const seriesHighlighted = this.isSeriesHighlighted(highlightedDatum, legendItemValues);
|
|
const drawingMode = this.ctx.chartService.highlight?.drawingMode ?? "overlay";
|
|
this.highlightGroup.visible = visible && seriesHighlighted;
|
|
this.labelGroup.visible = visible;
|
|
this.innerCircleSelection.each((node, { radius }) => {
|
|
node.setProperties({
|
|
fill: this.properties.innerCircle?.fill,
|
|
opacity: this.properties.innerCircle?.fillOpacity,
|
|
size: radius
|
|
});
|
|
});
|
|
const innerRadius = this.radiusScale.range[0];
|
|
const outerRadius = this.radiusScale.range[1];
|
|
const fillBBox = this.getShapeFillBBox();
|
|
const animationDisabled = this.ctx.animationManager.isSkipped();
|
|
const updateSectorFn = (sector, datum, _index, isDatumHighlighted, mode) => {
|
|
const format = this.getItemStyle(datum, isDatumHighlighted, void 0, legendItemValues);
|
|
datum.sectorFormat.fill = format.fill;
|
|
datum.sectorFormat.stroke = format.stroke;
|
|
if (animationDisabled) {
|
|
sector.startAngle = datum.startAngle;
|
|
sector.endAngle = datum.endAngle;
|
|
sector.innerRadius = datum.innerRadius;
|
|
sector.outerRadius = datum.outerRadius;
|
|
}
|
|
if (isDatumHighlighted || animationDisabled) {
|
|
sector.fill = format.fill;
|
|
sector.stroke = format.stroke;
|
|
}
|
|
const fillParams = this.getFillParams(format.fill, innerRadius, outerRadius);
|
|
sector.setStyleProperties(format, fillBBox, fillParams);
|
|
sector.drawingMode = mode;
|
|
sector.cornerRadius = format.cornerRadius;
|
|
sector.fillShadow = this.properties.shadow;
|
|
const inset = Math.max(
|
|
(this.properties.sectorSpacing + (format.stroke == null ? 0 : format.strokeWidth)) / 2,
|
|
0
|
|
);
|
|
sector.inset = inset;
|
|
sector.lineJoin = this.properties.sectorSpacing >= 0 || inset > 0 ? "miter" : "round";
|
|
};
|
|
this.itemSelection.each((node, datum, index) => updateSectorFn(node, datum, index, false, "overlay"));
|
|
this.phantomSelection.each((node, datum, index) => updateSectorFn(node, datum, index, false, "overlay"));
|
|
this.highlightSelection.each((node, datum, index) => {
|
|
updateSectorFn(node, datum, index, true, drawingMode);
|
|
node.visible = datum.datumIndex === highlightedDatum?.datumIndex;
|
|
});
|
|
this.phantomHighlightSelection.each((node, datum, index) => {
|
|
updateSectorFn(node, datum, index, true, drawingMode);
|
|
node.visible = datum.datumIndex === highlightedDatum?.datumIndex;
|
|
});
|
|
this.updateCalloutLineNodes();
|
|
this.updateCalloutLabelNodes(seriesRect);
|
|
this.updateSectorLabelNodes();
|
|
this.updateInnerLabelNodes();
|
|
this.updateZerosumRings();
|
|
this.animationState.transition("update");
|
|
}
|
|
updateCalloutLineNodes() {
|
|
const { strokes } = this.properties;
|
|
const { offset } = this.properties.calloutLabel;
|
|
const highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
const seriesHighlighted = this.isSeriesHighlighted(highlightedDatum);
|
|
for (const line of this.calloutLabelSelection.selectByTag(0 /* CalloutLine */)) {
|
|
const datum = line.closestDatum();
|
|
const isDatumHighlighted = seriesHighlighted && this.isItemHighlighted(highlightedDatum, datum.datumIndex) === true;
|
|
const { length: calloutLength, strokeWidth, color: color8, colors } = this.getCalloutLineStyle(datum, false);
|
|
const calloutStrokeWidth = strokeWidth;
|
|
const calloutColors = (0, import_ag_charts_core269.isStringFillArray)(colors) ? colors : strokes;
|
|
const { calloutLabel: label, outerRadius, datumIndex } = datum;
|
|
if (label?.text && !label.hidden && outerRadius !== 0) {
|
|
line.visible = true;
|
|
line.strokeWidth = calloutStrokeWidth;
|
|
line.stroke = color8 ?? calloutColors[datumIndex % calloutColors.length];
|
|
line.strokeOpacity = this.getHighlightStyle(isDatumHighlighted, datum.datumIndex).opacity ?? 1;
|
|
line.fill = void 0;
|
|
const x1 = datum.midCos * outerRadius;
|
|
const y1 = datum.midSin * outerRadius;
|
|
let x2 = datum.midCos * (outerRadius + calloutLength);
|
|
let y2 = datum.midSin * (outerRadius + calloutLength);
|
|
const isMoved = label.collisionTextAlign ?? label.collisionOffsetY !== 0;
|
|
if (isMoved && label.box != null) {
|
|
const box = label.box;
|
|
let cx = x2;
|
|
let cy = y2;
|
|
if (x2 < box.x) {
|
|
cx = box.x;
|
|
} else if (x2 > box.x + box.width) {
|
|
cx = box.x + box.width;
|
|
}
|
|
if (y2 < box.y) {
|
|
cy = box.y;
|
|
} else if (y2 > box.y + box.height) {
|
|
cy = box.y + box.height;
|
|
}
|
|
const dx = cx - x2;
|
|
const dy = cy - y2;
|
|
const length = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
|
|
const paddedLength = length - offset;
|
|
if (paddedLength > 0) {
|
|
x2 = x2 + dx * paddedLength / length;
|
|
y2 = y2 + dy * paddedLength / length;
|
|
}
|
|
}
|
|
line.x1 = x1;
|
|
line.y1 = y1;
|
|
line.x2 = x2;
|
|
line.y2 = y2;
|
|
} else {
|
|
line.visible = false;
|
|
}
|
|
}
|
|
}
|
|
getLabelOverflow(box, seriesRect) {
|
|
const seriesLeft = -this.centerX;
|
|
const seriesRight = seriesLeft + seriesRect.width;
|
|
const seriesTop = -this.centerY;
|
|
const seriesBottom = seriesTop + seriesRect.height;
|
|
const errPx = 1;
|
|
let maxWidth = box.width;
|
|
if (box.x + errPx < seriesLeft) {
|
|
maxWidth = (box.x + box.width - seriesLeft) / box.width;
|
|
} else if (box.x + box.width - errPx > seriesRight) {
|
|
maxWidth = (seriesRight - box.x) / box.width;
|
|
}
|
|
const hasVerticalOverflow = box.y + errPx < seriesTop || box.y + box.height - errPx > seriesBottom;
|
|
const hasSurroundingSeriesOverflow = this.bboxIntersectsSurroundingSeries(box);
|
|
return { maxWidth, hasVerticalOverflow, hasSurroundingSeriesOverflow };
|
|
}
|
|
bboxIntersectsSurroundingSeries(box) {
|
|
const { surroundingRadius } = this;
|
|
if (surroundingRadius == null) {
|
|
return false;
|
|
}
|
|
const corners = [
|
|
{ x: box.x, y: box.y },
|
|
{ x: box.x + box.width, y: box.y },
|
|
{ x: box.x + box.width, y: box.y + box.height },
|
|
{ x: box.x, y: box.y + box.height }
|
|
];
|
|
const sur2 = surroundingRadius ** 2;
|
|
return corners.some((corner) => corner.x ** 2 + corner.y ** 2 > sur2);
|
|
}
|
|
computeCalloutLabelCollisionOffsets() {
|
|
const { radiusScale } = this;
|
|
const { calloutLabel } = this.properties;
|
|
const { offset, minSpacing } = calloutLabel;
|
|
const innerRadius = radiusScale.convert(0);
|
|
const shouldSkip = (datum) => {
|
|
const label = datum.calloutLabel;
|
|
return !label || datum.outerRadius === 0;
|
|
};
|
|
const fullData = this.calloutNodeData;
|
|
const data = fullData.filter((t) => !shouldSkip(t));
|
|
for (const datum of data) {
|
|
const label = datum.calloutLabel;
|
|
if (label == null)
|
|
continue;
|
|
label.hidden = false;
|
|
label.collisionTextAlign = void 0;
|
|
label.collisionOffsetY = 0;
|
|
}
|
|
if (data.length <= 1) {
|
|
return;
|
|
}
|
|
const leftLabels = data.filter((d) => d.midCos < 0).sort((a, b) => a.midSin - b.midSin);
|
|
const rightLabels = data.filter((d) => d.midCos >= 0).sort((a, b) => a.midSin - b.midSin);
|
|
const topLabels = data.filter((d) => d.midSin < 0 && d.calloutLabel?.textAlign === "center").sort((a, b) => a.midCos - b.midCos);
|
|
const bottomLabels = data.filter((d) => d.midSin >= 0 && d.calloutLabel?.textAlign === "center").sort((a, b) => a.midCos - b.midCos);
|
|
const getTextBBox = (datum) => {
|
|
const label = datum.calloutLabel;
|
|
if (label == null)
|
|
return BBox.zero.clone();
|
|
const style = this.getLabelStyle(datum, calloutLabel, "calloutLabel");
|
|
const padding2 = expandLabelPadding(style);
|
|
const calloutLength = this.getCalloutLineStyle(datum, false).length;
|
|
const labelRadius = datum.outerRadius + calloutLength + offset;
|
|
const x = datum.midCos * labelRadius;
|
|
const y = datum.midSin * labelRadius + label.collisionOffsetY;
|
|
const textAlign = label.collisionTextAlign ?? label.textAlign;
|
|
const textBaseline = label.textBaseline;
|
|
return Text.measureBBox(label.text, x, y, {
|
|
font: this.properties.calloutLabel,
|
|
textAlign,
|
|
textBaseline
|
|
}).grow(padding2);
|
|
};
|
|
const avoidNeighbourYCollision = (label, next, direction) => {
|
|
const box = getTextBBox(label).grow(minSpacing / 2);
|
|
const other = getTextBBox(next).grow(minSpacing / 2);
|
|
const collidesOrBehind = box.x < other.x + other.width && box.x + box.width > other.x && (direction === "to-top" ? box.y < other.y + other.height : box.y + box.height > other.y);
|
|
if (collidesOrBehind) {
|
|
next.calloutLabel.collisionOffsetY = direction === "to-top" ? box.y - other.y - other.height : box.y + box.height - other.y;
|
|
}
|
|
};
|
|
const avoidYCollisions = (labels) => {
|
|
const midLabel = labels.slice().sort((a, b) => Math.abs(a.midSin) - Math.abs(b.midSin))[0];
|
|
const midIndex = labels.indexOf(midLabel);
|
|
for (let i = midIndex - 1; i >= 0; i--) {
|
|
const prev = labels[i + 1];
|
|
const next = labels[i];
|
|
avoidNeighbourYCollision(prev, next, "to-top");
|
|
}
|
|
for (let i = midIndex + 1; i < labels.length; i++) {
|
|
const prev = labels[i - 1];
|
|
const next = labels[i];
|
|
avoidNeighbourYCollision(prev, next, "to-bottom");
|
|
}
|
|
};
|
|
const avoidXCollisions = (labels) => {
|
|
const labelsCollideLabelsByY = data.some((datum) => datum.calloutLabel.collisionOffsetY !== 0);
|
|
const boxes = labels.map((label) => getTextBBox(label));
|
|
const paddedBoxes = boxes.map((box) => box.clone().grow(minSpacing / 2));
|
|
let labelsCollideLabelsByX = false;
|
|
for (let i = 0; i < paddedBoxes.length && !labelsCollideLabelsByX; i++) {
|
|
const box = paddedBoxes[i];
|
|
for (let j = i + 1; j < labels.length; j++) {
|
|
const other = paddedBoxes[j];
|
|
if (box.collidesBBox(other)) {
|
|
labelsCollideLabelsByX = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
const sectors = fullData.map((datum) => {
|
|
const { startAngle, endAngle, outerRadius } = datum;
|
|
return { startAngle, endAngle, innerRadius, outerRadius };
|
|
});
|
|
const labelsCollideSectors = boxes.some((box) => sectors.some((sector) => boxCollidesSector(box, sector)));
|
|
if (!labelsCollideLabelsByX && !labelsCollideLabelsByY && !labelsCollideSectors)
|
|
return;
|
|
for (const d of labels) {
|
|
if (d.calloutLabel.textAlign !== "center")
|
|
continue;
|
|
const label = d.calloutLabel;
|
|
if (d.midCos < 0) {
|
|
label.collisionTextAlign = "right";
|
|
} else if (d.midCos > 0) {
|
|
label.collisionTextAlign = "left";
|
|
} else {
|
|
label.collisionTextAlign = "center";
|
|
}
|
|
}
|
|
};
|
|
avoidYCollisions(leftLabels);
|
|
avoidYCollisions(rightLabels);
|
|
avoidXCollisions(topLabels);
|
|
avoidXCollisions(bottomLabels);
|
|
}
|
|
getLabelStyle(datum, label, labelPath, isHighlight = false) {
|
|
const activeHighlight = this.ctx.highlightManager?.getActiveHighlight();
|
|
return getLabelStyles(this, datum, this.properties, label, isHighlight, activeHighlight, [
|
|
"series",
|
|
`${this.declarationOrder}`,
|
|
labelPath
|
|
]);
|
|
}
|
|
updateCalloutLabelNodes(seriesRect) {
|
|
const { radiusScale } = this;
|
|
const { calloutLabel } = this.properties;
|
|
const tempTextNode = new Text();
|
|
const highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
const seriesHighlighted = this.isSeriesHighlighted(highlightedDatum);
|
|
for (const text of this.calloutLabelSelection.selectByTag(1 /* CalloutLabel */)) {
|
|
const datum = text.closestDatum();
|
|
const label = datum.calloutLabel;
|
|
const radius = radiusScale.convert(datum.radius);
|
|
const outerRadius = Math.max(0, radius);
|
|
if (!label?.text || outerRadius === 0 || label.hidden) {
|
|
text.visible = false;
|
|
continue;
|
|
}
|
|
const isDatumHighlighted = seriesHighlighted && this.isItemHighlighted(highlightedDatum, datum.datumIndex) === true;
|
|
const style = this.getLabelStyle(datum, calloutLabel, "calloutLabel", isDatumHighlighted);
|
|
const calloutLength = this.getCalloutLineStyle(datum, false).length;
|
|
const labelRadius = outerRadius + calloutLength + calloutLabel.offset;
|
|
const x = datum.midCos * labelRadius;
|
|
const y = datum.midSin * labelRadius + label.collisionOffsetY;
|
|
const align2 = {
|
|
textAlign: label.collisionTextAlign ?? label.textAlign,
|
|
textBaseline: label.textBaseline
|
|
};
|
|
tempTextNode.text = label.text;
|
|
tempTextNode.x = x;
|
|
tempTextNode.y = y;
|
|
tempTextNode.setFont(style);
|
|
tempTextNode.setAlign(align2);
|
|
tempTextNode.setBoxing(style);
|
|
const box = tempTextNode.getBBox();
|
|
let displayText = label.text;
|
|
let visible = true;
|
|
if (calloutLabel.avoidCollisions) {
|
|
const { maxWidth, hasVerticalOverflow } = this.getLabelOverflow(box, seriesRect);
|
|
if (box.width > maxWidth) {
|
|
const options = {
|
|
font: this.properties.calloutLabel,
|
|
textWrap: "on-space",
|
|
overflow: "hide",
|
|
maxWidth
|
|
};
|
|
displayText = (0, import_ag_charts_core269.wrapTextOrSegments)(label.text, options);
|
|
}
|
|
visible = !hasVerticalOverflow;
|
|
}
|
|
text.text = displayText;
|
|
text.x = x;
|
|
text.y = y;
|
|
text.setFont(style);
|
|
text.setAlign(align2);
|
|
text.setBoxing(style);
|
|
text.fill = style.color;
|
|
text.fillOpacity = this.getHighlightStyle(isDatumHighlighted, datum.datumIndex).opacity ?? 1;
|
|
text.visible = visible;
|
|
}
|
|
}
|
|
computeLabelsBBox(options, seriesRect) {
|
|
const { calloutLabel } = this.properties;
|
|
const { offset, maxCollisionOffset, minSpacing } = calloutLabel;
|
|
if (!calloutLabel.avoidCollisions) {
|
|
return null;
|
|
}
|
|
this.maybeRefreshNodeData();
|
|
this.updateRadiusScale(false);
|
|
this.computeCalloutLabelCollisionOffsets();
|
|
const textBoxes = [];
|
|
const text = new Text();
|
|
let titleBox = void 0;
|
|
const { title } = this.properties;
|
|
if (title?.text && title.enabled) {
|
|
const dy = this.getTitleTranslationY();
|
|
if (Number.isFinite(dy)) {
|
|
text.text = title.text;
|
|
text.x = 0;
|
|
text.y = dy;
|
|
text.setFont(title);
|
|
text.setAlign({
|
|
textBaseline: "bottom",
|
|
textAlign: "center"
|
|
});
|
|
titleBox = text.getBBox();
|
|
textBoxes.push(titleBox);
|
|
}
|
|
}
|
|
for (const datum of this.calloutNodeData) {
|
|
const label = datum.calloutLabel;
|
|
if (!label || datum.outerRadius === 0) {
|
|
continue;
|
|
}
|
|
const style = this.getLabelStyle(datum, calloutLabel, "calloutLabel");
|
|
const calloutLength = this.getCalloutLineStyle(datum, false).length;
|
|
const labelRadius = datum.outerRadius + calloutLength + offset;
|
|
const x = datum.midCos * labelRadius;
|
|
const y = datum.midSin * labelRadius + label.collisionOffsetY;
|
|
text.text = label.text;
|
|
text.x = x;
|
|
text.y = y;
|
|
text.setFont(style);
|
|
text.setAlign({
|
|
textAlign: label.collisionTextAlign ?? label.textAlign,
|
|
textBaseline: label.textBaseline
|
|
});
|
|
text.setBoxing(style);
|
|
const box = text.getBBox();
|
|
label.box = box;
|
|
if (Math.abs(label.collisionOffsetY) > maxCollisionOffset) {
|
|
label.hidden = true;
|
|
continue;
|
|
}
|
|
if (titleBox) {
|
|
const seriesTop = -this.centerY;
|
|
const titleCleanArea = new BBox(
|
|
titleBox.x - minSpacing,
|
|
seriesTop,
|
|
titleBox.width + 2 * minSpacing,
|
|
titleBox.y + titleBox.height + minSpacing - seriesTop
|
|
);
|
|
if (box.collidesBBox(titleCleanArea)) {
|
|
label.hidden = true;
|
|
continue;
|
|
}
|
|
}
|
|
if (options.hideWhenNecessary) {
|
|
const { maxWidth, hasVerticalOverflow, hasSurroundingSeriesOverflow } = this.getLabelOverflow(
|
|
box,
|
|
seriesRect
|
|
);
|
|
const isTooShort = box.width > maxWidth;
|
|
if (hasVerticalOverflow || isTooShort || hasSurroundingSeriesOverflow) {
|
|
label.hidden = true;
|
|
continue;
|
|
}
|
|
}
|
|
label.hidden = false;
|
|
textBoxes.push(box);
|
|
}
|
|
if (textBoxes.length === 0) {
|
|
return null;
|
|
}
|
|
return BBox.merge(textBoxes);
|
|
}
|
|
updateSectorLabelNodes() {
|
|
const { properties } = this;
|
|
const { positionOffset, positionRatio } = this.properties.sectorLabel;
|
|
const highlightedDatum = this.ctx.highlightManager?.getActiveHighlight();
|
|
const seriesHighlighted = this.isSeriesHighlighted(highlightedDatum);
|
|
const innerRadius = this.radiusScale.convert(0);
|
|
const shouldPutTextInCenter = innerRadius <= 0 && // is donut?
|
|
this.ctx.legendManager.getData(this.id)?.filter((d) => d.enabled).length === 1;
|
|
const align2 = { textAlign: "center", textBaseline: "middle" };
|
|
const updateSelection = (selection) => selection.each((text, datum) => {
|
|
const { outerRadius, startAngle, endAngle } = datum;
|
|
const isDatumHighlighted = seriesHighlighted && this.isItemHighlighted(highlightedDatum, datum.datumIndex) === true;
|
|
let isTextVisible = false;
|
|
if (datum.sectorLabel && outerRadius !== 0) {
|
|
const style = this.getLabelStyle(datum, properties.sectorLabel, "sectorLabel", isDatumHighlighted);
|
|
const labelRadius = innerRadius * (1 - positionRatio) + outerRadius * positionRatio + positionOffset;
|
|
text.fill = style.color;
|
|
text.fillOpacity = this.getHighlightStyle(isDatumHighlighted, datum.datumIndex).opacity ?? 1;
|
|
text.text = datum.sectorLabel.text;
|
|
if (shouldPutTextInCenter) {
|
|
text.x = 0;
|
|
text.y = 0;
|
|
} else {
|
|
text.x = datum.midCos * labelRadius;
|
|
text.y = datum.midSin * labelRadius;
|
|
}
|
|
text.setFont(style);
|
|
text.setAlign(align2);
|
|
text.setBoxing(style);
|
|
const bbox = text.getBBox();
|
|
const corners = [
|
|
[bbox.x, bbox.y],
|
|
[bbox.x + bbox.width, bbox.y],
|
|
[bbox.x + bbox.width, bbox.y + bbox.height],
|
|
[bbox.x, bbox.y + bbox.height]
|
|
];
|
|
const sectorBounds = { startAngle, endAngle, innerRadius, outerRadius };
|
|
if (corners.every(([x, y]) => isPointInSector(x, y, sectorBounds))) {
|
|
isTextVisible = true;
|
|
}
|
|
}
|
|
text.visible = isTextVisible;
|
|
});
|
|
updateSelection(this.labelSelection);
|
|
updateSelection(this.highlightLabelSelection);
|
|
}
|
|
updateInnerLabelNodes() {
|
|
const textBBoxes = [];
|
|
const margins = [];
|
|
this.innerLabelsSelection.each((text, datum) => {
|
|
const { fontStyle, fontWeight: fontWeight2, fontSize, fontFamily, color: color8 } = datum;
|
|
text.fontStyle = fontStyle;
|
|
text.fontWeight = fontWeight2;
|
|
text.fontSize = fontSize;
|
|
text.fontFamily = fontFamily;
|
|
text.text = datum.text;
|
|
text.x = 0;
|
|
text.y = 0;
|
|
text.fill = color8;
|
|
text.textAlign = "center";
|
|
textBBoxes.push(text.getBBox());
|
|
margins.push(datum.spacing);
|
|
});
|
|
const getMarginTop = (index) => index === 0 ? 0 : margins[index];
|
|
const getMarginBottom = (index) => index === margins.length - 1 ? 0 : margins[index];
|
|
const totalWidth = textBBoxes.reduce((max, bbox) => Math.max(max, bbox.width), 0);
|
|
const totalHeight = textBBoxes.reduce(
|
|
(sum, bbox, i) => sum + bbox.height + getMarginTop(i) + getMarginBottom(i),
|
|
0
|
|
);
|
|
const innerRadius = this.getInnerRadius();
|
|
const labelRadius = Math.sqrt(Math.pow(totalWidth / 2, 2) + Math.pow(totalHeight / 2, 2));
|
|
const labelsVisible = labelRadius <= (innerRadius > 0 ? innerRadius : this.getOuterRadius());
|
|
const textBottoms = [];
|
|
for (let i = 0, prev = -totalHeight / 2; i < textBBoxes.length; i++) {
|
|
const bbox = textBBoxes[i];
|
|
const bottom = bbox.height + prev + getMarginTop(i);
|
|
textBottoms.push(bottom);
|
|
prev = bottom + getMarginBottom(i);
|
|
}
|
|
this.innerLabelsSelection.each((text, _datum, index) => {
|
|
text.visible = labelsVisible;
|
|
if (Array.isArray(text.text)) {
|
|
text.y = textBottoms[index] - textBBoxes[index].height;
|
|
} else {
|
|
text.y = textBottoms[index];
|
|
}
|
|
});
|
|
}
|
|
updateZerosumRings() {
|
|
this.zerosumOuterRing.size = this.getOuterRadius() * 2;
|
|
this.zerosumInnerRing.size = this.getInnerRadius() * 2;
|
|
}
|
|
pickNodeClosestDatum(point) {
|
|
return pickByMatchingAngle(this, point);
|
|
}
|
|
getTooltipContent(datumIndex) {
|
|
const {
|
|
id: seriesId,
|
|
dataModel,
|
|
processedData,
|
|
properties,
|
|
ctx: { formatManager }
|
|
} = this;
|
|
const {
|
|
legendItemKey,
|
|
calloutLabelKey,
|
|
calloutLabelName,
|
|
sectorLabelKey,
|
|
sectorLabelName,
|
|
angleKey,
|
|
angleName,
|
|
radiusKey,
|
|
radiusName,
|
|
tooltip
|
|
} = properties;
|
|
const title = this.properties.title.node.getPlainText();
|
|
if (!dataModel || !processedData)
|
|
return;
|
|
const datum = processedData.dataSources.get(this.id)?.data?.[datumIndex];
|
|
const processedDataValues = this.getProcessedDataValues(dataModel, processedData);
|
|
const { angleRawValues } = processedDataValues;
|
|
const angleRawValue = angleRawValues[datumIndex];
|
|
const labelValues = this.getLabelContent(datumIndex, datum, processedDataValues);
|
|
const label = labelValues.legendItem ?? labelValues.callout ?? labelValues.sector ?? angleName;
|
|
const domain = (0, import_ag_charts_core269.extractDomain)(dataModel.getDomain(this, `angleRaw`, "value", processedData));
|
|
const angleContent = formatManager.format(this.callWithContext.bind(this), {
|
|
type: "number",
|
|
value: angleRawValue,
|
|
datum,
|
|
seriesId,
|
|
legendItemName: void 0,
|
|
key: angleKey,
|
|
source: "tooltip",
|
|
property: "angle",
|
|
domain,
|
|
boundSeries: this.getFormatterContext("angle"),
|
|
fractionDigits: void 0,
|
|
visibleDomain: void 0
|
|
}) ?? (0, import_ag_charts_core269.formatValue)(angleRawValue, 3);
|
|
return this.formatTooltipWithContext(
|
|
tooltip,
|
|
{
|
|
title,
|
|
symbol: this.legendItemSymbol(datumIndex),
|
|
data: [{ label: (0, import_ag_charts_core269.toPlainText)(label), fallbackLabel: angleKey, value: angleContent }]
|
|
},
|
|
{
|
|
seriesId,
|
|
datum,
|
|
title: angleName,
|
|
legendItemKey,
|
|
calloutLabelKey,
|
|
calloutLabelName,
|
|
sectorLabelKey,
|
|
sectorLabelName,
|
|
angleKey,
|
|
angleName,
|
|
radiusKey,
|
|
radiusName,
|
|
...this.getItemStyle({ datum, datumIndex }, false)
|
|
}
|
|
);
|
|
}
|
|
legendItemSymbol(datumIndex) {
|
|
const datum = this.processedData?.dataSources.get(this.id)?.data?.[datumIndex];
|
|
const sectorFormat = this.getItemStyle({ datum, datumIndex }, false);
|
|
const { fillOpacity, strokeOpacity, strokeWidth, lineDash, lineDashOffset } = this.properties;
|
|
let { fill } = sectorFormat;
|
|
const { stroke } = sectorFormat;
|
|
if ((0, import_ag_charts_core269.isGradientFill)(fill)) {
|
|
fill = { ...fill, gradient: "linear", rotation: 0, reverse: false };
|
|
}
|
|
return {
|
|
marker: {
|
|
fill,
|
|
stroke,
|
|
fillOpacity,
|
|
strokeOpacity,
|
|
strokeWidth,
|
|
lineDash,
|
|
lineDashOffset
|
|
}
|
|
};
|
|
}
|
|
getLegendData(legendType) {
|
|
const {
|
|
visible,
|
|
processedData,
|
|
dataModel,
|
|
id: seriesId,
|
|
ctx: { legendManager }
|
|
} = this;
|
|
if (!dataModel || !processedData || legendType !== "category") {
|
|
return [];
|
|
}
|
|
const { angleKey, calloutLabelKey, sectorLabelKey, legendItemKey, showInLegend } = this.properties;
|
|
if (!legendItemKey && (!calloutLabelKey || calloutLabelKey === angleKey) && (!sectorLabelKey || sectorLabelKey === angleKey)) {
|
|
return [];
|
|
}
|
|
const processedDataValues = this.getProcessedDataValues(dataModel, processedData);
|
|
const { angleRawValues } = processedDataValues;
|
|
const titleText = this.properties.title?.showInLegend && this.properties.title.text;
|
|
const legendData = [];
|
|
const hideZeros = this.properties.hideZeroValueSectorsInLegend;
|
|
const rawData = processedData.dataSources.get(this.id)?.data;
|
|
const invalidData = processedData.invalidData?.get(this.id);
|
|
for (let datumIndex = 0; datumIndex < processedData.input.count; datumIndex++) {
|
|
const datum = rawData?.[datumIndex];
|
|
const angleRawValue = angleRawValues[datumIndex];
|
|
if (invalidData?.[datumIndex] === true || hideZeros && angleRawValue === 0) {
|
|
continue;
|
|
}
|
|
const labelParts = [];
|
|
if (titleText) {
|
|
labelParts.push(titleText);
|
|
}
|
|
const labels = this.getLabelContent(datumIndex, datum, processedDataValues);
|
|
if (legendItemKey && labels.legendItem !== void 0) {
|
|
labelParts.push(labels.legendItem);
|
|
} else if (calloutLabelKey && calloutLabelKey !== angleKey && labels.callout !== void 0) {
|
|
labelParts.push(labels.callout);
|
|
} else if (sectorLabelKey && sectorLabelKey !== angleKey && labels.sector !== void 0) {
|
|
labelParts.push(labels.sector);
|
|
}
|
|
if (labelParts.length === 0)
|
|
continue;
|
|
legendData.push({
|
|
legendType: "category",
|
|
id: seriesId,
|
|
datum,
|
|
itemId: datumIndex,
|
|
seriesId,
|
|
hideToggleOtherSeries: true,
|
|
enabled: visible && legendManager.getItemEnabled({ seriesId, itemId: datumIndex }),
|
|
label: {
|
|
text: labelParts.map((s) => (0, import_ag_charts_core269.toPlainText)(s)).join(" - ")
|
|
},
|
|
symbol: this.legendItemSymbol(datumIndex),
|
|
legendItemName: legendItemKey == null ? void 0 : datum[legendItemKey],
|
|
hideInLegend: !showInLegend
|
|
});
|
|
}
|
|
return legendData;
|
|
}
|
|
// Used for grid
|
|
setLegendState(enabledItems) {
|
|
const {
|
|
id: seriesId,
|
|
ctx: { legendManager, updateService }
|
|
} = this;
|
|
for (const [itemId, enabled] of enabledItems.entries()) {
|
|
legendManager.toggleItem(enabled, seriesId, itemId);
|
|
}
|
|
legendManager.update();
|
|
updateService.update(import_ag_charts_core269.ChartUpdateType.SERIES_UPDATE);
|
|
}
|
|
animateEmptyUpdateReady(_data) {
|
|
const { animationManager } = this.ctx;
|
|
const fns = preparePieSeriesAnimationFunctions(
|
|
true,
|
|
this.properties.rotation,
|
|
this.radiusScale,
|
|
this.previousRadiusScale
|
|
);
|
|
fromToMotion(
|
|
this.id,
|
|
"nodes",
|
|
animationManager,
|
|
[this.itemSelection, this.highlightSelection, this.phantomSelection, this.phantomHighlightSelection],
|
|
fns.nodes,
|
|
(_, datum) => this.getDatumId(datum.datumIndex)
|
|
);
|
|
fromToMotion(this.id, `innerCircle`, animationManager, [this.innerCircleSelection], fns.innerCircle);
|
|
seriesLabelFadeInAnimation(this, "callout", animationManager, this.calloutLabelSelection);
|
|
seriesLabelFadeInAnimation(this, "sector", animationManager, this.labelSelection, this.highlightLabelSelection);
|
|
seriesLabelFadeInAnimation(this, "inner", animationManager, this.innerLabelsSelection);
|
|
this.previousRadiusScale.range = this.radiusScale.range;
|
|
}
|
|
animateWaitingUpdateReady() {
|
|
const {
|
|
itemSelection,
|
|
highlightSelection,
|
|
phantomSelection,
|
|
phantomHighlightSelection,
|
|
processedData,
|
|
radiusScale,
|
|
previousRadiusScale
|
|
} = this;
|
|
const { animationManager } = this.ctx;
|
|
const dataDiff = processedData?.reduced?.diff?.[this.id];
|
|
this.ctx.animationManager.stopByAnimationGroupId(this.id);
|
|
const supportedDiff = (dataDiff?.moved.size ?? 0) === 0;
|
|
const hasKeys = (processedData?.defs.keys.length ?? 0) > 0;
|
|
const hasUniqueKeys = processedData?.reduced?.animationValidation?.uniqueKeys ?? true;
|
|
if (!supportedDiff || !hasKeys || !hasUniqueKeys) {
|
|
this.ctx.animationManager.skipCurrentBatch();
|
|
}
|
|
const noVisibleData = !this.nodeData.some((n) => n.enabled);
|
|
const fns = preparePieSeriesAnimationFunctions(
|
|
false,
|
|
this.properties.rotation,
|
|
radiusScale,
|
|
previousRadiusScale
|
|
);
|
|
fromToMotion(
|
|
this.id,
|
|
"nodes",
|
|
animationManager,
|
|
[itemSelection, highlightSelection, phantomSelection, phantomHighlightSelection],
|
|
fns.nodes,
|
|
(_, datum) => this.getDatumId(datum.datumIndex),
|
|
dataDiff
|
|
);
|
|
fromToMotion(this.id, `innerCircle`, animationManager, [this.innerCircleSelection], fns.innerCircle);
|
|
seriesLabelFadeInAnimation(this, "callout", this.ctx.animationManager, this.calloutLabelSelection);
|
|
seriesLabelFadeInAnimation(
|
|
this,
|
|
"sector",
|
|
this.ctx.animationManager,
|
|
this.labelSelection,
|
|
this.highlightLabelSelection
|
|
);
|
|
if (this.noVisibleData !== noVisibleData) {
|
|
this.noVisibleData = noVisibleData;
|
|
seriesLabelFadeInAnimation(this, "inner", this.ctx.animationManager, this.innerLabelsSelection);
|
|
}
|
|
this.previousRadiusScale.range = this.radiusScale.range;
|
|
}
|
|
animateClearingUpdateEmpty() {
|
|
const {
|
|
itemSelection,
|
|
highlightSelection,
|
|
phantomSelection,
|
|
phantomHighlightSelection,
|
|
radiusScale,
|
|
previousRadiusScale
|
|
} = this;
|
|
const { animationManager } = this.ctx;
|
|
const fns = preparePieSeriesAnimationFunctions(
|
|
false,
|
|
this.properties.rotation,
|
|
radiusScale,
|
|
previousRadiusScale
|
|
);
|
|
fromToMotion(
|
|
this.id,
|
|
"nodes",
|
|
animationManager,
|
|
[itemSelection, highlightSelection, phantomSelection, phantomHighlightSelection],
|
|
fns.nodes,
|
|
(_, datum) => this.getDatumId(datum.datumIndex)
|
|
);
|
|
fromToMotion(this.id, `innerCircle`, animationManager, [this.innerCircleSelection], fns.innerCircle);
|
|
seriesLabelFadeOutAnimation(this, "callout", this.ctx.animationManager, this.calloutLabelSelection);
|
|
seriesLabelFadeOutAnimation(
|
|
this,
|
|
"sector",
|
|
this.ctx.animationManager,
|
|
this.labelSelection,
|
|
this.highlightLabelSelection
|
|
);
|
|
seriesLabelFadeOutAnimation(this, "inner", this.ctx.animationManager, this.innerLabelsSelection);
|
|
this.previousRadiusScale.range = this.radiusScale.range;
|
|
}
|
|
getDatumId(datumIndex) {
|
|
const { dataModel, processedData } = this;
|
|
if (!dataModel || !processedData) {
|
|
return `${datumIndex}`;
|
|
}
|
|
const { calloutLabelKey, sectorLabelKey, legendItemKey } = this.properties;
|
|
if (!processedData.reduced?.animationValidation?.uniqueKeys) {
|
|
return `${datumIndex}`;
|
|
}
|
|
if (legendItemKey) {
|
|
const legendItemKeys = dataModel.resolveKeysById(this, "legendItemKey", processedData);
|
|
return createDatumId(legendItemKeys[datumIndex]);
|
|
} else if (calloutLabelKey) {
|
|
const calloutLabelKeys = dataModel.resolveKeysById(this, "calloutLabelKey", processedData);
|
|
return createDatumId(calloutLabelKeys[datumIndex]);
|
|
} else if (sectorLabelKey) {
|
|
const sectorLabelKeys = dataModel.resolveKeysById(this, "sectorLabelKey", processedData);
|
|
return createDatumId(sectorLabelKeys[datumIndex]);
|
|
}
|
|
return `${datumIndex}`;
|
|
}
|
|
hasItemStylers() {
|
|
return !(this.properties.itemStyler == null && this.properties.calloutLabel.itemStyler == null && this.properties.sectorLabel.itemStyler == null && this.properties.innerLabels.every((innerLabel) => innerLabel.itemStyler == null));
|
|
}
|
|
};
|
|
DonutSeries.className = "DonutSeries";
|
|
DonutSeries.type = "donut";
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/donutTheme.ts
|
|
var import_ag_charts_core271 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/pieTheme.ts
|
|
var import_ag_charts_core270 = require("ag-charts-core");
|
|
var pieTheme = {
|
|
series: {
|
|
title: {
|
|
enabled: true,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $rem: import_ag_charts_core270.FONT_SIZE_RATIO.LARGE },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "subtleTextColor" },
|
|
spacing: 5
|
|
},
|
|
calloutLabel: {
|
|
...import_ag_charts_core270.LABEL_BOXING_DEFAULTS,
|
|
enabled: true,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" },
|
|
offset: 3,
|
|
minAngle: 1e-3
|
|
},
|
|
sectorLabel: {
|
|
...import_ag_charts_core270.LABEL_BOXING_DEFAULTS,
|
|
enabled: true,
|
|
fontWeight: { $ref: "fontWeight" },
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
color: { $ref: "chartBackgroundColor" },
|
|
positionOffset: 0,
|
|
positionRatio: 0.5
|
|
},
|
|
calloutLine: {
|
|
length: 10,
|
|
strokeWidth: 2,
|
|
colors: {
|
|
$map: [
|
|
{
|
|
$if: [
|
|
{
|
|
$or: [
|
|
{ $isGradient: { $value: "$1" } },
|
|
{ $isPattern: { $value: "$1" } },
|
|
{ $isImage: { $value: "$1" } }
|
|
]
|
|
},
|
|
{ $path: ["../../strokes/$index", { $ref: "foregroundColor" }] },
|
|
{ $value: "$1" }
|
|
]
|
|
},
|
|
{
|
|
$if: [
|
|
{ $eq: [{ $path: "../strokeWidth" }, 0] },
|
|
{ $path: "../fills" },
|
|
{ $path: "../strokes" }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
fills: {
|
|
$applyCycle: [
|
|
{ $cacheMax: { $size: { $path: ["./data", { $path: "/data" }] } } },
|
|
{ $palette: "fills" },
|
|
{
|
|
$applySwitch: [
|
|
{ $path: ["/type", void 0, { $value: "$1" }] },
|
|
{ $value: "$1" },
|
|
["gradient", import_ag_charts_core270.FILL_GRADIENT_RADIAL_REVERSED_SERIES_DEFAULTS],
|
|
["pattern", import_ag_charts_core270.FILL_PATTERN_DEFAULTS],
|
|
["image", import_ag_charts_core270.FILL_IMAGE_DEFAULTS]
|
|
]
|
|
}
|
|
]
|
|
},
|
|
strokes: {
|
|
$applyCycle: [{ $cacheMax: { $size: { $path: ["./data", { $path: "/data" }] } } }, { $palette: "strokes" }]
|
|
},
|
|
fillOpacity: 1,
|
|
strokeOpacity: 1,
|
|
strokeWidth: { $isUserOption: ["./strokes/0", 2, 0] },
|
|
lineDash: [0],
|
|
lineDashOffset: 0,
|
|
rotation: 0,
|
|
sectorSpacing: 1,
|
|
shadow: {
|
|
enabled: false,
|
|
color: import_ag_charts_core270.DEFAULT_SHADOW_COLOUR,
|
|
xOffset: 3,
|
|
yOffset: 3,
|
|
blur: 5
|
|
},
|
|
highlight: import_ag_charts_core270.PART_WHOLE_HIGHLIGHT_STYLE
|
|
},
|
|
legend: { enabled: true }
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/donutTheme.ts
|
|
var donutTheme = {
|
|
...pieTheme,
|
|
series: {
|
|
...pieTheme.series,
|
|
innerRadiusRatio: {
|
|
$if: [{ $eq: [{ $path: ["./innerRadiusOffset", void 0] }, void 0] }, 0.7, void 0]
|
|
},
|
|
innerLabels: {
|
|
$apply: {
|
|
...import_ag_charts_core271.LABEL_BOXING_DEFAULTS,
|
|
fontSize: { $ref: "fontSize" },
|
|
fontFamily: { $ref: "fontFamily" },
|
|
fontWeight: { $ref: "fontWeight" },
|
|
color: { $ref: "textColor" },
|
|
spacing: 2
|
|
}
|
|
},
|
|
highlight: import_ag_charts_core271.PART_WHOLE_HIGHLIGHT_STYLE
|
|
}
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/donutSeriesModule.ts
|
|
var DonutSeriesModule = {
|
|
type: "series",
|
|
name: "donut",
|
|
chartType: "polar",
|
|
version: VERSION,
|
|
dependencies: [PolarChartModule],
|
|
options: donutSeriesOptionsDef,
|
|
themeTemplate: donutTheme,
|
|
create: (ctx) => new DonutSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/pieSeries.ts
|
|
var PieSeries = class extends DonutSeries {
|
|
};
|
|
PieSeries.className = "PieSeries";
|
|
PieSeries.type = "pie";
|
|
|
|
// packages/ag-charts-community/src/chart/series/polar/pieSeriesModule.ts
|
|
var PieSeriesModule = {
|
|
type: "series",
|
|
name: "pie",
|
|
chartType: "polar",
|
|
version: VERSION,
|
|
dependencies: [PolarChartModule],
|
|
options: pieSeriesOptionsDef,
|
|
themeTemplate: pieTheme,
|
|
create: (ctx) => new PieSeries(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/locale/localeModule.ts
|
|
var import_ag_charts_core273 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/locale/locale.ts
|
|
var import_ag_charts_core272 = require("ag-charts-core");
|
|
var Locale = class extends import_ag_charts_core272.AbstractModuleInstance {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.localeText = void 0;
|
|
}
|
|
};
|
|
__decorateClass([
|
|
(0, import_ag_charts_core272.ObserveChanges)((target) => {
|
|
target.ctx.localeManager.setLocaleText(target.localeText);
|
|
}),
|
|
import_ag_charts_core272.Property
|
|
], Locale.prototype, "localeText", 2);
|
|
__decorateClass([
|
|
(0, import_ag_charts_core272.ObserveChanges)((target) => {
|
|
target.ctx.localeManager.setLocaleTextFormatter(target.getLocaleText);
|
|
}),
|
|
import_ag_charts_core272.Property
|
|
], Locale.prototype, "getLocaleText", 2);
|
|
|
|
// packages/ag-charts-community/src/locale/localeModule.ts
|
|
var LocaleModule = {
|
|
type: "plugin",
|
|
name: "locale",
|
|
version: VERSION,
|
|
options: {
|
|
localeText: import_ag_charts_core273.object,
|
|
getLocaleText: (0, import_ag_charts_core273.callbackOf)(import_ag_charts_core273.string)
|
|
},
|
|
create: (ctx) => new Locale(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/module/axis-modules/numberAxisModule.ts
|
|
var import_ag_charts_core274 = require("ag-charts-core");
|
|
var NumberAxisModule = {
|
|
type: "axis",
|
|
name: "number",
|
|
chartType: "cartesian",
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: numberAxisOptionsDefs,
|
|
themeTemplate: {
|
|
line: { enabled: false }
|
|
},
|
|
create: (ctx) => new NumberAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/module/axis-modules/logAxisModule.ts
|
|
var import_ag_charts_core275 = require("ag-charts-core");
|
|
var LogAxisModule = {
|
|
type: "axis",
|
|
name: "log",
|
|
chartType: "cartesian",
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: logAxisOptionsDefs,
|
|
themeTemplate: {
|
|
base: 10,
|
|
line: { enabled: false }
|
|
},
|
|
create: (ctx) => new LogAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/module/axis-modules/timeAxisModule.ts
|
|
var import_ag_charts_core276 = require("ag-charts-core");
|
|
var TimeAxisModule = {
|
|
type: "axis",
|
|
name: "time",
|
|
chartType: "cartesian",
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: timeAxisOptionsDefs,
|
|
themeTemplate: {
|
|
gridLine: { enabled: false }
|
|
},
|
|
create: (ctx) => new TimeAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/module/axis-modules/categoryAxisModule.ts
|
|
var import_ag_charts_core277 = require("ag-charts-core");
|
|
var CategoryAxisModule = {
|
|
type: "axis",
|
|
name: "category",
|
|
chartType: "cartesian",
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: categoryAxisOptionsDefs,
|
|
themeTemplate: {
|
|
groupPaddingInner: 0.1,
|
|
label: { autoRotate: true, wrapping: "on-space" },
|
|
gridLine: { enabled: false },
|
|
interval: { placement: "between" }
|
|
},
|
|
create: (ctx) => new CategoryAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/module/axis-modules/groupedCategoryAxisModule.ts
|
|
var import_ag_charts_core278 = require("ag-charts-core");
|
|
var GroupedCategoryAxisModule = {
|
|
type: "axis",
|
|
name: "grouped-category",
|
|
chartType: "cartesian",
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: groupedCategoryAxisOptionsDefs,
|
|
themeTemplate: {
|
|
tick: { enabled: true, stroke: { $ref: "separationLinesColor" } },
|
|
label: { spacing: 10, rotation: 270, wrapping: "on-space" },
|
|
maxThicknessRatio: 0.5,
|
|
paddingInner: 0.4,
|
|
groupPaddingInner: 0.2
|
|
},
|
|
create: (ctx) => new GroupedCategoryAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/module/axis-modules/unitTimeAxisModule.ts
|
|
var import_ag_charts_core280 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/chart/axis/unitTimeAxis.ts
|
|
var import_ag_charts_core279 = require("ag-charts-core");
|
|
var UnitTimeAxis = class extends DiscreteTimeAxis {
|
|
constructor(moduleCtx) {
|
|
super(moduleCtx, new UnitTimeScale(), false);
|
|
this.parentLevel = new TimeAxisParentLevel();
|
|
this.min = void 0;
|
|
this.max = void 0;
|
|
this.preferredMin = void 0;
|
|
this.preferredMax = void 0;
|
|
// eslint-disable-next-line sonarjs/use-type-alias
|
|
this.unit = void 0;
|
|
this.defaultUnit = void 0;
|
|
}
|
|
get primaryLabel() {
|
|
return this.parentLevel.enabled ? this.parentLevel.label : void 0;
|
|
}
|
|
get primaryTick() {
|
|
return this.parentLevel.enabled ? this.parentLevel.tick : void 0;
|
|
}
|
|
hasDefinedDomain() {
|
|
const { min, max } = this;
|
|
return min != null && max != null && min < max;
|
|
}
|
|
isCategoryLike() {
|
|
return true;
|
|
}
|
|
processData() {
|
|
super.processData();
|
|
let defaultUnit;
|
|
const { domain } = this.dataDomain;
|
|
if (domain.length === 2 && domain[0].valueOf() === domain[1].valueOf()) {
|
|
defaultUnit = (0, import_ag_charts_core279.lowestGranularityUnitForValue)(domain[0]);
|
|
} else {
|
|
const { boundSeries, direction, min, max } = this;
|
|
defaultUnit = calculateDefaultUnit(boundSeries, direction, min, max);
|
|
}
|
|
if (!(0, import_ag_charts_core279.objectsEqual)(this.defaultUnit, defaultUnit)) {
|
|
this.defaultUnit = defaultUnit;
|
|
}
|
|
}
|
|
updateScale() {
|
|
super.updateScale();
|
|
this.scale.interval = this.unit ?? this.defaultUnit;
|
|
}
|
|
normaliseDataDomain(d) {
|
|
const { extent: extent6, clipped } = (0, import_ag_charts_core279.normalisedTimeExtentWithMetadata)(
|
|
d,
|
|
this.min,
|
|
this.max,
|
|
this.preferredMin,
|
|
this.preferredMax
|
|
);
|
|
return { domain: extent6, clipped };
|
|
}
|
|
tickFormatParams(domain, ticks, _fractionDigits, timeInterval2) {
|
|
timeInterval2 ?? (timeInterval2 = (0, import_ag_charts_core279.lowestGranularityUnitForTicks)(ticks));
|
|
const truncateDate = (0, import_ag_charts_core279.dateTruncationForDomain)(domain);
|
|
const unit = (0, import_ag_charts_core279.intervalUnit)(timeInterval2);
|
|
const step = (0, import_ag_charts_core279.intervalStep)(timeInterval2);
|
|
const epoch = (0, import_ag_charts_core279.intervalEpoch)(timeInterval2);
|
|
return { type: "date", unit, step, epoch, truncateDate };
|
|
}
|
|
datumFormatParams(value, params, _fractionDigits, timeInterval2, style) {
|
|
const interval = this.unit ?? this.defaultUnit ?? "millisecond";
|
|
timeInterval2 ?? (timeInterval2 = interval);
|
|
const { datum, seriesId, legendItemName, key, source, property, domain, boundSeries } = params;
|
|
const unit = (0, import_ag_charts_core279.intervalUnit)(timeInterval2);
|
|
const step = (0, import_ag_charts_core279.intervalStep)(timeInterval2);
|
|
const epoch = (0, import_ag_charts_core279.intervalEpoch)(timeInterval2);
|
|
return {
|
|
type: "date",
|
|
value: (0, import_ag_charts_core279.intervalFloor)(interval, value),
|
|
datum,
|
|
seriesId,
|
|
legendItemName,
|
|
key,
|
|
source,
|
|
property,
|
|
domain,
|
|
boundSeries,
|
|
unit,
|
|
step,
|
|
epoch,
|
|
style
|
|
};
|
|
}
|
|
};
|
|
UnitTimeAxis.className = "UnitTimeAxis";
|
|
UnitTimeAxis.type = "unit-time";
|
|
__decorateClass([
|
|
import_ag_charts_core279.Property
|
|
], UnitTimeAxis.prototype, "parentLevel", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core279.Property
|
|
], UnitTimeAxis.prototype, "min", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core279.Property
|
|
], UnitTimeAxis.prototype, "max", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core279.Property
|
|
], UnitTimeAxis.prototype, "preferredMin", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core279.Property
|
|
], UnitTimeAxis.prototype, "preferredMax", 2);
|
|
__decorateClass([
|
|
import_ag_charts_core279.Property
|
|
], UnitTimeAxis.prototype, "unit", 2);
|
|
|
|
// packages/ag-charts-community/src/module/axis-modules/unitTimeAxisModule.ts
|
|
var UnitTimeAxisModule = {
|
|
type: "axis",
|
|
name: "unit-time",
|
|
chartType: "cartesian",
|
|
version: VERSION,
|
|
dependencies: [CartesianChartModule],
|
|
options: unitTimeAxisOptionsDefs,
|
|
themeTemplate: {
|
|
groupPaddingInner: 0.1,
|
|
label: { autoRotate: false },
|
|
gridLine: { enabled: false },
|
|
parentLevel: { enabled: true },
|
|
interval: { placement: "between" }
|
|
},
|
|
create: (ctx) => new UnitTimeAxis(ctx)
|
|
};
|
|
|
|
// packages/ag-charts-community/src/module-bundles/all.ts
|
|
var import_ag_charts_core281 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/module-bundles/cartesian-axes.ts
|
|
var AllCartesianAxesModule = [
|
|
NumberAxisModule,
|
|
LogAxisModule,
|
|
TimeAxisModule,
|
|
CategoryAxisModule,
|
|
GroupedCategoryAxisModule,
|
|
UnitTimeAxisModule
|
|
];
|
|
|
|
// packages/ag-charts-community/src/module-bundles/cartesian-series.ts
|
|
var AllCartesianSeriesModule = [
|
|
AreaSeriesModule,
|
|
BarSeriesModule,
|
|
BubbleSeriesModule,
|
|
HistogramSeriesModule,
|
|
LineSeriesModule,
|
|
ScatterSeriesModule
|
|
];
|
|
|
|
// packages/ag-charts-community/src/module-bundles/cartesian.ts
|
|
var AllCartesianModule = [
|
|
AllCartesianAxesModule,
|
|
AllCartesianSeriesModule,
|
|
LegendModule,
|
|
LocaleModule
|
|
].flat();
|
|
|
|
// packages/ag-charts-community/src/module-bundles/polar.ts
|
|
var AllPolarModule = [
|
|
PolarChartModule,
|
|
DonutSeriesModule,
|
|
PieSeriesModule,
|
|
LegendModule,
|
|
LocaleModule
|
|
];
|
|
|
|
// packages/ag-charts-community/src/module-bundles/all.ts
|
|
var AllCommunityModule = [
|
|
AllCartesianModule,
|
|
AllPolarModule,
|
|
// Presets
|
|
SparklinePresetModule
|
|
].flat();
|
|
|
|
// packages/ag-charts-community/src/module-bundles/integrated.ts
|
|
var import_ag_charts_core285 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/integrated-charts-scene.ts
|
|
var integrated_charts_scene_exports = {};
|
|
__export(integrated_charts_scene_exports, {
|
|
Arc: () => Arc,
|
|
BBox: () => BBox,
|
|
Caption: () => Caption,
|
|
CategoryScale: () => CategoryScale,
|
|
Group: () => Group,
|
|
Line: () => Line,
|
|
LinearScale: () => LinearScale,
|
|
Marker: () => Marker,
|
|
Path: () => Path,
|
|
RadialColumnShape: () => RadialColumnShape,
|
|
Rect: () => Rect,
|
|
Scene: () => Scene,
|
|
Sector: () => Sector,
|
|
Shape: () => Shape,
|
|
TranslatableGroup: () => TranslatableGroup,
|
|
getRadialColumnWidth: () => getRadialColumnWidth,
|
|
toRadians: () => import_ag_charts_core282.toRadians
|
|
});
|
|
var import_ag_charts_core282 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/integrated-charts-theme.ts
|
|
var integrated_charts_theme_exports = {};
|
|
__export(integrated_charts_theme_exports, {
|
|
ChartTheme: () => ChartTheme,
|
|
getChartTheme: () => getChartTheme,
|
|
resolveOperation: () => resolveOperation,
|
|
themeNames: () => themeNames,
|
|
themeSymbols: () => themeSymbols,
|
|
themes: () => themes
|
|
});
|
|
var import_ag_charts_core283 = require("ag-charts-core");
|
|
__reExport(integrated_charts_theme_exports, require("ag-charts-core"));
|
|
var themeSymbols = {
|
|
DEFAULT_ANNOTATION_HANDLE_FILL: import_ag_charts_core283.DEFAULT_ANNOTATION_HANDLE_FILL,
|
|
DEFAULT_ANNOTATION_STATISTICS_COLOR: import_ag_charts_core283.DEFAULT_ANNOTATION_STATISTICS_COLOR,
|
|
DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE: import_ag_charts_core283.DEFAULT_ANNOTATION_STATISTICS_DIVIDER_STROKE,
|
|
DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL: import_ag_charts_core283.DEFAULT_ANNOTATION_STATISTICS_DOWN_FILL,
|
|
DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE: import_ag_charts_core283.DEFAULT_ANNOTATION_STATISTICS_DOWN_STROKE,
|
|
DEFAULT_ANNOTATION_STATISTICS_FILL: import_ag_charts_core283.DEFAULT_ANNOTATION_STATISTICS_FILL,
|
|
DEFAULT_ANNOTATION_STATISTICS_STROKE: import_ag_charts_core283.DEFAULT_ANNOTATION_STATISTICS_STROKE,
|
|
DEFAULT_CAPTION_ALIGNMENT: import_ag_charts_core283.DEFAULT_CAPTION_ALIGNMENT,
|
|
DEFAULT_CAPTION_LAYOUT_STYLE: import_ag_charts_core283.DEFAULT_CAPTION_LAYOUT_STYLE,
|
|
DEFAULT_FIBONACCI_STROKES: import_ag_charts_core283.DEFAULT_FIBONACCI_STROKES,
|
|
DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL: import_ag_charts_core283.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_BACKGROUND_FILL,
|
|
DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR: import_ag_charts_core283.DEFAULT_FINANCIAL_CHARTS_ANNOTATION_COLOR,
|
|
DEFAULT_POLAR_SERIES_STROKE: import_ag_charts_core283.DEFAULT_POLAR_SERIES_STROKE,
|
|
DEFAULT_SHADOW_COLOUR: import_ag_charts_core283.DEFAULT_SHADOW_COLOUR,
|
|
DEFAULT_SPARKLINE_CROSSHAIR_STROKE: import_ag_charts_core283.DEFAULT_SPARKLINE_CROSSHAIR_STROKE,
|
|
DEFAULT_TEXTBOX_COLOR: import_ag_charts_core283.DEFAULT_TEXTBOX_COLOR,
|
|
DEFAULT_TEXTBOX_FILL: import_ag_charts_core283.DEFAULT_TEXTBOX_FILL,
|
|
DEFAULT_TEXTBOX_STROKE: import_ag_charts_core283.DEFAULT_TEXTBOX_STROKE,
|
|
DEFAULT_TEXT_ANNOTATION_COLOR: import_ag_charts_core283.DEFAULT_TEXT_ANNOTATION_COLOR,
|
|
DEFAULT_TOOLBAR_POSITION: import_ag_charts_core283.DEFAULT_TOOLBAR_POSITION,
|
|
IS_DARK_THEME: import_ag_charts_core283.IS_DARK_THEME,
|
|
PALETTE_ALT_DOWN_FILL: import_ag_charts_core283.PALETTE_ALT_DOWN_FILL,
|
|
PALETTE_ALT_DOWN_STROKE: import_ag_charts_core283.PALETTE_ALT_DOWN_STROKE,
|
|
PALETTE_ALT_NEUTRAL_FILL: import_ag_charts_core283.PALETTE_ALT_NEUTRAL_FILL,
|
|
PALETTE_ALT_NEUTRAL_STROKE: import_ag_charts_core283.PALETTE_ALT_NEUTRAL_STROKE,
|
|
PALETTE_ALT_UP_FILL: import_ag_charts_core283.PALETTE_ALT_UP_FILL,
|
|
PALETTE_ALT_UP_STROKE: import_ag_charts_core283.PALETTE_ALT_UP_STROKE,
|
|
PALETTE_DOWN_FILL: import_ag_charts_core283.PALETTE_DOWN_FILL,
|
|
PALETTE_DOWN_STROKE: import_ag_charts_core283.PALETTE_DOWN_STROKE,
|
|
PALETTE_NEUTRAL_FILL: import_ag_charts_core283.PALETTE_NEUTRAL_FILL,
|
|
PALETTE_NEUTRAL_STROKE: import_ag_charts_core283.PALETTE_NEUTRAL_STROKE,
|
|
PALETTE_UP_FILL: import_ag_charts_core283.PALETTE_UP_FILL,
|
|
PALETTE_UP_STROKE: import_ag_charts_core283.PALETTE_UP_STROKE
|
|
};
|
|
var themeNames = Object.keys(themes);
|
|
function resolveOperation(operation) {
|
|
const params = ChartTheme.getDefaultPublicParameters();
|
|
const palette = ChartTheme.getDefaultColors();
|
|
const graph = new OptionsGraph({ line: { operation } }, { series: [{ type: "line" }] }, params, palette);
|
|
const resolved = graph.resolve();
|
|
return resolved.operation;
|
|
}
|
|
|
|
// packages/ag-charts-community/src/integrated-charts-util.ts
|
|
var integrated_charts_util_exports = {};
|
|
__export(integrated_charts_util_exports, {
|
|
Color: () => import_ag_charts_core284.Color,
|
|
interpolateColor: () => interpolateColor
|
|
});
|
|
var import_ag_charts_core284 = require("ag-charts-core");
|
|
|
|
// packages/ag-charts-community/src/module-bundles/integrated.ts
|
|
var AgChartsCommunityModule = {
|
|
VERSION,
|
|
_Scene: integrated_charts_scene_exports,
|
|
_Theme: integrated_charts_theme_exports,
|
|
_Util: integrated_charts_util_exports,
|
|
create: AgCharts.create.bind(AgCharts),
|
|
createSparkline: AgCharts.__createSparkline.bind(AgCharts),
|
|
setup: () => {
|
|
import_ag_charts_core285.ModuleRegistry.setRegistryMode(import_ag_charts_core285.ModuleRegistry.RegistryMode.Integrated);
|
|
import_ag_charts_core285.ModuleRegistry.registerModules(AllCommunityModule);
|
|
},
|
|
isEnterprise: false
|
|
};
|