UNPKG

@amcharts/amcharts4

Version:
1,112 lines 105 kB
/** * DateAxis module */ import { __assign, __extends } from "tslib"; /** * ============================================================================ * IMPORTS * ============================================================================ * @hidden */ import { ValueAxis, ValueAxisDataItem } from "./ValueAxis"; import { List } from "../../core/utils/List"; import { Dictionary } from "../../core/utils/Dictionary"; import { DateAxisBreak } from "./DateAxisBreak"; import { registry } from "../../core/Registry"; import * as $time from "../../core/utils/Time"; import * as $type from "../../core/utils/Type"; import * as $iter from "../../core/utils/Iterator"; import * as $math from "../../core/utils/Math"; import * as $array from "../../core/utils/Array"; import * as $object from "../../core/utils/Object"; import * as $utils from "../../core/utils/Utils"; import { OrderedListTemplate } from "../../core/utils/SortedList"; /** * ============================================================================ * DATA ITEM * ============================================================================ * @hidden */ /** * Defines data item for [[DateAxis]]. * * @see {@link DataItem} */ var DateAxisDataItem = /** @class */ (function (_super) { __extends(DateAxisDataItem, _super); /** * Constructor */ function DateAxisDataItem() { var _this = _super.call(this) || this; _this.className = "DateAxisDataItem"; _this.applyTheme(); _this.values.date = {}; _this.values.endDate = {}; return _this; } Object.defineProperty(DateAxisDataItem.prototype, "date", { /** * @return Date */ get: function () { return this.dates["date"]; }, /** * Date position of the data item. * * @param date Date */ set: function (date) { this.setDate("date", date); this.value = date.getTime(); }, enumerable: true, configurable: true }); Object.defineProperty(DateAxisDataItem.prototype, "endDate", { /** * @return End date */ get: function () { return this.dates["endDate"]; }, /** * End date for data item. * * @param date End date */ set: function (date) { this.setDate("endDate", date); this.endValue = date.getTime(); }, enumerable: true, configurable: true }); return DateAxisDataItem; }(ValueAxisDataItem)); export { DateAxisDataItem }; /** * ============================================================================ * MAIN CLASS * ============================================================================ * @hidden */ /** * Used to create a date/time-based axis for the chart. * * ```TypeScript * // Create the axis * let xAxis = chart.xAxes.push(new am4charts.DateAxis()); * * // Set settings * xAxis.title.text = "Time"; * ``` * ```JavaScript * // Create the axis * var valueAxis = chart.xAxes.push(new am4charts.DateAxis()); * * // Set settings * valueAxis.title.text = "Time"; * ``` * ```JSON * "xAxes": [{ * "type": "DateAxis", * "title": { * "text": "Time" * } * }] * ``` * * @see {@link IDateAxisEvents} for a list of available Events * @see {@link IDateAxisAdapters} for a list of available Adapters * @see {@link https://www.amcharts.com/docs/v4/concepts/axes/date-axis/} got `DateAxis` documention * @important */ var DateAxis = /** @class */ (function (_super) { __extends(DateAxis, _super); /** * Constructor */ function DateAxis() { var _this = // Init _super.call(this) || this; _this._gapBreaks = false; /** * A list of date/time intervals for Date axis. * * This define various granularities available for the axis. For example * if you have an axis spanning an hour, and space for 6 grid lines / labels * the axis will choose the granularity of 10 minutes, displaying a label * every 10 minutes. * * Default intervals: * * ```JSON * [ * { timeUnit: "millisecond", count: 1 }, * { timeUnit: "millisecond", count: 5 }, * { timeUnit: "millisecond", count: 10 }, * { timeUnit: "millisecond", count: 50 }, * { timeUnit: "millisecond", count: 100 }, * { timeUnit: "millisecond", count: 500 }, * { timeUnit: "second", count: 1 }, * { timeUnit: "second", count: 5 }, * { timeUnit: "second", count: 10 }, * { timeUnit: "second", count: 30 }, * { timeUnit: "minute", count: 1 }, * { timeUnit: "minute", count: 5 }, * { timeUnit: "minute", count: 10 }, * { timeUnit: "minute", count: 30 }, * { timeUnit: "hour", count: 1 }, * { timeUnit: "hour", count: 3 }, * { timeUnit: "hour", count: 6 }, * { timeUnit: "hour", count: 12 }, * { timeUnit: "day", count: 1 }, * { timeUnit: "day", count: 2 }, * { timeUnit: "day", count: 3 }, * { timeUnit: "day", count: 4 }, * { timeUnit: "day", count: 5 }, * { timeUnit: "week", count: 1 }, * { timeUnit: "month", count: 1 }, * { timeUnit: "month", count: 2 }, * { timeUnit: "month", count: 3 }, * { timeUnit: "month", count: 6 }, * { timeUnit: "year", count: 1 }, * { timeUnit: "year", count: 2 }, * { timeUnit: "year", count: 5 }, * { timeUnit: "year", count: 10 }, * { timeUnit: "year", count: 50 }, * { timeUnit: "year", count: 100 } * ] * ``` */ _this.gridIntervals = new List(); /** * If data aggregation is enabled by setting Axis' `groupData = true`, the * chart will try to aggregate data items into grouped data items. * * If there are more data items in selected period than `groupCount`, it will * group data items into bigger period. * * For example seconds might be grouped into 10-second aggregate data items. * * This setting indicates what group intervals can the chart group to. * * Default intervals: * * ```JSON * [ * { timeUnit: "millisecond", count: 1}, * { timeUnit: "millisecond", count: 10 }, * { timeUnit: "millisecond", count: 100 }, * { timeUnit: "second", count: 1 }, * { timeUnit: "second", count: 10 }, * { timeUnit: "minute", count: 1 }, * { timeUnit: "minute", count: 10 }, * { timeUnit: "hour", count: 1 }, * { timeUnit: "day", count: 1 }, * { timeUnit: "week", count: 1 }, * { timeUnit: "month", count: 1 }, * { timeUnit: "year", count: 1 } * ] * ``` * `groupData = true` does not work in combination with `skipEmptyPeriods = true`. * * @since 4.7.0 * @see {@link https://www.amcharts.com/docs/v4/concepts/axes/date-axis/#Dynamic_data_item_grouping} for more information about dynamic data item grouping. */ _this.groupIntervals = new List(); /** * A collection of date formats to use when formatting different time units * on Date/time axis. * * Actual defaults will depend on the language locale set for the chart. * * To override format for a specific time unit, say days, you need to set * the appropriate key to a format string. E.g.: * * ```TypeScript * axis.dateFormats.setKey("day", "MMMM d, yyyy"); * ``` * ```JavaScript * axis.dateFormats.setKey("day", "MMMM d, yyyy"); * ``` * ```JSON * "xAxes": [{ * "type": "DateAxis", * "dateFormats": { * "day": "MMMM d, yyyy" * } * }] * ``` * * @see {@link DateFormatter} */ _this.dateFormats = new Dictionary(); /** * These formats are applied to labels that are first in a larger unit. * * For example, if we have a DateAxis with days on it, the first day of month * indicates a break in month - a start of the bigger period. * * For those labels, `periodChangeDateFormats` are applied instead of * `dateFormats`. * * This allows us implement convenient structures, like instead of: * * `Jan 1 - Jan 2 - Jan 3 - ...` * * We can have: * * `Jan - 1 - 2 - 3 - ...` * * This can be disabled by setting `markUnitChange = false`. */ _this.periodChangeDateFormats = new Dictionary(); /** * Actual interval (granularity) derived from the actual data. */ _this._baseIntervalReal = { timeUnit: "day", count: 1 }; /** */ _this._prevSeriesTime = {}; /** * [_minDifference description] * * @todo Description */ _this._minDifference = {}; /** * @ignore */ _this._firstWeekDay = 1; /** * A collection of start timestamps to use as axis' min timestamp for * particular data item item periods. * * @since 4.7.0 * @readonly */ _this.groupMin = {}; /** * A collection of start timestamps to use as axis' max timestamp for * particular data item item periods. * * @since 4.7.0 * @readonly */ _this.groupMax = {}; _this._intervalMax = {}; _this._intervalMin = {}; _this.className = "DateAxis"; _this.setPropertyValue("markUnitChange", true); _this.snapTooltip = true; _this.tooltipPosition = "pointer"; _this.setPropertyValue("groupData", false); _this.groupCount = 200; _this.events.on("parentset", _this.getDFFormatter, _this, false); // Translatable defaults are applied in `applyInternalDefaults()` // ... // Define default intervals _this.gridIntervals.pushAll([ { timeUnit: "millisecond", count: 1 }, { timeUnit: "millisecond", count: 5 }, { timeUnit: "millisecond", count: 10 }, { timeUnit: "millisecond", count: 50 }, { timeUnit: "millisecond", count: 100 }, { timeUnit: "millisecond", count: 500 }, { timeUnit: "second", count: 1 }, { timeUnit: "second", count: 5 }, { timeUnit: "second", count: 10 }, { timeUnit: "second", count: 30 }, { timeUnit: "minute", count: 1 }, { timeUnit: "minute", count: 5 }, { timeUnit: "minute", count: 10 }, { timeUnit: "minute", count: 15 }, { timeUnit: "minute", count: 30 }, { timeUnit: "hour", count: 1 }, { timeUnit: "hour", count: 3 }, { timeUnit: "hour", count: 6 }, { timeUnit: "hour", count: 12 }, { timeUnit: "day", count: 1 }, { timeUnit: "day", count: 2 }, { timeUnit: "day", count: 3 }, { timeUnit: "day", count: 4 }, { timeUnit: "day", count: 5 }, { timeUnit: "week", count: 1 }, { timeUnit: "month", count: 1 }, { timeUnit: "month", count: 2 }, { timeUnit: "month", count: 3 }, { timeUnit: "month", count: 6 }, { timeUnit: "year", count: 1 }, { timeUnit: "year", count: 2 }, { timeUnit: "year", count: 5 }, { timeUnit: "year", count: 10 }, { timeUnit: "year", count: 50 }, { timeUnit: "year", count: 100 }, { timeUnit: "year", count: 200 }, { timeUnit: "year", count: 500 }, { timeUnit: "year", count: 1000 }, { timeUnit: "year", count: 2000 }, { timeUnit: "year", count: 5000 }, { timeUnit: "year", count: 10000 }, { timeUnit: "year", count: 100000 } ]); _this.groupIntervals.pushAll([ { timeUnit: "millisecond", count: 1 }, { timeUnit: "millisecond", count: 10 }, { timeUnit: "millisecond", count: 100 }, { timeUnit: "second", count: 1 }, { timeUnit: "second", count: 10 }, { timeUnit: "minute", count: 1 }, { timeUnit: "minute", count: 10 }, { timeUnit: "hour", count: 1 }, { timeUnit: "day", count: 1 }, { timeUnit: "week", count: 1 }, { timeUnit: "month", count: 1 }, { timeUnit: "year", count: 1 } ]); // Set field name _this.axisFieldName = "date"; // Apply theme _this.applyTheme(); return _this; } /** * A function which applies fills to axis cells. * * Default function fills every second fill. You can set this to a function * that follows some other logic. * * Function should accept a [[DateAxisDataItem]] and modify its `axisFill` * property accordingly. */ DateAxis.prototype.fillRule = function (dataItem) { var value = dataItem.value; var axis = dataItem.component; var gridInterval = axis._gridInterval; var gridDuration = $time.getDuration(gridInterval.timeUnit, gridInterval.count); if (Math.round((value - axis.min) / gridDuration) / 2 == Math.round(Math.round((value - axis.min) / gridDuration) / 2)) { dataItem.axisFill.__disabled = true; } else { dataItem.axisFill.__disabled = false; } }; /** * Sets defaults that instantiate some objects that rely on parent, so they * cannot be set in constructor. */ DateAxis.prototype.applyInternalDefaults = function () { _super.prototype.applyInternalDefaults.call(this); // Set default date formats if (!this.dateFormats.hasKey("millisecond")) { this.dateFormats.setKey("millisecond", this.language.translate("_date_millisecond")); } if (!this.dateFormats.hasKey("second")) { this.dateFormats.setKey("second", this.language.translate("_date_second")); } if (!this.dateFormats.hasKey("minute")) { this.dateFormats.setKey("minute", this.language.translate("_date_minute")); } if (!this.dateFormats.hasKey("hour")) { this.dateFormats.setKey("hour", this.language.translate("_date_hour")); } if (!this.dateFormats.hasKey("day")) { this.dateFormats.setKey("day", this.language.translate("_date_day")); } if (!this.dateFormats.hasKey("week")) { this.dateFormats.setKey("week", this.language.translate("_date_day")); // not a mistake } if (!this.dateFormats.hasKey("month")) { this.dateFormats.setKey("month", this.language.translate("_date_month")); } if (!this.dateFormats.hasKey("year")) { this.dateFormats.setKey("year", this.language.translate("_date_year")); } if (!this.periodChangeDateFormats.hasKey("millisecond")) { this.periodChangeDateFormats.setKey("millisecond", this.language.translate("_date_millisecond")); } if (!this.periodChangeDateFormats.hasKey("second")) { this.periodChangeDateFormats.setKey("second", this.language.translate("_date_second")); } if (!this.periodChangeDateFormats.hasKey("minute")) { this.periodChangeDateFormats.setKey("minute", this.language.translate("_date_minute")); } if (!this.periodChangeDateFormats.hasKey("hour")) { this.periodChangeDateFormats.setKey("hour", this.language.translate("_date_day")); } if (!this.periodChangeDateFormats.hasKey("day")) { this.periodChangeDateFormats.setKey("day", this.language.translate("_date_day")); } if (!this.periodChangeDateFormats.hasKey("week")) { this.periodChangeDateFormats.setKey("week", this.language.translate("_date_day")); } if (!this.periodChangeDateFormats.hasKey("month")) { this.periodChangeDateFormats.setKey("month", this.language.translate("_date_month") + " " + this.language.translate("_date_year")); } }; /** * Returns a new/empty [[DataItem]] of the type appropriate for this object. * * @see {@link DataItem} * @return Data Item */ DateAxis.prototype.createDataItem = function () { return new DateAxisDataItem(); }; /** * Returns a new/empty [[AxisBreak]] of the appropriate type. * * @return Axis break */ DateAxis.prototype.createAxisBreak = function () { return new DateAxisBreak(); }; /** * Validates Axis' data items. * * @ignore Exclude from docs */ DateAxis.prototype.validateDataItems = function () { // allows to keep selection of the same size var start = this.start; var end = this.end; var baseDuration = this.baseDuration; var periodCount = (this.max - this.min) / baseDuration; this._firstWeekDay = this.getFirstWeekDay(); this.getDFFormatter(); _super.prototype.validateDataItems.call(this); var mainBaseDuration = $time.getDuration(this.mainBaseInterval.timeUnit, this.mainBaseInterval.count); this.maxZoomFactor = Math.max(1, (this.max - this.min) / mainBaseDuration); this._deltaMinMax = this.baseDuration / 2; // allows to keep selection of the same size var newPeriodCount = (this.max - this.min) / baseDuration; start = start + (end - start) * (1 - periodCount / newPeriodCount); this.zoom({ start: start, end: end }, false, true); // added instantlyto solve zoomout problem when we have axes gaps. @todo: check how this affects maxZoomFactor }; /** * Handles process after zoom. * * @ignore Exclude from docs * @todo Does nothing? */ DateAxis.prototype.handleSelectionExtremesChange = function () { }; /** * @ignore */ DateAxis.prototype.getIntervalMax = function (interval) { return this._intervalMax[interval.timeUnit + interval.count]; }; /** * @ignore */ DateAxis.prototype.getIntervalMin = function (interval) { return this._intervalMin[interval.timeUnit + interval.count]; }; /** * Calculates all positions, related to axis as per current zoom. * * @ignore Exclude from docs */ DateAxis.prototype.calculateZoom = function () { var _this = this; _super.prototype.calculateZoom.call(this); var difference = this.adjustDifference(this._minZoomed, this._maxZoomed); var dataSetChanged = false; // if data has to be grouped, choose interval and set dataset if (this.groupData && $type.hasValue(difference)) { var mainBaseInterval = this.mainBaseInterval; var min = this.getIntervalMin(mainBaseInterval); var max = this.getIntervalMax(mainBaseInterval); var selectionMin = min + (max - min) * this.start; var selectionMax = min + (max - min) * this.end; var diff = this.adjustDifference(selectionMin, selectionMax); var modifiedDifference = diff + (this.startLocation + (1 - this.endLocation)) * this.baseDuration; var groupInterval = void 0; if (this.groupInterval) { groupInterval = __assign({}, this.groupInterval); } else { groupInterval = this.chooseInterval(0, modifiedDifference, this.groupCount, this.groupIntervals); if ($time.getDuration(groupInterval.timeUnit, groupInterval.count) < $time.getDuration(mainBaseInterval.timeUnit, mainBaseInterval.count)) { groupInterval = __assign({}, mainBaseInterval); } } this._groupInterval = groupInterval; var newId = groupInterval.timeUnit + groupInterval.count; if (this._currentDataSetId != newId) { this._currentDataSetId = newId; this.dispatch("groupperiodchanged"); } this.series.each(function (series) { if (series.baseAxis == _this) { if (series.setDataSet(_this._currentDataSetId)) { dataSetChanged = true; } } }); } var gridInterval = this.chooseInterval(0, difference, this._gridCount); if ($time.getDuration(gridInterval.timeUnit, gridInterval.count) < this.baseDuration) { gridInterval = __assign({}, this.baseInterval); } this._gridInterval = gridInterval; this._nextGridUnit = $time.getNextUnit(gridInterval.timeUnit); // the following is needed to avoid grid flickering while scrolling this._intervalDuration = $time.getDuration(gridInterval.timeUnit, gridInterval.count); this._gridDate = $time.round(new Date(this.minZoomed - $time.getDuration(gridInterval.timeUnit, gridInterval.count)), gridInterval.timeUnit, gridInterval.count, this._firstWeekDay, this._df.utc, new Date(this.min), this._df.timezoneMinutes, this._df.timezone); // tell series start/end $iter.each(this.series.iterator(), function (series) { if (series.baseAxis == _this) { var field_1 = series.getAxisField(_this); var minZoomed = $time.round(new Date(_this._minZoomed + _this.baseDuration * 0.05), _this.baseInterval.timeUnit, _this.baseInterval.count, _this._firstWeekDay, _this._df.utc, undefined, _this._df.timezoneMinutes, _this._df.timezone).getTime(); var minZoomedStr = minZoomed.toString(); var startDataItem = series.dataItemsByAxis.getKey(_this.uid).getKey(minZoomedStr + series.currentDataSetId); var startIndex = 0; if (_this.start != 0) { if (startDataItem) { startDataItem = _this.findFirst(startDataItem, minZoomed, field_1); startIndex = startDataItem.index; } else { startIndex = series.dataItems.findClosestIndex(_this._minZoomed, function (x) { return x[field_1]; }, "left"); } } // 1 millisecond is removed so that if only first item is selected, it would not count in the second. var baseInterval = _this.baseInterval; var maxZoomed = $time.add($time.round(new Date(_this._maxZoomed), baseInterval.timeUnit, baseInterval.count, _this._firstWeekDay, _this._df.utc, undefined, _this._df.timezoneMinutes, _this._df.timezone), baseInterval.timeUnit, baseInterval.count, _this._df.utc).getTime(); var maxZoomedStr = maxZoomed.toString(); var endDataItem = series.dataItemsByAxis.getKey(_this.uid).getKey(maxZoomedStr + series.currentDataSetId); var endIndex = series.dataItems.length; if (_this.end != 1) { if (endDataItem) { endIndex = endDataItem.index; } else { maxZoomed -= 1; endIndex = series.dataItems.findClosestIndex(maxZoomed, function (x) { return x[field_1]; }, "right"); // not good - if end is in the gap, indexes go like 5,4,3,4,2,1 //if (endIndex < series.dataItems.length) { endIndex++; //} } } if (series.max(_this) < minZoomed) { series.startIndex = series.dataItems.length; series.endIndex = series.dataItems.length; series.outOfRange = true; } else if (series.min(_this) > maxZoomed) { series.startIndex = 0; series.endIndex = 0; series.outOfRange = true; } else { series.outOfRange = false; series.startIndex = startIndex; series.endIndex = endIndex; } // console.log(series.name, startIndex, endIndex); if (!dataSetChanged && series.dataRangeInvalid) { series.validateDataRange(); } } }); }; DateAxis.prototype.findFirst = function (dataItem, time, key) { var index = dataItem.index; if (index > 0) { var series = dataItem.component; var previousDataItem = series.dataItems.getIndex(index - 1); var previousDate = previousDataItem[key]; if (!previousDate || previousDate.getTime() < time) { return dataItem; } else { return this.findFirst(previousDataItem, time, key); } } else { return dataItem; } }; /** * (Re)validates data. * * @ignore Exclude from docs */ DateAxis.prototype.validateData = function () { _super.prototype.validateData.call(this); if (!$type.isNumber(this.baseInterval.count)) { this.baseInterval.count = 1; } }; Object.defineProperty(DateAxis.prototype, "minDifference", { /** * @ignore */ get: function () { var _this = this; var minDifference = Number.MAX_VALUE; this.series.each(function (series) { if (minDifference > _this._minDifference[series.uid]) { minDifference = _this._minDifference[series.uid]; } }); if (minDifference == Number.MAX_VALUE || minDifference == 0) { minDifference = $time.getDuration("day"); } return minDifference; }, enumerable: true, configurable: true }); /** * [dataChangeUpdate description] * * * @ignore Exclude from docs * @todo Description */ DateAxis.prototype.seriesDataChangeUpdate = function (series) { this._minDifference[series.uid] = Number.MAX_VALUE; }; /** * [postProcessSeriesDataItems description] * * @ignore Exclude from docs * @todo Description */ DateAxis.prototype.postProcessSeriesDataItems = function (series) { var _this = this; this._firstWeekDay = this.getFirstWeekDay(); if (series) { this.seriesGroupUpdate(series); } else { this.series.each(function (series) { _this.seriesGroupUpdate(series); }); } this.addEmptyUnitsBreaks(); }; DateAxis.prototype.seriesGroupUpdate = function (series) { var _this = this; if (JSON.stringify(series._baseInterval[this.uid]) != JSON.stringify(this.mainBaseInterval)) { series._baseInterval[this.uid] = this.mainBaseInterval; series.mainDataSet.each(function (dataItem) { _this.postProcessSeriesDataItem(dataItem); }); if (this.groupData) { this.groupSeriesData(series); } } }; /** * Calculates series group data. * * @param series Series * @ignore */ DateAxis.prototype.groupSeriesData = function (series) { var _this = this; if (series.baseAxis == this && series.dataItems.length > 0 && !series.dataGrouped) { series.bulletsContainer.removeChildren(); // make array of intervals which will be used; var intervals_1 = []; var mainBaseInterval = this.mainBaseInterval; var mainIntervalDuration_1 = $time.getDuration(mainBaseInterval.timeUnit, mainBaseInterval.count); this.groupIntervals.each(function (interval) { var intervalDuration = $time.getDuration(interval.timeUnit, interval.count); if ((intervalDuration > mainIntervalDuration_1 && intervalDuration < (_this.max - _this.min)) || _this.groupInterval) { intervals_1.push(interval); } }); if (series._dataSets) { series._dataSets.each(function (key, dataItems) { dataItems.each(function (dataItem) { dataItem.dispose(); }); dataItems.clear(); }); series._dataSets.clear(); } series.dataGrouped = true; $array.each(intervals_1, function (interval) { //let mainBaseInterval = this._mainBaseInterval; var key = "date" + _this.axisLetter; // create data set var dataSetId = interval.timeUnit + interval.count; // todo: check where this clone goes var dataSet = new OrderedListTemplate(series.mainDataSet.template.clone()); series.dataSets.setKey(dataSetId, dataSet); var dataItems = series.mainDataSet; var previousTime = Number.NEGATIVE_INFINITY; var i = 0; var newDataItem; var dataFields = []; $object.each(series.dataFields, function (dfkey, df) { var dfk = dfkey; if (dfk != key && dfk.indexOf("Show") == -1) { dataFields.push(dfk); } }); var roundedDate; dataItems.each(function (dataItem) { var date = dataItem.getDate(key); if (date) { var time = date.getTime(); roundedDate = $time.round(new Date(time), interval.timeUnit, interval.count, _this._df.firstDayOfWeek, _this._df.utc, undefined, _this._df.timezoneMinutes, _this._df.timezone); var currentTime = roundedDate.getTime(); // changed period if (previousTime < currentTime) { if (newDataItem && series._adapterO) { $array.each(dataFields, function (vkey) { newDataItem.values[vkey].value = series._adapterO.apply("groupDataItem", { dataItem: newDataItem, interval: interval, dataField: vkey, date: roundedDate, value: newDataItem.values[vkey].value }).value; newDataItem.values[vkey].workingValue = newDataItem.values[vkey].value; }); } newDataItem = dataSet.create(); newDataItem.dataContext = {}; newDataItem.setWorkingLocation("dateX", series.dataItems.template.locations.dateX, 0); newDataItem.setWorkingLocation("openDateX", series.dataItems.template.locations.openDateX, 0); newDataItem.setWorkingLocation("dateY", series.dataItems.template.locations.dateY, 0); newDataItem.setWorkingLocation("openDateY", series.dataItems.template.locations.openDateY, 0); newDataItem.component = series; // other Dates? newDataItem.setDate(key, roundedDate); newDataItem._index = i; i++; $array.each(dataFields, function (vkey) { //let groupFieldName = vkey + "Group"; var dvalues = dataItem.values[vkey]; if (dvalues) { var value = dvalues.value; if (series._adapterO) { value = series._adapterO.apply("groupValue", { dataItem: dataItem, interval: interval, dataField: vkey, date: roundedDate, value: value }).value; } var values = newDataItem.values[vkey]; if ($type.isNumber(value)) { values.value = value; values.workingValue = value; values.open = value; values.close = value; values.low = value; values.high = value; values.sum = value; values.average = value; values.count = 1; } else { values.count = 0; } } }); _this.postProcessSeriesDataItem(newDataItem, interval); $object.each(series.propertyFields, function (key, fieldValue) { var f = key; var value = dataItem.properties[key]; if ($type.hasValue(value)) { newDataItem.hasProperties = true; newDataItem.setProperty(f, value); } }); newDataItem.groupDataItems = [dataItem]; previousTime = currentTime; } else { if (newDataItem) { $array.each(dataFields, function (vkey) { var groupFieldName = series.groupFields[vkey]; var dvalues = dataItem.values[vkey]; if (dvalues) { var value = dvalues.value; if (series._adapterO) { value = series._adapterO.apply("groupValue", { dataItem: dataItem, interval: interval, dataField: vkey, date: roundedDate, value: value }).value; } if ($type.isNumber(value)) { var values = newDataItem.values[vkey]; if (!$type.isNumber(values.open)) { values.open = value; } values.close = value; if (values.low > value || !$type.isNumber(values.low)) { values.low = value; } if (values.high < value || !$type.isNumber(values.high)) { values.high = value; } if ($type.isNumber(values.sum)) { values.sum += value; } else { values.sum = value; } values.count++; values.average = values.sum / values.count; if ($type.isNumber(values[groupFieldName])) { values.value = values[groupFieldName]; values.workingValue = values.value; } } } }); $utils.copyProperties(dataItem.properties, newDataItem.properties); $object.each(series.propertyFields, function (key, fieldValue) { var f = key; var value = dataItem.properties[key]; if ($type.hasValue(value)) { newDataItem.hasProperties = true; newDataItem.setProperty(f, value); } }); newDataItem.groupDataItems.push(dataItem); } } } if (newDataItem) { $utils.copyProperties(dataItem.dataContext, newDataItem.dataContext); } }); if (newDataItem && series._adapterO) { $array.each(dataFields, function (vkey) { newDataItem.values[vkey].value = series._adapterO.apply("groupDataItem", { dataItem: newDataItem, interval: interval, dataField: vkey, date: roundedDate, value: newDataItem.values[vkey].value }).value; newDataItem.values[vkey].workingValue = newDataItem.values[vkey].value; }); } }); this.calculateZoom(); } }; /** * @ignore */ DateAxis.prototype.getDFFormatter = function () { this._df = this.dateFormatter; }; /** * [postProcessSeriesDataItem description] * * @ignore Exclude from docs * @todo Description * @param dataItem Data item */ DateAxis.prototype.postProcessSeriesDataItem = function (dataItem, interval) { var _this = this; // we need to do this for all series data items not only added recently, as baseInterval might change var intervalID = ""; if (interval) { intervalID = interval.timeUnit + interval.count; } else { interval = this.mainBaseInterval; } var series = dataItem.component; var dataItemsByAxis = series.dataItemsByAxis.getKey(this.uid); $object.each(dataItem.dates, function (key) { var date = dataItem.getDate(key); var time = date.getTime(); var startDate = $time.round(new Date(time), interval.timeUnit, interval.count, _this._firstWeekDay, _this._df.utc, undefined, _this._df.timezoneMinutes, _this._df.timezone); var startTime = startDate.getTime(); var endDate = $time.add(new Date(startTime), interval.timeUnit, interval.count, _this._df.utc); dataItem.setCalculatedValue(key, startTime, "open"); dataItem.setCalculatedValue(key, endDate.getTime(), "close"); dataItemsByAxis.setKey(startTime + intervalID, dataItem); }); }; /** * Collapses empty stretches of date/time scale by creating [[AxisBreak]] * elements for them. * * Can be used to automatically remove strethes without data, like weekends. * * No, need to call this manually. It will automatically be done if * `skipEmptyPeriods = true`. * * @ignore Exclude from docs */ DateAxis.prototype.addEmptyUnitsBreaks = function () { var _this = this; if (this.skipEmptyPeriods && $type.isNumber(this.min) && $type.isNumber(this.max)) { var timeUnit = this.baseInterval.timeUnit; var count = this.baseInterval.count; if (this._axisBreaks) { this._axisBreaks.clear(); // TODO: what about breaks added by user? } var date = $time.round(new Date(this.min), timeUnit, count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone); var axisBreak = void 0; var _loop_1 = function () { $time.add(date, timeUnit, count, this_1._df.utc); var startTime = date.getTime(); var startTimeStr = startTime.toString(); var hasData = $iter.contains(this_1.series.iterator(), function (series) { return !!series.dataItemsByAxis.getKey(_this.uid).getKey(startTimeStr + series.currentDataSetId); }); // open break if not yet opened if (!hasData) { if (!axisBreak) { axisBreak = this_1.axisBreaks.create(); axisBreak.startDate = new Date(startTime); this_1._gapBreaks = true; } } else { // close if already opened if (axisBreak) { // close at end time minus one millisecond axisBreak.endDate = new Date(startTime - 1); axisBreak = undefined; } } }; var this_1 = this; while (date.getTime() < this.max - this.baseDuration) { _loop_1(); } } }; /** * Updates positioning of Axis breaks after something changes. * * @ignore Exclude from docs */ DateAxis.prototype.fixAxisBreaks = function () { var _this = this; _super.prototype.fixAxisBreaks.call(this); var axisBreaks = this._axisBreaks; if (axisBreaks) { if (axisBreaks.length > 0) { // process breaks axisBreaks.each(function (axisBreak) { var breakGridCount = Math.ceil(_this._gridCount * (Math.min(_this.end, axisBreak.endPosition) - Math.max(_this.start, axisBreak.startPosition)) / (_this.end - _this.start)); axisBreak.gridInterval = _this.chooseInterval(0, axisBreak.adjustedEndValue - axisBreak.adjustedStartValue, breakGridCount); var gridDate = $time.round(new Date(axisBreak.adjustedStartValue), axisBreak.gridInterval.timeUnit, axisBreak.gridInterval.count, _this._firstWeekDay, _this._df.utc, undefined, _this._df.timezoneMinutes, _this._df.timezone); if (gridDate.getTime() > axisBreak.startDate.getTime()) { $time.add(gridDate, axisBreak.gridInterval.timeUnit, axisBreak.gridInterval.count, _this._df.utc); } axisBreak.gridDate = gridDate; }); } } }; /** * @ignore */ DateAxis.prototype.getFirstWeekDay = function () { if (this._df) { return this._df.firstDayOfWeek; } return 1; }; /** * [getGridDate description] * * @ignore Exclude from docs * @todo Description * @param date [description] * @param intervalCount [description] * @return [description] */ DateAxis.prototype.getGridDate = function (date, intervalCount) { var timeUnit = this._gridInterval.timeUnit; var realIntervalCount = this._gridInterval.count; // round date $time.round(date, timeUnit, 1, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone); var prevTimestamp = date.getTime(); var newDate = $time.copy(date); // modify date by adding intervalcount var timestamp = $time.add(newDate, timeUnit, intervalCount, this._df.utc).getTime(); // if it's axis break, get first rounded date which is not in a break var axisBreak = this.isInBreak(timestamp); if (axisBreak && axisBreak.endDate) { newDate = new Date(axisBreak.endDate.getTime()); $time.round(newDate, timeUnit, realIntervalCount, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone); if (newDate.getTime() < axisBreak.endDate.getTime()) { $time.add(newDate, timeUnit, realIntervalCount, this._df.utc); } timestamp = newDate.getTime(); } // get duration between grid lines with break duration removed var durationBreaksRemoved = this.adjustDifference(prevTimestamp, timestamp); // calculate how many time units fit to this duration var countBreaksRemoved = Math.round(durationBreaksRemoved / $time.getDuration(timeUnit)); // if less units fit, add one and repeat if (countBreaksRemoved < realIntervalCount) { return this.getGridDate(date, intervalCount + realIntervalCount); } return newDate; }; /** * [getBreaklessDate description] * * @ignore Exclude from docs * @todo Description * @param axisBreak [description] * @param timeUnit [description] * @param count [description] * @return [description] */ DateAxis.prototype.getBreaklessDate = function (axisBreak, timeUnit, count) { var date = new Date(axisBreak.endValue); $time.round(date, timeUnit, count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone); $time.add(date, timeUnit, count, this._df.utc); var timestamp = date.getTime(); axisBreak = this.isInBreak(timestamp); if (axisBreak) { return this.getBreaklessDate(axisBreak, timeUnit, count); } return date; }; /** * (Re)validates all Axis elements. * * @ignore Exclude from docs * @todo Description (review) */ DateAxis.prototype.validateAxisElements = function () { var _this = this; if ($type.isNumber(this.max) && $type.isNumber(this.min)) { this.calculateZoom(); // first regular items var timestamp = this._gridDate.getTime(); var timeUnit = this._gridInterval.timeUnit; var intervalCount = this._gridInterval.count; var prevGridDate = $time.copy(this._gridDate); var dataItemsIterator_1 = this._dataItemsIterator; this.resetIterators(); var _loop_2 = function () { var date = this_2.getGridDate($time.copy(prevGridDate), intervalCount); timestamp = date.getTime(); var endDate = $time.copy(date); // you might think it's easier to add intervalduration to timestamp, however it won't work for months or years which are not of the same length endDate = $time.add(endDate, timeUnit, intervalCount, this_2._df.utc); var format = this_2.dateFormats.getKey(timeUnit); if (this_2.markUnitChange && prevGridDate) { if ($time.checkChange(date,