UNPKG

104 kBJavaScriptView Raw
1/**
2 * DateAxis module
3 */
4import { __assign, __extends } from "tslib";
5/**
6 * ============================================================================
7 * IMPORTS
8 * ============================================================================
9 * @hidden
10 */
11import { ValueAxis, ValueAxisDataItem } from "./ValueAxis";
12import { List } from "../../core/utils/List";
13import { Dictionary } from "../../core/utils/Dictionary";
14import { DateAxisBreak } from "./DateAxisBreak";
15import { registry } from "../../core/Registry";
16import * as $time from "../../core/utils/Time";
17import * as $type from "../../core/utils/Type";
18import * as $iter from "../../core/utils/Iterator";
19import * as $math from "../../core/utils/Math";
20import * as $array from "../../core/utils/Array";
21import * as $object from "../../core/utils/Object";
22import * as $utils from "../../core/utils/Utils";
23import { OrderedListTemplate } from "../../core/utils/SortedList";
24/**
25 * ============================================================================
26 * DATA ITEM
27 * ============================================================================
28 * @hidden
29 */
30/**
31 * Defines data item for [[DateAxis]].
32 *
33 * @see {@link DataItem}
34 */
35var DateAxisDataItem = /** @class */ (function (_super) {
36 __extends(DateAxisDataItem, _super);
37 /**
38 * Constructor
39 */
40 function DateAxisDataItem() {
41 var _this = _super.call(this) || this;
42 _this.className = "DateAxisDataItem";
43 _this.applyTheme();
44 _this.values.date = {};
45 _this.values.endDate = {};
46 return _this;
47 }
48 Object.defineProperty(DateAxisDataItem.prototype, "date", {
49 /**
50 * @return Date
51 */
52 get: function () {
53 return this.dates["date"];
54 },
55 /**
56 * Date position of the data item.
57 *
58 * @param date Date
59 */
60 set: function (date) {
61 this.setDate("date", date);
62 this.value = date.getTime();
63 },
64 enumerable: true,
65 configurable: true
66 });
67 Object.defineProperty(DateAxisDataItem.prototype, "endDate", {
68 /**
69 * @return End date
70 */
71 get: function () {
72 return this.dates["endDate"];
73 },
74 /**
75 * End date for data item.
76 *
77 * @param date End date
78 */
79 set: function (date) {
80 this.setDate("endDate", date);
81 this.endValue = date.getTime();
82 },
83 enumerable: true,
84 configurable: true
85 });
86 return DateAxisDataItem;
87}(ValueAxisDataItem));
88export { DateAxisDataItem };
89/**
90 * ============================================================================
91 * MAIN CLASS
92 * ============================================================================
93 * @hidden
94 */
95/**
96 * Used to create a date/time-based axis for the chart.
97 *
98 * ```TypeScript
99 * // Create the axis
100 * let xAxis = chart.xAxes.push(new am4charts.DateAxis());
101 *
102 * // Set settings
103 * xAxis.title.text = "Time";
104 * ```
105 * ```JavaScript
106 * // Create the axis
107 * var valueAxis = chart.xAxes.push(new am4charts.DateAxis());
108 *
109 * // Set settings
110 * valueAxis.title.text = "Time";
111 * ```
112 * ```JSON
113 * "xAxes": [{
114 * "type": "DateAxis",
115 * "title": {
116 * "text": "Time"
117 * }
118 * }]
119 * ```
120 *
121 * @see {@link IDateAxisEvents} for a list of available Events
122 * @see {@link IDateAxisAdapters} for a list of available Adapters
123 * @see {@link https://www.amcharts.com/docs/v4/concepts/axes/date-axis/} got `DateAxis` documention
124 * @important
125 */
126var DateAxis = /** @class */ (function (_super) {
127 __extends(DateAxis, _super);
128 /**
129 * Constructor
130 */
131 function DateAxis() {
132 var _this =
133 // Init
134 _super.call(this) || this;
135 _this._gapBreaks = false;
136 /**
137 * A list of date/time intervals for Date axis.
138 *
139 * This define various granularities available for the axis. For example
140 * if you have an axis spanning an hour, and space for 6 grid lines / labels
141 * the axis will choose the granularity of 10 minutes, displaying a label
142 * every 10 minutes.
143 *
144 * Default intervals:
145 *
146 * ```JSON
147 * [
148 * { timeUnit: "millisecond", count: 1 },
149 * { timeUnit: "millisecond", count: 5 },
150 * { timeUnit: "millisecond", count: 10 },
151 * { timeUnit: "millisecond", count: 50 },
152 * { timeUnit: "millisecond", count: 100 },
153 * { timeUnit: "millisecond", count: 500 },
154 * { timeUnit: "second", count: 1 },
155 * { timeUnit: "second", count: 5 },
156 * { timeUnit: "second", count: 10 },
157 * { timeUnit: "second", count: 30 },
158 * { timeUnit: "minute", count: 1 },
159 * { timeUnit: "minute", count: 5 },
160 * { timeUnit: "minute", count: 10 },
161 * { timeUnit: "minute", count: 30 },
162 * { timeUnit: "hour", count: 1 },
163 * { timeUnit: "hour", count: 3 },
164 * { timeUnit: "hour", count: 6 },
165 * { timeUnit: "hour", count: 12 },
166 * { timeUnit: "day", count: 1 },
167 * { timeUnit: "day", count: 2 },
168 * { timeUnit: "day", count: 3 },
169 * { timeUnit: "day", count: 4 },
170 * { timeUnit: "day", count: 5 },
171 * { timeUnit: "week", count: 1 },
172 * { timeUnit: "month", count: 1 },
173 * { timeUnit: "month", count: 2 },
174 * { timeUnit: "month", count: 3 },
175 * { timeUnit: "month", count: 6 },
176 * { timeUnit: "year", count: 1 },
177 * { timeUnit: "year", count: 2 },
178 * { timeUnit: "year", count: 5 },
179 * { timeUnit: "year", count: 10 },
180 * { timeUnit: "year", count: 50 },
181 * { timeUnit: "year", count: 100 }
182 * ]
183 * ```
184 */
185 _this.gridIntervals = new List();
186 /**
187 * If data aggregation is enabled by setting Axis' `groupData = true`, the
188 * chart will try to aggregate data items into grouped data items.
189 *
190 * If there are more data items in selected period than `groupCount`, it will
191 * group data items into bigger period.
192 *
193 * For example seconds might be grouped into 10-second aggregate data items.
194 *
195 * This setting indicates what group intervals can the chart group to.
196 *
197 * Default intervals:
198 *
199 * ```JSON
200 * [
201 * { timeUnit: "millisecond", count: 1},
202 * { timeUnit: "millisecond", count: 10 },
203 * { timeUnit: "millisecond", count: 100 },
204 * { timeUnit: "second", count: 1 },
205 * { timeUnit: "second", count: 10 },
206 * { timeUnit: "minute", count: 1 },
207 * { timeUnit: "minute", count: 10 },
208 * { timeUnit: "hour", count: 1 },
209 * { timeUnit: "day", count: 1 },
210 * { timeUnit: "week", count: 1 },
211 * { timeUnit: "month", count: 1 },
212 * { timeUnit: "year", count: 1 }
213 * ]
214 * ```
215 * `groupData = true` does not work in combination with `skipEmptyPeriods = true`.
216 *
217 * @since 4.7.0
218 * @see {@link https://www.amcharts.com/docs/v4/concepts/axes/date-axis/#Dynamic_data_item_grouping} for more information about dynamic data item grouping.
219 */
220 _this.groupIntervals = new List();
221 /**
222 * A collection of date formats to use when formatting different time units
223 * on Date/time axis.
224 *
225 * Actual defaults will depend on the language locale set for the chart.
226 *
227 * To override format for a specific time unit, say days, you need to set
228 * the appropriate key to a format string. E.g.:
229 *
230 * ```TypeScript
231 * axis.dateFormats.setKey("day", "MMMM d, yyyy");
232 * ```
233 * ```JavaScript
234 * axis.dateFormats.setKey("day", "MMMM d, yyyy");
235 * ```
236 * ```JSON
237 * "xAxes": [{
238 * "type": "DateAxis",
239 * "dateFormats": {
240 * "day": "MMMM d, yyyy"
241 * }
242 * }]
243 * ```
244 *
245 * @see {@link DateFormatter}
246 */
247 _this.dateFormats = new Dictionary();
248 /**
249 * These formats are applied to labels that are first in a larger unit.
250 *
251 * For example, if we have a DateAxis with days on it, the first day of month
252 * indicates a break in month - a start of the bigger period.
253 *
254 * For those labels, `periodChangeDateFormats` are applied instead of
255 * `dateFormats`.
256 *
257 * This allows us implement convenient structures, like instead of:
258 *
259 * `Jan 1 - Jan 2 - Jan 3 - ...`
260 *
261 * We can have:
262 *
263 * `Jan - 1 - 2 - 3 - ...`
264 *
265 * This can be disabled by setting `markUnitChange = false`.
266 */
267 _this.periodChangeDateFormats = new Dictionary();
268 /**
269 * Actual interval (granularity) derived from the actual data.
270 */
271 _this._baseIntervalReal = { timeUnit: "day", count: 1 };
272 /**
273 */
274 _this._prevSeriesTime = {};
275 /**
276 * [_minDifference description]
277 *
278 * @todo Description
279 */
280 _this._minDifference = {};
281 /**
282 * @ignore
283 */
284 _this._firstWeekDay = 1;
285 /**
286 * A collection of start timestamps to use as axis' min timestamp for
287 * particular data item item periods.
288 *
289 * @since 4.7.0
290 * @readonly
291 */
292 _this.groupMin = {};
293 /**
294 * A collection of start timestamps to use as axis' max timestamp for
295 * particular data item item periods.
296 *
297 * @since 4.7.0
298 * @readonly
299 */
300 _this.groupMax = {};
301 _this.className = "DateAxis";
302 _this.setPropertyValue("markUnitChange", true);
303 _this.snapTooltip = true;
304 _this.tooltipPosition = "pointer";
305 _this.setPropertyValue("groupData", false);
306 _this.groupCount = 200;
307 _this.events.on("parentset", _this.getDFFormatter, _this, false);
308 // Translatable defaults are applied in `applyInternalDefaults()`
309 // ...
310 // Define default intervals
311 _this.gridIntervals.pushAll([
312 { timeUnit: "millisecond", count: 1 },
313 { timeUnit: "millisecond", count: 5 },
314 { timeUnit: "millisecond", count: 10 },
315 { timeUnit: "millisecond", count: 50 },
316 { timeUnit: "millisecond", count: 100 },
317 { timeUnit: "millisecond", count: 500 },
318 { timeUnit: "second", count: 1 },
319 { timeUnit: "second", count: 5 },
320 { timeUnit: "second", count: 10 },
321 { timeUnit: "second", count: 30 },
322 { timeUnit: "minute", count: 1 },
323 { timeUnit: "minute", count: 5 },
324 { timeUnit: "minute", count: 10 },
325 { timeUnit: "minute", count: 15 },
326 { timeUnit: "minute", count: 30 },
327 { timeUnit: "hour", count: 1 },
328 { timeUnit: "hour", count: 3 },
329 { timeUnit: "hour", count: 6 },
330 { timeUnit: "hour", count: 12 },
331 { timeUnit: "day", count: 1 },
332 { timeUnit: "day", count: 2 },
333 { timeUnit: "day", count: 3 },
334 { timeUnit: "day", count: 4 },
335 { timeUnit: "day", count: 5 },
336 { timeUnit: "week", count: 1 },
337 { timeUnit: "month", count: 1 },
338 { timeUnit: "month", count: 2 },
339 { timeUnit: "month", count: 3 },
340 { timeUnit: "month", count: 6 },
341 { timeUnit: "year", count: 1 },
342 { timeUnit: "year", count: 2 },
343 { timeUnit: "year", count: 5 },
344 { timeUnit: "year", count: 10 },
345 { timeUnit: "year", count: 50 },
346 { timeUnit: "year", count: 100 },
347 { timeUnit: "year", count: 200 },
348 { timeUnit: "year", count: 500 },
349 { timeUnit: "year", count: 1000 },
350 { timeUnit: "year", count: 2000 },
351 { timeUnit: "year", count: 5000 },
352 { timeUnit: "year", count: 10000 },
353 { timeUnit: "year", count: 100000 }
354 ]);
355 _this.groupIntervals.pushAll([
356 { timeUnit: "millisecond", count: 1 },
357 { timeUnit: "millisecond", count: 10 },
358 { timeUnit: "millisecond", count: 100 },
359 { timeUnit: "second", count: 1 },
360 { timeUnit: "second", count: 10 },
361 { timeUnit: "minute", count: 1 },
362 { timeUnit: "minute", count: 10 },
363 { timeUnit: "hour", count: 1 },
364 { timeUnit: "day", count: 1 },
365 { timeUnit: "week", count: 1 },
366 { timeUnit: "month", count: 1 },
367 { timeUnit: "year", count: 1 }
368 ]);
369 // Set field name
370 _this.axisFieldName = "date";
371 // Apply theme
372 _this.applyTheme();
373 return _this;
374 }
375 /**
376 * A function which applies fills to axis cells.
377 *
378 * Default function fills every second fill. You can set this to a function
379 * that follows some other logic.
380 *
381 * Function should accept a [[DateAxisDataItem]] and modify its `axisFill`
382 * property accordingly.
383 */
384 DateAxis.prototype.fillRule = function (dataItem) {
385 var value = dataItem.value;
386 var axis = dataItem.component;
387 var gridInterval = axis._gridInterval;
388 var gridDuration = $time.getDuration(gridInterval.timeUnit, gridInterval.count);
389 if (Math.round((value - axis.min) / gridDuration) / 2 == Math.round(Math.round((value - axis.min) / gridDuration) / 2)) {
390 dataItem.axisFill.__disabled = true;
391 }
392 else {
393 dataItem.axisFill.__disabled = false;
394 }
395 };
396 /**
397 * Sets defaults that instantiate some objects that rely on parent, so they
398 * cannot be set in constructor.
399 */
400 DateAxis.prototype.applyInternalDefaults = function () {
401 _super.prototype.applyInternalDefaults.call(this);
402 // Set default date formats
403 if (!this.dateFormats.hasKey("millisecond")) {
404 this.dateFormats.setKey("millisecond", this.language.translate("_date_millisecond"));
405 }
406 if (!this.dateFormats.hasKey("second")) {
407 this.dateFormats.setKey("second", this.language.translate("_date_second"));
408 }
409 if (!this.dateFormats.hasKey("minute")) {
410 this.dateFormats.setKey("minute", this.language.translate("_date_minute"));
411 }
412 if (!this.dateFormats.hasKey("hour")) {
413 this.dateFormats.setKey("hour", this.language.translate("_date_hour"));
414 }
415 if (!this.dateFormats.hasKey("day")) {
416 this.dateFormats.setKey("day", this.language.translate("_date_day"));
417 }
418 if (!this.dateFormats.hasKey("week")) {
419 this.dateFormats.setKey("week", this.language.translate("_date_day")); // not a mistake
420 }
421 if (!this.dateFormats.hasKey("month")) {
422 this.dateFormats.setKey("month", this.language.translate("_date_month"));
423 }
424 if (!this.dateFormats.hasKey("year")) {
425 this.dateFormats.setKey("year", this.language.translate("_date_year"));
426 }
427 if (!this.periodChangeDateFormats.hasKey("millisecond")) {
428 this.periodChangeDateFormats.setKey("millisecond", this.language.translate("_date_millisecond"));
429 }
430 if (!this.periodChangeDateFormats.hasKey("second")) {
431 this.periodChangeDateFormats.setKey("second", this.language.translate("_date_second"));
432 }
433 if (!this.periodChangeDateFormats.hasKey("minute")) {
434 this.periodChangeDateFormats.setKey("minute", this.language.translate("_date_minute"));
435 }
436 if (!this.periodChangeDateFormats.hasKey("hour")) {
437 this.periodChangeDateFormats.setKey("hour", this.language.translate("_date_day"));
438 }
439 if (!this.periodChangeDateFormats.hasKey("day")) {
440 this.periodChangeDateFormats.setKey("day", this.language.translate("_date_day"));
441 }
442 if (!this.periodChangeDateFormats.hasKey("week")) {
443 this.periodChangeDateFormats.setKey("week", this.language.translate("_date_day"));
444 }
445 if (!this.periodChangeDateFormats.hasKey("month")) {
446 this.periodChangeDateFormats.setKey("month", this.language.translate("_date_month") + " " + this.language.translate("_date_year"));
447 }
448 };
449 /**
450 * Returns a new/empty [[DataItem]] of the type appropriate for this object.
451 *
452 * @see {@link DataItem}
453 * @return Data Item
454 */
455 DateAxis.prototype.createDataItem = function () {
456 return new DateAxisDataItem();
457 };
458 /**
459 * Returns a new/empty [[AxisBreak]] of the appropriate type.
460 *
461 * @return Axis break
462 */
463 DateAxis.prototype.createAxisBreak = function () {
464 return new DateAxisBreak();
465 };
466 /**
467 * Validates Axis' data items.
468 *
469 * @ignore Exclude from docs
470 */
471 DateAxis.prototype.validateDataItems = function () {
472 // allows to keep selection of the same size
473 var start = this.start;
474 var end = this.end;
475 var baseDuration = this.baseDuration;
476 var periodCount = (this.max - this.min) / baseDuration;
477 this._firstWeekDay = this.getFirstWeekDay();
478 this.getDFFormatter();
479 _super.prototype.validateDataItems.call(this);
480 var mainBaseDuration = $time.getDuration(this.mainBaseInterval.timeUnit, this.mainBaseInterval.count);
481 this.maxZoomFactor = Math.max(1, (this.max - this.min) / mainBaseDuration);
482 this._deltaMinMax = this.baseDuration / 2;
483 // allows to keep selection of the same size
484 var newPeriodCount = (this.max - this.min) / baseDuration;
485 start = start + (end - start) * (1 - periodCount / newPeriodCount);
486 this.zoom({ start: start, end: end }, false, true); // added instantlyto solve zoomout problem when we have axes gaps. @todo: check how this affects maxZoomFactor
487 };
488 /**
489 * Handles process after zoom.
490 *
491 * @ignore Exclude from docs
492 * @todo Does nothing?
493 */
494 DateAxis.prototype.handleSelectionExtremesChange = function () {
495 };
496 /**
497 * Calculates all positions, related to axis as per current zoom.
498 *
499 * @ignore Exclude from docs
500 */
501 DateAxis.prototype.calculateZoom = function () {
502 var _this = this;
503 _super.prototype.calculateZoom.call(this);
504 var difference = this.adjustDifference(this._minZoomed, this._maxZoomed);
505 var dataSetChanged = false;
506 // if data has to be grouped, choose interval and set dataset
507 if (this.groupData && $type.hasValue(difference)) {
508 var mainBaseInterval = this.mainBaseInterval;
509 var modifiedDifference = difference + (this.startLocation + (1 - this.endLocation)) * this.baseDuration;
510 var groupInterval = void 0;
511 if (this.groupInterval) {
512 groupInterval = __assign({}, this.groupInterval);
513 }
514 else {
515 groupInterval = this.chooseInterval(0, modifiedDifference, this.groupCount, this.groupIntervals);
516 if ($time.getDuration(groupInterval.timeUnit, groupInterval.count) < $time.getDuration(mainBaseInterval.timeUnit, mainBaseInterval.count)) {
517 groupInterval = __assign({}, mainBaseInterval);
518 }
519 }
520 this._groupInterval = groupInterval;
521 var newId = groupInterval.timeUnit + groupInterval.count;
522 if (this._currentDataSetId != newId) {
523 this._currentDataSetId = newId;
524 this.dispatch("groupperiodchanged");
525 }
526 this.series.each(function (series) {
527 if (series.baseAxis == _this) {
528 if (series.setDataSet(_this._currentDataSetId)) {
529 dataSetChanged = true;
530 }
531 }
532 });
533 }
534 var gridInterval = this.chooseInterval(0, difference, this._gridCount);
535 if ($time.getDuration(gridInterval.timeUnit, gridInterval.count) < this.baseDuration) {
536 gridInterval = __assign({}, this.baseInterval);
537 }
538 this._gridInterval = gridInterval;
539 this._nextGridUnit = $time.getNextUnit(gridInterval.timeUnit);
540 // the following is needed to avoid grid flickering while scrolling
541 this._intervalDuration = $time.getDuration(gridInterval.timeUnit, gridInterval.count);
542 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);
543 // tell series start/end
544 $iter.each(this.series.iterator(), function (series) {
545 if (series.baseAxis == _this) {
546 var field_1 = series.getAxisField(_this);
547 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();
548 var minZoomedStr = minZoomed.toString();
549 var startDataItem = series.dataItemsByAxis.getKey(_this.uid).getKey(minZoomedStr + series.currentDataSetId);
550 var startIndex = 0;
551 if (_this.start != 0) {
552 if (startDataItem) {
553 startDataItem = _this.findFirst(startDataItem, minZoomed, field_1);
554 startIndex = startDataItem.index;
555 }
556 else {
557 startIndex = series.dataItems.findClosestIndex(_this._minZoomed, function (x) { return x[field_1]; }, "left");
558 }
559 }
560 // 1 millisecond is removed so that if only first item is selected, it would not count in the second.
561 var baseInterval = _this.baseInterval;
562 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();
563 var maxZoomedStr = maxZoomed.toString();
564 var endDataItem = series.dataItemsByAxis.getKey(_this.uid).getKey(maxZoomedStr + series.currentDataSetId);
565 var endIndex = series.dataItems.length;
566 if (_this.end != 1) {
567 if (endDataItem) {
568 endIndex = endDataItem.index;
569 }
570 else {
571 maxZoomed -= 1;
572 endIndex = series.dataItems.findClosestIndex(maxZoomed, function (x) { return x[field_1]; }, "right");
573 // not good - if end is in the gap, indexes go like 5,4,3,4,2,1
574 //if (endIndex < series.dataItems.length) {
575 endIndex++;
576 //}
577 }
578 }
579 if (series.max(_this) < minZoomed) {
580 series.startIndex = series.dataItems.length;
581 series.endIndex = series.dataItems.length;
582 series.outOfRange = true;
583 }
584 else if (series.min(_this) > maxZoomed) {
585 series.startIndex = 0;
586 series.endIndex = 0;
587 series.outOfRange = true;
588 }
589 else {
590 series.outOfRange = false;
591 series.startIndex = startIndex;
592 series.endIndex = endIndex;
593 }
594 // console.log(series.name, startIndex, endIndex);
595 if (!dataSetChanged && series.dataRangeInvalid) {
596 series.validateDataRange();
597 }
598 }
599 });
600 };
601 DateAxis.prototype.findFirst = function (dataItem, time, key) {
602 var index = dataItem.index;
603 if (index > 0) {
604 var series = dataItem.component;
605 var previousDataItem = series.dataItems.getIndex(index - 1);
606 var previousDate = previousDataItem[key];
607 if (!previousDate || previousDate.getTime() < time) {
608 return dataItem;
609 }
610 else {
611 return this.findFirst(previousDataItem, time, key);
612 }
613 }
614 else {
615 return dataItem;
616 }
617 };
618 /**
619 * (Re)validates data.
620 *
621 * @ignore Exclude from docs
622 */
623 DateAxis.prototype.validateData = function () {
624 _super.prototype.validateData.call(this);
625 if (!$type.isNumber(this.baseInterval.count)) {
626 this.baseInterval.count = 1;
627 }
628 };
629 Object.defineProperty(DateAxis.prototype, "minDifference", {
630 /**
631 * @ignore
632 */
633 get: function () {
634 var _this = this;
635 var minDifference = Number.MAX_VALUE;
636 this.series.each(function (series) {
637 if (minDifference > _this._minDifference[series.uid]) {
638 minDifference = _this._minDifference[series.uid];
639 }
640 });
641 if (minDifference == Number.MAX_VALUE || minDifference == 0) {
642 minDifference = $time.getDuration("day");
643 }
644 return minDifference;
645 },
646 enumerable: true,
647 configurable: true
648 });
649 /**
650 * [dataChangeUpdate description]
651 *
652 *
653 * @ignore Exclude from docs
654 * @todo Description
655 */
656 DateAxis.prototype.seriesDataChangeUpdate = function (series) {
657 this._minDifference[series.uid] = Number.MAX_VALUE;
658 };
659 /**
660 * [postProcessSeriesDataItems description]
661 *
662 * @ignore Exclude from docs
663 * @todo Description
664 */
665 DateAxis.prototype.postProcessSeriesDataItems = function (series) {
666 var _this = this;
667 this._firstWeekDay = this.getFirstWeekDay();
668 if (series) {
669 this.seriesGroupUpdate(series);
670 }
671 else {
672 this.series.each(function (series) {
673 _this.seriesGroupUpdate(series);
674 });
675 }
676 this.addEmptyUnitsBreaks();
677 };
678 DateAxis.prototype.seriesGroupUpdate = function (series) {
679 var _this = this;
680 if (JSON.stringify(series._baseInterval[this.uid]) != JSON.stringify(this.mainBaseInterval)) {
681 series._baseInterval[this.uid] = this.mainBaseInterval;
682 series.mainDataSet.each(function (dataItem) {
683 _this.postProcessSeriesDataItem(dataItem);
684 });
685 if (this.groupData) {
686 this.groupSeriesData(series);
687 }
688 }
689 };
690 /**
691 * Calculates series group data.
692 *
693 * @param series Series
694 * @ignore
695 */
696 DateAxis.prototype.groupSeriesData = function (series) {
697 var _this = this;
698 if (series.baseAxis == this && series.dataItems.length > 0 && !series.dataGrouped) {
699 series.bulletsContainer.removeChildren();
700 // make array of intervals which will be used;
701 var intervals_1 = [];
702 var mainBaseInterval = this.mainBaseInterval;
703 var mainIntervalDuration_1 = $time.getDuration(mainBaseInterval.timeUnit, mainBaseInterval.count);
704 this.groupIntervals.each(function (interval) {
705 var intervalDuration = $time.getDuration(interval.timeUnit, interval.count);
706 if ((intervalDuration > mainIntervalDuration_1 && intervalDuration < (_this.max - _this.min)) || _this.groupInterval) {
707 intervals_1.push(interval);
708 }
709 });
710 if (series._dataSets) {
711 series._dataSets.each(function (key, dataItems) {
712 dataItems.each(function (dataItem) {
713 dataItem.dispose();
714 });
715 dataItems.clear();
716 });
717 series._dataSets.clear();
718 }
719 series.dataGrouped = true;
720 $array.each(intervals_1, function (interval) {
721 //let mainBaseInterval = this._mainBaseInterval;
722 var key = "date" + _this.axisLetter;
723 // create data set
724 var dataSetId = interval.timeUnit + interval.count;
725 // todo: check where this clone goes
726 var dataSet = new OrderedListTemplate(series.mainDataSet.template.clone());
727 series.dataSets.setKey(dataSetId, dataSet);
728 var dataItems = series.mainDataSet;
729 var previousTime = Number.NEGATIVE_INFINITY;
730 var i = 0;
731 var newDataItem;
732 var dataFields = [];
733 $object.each(series.dataFields, function (dfkey, df) {
734 var dfk = dfkey;
735 if (dfk != key && dfk.indexOf("Show") == -1) {
736 dataFields.push(dfk);
737 }
738 });
739 var roundedDate;
740 dataItems.each(function (dataItem) {
741 var date = dataItem.getDate(key);
742 if (date) {
743 var time = date.getTime();
744 roundedDate = $time.round(new Date(time), interval.timeUnit, interval.count, _this._df.firstDayOfWeek, _this._df.utc, undefined, _this._df.timezoneMinutes, _this._df.timezone);
745 var currentTime = roundedDate.getTime();
746 // changed period
747 if (previousTime < currentTime) {
748 if (newDataItem && series._adapterO) {
749 $array.each(dataFields, function (vkey) {
750 newDataItem.values[vkey].value = series._adapterO.apply("groupDataItem", {
751 dataItem: newDataItem,
752 interval: interval,
753 dataField: vkey,
754 date: roundedDate,
755 value: newDataItem.values[vkey].value
756 }).value;
757 newDataItem.values[vkey].workingValue = newDataItem.values[vkey].value;
758 });
759 }
760 newDataItem = dataSet.create();
761 newDataItem.dataContext = {};
762 newDataItem.setWorkingLocation("dateX", series.dataItems.template.locations.dateX, 0);
763 newDataItem.setWorkingLocation("openDateX", series.dataItems.template.locations.openDateX, 0);
764 newDataItem.setWorkingLocation("dateY", series.dataItems.template.locations.dateY, 0);
765 newDataItem.setWorkingLocation("openDateY", series.dataItems.template.locations.openDateY, 0);
766 newDataItem.component = series;
767 // other Dates?
768 newDataItem.setDate(key, roundedDate);
769 newDataItem._index = i;
770 i++;
771 $array.each(dataFields, function (vkey) {
772 //let groupFieldName = vkey + "Group";
773 var dvalues = dataItem.values[vkey];
774 if (dvalues) {
775 var value = dvalues.value;
776 if (series._adapterO) {
777 value = series._adapterO.apply("groupValue", {
778 dataItem: dataItem,
779 interval: interval,
780 dataField: vkey,
781 date: roundedDate,
782 value: value
783 }).value;
784 }
785 var values = newDataItem.values[vkey];
786 if ($type.isNumber(value)) {
787 values.value = value;
788 values.workingValue = value;
789 values.open = value;
790 values.close = value;
791 values.low = value;
792 values.high = value;
793 values.sum = value;
794 values.average = value;
795 values.count = 1;
796 }
797 else {
798 values.count = 0;
799 }
800 }
801 });
802 _this.postProcessSeriesDataItem(newDataItem, interval);
803 $object.each(series.propertyFields, function (key, fieldValue) {
804 var f = key;
805 var value = dataItem.properties[key];
806 if ($type.hasValue(value)) {
807 newDataItem.hasProperties = true;
808 newDataItem.setProperty(f, value);
809 }
810 });
811 newDataItem.groupDataItems = [dataItem];
812 previousTime = currentTime;
813 }
814 else {
815 if (newDataItem) {
816 $array.each(dataFields, function (vkey) {
817 var groupFieldName = series.groupFields[vkey];
818 var dvalues = dataItem.values[vkey];
819 if (dvalues) {
820 var value = dvalues.value;
821 if (series._adapterO) {
822 value = series._adapterO.apply("groupValue", {
823 dataItem: dataItem,
824 interval: interval,
825 dataField: vkey,
826 date: roundedDate,
827 value: value
828 }).value;
829 }
830 if ($type.isNumber(value)) {
831 var values = newDataItem.values[vkey];
832 if (!$type.isNumber(values.open)) {
833 values.open = value;
834 }
835 values.close = value;
836 if (values.low > value || !$type.isNumber(values.low)) {
837 values.low = value;
838 }
839 if (values.high < value || !$type.isNumber(values.high)) {
840 values.high = value;
841 }
842 if ($type.isNumber(values.sum)) {
843 values.sum += value;
844 }
845 else {
846 values.sum = value;
847 }
848 values.count++;
849 values.average = values.sum / values.count;
850 if ($type.isNumber(values[groupFieldName])) {
851 values.value = values[groupFieldName];
852 values.workingValue = values.value;
853 }
854 }
855 }
856 });
857 $utils.copyProperties(dataItem.properties, newDataItem.properties);
858 $object.each(series.propertyFields, function (key, fieldValue) {
859 var f = key;
860 var value = dataItem.properties[key];
861 if ($type.hasValue(value)) {
862 newDataItem.hasProperties = true;
863 newDataItem.setProperty(f, value);
864 }
865 });
866 newDataItem.groupDataItems.push(dataItem);
867 }
868 }
869 }
870 if (newDataItem) {
871 $utils.copyProperties(dataItem.dataContext, newDataItem.dataContext);
872 }
873 });
874 if (newDataItem && series._adapterO) {
875 $array.each(dataFields, function (vkey) {
876 newDataItem.values[vkey].value = series._adapterO.apply("groupDataItem", {
877 dataItem: newDataItem,
878 interval: interval,
879 dataField: vkey,
880 date: roundedDate,
881 value: newDataItem.values[vkey].value
882 }).value;
883 newDataItem.values[vkey].workingValue = newDataItem.values[vkey].value;
884 });
885 }
886 });
887 this.calculateZoom();
888 }
889 };
890 /**
891 * @ignore
892 */
893 DateAxis.prototype.getDFFormatter = function () {
894 this._df = this.dateFormatter;
895 };
896 /**
897 * [postProcessSeriesDataItem description]
898 *
899 * @ignore Exclude from docs
900 * @todo Description
901 * @param dataItem Data item
902 */
903 DateAxis.prototype.postProcessSeriesDataItem = function (dataItem, interval) {
904 var _this = this;
905 // we need to do this for all series data items not only added recently, as baseInterval might change
906 var intervalID = "";
907 if (interval) {
908 intervalID = interval.timeUnit + interval.count;
909 }
910 else {
911 interval = this.mainBaseInterval;
912 }
913 var series = dataItem.component;
914 var dataItemsByAxis = series.dataItemsByAxis.getKey(this.uid);
915 $object.each(dataItem.dates, function (key) {
916 var date = dataItem.getDate(key);
917 var time = date.getTime();
918 var startDate = $time.round(new Date(time), interval.timeUnit, interval.count, _this._firstWeekDay, _this._df.utc, undefined, _this._df.timezoneMinutes, _this._df.timezone);
919 var startTime = startDate.getTime();
920 var endDate = $time.add(new Date(startTime), interval.timeUnit, interval.count, _this._df.utc);
921 dataItem.setCalculatedValue(key, startTime, "open");
922 dataItem.setCalculatedValue(key, endDate.getTime(), "close");
923 dataItemsByAxis.setKey(startTime + intervalID, dataItem);
924 });
925 };
926 /**
927 * Collapses empty stretches of date/time scale by creating [[AxisBreak]]
928 * elements for them.
929 *
930 * Can be used to automatically remove strethes without data, like weekends.
931 *
932 * No, need to call this manually. It will automatically be done if
933 * `skipEmptyPeriods = true`.
934 *
935 * @ignore Exclude from docs
936 */
937 DateAxis.prototype.addEmptyUnitsBreaks = function () {
938 var _this = this;
939 if (this.skipEmptyPeriods && $type.isNumber(this.min) && $type.isNumber(this.max)) {
940 var timeUnit = this.baseInterval.timeUnit;
941 var count = this.baseInterval.count;
942 if (this._axisBreaks) {
943 this._axisBreaks.clear(); // TODO: what about breaks added by user?
944 }
945 var date = $time.round(new Date(this.min), timeUnit, count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone);
946 var axisBreak = void 0;
947 var _loop_1 = function () {
948 $time.add(date, timeUnit, count, this_1._df.utc);
949 var startTime = date.getTime();
950 var startTimeStr = startTime.toString();
951 var hasData = $iter.contains(this_1.series.iterator(), function (series) {
952 return !!series.dataItemsByAxis.getKey(_this.uid).getKey(startTimeStr + series.currentDataSetId);
953 });
954 // open break if not yet opened
955 if (!hasData) {
956 if (!axisBreak) {
957 axisBreak = this_1.axisBreaks.create();
958 axisBreak.startDate = new Date(startTime);
959 this_1._gapBreaks = true;
960 }
961 }
962 else {
963 // close if already opened
964 if (axisBreak) {
965 // close at end time minus one millisecond
966 axisBreak.endDate = new Date(startTime - 1);
967 axisBreak = undefined;
968 }
969 }
970 };
971 var this_1 = this;
972 while (date.getTime() < this.max - this.baseDuration) {
973 _loop_1();
974 }
975 }
976 };
977 /**
978 * Updates positioning of Axis breaks after something changes.
979 *
980 * @ignore Exclude from docs
981 */
982 DateAxis.prototype.fixAxisBreaks = function () {
983 var _this = this;
984 _super.prototype.fixAxisBreaks.call(this);
985 var axisBreaks = this._axisBreaks;
986 if (axisBreaks) {
987 if (axisBreaks.length > 0) {
988 // process breaks
989 axisBreaks.each(function (axisBreak) {
990 var breakGridCount = Math.ceil(_this._gridCount * (Math.min(_this.end, axisBreak.endPosition) - Math.max(_this.start, axisBreak.startPosition)) / (_this.end - _this.start));
991 axisBreak.gridInterval = _this.chooseInterval(0, axisBreak.adjustedEndValue - axisBreak.adjustedStartValue, breakGridCount);
992 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);
993 if (gridDate.getTime() > axisBreak.startDate.getTime()) {
994 $time.add(gridDate, axisBreak.gridInterval.timeUnit, axisBreak.gridInterval.count, _this._df.utc);
995 }
996 axisBreak.gridDate = gridDate;
997 });
998 }
999 }
1000 };
1001 /**
1002 * @ignore
1003 */
1004 DateAxis.prototype.getFirstWeekDay = function () {
1005 if (this._df) {
1006 return this._df.firstDayOfWeek;
1007 }
1008 return 1;
1009 };
1010 /**
1011 * [getGridDate description]
1012 *
1013 * @ignore Exclude from docs
1014 * @todo Description
1015 * @param date [description]
1016 * @param intervalCount [description]
1017 * @return [description]
1018 */
1019 DateAxis.prototype.getGridDate = function (date, intervalCount) {
1020 var timeUnit = this._gridInterval.timeUnit;
1021 var realIntervalCount = this._gridInterval.count;
1022 // round date
1023 $time.round(date, timeUnit, 1, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone);
1024 var prevTimestamp = date.getTime();
1025 var newDate = $time.copy(date);
1026 // modify date by adding intervalcount
1027 var timestamp = $time.add(newDate, timeUnit, intervalCount, this._df.utc).getTime();
1028 // if it's axis break, get first rounded date which is not in a break
1029 var axisBreak = this.isInBreak(timestamp);
1030 if (axisBreak && axisBreak.endDate) {
1031 newDate = new Date(axisBreak.endDate.getTime());
1032 $time.round(newDate, timeUnit, realIntervalCount, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone);
1033 if (newDate.getTime() < axisBreak.endDate.getTime()) {
1034 $time.add(newDate, timeUnit, realIntervalCount, this._df.utc);
1035 }
1036 timestamp = newDate.getTime();
1037 }
1038 // get duration between grid lines with break duration removed
1039 var durationBreaksRemoved = this.adjustDifference(prevTimestamp, timestamp);
1040 // calculate how many time units fit to this duration
1041 var countBreaksRemoved = Math.round(durationBreaksRemoved / $time.getDuration(timeUnit));
1042 // if less units fit, add one and repeat
1043 if (countBreaksRemoved < realIntervalCount) {
1044 return this.getGridDate(date, intervalCount + realIntervalCount);
1045 }
1046 return newDate;
1047 };
1048 /**
1049 * [getBreaklessDate description]
1050 *
1051 * @ignore Exclude from docs
1052 * @todo Description
1053 * @param axisBreak [description]
1054 * @param timeUnit [description]
1055 * @param count [description]
1056 * @return [description]
1057 */
1058 DateAxis.prototype.getBreaklessDate = function (axisBreak, timeUnit, count) {
1059 var date = new Date(axisBreak.endValue);
1060 $time.round(date, timeUnit, count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone);
1061 $time.add(date, timeUnit, count, this._df.utc);
1062 var timestamp = date.getTime();
1063 axisBreak = this.isInBreak(timestamp);
1064 if (axisBreak) {
1065 return this.getBreaklessDate(axisBreak, timeUnit, count);
1066 }
1067 return date;
1068 };
1069 /**
1070 * (Re)validates all Axis elements.
1071 *
1072 * @ignore Exclude from docs
1073 * @todo Description (review)
1074 */
1075 DateAxis.prototype.validateAxisElements = function () {
1076 var _this = this;
1077 if ($type.isNumber(this.max) && $type.isNumber(this.min)) {
1078 this.calculateZoom();
1079 // first regular items
1080 var timestamp = this._gridDate.getTime();
1081 var timeUnit = this._gridInterval.timeUnit;
1082 var intervalCount = this._gridInterval.count;
1083 var prevGridDate = $time.copy(this._gridDate);
1084 var dataItemsIterator_1 = this._dataItemsIterator;
1085 this.resetIterators();
1086 var _loop_2 = function () {
1087 var date = this_2.getGridDate($time.copy(prevGridDate), intervalCount);
1088 timestamp = date.getTime();
1089 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
1090 endDate = $time.add(endDate, timeUnit, intervalCount, this_2._df.utc);
1091 var format = this_2.dateFormats.getKey(timeUnit);
1092 if (this_2.markUnitChange && prevGridDate) {
1093 if ($time.checkChange(date, prevGridDate, this_2._nextGridUnit, this_2._df.utc)) {
1094 if (timeUnit !== "year") {
1095 format = this_2.periodChangeDateFormats.getKey(timeUnit);
1096 }
1097 }
1098 }
1099 var text = this_2._df.format(date, format);
1100 var dataItem = dataItemsIterator_1.find(function (x) { return x.text === text; });
1101 if (dataItem.__disabled) {
1102 dataItem.__disabled = false;
1103 }
1104 this_2.appendDataItem(dataItem);
1105 dataItem.axisBreak = undefined;
1106 dataItem.date = date;
1107 dataItem.endDate = endDate;
1108 dataItem.text = text;
1109 this_2.validateDataElement(dataItem);
1110 prevGridDate = date;
1111 };
1112 var this_2 = this;
1113 while (timestamp <= this._maxZoomed) {
1114 _loop_2();
1115 }
1116 // breaks later
1117 var renderer_1 = this.renderer;
1118 if (this._axisBreaks) {
1119 $iter.each(this._axisBreaks.iterator(), function (axisBreak) {
1120 if (axisBreak.breakSize > 0) {
1121 var timeUnit_1 = axisBreak.gridInterval.timeUnit;
1122 var intervalCount_1 = axisBreak.gridInterval.count;
1123 // only add grid if gap is bigger then minGridDistance
1124 if ($math.getDistance(axisBreak.startPoint, axisBreak.endPoint) > renderer_1.minGridDistance * 4) {
1125 var timestamp_1 = axisBreak.gridDate.getTime();
1126 var prevGridDate_1;
1127 var count = 0;
1128 var _loop_3 = function () {
1129 var date = $time.copy(axisBreak.gridDate);
1130 timestamp_1 = $time.add(date, timeUnit_1, intervalCount_1 * count, _this._df.utc).getTime();
1131 count++;
1132 if (timestamp_1 > axisBreak.adjustedStartValue && timestamp_1 < axisBreak.adjustedEndValue) {
1133 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
1134 endDate = $time.add(endDate, timeUnit_1, intervalCount_1, _this._df.utc);
1135 var format = _this.dateFormats.getKey(timeUnit_1);
1136 if (_this.markUnitChange && prevGridDate_1) {
1137 if ($time.checkChange(date, prevGridDate_1, _this._nextGridUnit, _this._df.utc)) {
1138 if (timeUnit_1 !== "year") {
1139 format = _this.periodChangeDateFormats.getKey(timeUnit_1);
1140 }
1141 }
1142 }
1143 var text_1 = _this._df.format(date, format);
1144 var dataItem = dataItemsIterator_1.find(function (x) { return x.text === text_1; });
1145 if (dataItem.__disabled) {
1146 dataItem.__disabled = false;
1147 }
1148 //this.processDataItem(dataItem);
1149 _this.appendDataItem(dataItem);
1150 dataItem.axisBreak = axisBreak;
1151 axisBreak.dataItems.moveValue(dataItem);
1152 dataItem.date = date;
1153 dataItem.endDate = endDate;
1154 dataItem.text = text_1;
1155 prevGridDate_1 = date;
1156 _this.validateDataElement(dataItem);
1157 }
1158 };
1159 while (timestamp_1 <= axisBreak.adjustedMax) {
1160 _loop_3();
1161 }
1162 }
1163 }
1164 });
1165 }
1166 }
1167 };
1168 /**
1169 * Validates Axis data item.
1170 *
1171 * @ignore Exclude from docs
1172 * @param dataItem Data item
1173 */
1174 DateAxis.prototype.validateDataElement = function (dataItem) {
1175 dataItem.itemIndex = this._axisItemCount;
1176 this._axisItemCount++;
1177 if ($type.isNumber(this.max) && $type.isNumber(this.min)) {
1178 var renderer = this.renderer;
1179 var timestamp = dataItem.value;
1180 var endTimestamp = dataItem.endValue;
1181 if (!$type.isNumber(endTimestamp)) {
1182 endTimestamp = timestamp;
1183 }
1184 var position = this.valueToPosition(timestamp);
1185 var endPosition = this.valueToPosition(endTimestamp);
1186 var fillEndPosition = endPosition;
1187 if (!dataItem.isRange && this._gridInterval.count > this.baseInterval.count) {
1188 endPosition = position + (endPosition - position) / (this._gridInterval.count / this.baseInterval.count);
1189 }
1190 dataItem.position = position;
1191 var tick = dataItem.tick;
1192 if (tick && !tick.disabled) {
1193 renderer.updateTickElement(tick, position, endPosition);
1194 }
1195 var grid = dataItem.grid;
1196 if (grid && !grid.disabled) {
1197 renderer.updateGridElement(grid, position, endPosition);
1198 }
1199 var fill = dataItem.axisFill;
1200 if (fill && !fill.disabled) {
1201 renderer.updateFillElement(fill, position, fillEndPosition);
1202 if (!dataItem.isRange) {
1203 this.fillRule(dataItem);
1204 }
1205 }
1206 var mask = dataItem.mask;
1207 if (mask) {
1208 renderer.updateFillElement(mask, position, endPosition);
1209 }
1210 if (dataItem.bullet) {
1211 renderer.updateBullet(dataItem.bullet, position, endPosition);
1212 }
1213 var label = dataItem.label;
1214 if (label && !label.disabled) {
1215 var location_1 = label.location;
1216 if (location_1 == 0) {
1217 if (this._gridInterval.count == 1 && this._gridInterval.timeUnit != "week" && !dataItem.isRange) {
1218 location_1 = 0.5;
1219 }
1220 else {
1221 location_1 = 0;
1222 }
1223 }
1224 renderer.updateLabelElement(label, position, endPosition, location_1);
1225 }
1226 }
1227 };
1228 Object.defineProperty(DateAxis.prototype, "baseDuration", {
1229 /**
1230 * A duration in milliseconds of the `baseInterval`.
1231 *
1232 * @return Duration (ms)
1233 */
1234 get: function () {
1235 return $time.getDuration(this.baseInterval.timeUnit, this.baseInterval.count);
1236 },
1237 enumerable: true,
1238 configurable: true
1239 });
1240 /**
1241 * Adjusts min/max values.
1242 *
1243 * @ignore Exclude from docs.
1244 * @todo Description (review)
1245 * @param min Min timestamp
1246 * @param max Max timestamp
1247 * @return Adjusted min/max step
1248 */
1249 DateAxis.prototype.adjustMinMax = function (min, max) {
1250 return { min: min, max: max, step: this.baseDuration };
1251 };
1252 /**
1253 * Adjusts the minimum timestamp as per cell start location.
1254 *
1255 * @param value Value
1256 * @return Adjusted value
1257 */
1258 DateAxis.prototype.fixMin = function (value) {
1259 // like this because months are not equal
1260 var interval = this.baseInterval;
1261 var startTime = $time.round(new Date(value), interval.timeUnit, interval.count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone).getTime();
1262 var endTime = $time.add(new Date(startTime), interval.timeUnit, interval.count, this._df.utc).getTime();
1263 return startTime + (endTime - startTime) * this.startLocation;
1264 };
1265 /**
1266 * Adjusts the maximum timestamp as per cell start location.
1267 *
1268 * @param value Value
1269 * @return Adjusted value
1270 */
1271 DateAxis.prototype.fixMax = function (value) {
1272 // like this because months are not equal
1273 var interval = this.baseInterval;
1274 var startTime = $time.round(new Date(value), interval.timeUnit, interval.count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone).getTime();
1275 var endTime = $time.add(new Date(startTime), interval.timeUnit, interval.count, this._df.utc).getTime();
1276 return startTime + (endTime - startTime) * this.endLocation;
1277 };
1278 /**
1279 * [chooseInterval description]
1280 *
1281 * @ignore Exclude from docs.
1282 * @todo Description
1283 * @param index [description]
1284 * @param duration [description]
1285 * @param gridCount [description]
1286 * @return [description]
1287 */
1288 DateAxis.prototype.chooseInterval = function (index, duration, gridCount, intervals) {
1289 if (!intervals) {
1290 intervals = this.gridIntervals;
1291 }
1292 var gridInterval = intervals.getIndex(index);
1293 var intervalDuration = $time.getDuration(gridInterval.timeUnit, gridInterval.count);
1294 var lastIndex = intervals.length - 1;
1295 if (index >= lastIndex) {
1296 return __assign({}, intervals.getIndex(lastIndex));
1297 }
1298 var count = Math.ceil(duration / intervalDuration);
1299 if (duration < intervalDuration && index > 0) {
1300 return __assign({}, intervals.getIndex(index - 1));
1301 }
1302 if (count <= gridCount) {
1303 return __assign({}, intervals.getIndex(index));
1304 }
1305 else {
1306 if (index + 1 < intervals.length) {
1307 return this.chooseInterval(index + 1, duration, gridCount, intervals);
1308 }
1309 else {
1310 return __assign({}, intervals.getIndex(index));
1311 }
1312 }
1313 };
1314 /**
1315 * Formats the value according to axis' own [[DateFormatter]].
1316 *
1317 * @param value Source value
1318 * @return Formatted value
1319 */
1320 DateAxis.prototype.formatLabel = function (value) {
1321 return this._df.format(value);
1322 };
1323 /**
1324 * Converts a Date to an asbolute pixel position within Axis.
1325 *
1326 * @param date Date
1327 * @return Position (px)
1328 */
1329 DateAxis.prototype.dateToPosition = function (date) {
1330 return this.valueToPosition(date.getTime());
1331 };
1332 /**
1333 * Converts a numeric timestamp or a `Date` to a relative position on axis.
1334 *
1335 * @param date Date or a timestamp
1336 * @return Relative position
1337 */
1338 DateAxis.prototype.anyToPosition = function (date) {
1339 if (date instanceof Date) {
1340 return this.dateToPosition(date);
1341 }
1342 else {
1343 return this.valueToPosition(date);
1344 }
1345 };
1346 /**
1347 * Converts date to orientation point (x, y, angle) on axis
1348 *
1349 * @param date Date
1350 * @return IOrientationPoint
1351 */
1352 DateAxis.prototype.dateToPoint = function (date) {
1353 var position = this.dateToPosition(date);
1354 var point = this.renderer.positionToPoint(position);
1355 var angle = this.renderer.positionToAngle(position);
1356 return { x: point.x, y: point.y, angle: angle };
1357 };
1358 /**
1359 * Converts a numeric value to orientation (x, y, angle) point on axis
1360 *
1361 * @param value Value
1362 * @return Orientation point
1363 */
1364 DateAxis.prototype.anyToPoint = function (date) {
1365 if (date instanceof Date) {
1366 return this.dateToPoint(date);
1367 }
1368 else {
1369 return this.valueToPoint(date);
1370 }
1371 };
1372 /**
1373 * Converts pixel position within Axis to a corresponding Date.
1374 *
1375 * @param position Position (px)
1376 * @return Date
1377 */
1378 DateAxis.prototype.positionToDate = function (position) {
1379 return new Date(this.positionToValue(position));
1380 };
1381 /**
1382 * Returns the relative position on axis for series' data item's value.
1383 *
1384 * @since 4.5.14
1385 * @param dataItem Data item
1386 * @param key Data field to get value from
1387 * @param location Location (0-1)
1388 * @return Relative position
1389 */
1390 DateAxis.prototype.getPositionX = function (dataItem, key, location, stackKey, range) {
1391 var value = this.getTimeByLocation(dataItem, key, location);
1392 //let stack: number = dataItem.getValue("valueX", "stack");
1393 if (!$type.isNumber(value)) {
1394 value = this.baseValue;
1395 }
1396 var position = this.valueToPosition(value);
1397 if (range) {
1398 position = $math.fitToRange(position, range.start, range.end);
1399 }
1400 return position;
1401 };
1402 /**
1403 * Returns relative position on axis for series' data item's value.
1404 *
1405 * @since 4.5.14
1406 * @param dataItem Data item
1407 * @param key Data field to get value from
1408 * @param location Location (0-1)
1409 * @return Relative position
1410 */
1411 DateAxis.prototype.getPositionY = function (dataItem, key, location, stackKey, range) {
1412 var value = this.getTimeByLocation(dataItem, key, location);
1413 var stack = dataItem.getValue("valueX", "stack");
1414 if (!$type.isNumber(value)) {
1415 value = this.baseValue;
1416 }
1417 var position = this.valueToPosition(value + stack);
1418 if (range) {
1419 position = $math.fitToRange(position, range.start, range.end);
1420 }
1421 return position;
1422 };
1423 /**
1424 * Returns an angle for series data item.
1425 *
1426 * @ignore Exclude from docs
1427 * @todo Description (review)
1428 * @param dataItem Data item
1429 * @param key Data field to get value from
1430 * @param location Location (0-1)
1431 * @param stackKey Stack ID
1432 * @param range Range to fit in
1433 * @return Angle
1434 */
1435 DateAxis.prototype.getAngle = function (dataItem, key, location, stackKey, range) {
1436 var value = this.getTimeByLocation(dataItem, key, location);
1437 var stack = dataItem.getValue(stackKey, "stack");
1438 if (!$type.isNumber(value)) {
1439 value = this.baseValue;
1440 }
1441 var position = this.valueToPosition(value + stack);
1442 if (range) {
1443 position = $math.fitToRange(position, range.start, range.end);
1444 }
1445 return this.positionToAngle(position);
1446 };
1447 /**
1448 * [getTimeByLocation description]
1449 *
1450 * @ignore Exclude from docs
1451 * @todo Description
1452 * @param dataItem [description]
1453 * @param key [description]
1454 * @param location [description]
1455 * @return [description]
1456 */
1457 DateAxis.prototype.getTimeByLocation = function (dataItem, key, location) {
1458 if (!$type.hasValue(key)) {
1459 return;
1460 }
1461 if (!$type.isNumber(location)) {
1462 location = dataItem.workingLocations[key];
1463 if (!$type.isNumber(location)) {
1464 location = 0;
1465 }
1466 }
1467 var startTime = dataItem.values[key]["open"];
1468 var endTime = dataItem.values[key]["close"];
1469 var workingValue = dataItem.values[key].workingValue;
1470 var value = dataItem.values[key].value;
1471 var difference = value - workingValue;
1472 startTime -= difference;
1473 endTime -= difference;
1474 if ($type.isNumber(startTime) && $type.isNumber(endTime)) {
1475 return startTime + (endTime - startTime) * location;
1476 }
1477 };
1478 /**
1479 * Processes a related series' data item.
1480 *
1481 * @ignore Exclude from docs
1482 * @todo Description
1483 * @param dataItem Data item
1484 */
1485 DateAxis.prototype.processSeriesDataItem = function (dataItem, axisLetter) {
1486 var series = dataItem.component;
1487 var time;
1488 var date = dataItem["date" + axisLetter];
1489 if ($type.isNumber(this.timezoneOffset)) {
1490 date.setTime(date.getTime() + (date.getTimezoneOffset() - this.timezoneOffset) * 60000);
1491 dataItem.setValue("date" + axisLetter, date.getTime(), 0);
1492 }
1493 else if ($type.hasValue(this.timezone)) {
1494 date = $time.setTimezone(date, this.timezone);
1495 dataItem.setValue("date" + axisLetter, date.getTime(), 0);
1496 dataItem["date" + axisLetter] = date;
1497 }
1498 if (date) {
1499 time = date.getTime();
1500 }
1501 else {
1502 return;
1503 }
1504 var openDate = dataItem["openDate" + axisLetter];
1505 var prevSeriesTime = this._prevSeriesTime[series.uid];
1506 var openTime;
1507 if (openDate) {
1508 openTime = openDate.getTime();
1509 }
1510 if ($type.isNumber(openTime)) {
1511 var difference = Math.abs(time - openTime);
1512 if (this._minDifference[series.uid] > difference) {
1513 this._minDifference[series.uid] = difference;
1514 }
1515 }
1516 var differece = time - prevSeriesTime;
1517 if (differece > 0) {
1518 if (this._minDifference[series.uid] > differece) {
1519 this._minDifference[series.uid] = differece;
1520 }
1521 }
1522 this._prevSeriesTime[series.uid] = time;
1523 if (series._baseInterval[this.uid]) {
1524 this.postProcessSeriesDataItem(dataItem);
1525 }
1526 };
1527 /**
1528 * [updateAxisBySeries description]
1529 *
1530 * @ignore Exclude from docs
1531 * @todo Description
1532 */
1533 DateAxis.prototype.updateAxisBySeries = function () {
1534 _super.prototype.updateAxisBySeries.call(this);
1535 var baseInterval = this.chooseInterval(0, this.minDifference, 1);
1536 // handle short months
1537 if (this.minDifference >= $time.getDuration("day", 27) && baseInterval.timeUnit == "week") {
1538 baseInterval.timeUnit = "month";
1539 baseInterval.count = 1;
1540 }
1541 if (baseInterval.timeUnit == "month") {
1542 if (this.minDifference >= $time.getDuration("day", 29 * 2) && baseInterval.count == 1) {
1543 baseInterval.count = 2;
1544 }
1545 if (this.minDifference >= $time.getDuration("day", 29 * 3) && baseInterval.count == 2) {
1546 baseInterval.count = 3;
1547 }
1548 if (this.minDifference >= $time.getDuration("day", 29 * 6) && baseInterval.count == 5) {
1549 baseInterval.count = 6;
1550 }
1551 }
1552 // handle daylight saving
1553 if (this.minDifference >= $time.getDuration("hour", 23) && baseInterval.timeUnit == "hour") {
1554 baseInterval.timeUnit = "day";
1555 baseInterval.count = 1;
1556 }
1557 if (this.minDifference >= $time.getDuration("week", 1) - $time.getDuration("hour", 1) && baseInterval.timeUnit == "day") {
1558 baseInterval.timeUnit = "week";
1559 baseInterval.count = 1;
1560 }
1561 if (this.minDifference >= $time.getDuration("year", 1) - $time.getDuration("day", 1.01) && baseInterval.timeUnit == "month") {
1562 baseInterval.timeUnit = "year";
1563 baseInterval.count = 1;
1564 }
1565 this._baseIntervalReal = baseInterval;
1566 this._mainBaseInterval = baseInterval;
1567 // no need to invalidate
1568 };
1569 Object.defineProperty(DateAxis.prototype, "baseInterval", {
1570 /**
1571 * @return Base interval
1572 */
1573 get: function () {
1574 if (this._groupInterval) {
1575 return this._groupInterval;
1576 }
1577 else if (this._baseInterval) {
1578 return this._baseInterval;
1579 }
1580 else {
1581 return this._baseIntervalReal;
1582 }
1583 },
1584 /**
1585 * A base interval (granularity) of data.
1586 *
1587 * Used to indicate what are the base units of your data.
1588 *
1589 * For example, if you have a data set that has a data point every 5 minutes,
1590 * you may want to set this to `{ timeUnit: "minute", count: 5 }`.
1591 *
1592 * If not set, the Axis will try to determine the setting by its own, looking
1593 * at actual data.
1594 *
1595 * For best results, try to follow these values for `count`:
1596 *
1597 * When unit is "month", use 12 / count = round number
1598 * When unit is "hour", use 24 / count = round number
1599 * When unit is "second" and "minute", use 60 / count = round number
1600 *
1601 * @param timeInterval base interval
1602 */
1603 set: function (timeInterval) {
1604 if (JSON.stringify(this._baseInterval) != JSON.stringify(timeInterval)) {
1605 this._baseInterval = timeInterval;
1606 this._mainBaseInterval = timeInterval;
1607 if (!$type.isNumber(timeInterval.count)) {
1608 timeInterval.count = 1;
1609 }
1610 this.invalidate();
1611 this.postProcessSeriesDataItems();
1612 }
1613 },
1614 enumerable: true,
1615 configurable: true
1616 });
1617 Object.defineProperty(DateAxis.prototype, "mainBaseInterval", {
1618 /**
1619 * Indicates granularity of the data of source (unaggregated) data.
1620 *
1621 * @since 4.7.0
1622 * @return Granularity of the main data set
1623 */
1624 get: function () {
1625 if (this._baseInterval) {
1626 return this._baseInterval;
1627 }
1628 else if (this._mainBaseInterval) {
1629 return this._mainBaseInterval;
1630 }
1631 else {
1632 return this._baseIntervalReal;
1633 }
1634 },
1635 enumerable: true,
1636 configurable: true
1637 });
1638 Object.defineProperty(DateAxis.prototype, "skipEmptyPeriods", {
1639 /**
1640 * @return Remove empty stretches of time?
1641 */
1642 get: function () {
1643 return this.getPropertyValue("skipEmptyPeriods");
1644 },
1645 /**
1646 * If enabled, axis will automatically collapse empty (without data points)
1647 * periods of time, i.e. weekends.
1648 *
1649 * An "empty" period is considered a stretch of time in the length of current
1650 * `baseInterval` without a single data point in it.
1651 *
1652 * For each such empty period, axis will automatically create an
1653 * [[AxisBreak]]. By default they will be invisible. You can still configure
1654 * them by accessing `axis.breaks.template`.
1655 *
1656 * [More info about breaks](https://www.amcharts.com/docs/v4/concepts/axes/#Breaks).
1657 *
1658 * Important notes:
1659 * * If you set this property to `true`, you can not add your custom axis breaks to this axis anymore.
1660 * * Using this feature affects performance. Use only if you need it.
1661 * * Setting this to `true` will reset appearance of breaks. If you want to modify appearance, do it *after* you set `skipEmptyPeriods`.
1662 * * Some axis label overlapping might happen.
1663 * * This setting is not compatible with `groupData = true`.
1664 *
1665 * @default false
1666 * @param value Remove empty stretches of time?
1667 */
1668 set: function (value) {
1669 if (value) {
1670 var breakTemplate = this.axisBreaks.template;
1671 breakTemplate.startLine.disabled = true;
1672 breakTemplate.endLine.disabled = true;
1673 breakTemplate.fillShape.disabled = true;
1674 breakTemplate.breakSize = 0;
1675 }
1676 else {
1677 if (this._gapBreaks) {
1678 this.axisBreaks.clear();
1679 this._gapBreaks = false;
1680 }
1681 }
1682 if (this.setPropertyValue("skipEmptyPeriods", value)) {
1683 this.invalidate();
1684 this.postProcessSeriesDataItems();
1685 this.invalidateSeries();
1686 }
1687 },
1688 enumerable: true,
1689 configurable: true
1690 });
1691 Object.defineProperty(DateAxis.prototype, "tooltipDateFormat", {
1692 /**
1693 * @return Date format
1694 */
1695 get: function () {
1696 return this.getPropertyValue("tooltipDateFormat");
1697 },
1698 /**
1699 * A special date format to apply axis tooltips.
1700 *
1701 * Will use same format as for labels, if not set.
1702 *
1703 * @param value Date format
1704 */
1705 set: function (value) {
1706 this.setPropertyValue("tooltipDateFormat", value);
1707 },
1708 enumerable: true,
1709 configurable: true
1710 });
1711 Object.defineProperty(DateAxis.prototype, "markUnitChange", {
1712 /**
1713 * @return Use different format for period beginning?
1714 */
1715 get: function () {
1716 return this.getPropertyValue("markUnitChange");
1717 },
1718 /**
1719 * Use `periodChangeDateFormats` to apply different formats to the first
1720 * label in bigger time unit.
1721 *
1722 * @default true
1723 * @param value Use different format for period beginning?
1724 */
1725 set: function (value) {
1726 if (this.setPropertyValue("markUnitChange", value)) {
1727 this.invalidateData();
1728 }
1729 },
1730 enumerable: true,
1731 configurable: true
1732 });
1733 /**
1734 * Returns text to show in a tooltip, based on specific relative position
1735 * within axis.
1736 *
1737 * The label will be formatted as per [[DateFormatter]] set for the whole
1738 * chart, or explicitly for this Axis.
1739 *
1740 * @ignore Exclude from docs
1741 * @param position Position
1742 * @return Label (formatted date)
1743 */
1744 DateAxis.prototype.getTooltipText = function (position) {
1745 var text;
1746 var date = this.positionToDate(position);
1747 date = $time.round(date, this.baseInterval.timeUnit, this.baseInterval.count, this._firstWeekDay, this._df.utc, new Date(this.min), this._df.timezoneMinutes, this._df.timezone);
1748 this.tooltipDate = date;
1749 if ($type.hasValue(this.tooltipDateFormat)) {
1750 text = this._df.format(date, this.tooltipDateFormat, ["day", "month", "week", "year"].indexOf(this.baseInterval.timeUnit) == -1);
1751 }
1752 else {
1753 var dateFormat = this.dateFormats.getKey(this.baseInterval.timeUnit);
1754 if (dateFormat) {
1755 text = this._df.format(date, dateFormat);
1756 }
1757 else {
1758 text = this.getPositionLabel(position);
1759 }
1760 }
1761 if (!this._adapterO) {
1762 return text;
1763 }
1764 else {
1765 return this._adapterO.apply("getTooltipText", text);
1766 }
1767 };
1768 /**
1769 * Takes an absolute position within axis and adjust it to a specific position within base interval. (cell)
1770 *
1771 * @ignore Exclude from docs
1772 * @param position Source position
1773 * @param location Location in the cell
1774 * @return Adjusted position
1775 */
1776 DateAxis.prototype.roundPosition = function (position, location, axisLocation) {
1777 var baseInterval = this.baseInterval;
1778 var timeUnit = baseInterval.timeUnit;
1779 var count = baseInterval.count;
1780 var date = this.positionToDate(position);
1781 $time.round(date, timeUnit, count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone);
1782 if (location > 0) {
1783 $time.add(date, timeUnit, location * count, this._df.utc);
1784 }
1785 if (axisLocation > 0 && axisLocation < 1) {
1786 date.setTime(date.getTime() + this.baseDuration * axisLocation);
1787 }
1788 if (this.isInBreak(date.getTime())) {
1789 while (date.getTime() < this.max) {
1790 $time.add(date, timeUnit, count, this._df.utc);
1791 if (!this.isInBreak(date.getTime())) {
1792 break;
1793 }
1794 }
1795 }
1796 return this.dateToPosition(date);
1797 };
1798 /**
1799 * Returns an relative position of the start of the cell (period), that specific position value falls into.
1800 *
1801 * @ignore Exclude from docs
1802 * @todo Description (review)
1803 * @param position Relative position
1804 * @return Cell start relative position
1805 */
1806 DateAxis.prototype.getCellStartPosition = function (position) {
1807 return this.roundPosition(position, 0);
1808 };
1809 /**
1810 * Returns an relative position of the end of the cell (period), that specific position value falls into.
1811 *
1812 * @ignore Exclude from docs
1813 * @todo Description (review)
1814 * @param position Relative position
1815 * @return Cell end relative position
1816 */
1817 DateAxis.prototype.getCellEndPosition = function (position) {
1818 return this.roundPosition(position, 1);
1819 //return this.dateToPosition($time.add(this.positionToDate(this.roundPosition(position, 1)), this.baseInterval.timeUnit, this.baseInterval.count));
1820 };
1821 /**
1822 * Returns a Series data item that corresponds to the specific pixel position
1823 * of the Axis.
1824 *
1825 * If `findNearest` (third parameter) is set to `true`, the method will try
1826 * to locate nearest available data item if none is found directly under
1827 * `position`.
1828 *
1829 * @param series Series
1830 * @param position Position (px)
1831 * @param findNearest Should axis try to find nearest tooltip if there is no data item at exact position
1832 * @return Data item
1833 */
1834 DateAxis.prototype.getSeriesDataItem = function (series, position, findNearest) {
1835 var value = this.positionToValue(position);
1836 var location = 0.5;
1837 if (this.axisLetter == "Y") {
1838 location = series.dataItems.template.locations.dateY;
1839 }
1840 else {
1841 location = series.dataItems.template.locations.dateX;
1842 }
1843 var deltaValue = value - location * this.baseDuration;
1844 var date = $time.round(new Date(value), this.baseInterval.timeUnit, this.baseInterval.count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone);
1845 var nextDate = $time.round(new Date(value + this.baseDuration), this.baseInterval.timeUnit, this.baseInterval.count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone);
1846 if (nextDate.getTime() > date.getTime()) {
1847 if (Math.abs(nextDate.getTime() - deltaValue) < Math.abs(deltaValue - date.getTime())) {
1848 date = nextDate;
1849 }
1850 }
1851 var dataItemsByAxis = series.dataItemsByAxis.getKey(this.uid);
1852 var dataItem = dataItemsByAxis.getKey(date.getTime() + series.currentDataSetId);
1853 // todo: alternatively we can find closiest here
1854 if (!dataItem && findNearest) {
1855 var key_1;
1856 if (this.axisLetter == "Y") {
1857 key_1 = "dateY";
1858 }
1859 else {
1860 key_1 = "dateX";
1861 }
1862 dataItem = series.dataItems.getIndex(series.dataItems.findClosestIndex(date.getTime(), function (x) {
1863 if (x[key_1]) {
1864 return x[key_1].getTime();
1865 }
1866 else {
1867 return -Infinity;
1868 }
1869 }, "any"));
1870 }
1871 return dataItem;
1872 };
1873 /**
1874 * Returns a formatted date based on position in axis scale.
1875 *
1876 * Please note that `position` represents position within axis which may be
1877 * zoomed and not correspond to Cursor's `position`.
1878 *
1879 * To convert Cursor's `position` to Axis' `position` use `toAxisPosition()` method.
1880 *
1881 * @see {@link https://www.amcharts.com/docs/v4/tutorials/tracking-cursors-position-via-api/#Tracking_Cursor_s_position} For more information about cursor tracking.
1882 * @param position Relative position on axis (0-1)
1883 * @return Position label
1884 */
1885 DateAxis.prototype.getPositionLabel = function (position) {
1886 // @todo Better format recognition
1887 var date = this.positionToDate(position);
1888 return this._df.format(date, this.getCurrentLabelFormat());
1889 };
1890 /**
1891 * Returns label date format based on currently used time units
1892 *
1893 * @return Format
1894 */
1895 DateAxis.prototype.getCurrentLabelFormat = function () {
1896 return this.dateFormats.getKey(this._gridInterval ? this._gridInterval.timeUnit : "day");
1897 };
1898 /**
1899 * Initializes an Axis renderer.
1900 *
1901 * @ignore Exclude from docs
1902 */
1903 DateAxis.prototype.initRenderer = function () {
1904 _super.prototype.initRenderer.call(this);
1905 var renderer = this.renderer;
1906 if (renderer) {
1907 // Set defaults
1908 renderer.ticks.template.location = 0;
1909 renderer.grid.template.location = 0;
1910 renderer.labels.template.location = 0;
1911 renderer.baseGrid.disabled = true;
1912 }
1913 };
1914 Object.defineProperty(DateAxis.prototype, "basePoint", {
1915 /**
1916 * Coordinates of the actual axis start.
1917 *
1918 * @ignore Exclude from docs
1919 * @return Base point
1920 */
1921 get: function () {
1922 return { x: 0, y: 0 };
1923 },
1924 enumerable: true,
1925 configurable: true
1926 });
1927 /**
1928 * @ignore
1929 */
1930 DateAxis.prototype.animateMinMax = function (min, max) {
1931 var _this = this;
1932 var animation = this.animate([{ property: "_minAdjusted", from: this._minAdjusted, to: min }, { property: "_maxAdjusted", from: this._maxAdjusted, to: max }], this.rangeChangeDuration, this.rangeChangeEasing);
1933 animation.events.on("animationprogress", function () {
1934 _this.dispatch("extremeschanged");
1935 });
1936 return animation;
1937 };
1938 /**
1939 * Invalidates axis data items when series extremes change
1940 */
1941 DateAxis.prototype.handleExtremesChange = function () {
1942 _super.prototype.handleExtremesChange.call(this);
1943 if (this.groupData) {
1944 var id = this.baseInterval.timeUnit + this.baseInterval.count;
1945 this.groupMin[id] = this._finalMin;
1946 this.groupMax[id] = this._finalMax;
1947 }
1948 };
1949 /**
1950 * Zooms axis to specific Dates.
1951 *
1952 * @param startDate Start date
1953 * @param endValue End date
1954 * @param skipRangeEvent Do not invoke events
1955 * @param instantly Do not play zoom animations
1956 */
1957 DateAxis.prototype.zoomToDates = function (startDate, endDate, skipRangeEvent, instantly, adjust) {
1958 startDate = this._df.parse(startDate);
1959 endDate = this._df.parse(endDate);
1960 this.zoomToValues(startDate.getTime(), endDate.getTime(), skipRangeEvent, instantly, adjust);
1961 };
1962 /**
1963 * Zooms axis to specific values.
1964 *
1965 * @param startValue Start value
1966 * @param endValue End value
1967 * @param skipRangeEvent Do not invoke events
1968 * @param instantly Do not play zoom animations
1969 */
1970 DateAxis.prototype.zoomToValues = function (startValue, endValue, skipRangeEvent, instantly, adjust) {
1971 var _this = this;
1972 if (!this.groupData) {
1973 //let start: number = (startValue - this.min) / (this.max - this.min);
1974 //let end: number = (endValue - this.min) / (this.max - this.min);
1975 var start = this.valueToPosition(startValue);
1976 var end = this.valueToPosition(endValue);
1977 this.zoom({ start: start, end: end }, skipRangeEvent, instantly);
1978 }
1979 else {
1980 var difference = this.adjustDifference(startValue, endValue);
1981 var isEnd = false;
1982 if (endValue == this.max) {
1983 isEnd = true;
1984 }
1985 var isStart = false;
1986 if (startValue == this.min) {
1987 isStart = true;
1988 }
1989 if ($type.hasValue(difference)) {
1990 var mainBaseInterval = this.mainBaseInterval;
1991 var groupInterval_1 = this.chooseInterval(0, difference, this.groupCount, this.groupIntervals);
1992 if ((groupInterval_1.timeUnit == mainBaseInterval.timeUnit && groupInterval_1.count < mainBaseInterval.count) || $time.getDuration(groupInterval_1.timeUnit, 1) < $time.getDuration(mainBaseInterval.timeUnit, 1)) {
1993 groupInterval_1 = __assign({}, mainBaseInterval);
1994 }
1995 var id = groupInterval_1.timeUnit + groupInterval_1.count;
1996 var min_1 = this.groupMin[id];
1997 var max_1 = this.groupMax[id];
1998 if (!$type.isNumber(min_1) || !$type.isNumber(max_1)) {
1999 min_1 = Number.POSITIVE_INFINITY;
2000 max_1 = Number.NEGATIVE_INFINITY;
2001 this.series.each(function (series) {
2002 var seriesMin = series.min(_this);
2003 var seriesMax = series.max(_this);
2004 if (series._dataSets) {
2005 var ds = series._dataSets.getKey(groupInterval_1.timeUnit + groupInterval_1.count);
2006 if (ds) {
2007 var mindi = ds.getIndex(0);
2008 var maxdi = ds.getIndex(ds.length - 1);
2009 if (mindi) {
2010 if (series.xAxis == _this) {
2011 seriesMin = mindi.dateX.getTime();
2012 }
2013 else if (series.yAxis == _this) {
2014 seriesMin = mindi.dateY.getTime();
2015 }
2016 }
2017 if (maxdi) {
2018 if (series.xAxis == _this) {
2019 seriesMax = maxdi.dateX.getTime();
2020 }
2021 else if (series.yAxis == _this) {
2022 seriesMax = maxdi.dateY.getTime();
2023 }
2024 }
2025 }
2026 }
2027 seriesMax = $time.round($time.add(new Date(seriesMax), groupInterval_1.timeUnit, 1, _this._df.utc), groupInterval_1.timeUnit, 1, _this._df.firstDayOfWeek, _this._df.utc, undefined, _this._df.timezoneMinutes, _this._df.timezone).getTime();
2028 if (seriesMin < min_1) {
2029 min_1 = seriesMin;
2030 }
2031 if (seriesMax > max_1) {
2032 max_1 = seriesMax;
2033 }
2034 });
2035 this.groupMin[id] = min_1;
2036 this.groupMax[id] = max_1;
2037 }
2038 startValue = $math.fitToRange(startValue, min_1, max_1);
2039 endValue = $math.fitToRange(endValue, min_1, max_1);
2040 if (adjust) {
2041 if (isEnd) {
2042 startValue = endValue - difference;
2043 startValue = $math.fitToRange(startValue, min_1, max_1);
2044 }
2045 if (isStart) {
2046 endValue = startValue + difference;
2047 endValue = $math.fitToRange(endValue, min_1, max_1);
2048 }
2049 }
2050 var start = (startValue - min_1) / (max_1 - min_1);
2051 var end = (endValue - min_1) / (max_1 - min_1);
2052 this.zoom({ start: start, end: end }, skipRangeEvent, instantly);
2053 }
2054 }
2055 };
2056 /**
2057 * Adds `baseInterval` to "as is" fields.
2058 *
2059 * @param field Field name
2060 * @return Assign as is?
2061 */
2062 DateAxis.prototype.asIs = function (field) {
2063 return field == "baseInterval" || _super.prototype.asIs.call(this, field);
2064 };
2065 /**
2066 * Copies all properties and related data from a different instance of Axis.
2067 *
2068 * @param source Source Axis
2069 */
2070 DateAxis.prototype.copyFrom = function (source) {
2071 var _this = this;
2072 _super.prototype.copyFrom.call(this, source);
2073 this.dateFormats = source.dateFormats;
2074 this.periodChangeDateFormats = source.periodChangeDateFormats;
2075 this.groupIntervals.clear();
2076 source.groupIntervals.each(function (interval) {
2077 _this.groupIntervals.push(__assign({}, interval));
2078 });
2079 this.gridIntervals.clear();
2080 source.gridIntervals.each(function (interval) {
2081 _this.gridIntervals.push(__assign({}, interval));
2082 });
2083 if (source._baseInterval) {
2084 this.baseInterval = source._baseInterval;
2085 }
2086 };
2087 /**
2088 * Shows Axis tooltip at specific relative position within Axis. (0-1)
2089 *
2090 * @param position Position (0-1)
2091 * @param local or global position
2092 */
2093 DateAxis.prototype.showTooltipAtPosition = function (position, local) {
2094 var _this = this;
2095 if (!local) {
2096 position = this.toAxisPosition(position);
2097 }
2098 if (this.snapTooltip) {
2099 // rounding is not good, pen/aac4e7f66f019d36b2447f050c600c13 (no last tootltip shown)
2100 var actualDate = this.positionToDate(position); //$time.round(this.positionToDate(position), this.baseInterval.timeUnit, 1, this.getFirstWeekDay(), this.dateFormatter.utc, undefined, this._df.timezoneMinutes, this._df.timezone);
2101 var actualTime_1 = actualDate.getTime();
2102 var closestDate_1;
2103 this.series.each(function (series) {
2104 if (series.baseAxis == _this) {
2105 var dataItem = _this.getSeriesDataItem(series, position, true);
2106 if (dataItem) {
2107 var date = void 0;
2108 if (series.xAxis == _this) {
2109 date = dataItem.dateX;
2110 }
2111 if (series.yAxis == _this) {
2112 date = dataItem.dateY;
2113 }
2114 if (!closestDate_1) {
2115 closestDate_1 = date;
2116 }
2117 else {
2118 if (Math.abs(closestDate_1.getTime() - actualTime_1) > Math.abs(date.getTime() - actualTime_1)) {
2119 closestDate_1 = date;
2120 }
2121 }
2122 }
2123 }
2124 });
2125 if (closestDate_1) {
2126 var closestTime_1 = closestDate_1.getTime();
2127 closestDate_1 = $time.round(new Date(closestTime_1), this.baseInterval.timeUnit, this.baseInterval.count, this._firstWeekDay, this._df.utc, undefined, this._df.timezoneMinutes, this._df.timezone);
2128 closestTime_1 = closestDate_1.getTime();
2129 var tooltipLocation = this.renderer.tooltipLocation;
2130 if (tooltipLocation == 0) {
2131 tooltipLocation = 0.0001;
2132 }
2133 closestDate_1 = new Date(closestDate_1.getTime() + this.baseDuration * tooltipLocation);
2134 position = this.dateToPosition(closestDate_1);
2135 if (this.chart.cursor && this.chart.cursor.snapToSeries) {
2136 //void
2137 }
2138 else {
2139 this.series.each(function (series) {
2140 var dataItem = series.dataItemsByAxis.getKey(_this.uid).getKey(closestTime_1 + series.currentDataSetId);
2141 var point = series.showTooltipAtDataItem(dataItem);
2142 if (point) {
2143 _this.chart._seriesPoints.push({ series: series, point: point });
2144 }
2145 else {
2146 // check, otherwise column tooltip will be hidden
2147 if (series.tooltipText || series.tooltipHTML) {
2148 series.hideTooltip();
2149 }
2150 }
2151 });
2152 }
2153 //this.chart.sortSeriesTooltips(seriesPoints);
2154 }
2155 }
2156 _super.prototype.showTooltipAtPosition.call(this, position, true);
2157 };
2158 Object.defineProperty(DateAxis.prototype, "snapTooltip", {
2159 /**
2160 * @return Should snap?
2161 */
2162 get: function () {
2163 return this.getPropertyValue("snapTooltip");
2164 },
2165 /**
2166 * Should the nearest tooltip be shown if no data item is found on the
2167 * current cursor position.
2168 *
2169 * @default true
2170 * @param value Should snap?
2171 */
2172 set: function (value) {
2173 this.setPropertyValue("snapTooltip", value);
2174 },
2175 enumerable: true,
2176 configurable: true
2177 });
2178 Object.defineProperty(DateAxis.prototype, "groupData", {
2179 /**
2180 * @return Group data points?
2181 */
2182 get: function () {
2183 return this.getPropertyValue("groupData");
2184 },
2185 /**
2186 * Indicates if data should be aggregated to composide data items if there
2187 * are more data items in selected range than `groupCount`.
2188 *
2189 * Grouping will occur automatically, based on current selection range, and
2190 * will change dynamically when user zooms in/out the chart.
2191 *
2192 * NOTE: This works only if [[DateAxis]] is base axis of an [[XYSeries]].
2193 *
2194 * The related [[XYSeries]] also needs to be set up to take advantage of, by
2195 * setting its [`groupFields`](https://www.amcharts.com/docs/v4/reference/xyseries/#groupFields_property).
2196 *
2197 * The group intervals to aggregate data to is defined by `groupIntervals`
2198 * property.
2199 *
2200 * ```TypeScript
2201 * let dateAxis = chart.xAxes.push(new am4charts.DateAxis());
2202 * dateAxis.groupData = true;
2203 *
2204 * let valueAxis = chart.xAxes.push(new am4charts.valueAxis());
2205 *
2206 * let series = chart.series.push(new am4charts.LineSeries());
2207 * series.dataFields.dateX = "date";
2208 * series.dataFields.valueY = "value";
2209 * series.groupFields.valueY = "average";
2210 * ```
2211 * ```JavaScript
2212 * var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
2213 * dateAxis.groupData = true;
2214 *
2215 * var valueAxis = chart.xAxes.push(new am4charts.valueAxis());
2216 *
2217 * var series = chart.series.push(new am4charts.LineSeries());
2218 * series.dataFields.dateX = "date";
2219 * series.dataFields.valueY = "value";
2220 * series.groupFields.valueY = "average";
2221 * ```
2222 * ```JSON
2223 * {
2224 * // ...
2225 * "xAxes": [{
2226 * "type": "DateAxis",
2227 * "groupData": true
2228 * }],
2229 * "yAxes": [{
2230 * "type": "ValueAxis"
2231 * }],
2232 * "series": [{
2233 * "type": "LineSeries",
2234 * "dataFields": {
2235 * "dateX": "date",
2236 * "valueY": "value"
2237 * },
2238 * "groupFields": {
2239 * "valueY": "average"
2240 * }
2241 * }]
2242 * }
2243 * ```
2244 *
2245 * @default false
2246 * @see {@link https://www.amcharts.com/docs/v4/concepts/axes/date-axis/#Dynamic_data_item_grouping} for more information about dynamic data item grouping.
2247 * @since 4.7.0
2248 * @param value Group data points?
2249 */
2250 set: function (value) {
2251 var _this = this;
2252 if (this.setPropertyValue("groupData", value)) {
2253 this.series.each(function (series) {
2254 series.setDataSet("");
2255 if (value && !series.dataGrouped && series.inited) {
2256 series._baseInterval[_this.uid] = _this.mainBaseInterval;
2257 _this.groupSeriesData(series);
2258 }
2259 });
2260 this._currentDataSetId = "";
2261 this._groupInterval = undefined;
2262 this.invalidate();
2263 this.invalidateSeries();
2264 }
2265 },
2266 enumerable: true,
2267 configurable: true
2268 });
2269 Object.defineProperty(DateAxis.prototype, "groupInterval", {
2270 /**
2271 * @return Interval
2272 */
2273 get: function () {
2274 return this.getPropertyValue("groupInterval");
2275 },
2276 /**
2277 * Disables automatic selection of data grouping intervals and always uses
2278 * `groupInterval` if set. Works only if `groupData = true`.
2279 *
2280 * @since 4.9.24
2281 * @param value Interval
2282 */
2283 set: function (value) {
2284 if (this.setPropertyValue("groupInterval", value)) {
2285 this.invalidate();
2286 this.invalidateSeries();
2287 }
2288 },
2289 enumerable: true,
2290 configurable: true
2291 });
2292 Object.defineProperty(DateAxis.prototype, "groupCount", {
2293 /**
2294 * @return Number of data items
2295 */
2296 get: function () {
2297 return this.getPropertyValue("groupCount");
2298 },
2299 /**
2300 * Indicates threshold of data items in selected range at which to start
2301 * aggregating data items if `groupData = true`.
2302 *
2303 * @default 200
2304 * @since 4.7.0
2305 * @param value Number of data items
2306 */
2307 set: function (value) {
2308 this.setPropertyValue("groupCount", value);
2309 },
2310 enumerable: true,
2311 configurable: true
2312 });
2313 Object.defineProperty(DateAxis.prototype, "timezoneOffset", {
2314 /**
2315 * @todo Timezone offset in minutes
2316 */
2317 get: function () {
2318 return this.getPropertyValue("timezoneOffset");
2319 },
2320 /**
2321 * If set will recalculate all timestamps in data by applying specific offset
2322 * in minutes.
2323 *
2324 * IMPORTANT: do not set `timezoneOffset` on both `DateAxis` and `dateFormatter`. It
2325 * will skew your results by applying offset twice.
2326 *
2327 * @since 4.8.5
2328 * @param value Time zone offset in minutes
2329 */
2330 set: function (value) {
2331 this.setPropertyValue("timezoneOffset", value);
2332 },
2333 enumerable: true,
2334 configurable: true
2335 });
2336 Object.defineProperty(DateAxis.prototype, "timezone", {
2337 /**
2338 * @return Timezone
2339 */
2340 get: function () {
2341 return this.getPropertyValue("timezone");
2342 },
2343 /**
2344 * If set will recalculate all timestamps in data to specific named timezone,
2345 * e.g. `"America/Vancouver"`, `"Australia/Sydney"`, `"UTC"`, etc.
2346 *
2347 * IMPORTANT: it is no longer recommended to use this setting. Please
2348 * set`timezone` on `dateFormatter`.
2349 *
2350 * @deprecated
2351 * @since 4.10.1
2352 * @param value Time zone
2353 */
2354 set: function (value) {
2355 this.setPropertyValue("timezone", value);
2356 },
2357 enumerable: true,
2358 configurable: true
2359 });
2360 Object.defineProperty(DateAxis.prototype, "gridInterval", {
2361 /**
2362 * Current grid interval.
2363 *
2364 * @return Grid interval
2365 */
2366 get: function () {
2367 return this._gridInterval;
2368 },
2369 enumerable: true,
2370 configurable: true
2371 });
2372 /**
2373 * @ignore
2374 */
2375 DateAxis.prototype.makeGap = function (dataItem, previous) {
2376 var series = dataItem.component;
2377 if (dataItem && previous) {
2378 if (!series.connect && $type.isNumber(series.autoGapCount)) {
2379 if (series.baseAxis == this) {
2380 var date = dataItem.dates["date" + this.axisLetter];
2381 var prevDate = previous.dates["date" + this.axisLetter];
2382 if (date && prevDate) {
2383 var time = date.getTime();
2384 var prevTime = prevDate.getTime();
2385 if (time - prevTime > series.autoGapCount * this.baseDuration) {
2386 return true;
2387 }
2388 }
2389 }
2390 }
2391 }
2392 return false;
2393 };
2394 Object.defineProperty(DateAxis.prototype, "baseValue", {
2395 /**
2396 * @return base value
2397 */
2398 get: function () {
2399 return this.min;
2400 },
2401 enumerable: true,
2402 configurable: true
2403 });
2404 return DateAxis;
2405}(ValueAxis));
2406export { DateAxis };
2407/**
2408 * Register class in system, so that it can be instantiated using its name from
2409 * anywhere.
2410 *
2411 * @ignore
2412 */
2413registry.registeredClasses["DateAxis"] = DateAxis;
2414registry.registeredClasses["DateAxisDataItem"] = DateAxisDataItem;
2415//# sourceMappingURL=DateAxis.js.map
\No newline at end of file