UNPKG

highcharts

Version:
464 lines (463 loc) 17.2 kB
/* * * * (c) 2010-2025 Torstein Honsi * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ 'use strict'; import DataGroupingAxisComposition from './DataGroupingAxisComposition.js'; import DataGroupingDefaults from './DataGroupingDefaults.js'; import DataGroupingSeriesComposition from './DataGroupingSeriesComposition.js'; import F from '../../Core/Templating.js'; const { format } = F; import H from '../../Core/Globals.js'; const { composed } = H; import U from '../../Core/Utilities.js'; const { addEvent, extend, isNumber, pick, pushUnique } = U; /* * * * Functions * * */ /** * @private */ function compose(AxisClass, SeriesClass, TooltipClass) { DataGroupingAxisComposition.compose(AxisClass); DataGroupingSeriesComposition.compose(SeriesClass); if (TooltipClass && pushUnique(composed, 'DataGrouping')) { addEvent(TooltipClass, 'headerFormatter', onTooltipHeaderFormatter); } } /** * Extend the original method, make the tooltip's header reflect the grouped * range. * @private */ function onTooltipHeaderFormatter(e) { const chart = this.chart, time = chart.time, point = e.point, series = point.series, options = series.options, tooltipOptions = series.tooltipOptions, dataGroupingOptions = options.dataGrouping, xAxis = series.xAxis; let xDateFormat = tooltipOptions.xDateFormat || '', xDateFormatEnd, currentDataGrouping, dateTimeLabelFormats, labelFormats, formattedKey, formatString = tooltipOptions[e.isFooter ? 'footerFormat' : 'headerFormat']; // Apply only to grouped series if (xAxis && xAxis.options.type === 'datetime' && dataGroupingOptions && isNumber(point.key)) { // Set variables currentDataGrouping = series.currentDataGrouping; dateTimeLabelFormats = dataGroupingOptions.dateTimeLabelFormats || // Fallback to commonOptions (#9693) DataGroupingDefaults.common.dateTimeLabelFormats; // If we have grouped data, use the grouping information to get the // right format if (currentDataGrouping) { labelFormats = dateTimeLabelFormats[currentDataGrouping.unitName]; if (currentDataGrouping.count === 1) { xDateFormat = labelFormats[0]; } else { xDateFormat = labelFormats[1]; xDateFormatEnd = labelFormats[2]; } // If not grouped, and we don't have set the xDateFormat option, get the // best fit, so if the least distance between points is one minute, show // it, but if the least distance is one day, skip hours and minutes etc. } else if (!xDateFormat && dateTimeLabelFormats && xAxis.dateTime) { xDateFormat = xAxis.dateTime.getXDateFormat(point.x, tooltipOptions.dateTimeLabelFormats); } const groupStart = pick(series.groupMap?.[point.index].groupStart, point.key), groupEnd = groupStart + (currentDataGrouping?.totalRange || 0) - 1; formattedKey = time.dateFormat(xDateFormat, groupStart); if (xDateFormatEnd) { formattedKey += time.dateFormat(xDateFormatEnd, groupEnd); } // Replace default header style with class name if (series.chart.styledMode) { formatString = this.styledModeFormat(formatString); } // Return the replaced format e.text = format(formatString, { point: extend(point, { key: formattedKey }), series }, chart); e.preventDefault(); } } /* * * * Default Export * * */ const DataGroupingComposition = { compose, groupData: DataGroupingSeriesComposition.groupData }; export default DataGroupingComposition; /* * * * API Declarations * * */ /** * @typedef {"average"|"averages"|"open"|"high"|"low"|"close"|"sum"} Highcharts.DataGroupingApproximationValue */ /** * The position of the point inside the group. * * @typedef {"start"|"middle"|"end"} Highcharts.DataGroupingAnchor */ /** * The position of the first or last point in the series inside the group. * * @typedef {"start"|"middle"|"end"|"firstPoint"|"lastPoint"} Highcharts.DataGroupingAnchorExtremes */ /** * Highcharts Stock only. * * @product highstock * @interface Highcharts.DataGroupingInfoObject */ /** * @name Highcharts.DataGroupingInfoObject#length * @type {number} */ /** * @name Highcharts.DataGroupingInfoObject#options * @type {Highcharts.SeriesOptionsType|undefined} */ /** * @name Highcharts.DataGroupingInfoObject#start * @type {number} */ /** * Highcharts Stock only. * * @product highstock * @interface Highcharts.DataGroupingResultObject */ /** * @name Highcharts.DataGroupingResultObject#groupedXData * @type {Array<number>} */ /** * @name Highcharts.DataGroupingResultObject#groupedYData * @type {Array<(number|null|undefined)>|Array<Array<(number|null|undefined)>>} */ /** * @name Highcharts.DataGroupingResultObject#groupMap * @type {Array<DataGroupingInfoObject>} */ /** * Highcharts Stock only. If a point object is created by data * grouping, it doesn't reflect actual points in the raw * data. In this case, the `dataGroup` property holds * information that points back to the raw data. * * - `dataGroup.start` is the index of the first raw data * point in the group. * * - `dataGroup.length` is the amount of points in the * group. * * @sample stock/members/point-datagroup * Click to inspect raw data points * * @product highstock * * @name Highcharts.Point#dataGroup * @type {Highcharts.DataGroupingInfoObject|undefined} */ (''); // Detach doclets above /* * * * API Options * * */ /** * Data grouping is the concept of sampling the data values into larger * blocks in order to ease readability and increase performance of the * JavaScript charts. Highcharts Stock by default applies data grouping when * the points become closer than a certain pixel value, determined by * the `groupPixelWidth` option. * * If data grouping is applied, the grouping information of grouped * points can be read from the [Point.dataGroup]( * /class-reference/Highcharts.Point#dataGroup). If point options other than * the data itself are set, for example `name` or `color` or custom properties, * the grouping logic doesn't know how to group it. In this case the options of * the first point instance are copied over to the group point. This can be * altered through a custom `approximation` callback function. * * @declare Highcharts.DataGroupingOptionsObject * @product highstock * @requires modules/stock * @apioption plotOptions.series.dataGrouping */ /** * Specifies how the points should be located on the X axis inside the group. * Points that are extremes can be set separately. Available options: * * - `start` places the point at the beginning of the group * (e.g. range 00:00:00 - 23:59:59 -> 00:00:00) * * - `middle` places the point in the middle of the group * (e.g. range 00:00:00 - 23:59:59 -> 12:00:00) * * - `end` places the point at the end of the group * (e.g. range 00:00:00 - 23:59:59 -> 23:59:59) * * @sample {highstock} stock/plotoptions/series-datagrouping-anchor * Changing the point x-coordinate inside the group. * * @see [dataGrouping.firstAnchor](#plotOptions.series.dataGrouping.firstAnchor) * @see [dataGrouping.lastAnchor](#plotOptions.series.dataGrouping.lastAnchor) * * @type {Highcharts.DataGroupingAnchor} * @since 9.1.0 * @default start * @apioption plotOptions.series.dataGrouping.anchor */ /** * The method of approximation inside a group. When for example 30 days * are grouped into one month, this determines what value should represent * the group. Possible values are "average", "averages", "open", "high", * "low", "close" and "sum". For OHLC and candlestick series the approximation * is "ohlc" by default, which finds the open, high, low and close values * within all the grouped data. For ranges, the approximation is "range", * which finds the low and high values. For multi-dimensional data, * like ranges and OHLC, "averages" will compute the average for each * dimension. * * Custom aggregate methods can be added by assigning a callback function * as the approximation. This function takes a numeric array as the * argument and should return a single numeric value or `null`. Note * that the numeric array will never contain null values, only true * numbers. Instead, if null values are present in the raw data, the * numeric array will have an `.hasNulls` property set to `true`. For * single-value data sets the data is available in the first argument * of the callback function. For OHLC data sets, all the open values * are in the first argument, all high values in the second etc. * * Since v4.2.7, grouping meta data is available in the approximation * callback from `this.dataGroupInfo`. It can be used to extract information * from the raw data. * * Defaults to `average` for line-type series, `sum` for columns, `range` * for range series, `hlc` for HLC, and `ohlc` for OHLC and candlestick. * * @sample {highstock} stock/plotoptions/series-datagrouping-approximation * Approximation callback with custom data * @sample {highstock} stock/plotoptions/series-datagrouping-simple-approximation * Simple approximation demo * * @type {Highcharts.DataGroupingApproximationValue|Function} * @apioption plotOptions.series.dataGrouping.approximation */ /** * Datetime formats for the header of the tooltip in a stock chart. * The format can vary within a chart depending on the currently selected * time range and the current data grouping. * * The default formats are: * ```js * { * millisecond: [ * '%A, %e %b, %H:%M:%S.%L', '%A, %e %b, %H:%M:%S.%L', '-%H:%M:%S.%L' * ], * second: ['%A, %e %b, %H:%M:%S', '%A, %e %b, %H:%M:%S', '-%H:%M:%S'], * minute: ['%A, %e %b, %H:%M', '%A, %e %b, %H:%M', '-%H:%M'], * hour: ['%A, %e %b, %H:%M', '%A, %e %b, %H:%M', '-%H:%M'], * day: ['%A, %e %b %Y', '%A, %e %b', '-%A, %e %b %Y'], * week: ['%v %A, %e %b %Y', '%A, %e %b', '-%A, %e %b %Y'], * month: ['%B %Y', '%B', '-%B %Y'], * year: ['%Y', '%Y', '-%Y'] * } * ``` * * For each of these array definitions, the first item is the format * used when the active time span is one unit. For instance, if the * current data applies to one week, the first item of the week array * is used. The second and third items are used when the active time * span is more than two units. For instance, if the current data applies * to two weeks, the second and third item of the week array are used, * and applied to the start and end date of the time span. * * @type {Object} * @apioption plotOptions.series.dataGrouping.dateTimeLabelFormats */ /** * Enable or disable data grouping. * * @type {boolean} * @default true * @apioption plotOptions.series.dataGrouping.enabled */ /** * Specifies how the first grouped point is positioned on the xAxis. * If firstAnchor and/or lastAnchor are defined, then those options take * precedence over anchor for the first and/or last grouped points. * Available options: * * -`start` places the point at the beginning of the group * (e.g. range 00:00:00 - 23:59:59 -> 00:00:00) * * -`middle` places the point in the middle of the group * (e.g. range 00:00:00 - 23:59:59 -> 12:00:00) * * -`end` places the point at the end of the group * (e.g. range 00:00:00 - 23:59:59 -> 23:59:59) * * -`firstPoint` the first point in the group * (e.g. points at 00:13, 00:35, 00:59 -> 00:13) * * -`lastPoint` the last point in the group * (e.g. points at 00:13, 00:35, 00:59 -> 00:59) * * @sample {highstock} stock/plotoptions/series-datagrouping-first-anchor * Applying first and last anchor. * * @see [dataGrouping.anchor](#plotOptions.series.dataGrouping.anchor) * * @type {Highcharts.DataGroupingAnchorExtremes} * @since 9.1.0 * @default start * @apioption plotOptions.series.dataGrouping.firstAnchor */ /** * When data grouping is forced, it runs no matter how small the intervals * are. This can be handy for example when the sum should be calculated * for values appearing at random times within each hour. * * @type {boolean} * @default false * @apioption plotOptions.series.dataGrouping.forced */ /** * The approximate pixel width of each group. If for example a series * with 30 points is displayed over a 600 pixel wide plot area, no grouping * is performed. If however the series contains so many points that * the spacing is less than the groupPixelWidth, Highcharts will try * to group it into appropriate groups so that each is more or less * two pixels wide. If multiple series with different group pixel widths * are drawn on the same x axis, all series will take the greatest width. * For example, line series have 2px default group width, while column * series have 10px. If combined, both the line and the column will * have 10px by default. * * @type {number} * @default 2 * @apioption plotOptions.series.dataGrouping.groupPixelWidth */ /** * By default only points within the visible range are grouped. Enabling this * option will force data grouping to calculate all grouped points for a given * dataset. That option prevents for example a column series from calculating * a grouped point partially. The effect is similar to * [Series.getExtremesFromAll](#plotOptions.series.getExtremesFromAll) but does * not affect yAxis extremes. * * @sample {highstock} stock/plotoptions/series-datagrouping-groupall/ * Two series with the same data but different groupAll setting * * @type {boolean} * @default false * @since 6.1.0 * @apioption plotOptions.series.dataGrouping.groupAll */ /** * Specifies how the last grouped point is positioned on the xAxis. * If firstAnchor and/or lastAnchor are defined, then those options take * precedence over anchor for the first and/or last grouped points. * Available options: * * -`start` places the point at the beginning of the group * (e.g. range 00:00:00 - 23:59:59 -> 00:00:00) * * -`middle` places the point in the middle of the group * (e.g. range 00:00:00 - 23:59:59 -> 12:00:00) * * -`end` places the point at the end of the group * (e.g. range 00:00:00 - 23:59:59 -> 23:59:59) * * -`firstPoint` the first point in the group * (e.g. points at 00:13, 00:35, 00:59 -> 00:13) * * -`lastPoint` the last point in the group * (e.g. points at 00:13, 00:35, 00:59 -> 00:59) * * @sample {highstock} stock/plotoptions/series-datagrouping-first-anchor * Applying first and last anchor. * * @sample {highstock} stock/plotoptions/series-datagrouping-last-anchor * Applying the last anchor in the chart with live data. * * @see [dataGrouping.anchor](#plotOptions.series.dataGrouping.anchor) * * @type {Highcharts.DataGroupingAnchorExtremes} * @since 9.1.0 * @default start * @apioption plotOptions.series.dataGrouping.lastAnchor */ /** * Normally, a group is indexed by the start of that group, so for example * when 30 daily values are grouped into one month, that month's x value * will be the 1st of the month. This apparently shifts the data to * the left. When the smoothed option is true, this is compensated for. * The data is shifted to the middle of the group, and min and max * values are preserved. Internally, this is used in the Navigator series. * * @type {boolean} * @default false * @deprecated * @apioption plotOptions.series.dataGrouping.smoothed */ /** * An array determining what time intervals the data is allowed to be * grouped to. Each array item is an array where the first value is * the time unit and the second value another array of allowed multiples. * * Defaults to: * ```js * units: [[ * 'millisecond', // unit name * [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples * ], [ * 'second', * [1, 2, 5, 10, 15, 30] * ], [ * 'minute', * [1, 2, 5, 10, 15, 30] * ], [ * 'hour', * [1, 2, 3, 4, 6, 8, 12] * ], [ * 'day', * [1] * ], [ * 'week', * [1] * ], [ * 'month', * [1, 3, 6] * ], [ * 'year', * null * ]] * ``` * * @type {Array<Array<string,(Array<number>|null)>>} * @apioption plotOptions.series.dataGrouping.units */ /** * The approximate pixel width of each group. If for example a series * with 30 points is displayed over a 600 pixel wide plot area, no grouping * is performed. If however the series contains so many points that * the spacing is less than the groupPixelWidth, Highcharts will try * to group it into appropriate groups so that each is more or less * two pixels wide. Defaults to `10`. * * @sample {highstock} stock/plotoptions/series-datagrouping-grouppixelwidth/ * Two series with the same data density but different groupPixelWidth * * @type {number} * @default 10 * @apioption plotOptions.column.dataGrouping.groupPixelWidth */ ''; // Required by JSDoc parsing