@amcharts/amcharts4
Version:
amCharts 4
1,112 lines • 105 kB
JavaScript
/**
* 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,