@syncfusion/ej2-charts
Version:
Feature-rich chart control with built-in support for over 25 chart types, technical indictors, trendline, zooming, tooltip, selection, crosshair and trackball.
510 lines (509 loc) • 23.9 kB
JavaScript
import { createElement, isNullOrUndefined, Browser, remove } from '@syncfusion/ej2-base';
import { Toolbar } from '@syncfusion/ej2-navigations';
import { DateRangePicker } from '@syncfusion/ej2-calendars';
import { getElement } from '../../common/utils/helper';
import { Rect } from '@syncfusion/ej2-svg-base';
/**
* Configures the period selector class.
*
* @private
*/
var PeriodSelector = /** @class */ (function () {
//constructor for period selector
function PeriodSelector(control) {
this.control = {};
this.isDatetimeCategory = false;
this.sortedData = [];
this.startValue = 0;
this.endValue = 0;
this.rootControl = control;
if (this.rootControl.getModuleName() === 'stockChart') {
this.sortedData = this.rootControl.sortedData;
this.isDatetimeCategory = this.rootControl.isDateTimeCategory;
}
}
/**
* To set the control values
*
* @param control
* @returns {void}
*/
PeriodSelector.prototype.setControlValues = function (control) {
if (control.getModuleName() === 'rangeNavigator') {
this.control.periods = this.rootControl.periodSelectorSettings.periods;
this.control.seriesXMax = control.chartSeries.xMax;
this.control.seriesXMin = control.chartSeries.xMin;
this.control.rangeSlider = control.rangeSlider;
this.control.rangeNavigatorControl = control;
this.control.endValue = control.endValue;
this.control.startValue = control.startValue;
}
else {
this.control.periods = this.rootControl.periods;
this.control.endValue = this.control.seriesXMax = control.seriesXMax;
this.control.startValue = this.control.seriesXMin = control.seriesXMin;
this.control.rangeNavigatorControl = this.rootControl.rangeNavigator;
if (this.control.rangeNavigatorControl) {
this.control.rangeSlider = this.rootControl.rangeNavigator.rangeSlider;
}
}
this.control.element = control.element;
this.control.disableRangeSelector = control.disableRangeSelector;
};
/**
* To initialize the period selector properties.
*
* @param options
* @param x
* @param options
* @param x
*/
PeriodSelector.prototype.appendSelector = function (options, x) {
if (x === void 0) { x = 0; }
this.renderSelectorElement(null, options, x);
this.renderSelector();
};
/**
* renderSelector div.
*
* @param control
* @param options
* @param x
* @param options
* @param x
*/
PeriodSelector.prototype.renderSelectorElement = function (control, options, x) {
//render border
this.periodSelectorSize = control ? this.periodSelectorSize : new Rect(x, this.rootControl.titleSize.height ?
this.rootControl.titleSize.height : 10, options.width, options.height);
var thumbSize;
var element;
if (control) {
thumbSize = control.themeStyle.thumbWidth;
element = control.element;
}
else {
thumbSize = options.thumbSize;
element = options.element;
}
if (getElement(element.id + '_Secondary_Element')) {
remove(getElement(element.id + '_Secondary_Element'));
}
this.periodSelectorDiv = createElement('div', {
id: element.id + '_Secondary_Element',
styles: 'width: ' + (this.periodSelectorSize.width - thumbSize) + 'px;height: ' +
this.periodSelectorSize.height + 'px;top:' +
this.periodSelectorSize.y + 'px;left:' +
(this.periodSelectorSize.x + thumbSize / 2) + 'px; position: absolute'
});
element.appendChild(this.periodSelectorDiv);
};
/**
* Renders the selector elements.
*
* @returns {void}
*/
PeriodSelector.prototype.renderSelector = function () {
var _this = this;
this.setControlValues(this.rootControl);
var enableCustom = true;
var controlId = this.control.element.id;
var selectorElement = createElement('div', { id: controlId + '_selector' });
var buttons = this.control.periods;
var selector = this.updateCustomElement();
var buttonStyles = 'text-transform: none; text-overflow: unset';
var isStringTemplate = 'isStringTemplate';
var dateRangeId = controlId + 'customRange';
var selectedPeriod;
this.periodSelectorDiv.appendChild(selectorElement);
for (var i = 0; i < buttons.length; i++) {
selector.push({ align: 'Left', text: buttons[i].text });
}
if (this.rootControl.getModuleName() === 'stockChart') {
enableCustom = this.rootControl.enableCustomRange;
}
if (enableCustom) {
this.calendarId = controlId + '_calendar';
selector.push({ template: '<button id=' + this.calendarId + '></button>', align: 'Right' });
}
var selctorArgs = {
selector: selector, name: 'RangeSelector', cancel: false, enableCustomFormat: true, content: 'Date Range'
};
if (this.rootControl.getModuleName() === 'stockChart') {
if (this.rootControl.exportType.length) {
var exportElement = createElement('button', { id: controlId + '_export', styles: buttonStyles,
className: 'e-dropdown-btn e-btn e-flat' });
exportElement.innerText = 'Export';
selector.push({ template: exportElement,
align: 'Right' });
}
}
this.rootControl.trigger('selectorRender', selctorArgs);
this.toolbar = new Toolbar({
items: selctorArgs.selector, height: this.periodSelectorSize.height,
clicked: function (args) {
_this.buttonClick(args, _this.control);
}, created: function () {
_this.nodes = _this.toolbar.element.querySelectorAll('.e-toolbar-left')[0];
if (isNullOrUndefined(_this.selectedIndex)) {
buttons.map(function (period, index) {
if (period.selected && _this.selectedPeriod !== null) {
selectedPeriod = period;
_this.control.startValue = _this.changedRange(period.intervalType, _this.control.endValue, period.interval).getTime();
if (_this.isDatetimeCategory) {
_this.control.startValue = _this.rootControl.getModuleName() !== 'stockChart' ? _this.findStartValue(_this.control.startValue, _this.control.endValue) : _this.rootControl.startValue;
}
_this.control.startValue = (period.text && period.text.toLowerCase() === 'all') ? _this.control.seriesXMin : _this.control.startValue;
_this.control.endValue = (period.text && period.text.toLowerCase() === 'all') ? _this.control.seriesXMax : _this.control.endValue;
_this.selectedIndex = (_this.nodes.childNodes.length - buttons.length) + index;
var slider = _this.control.rangeSlider;
if (slider) {
slider.selectedPeriod = period.text;
}
}
});
}
if (!selectedPeriod && _this.rootControl.getModuleName() !== 'stockChart') {
var selectedIndex = _this.findSelectedIndex(_this.control.startValue, _this.control.endValue, buttons);
_this.selectedIndex = selectedIndex ? selectedIndex : _this.selectedIndex;
}
_this.setSelectedStyle(_this.selectedIndex);
}
});
this.toolbar[isStringTemplate] = true;
this.toolbar.appendTo(selectorElement);
this.triggerChange = true;
if (enableCustom) {
this.datePicker = new DateRangePicker({
min: this.isDatetimeCategory ? new Date(this.sortedData[this.control.seriesXMin]) : new Date(this.control.seriesXMin),
max: this.isDatetimeCategory ? new Date(this.sortedData[this.control.seriesXMax]) : new Date(this.control.seriesXMax),
format: 'dd/MM/yyyy', placeholder: 'Select a range',
showClearButton: false,
startDate: this.isDatetimeCategory ? new Date(this.sortedData[Math.floor(this.control.startValue)]) :
new Date(this.control.startValue),
endDate: this.isDatetimeCategory ? new Date(this.sortedData[Math.floor(this.control.endValue)]) :
new Date(this.control.endValue),
created: function () {
if (selctorArgs.enableCustomFormat) {
var datePicker = document.getElementsByClassName('e-date-range-wrapper');
var datePickerElement = void 0;
for (var i = 0; i < datePicker.length; i++) {
if (datePicker[i].children[0].id.indexOf(controlId) !== -1) {
datePickerElement = datePicker[i];
}
}
datePickerElement.style.display = 'none';
var element = createElement('div', {
id: dateRangeId,
className: 'e-control e-btn e-dropdown-btn e-flat',
styles: 'font-size: 14px; font-weight: 500; text-transform: none '
});
element.innerText = selctorArgs.content;
datePickerElement.insertAdjacentElement('afterend', element);
getElement(dateRangeId).insertAdjacentElement('afterbegin', (createElement('span', {
id: controlId + 'dateIcon', className: 'e-input-group-icon e-range-icon e-btn-icon e-icons',
styles: 'font-size: 16px; min-height: 0px; margin: -3px 0 0 0; outline: none; min-width: 30px'
// fix for date range icon alignment issue.
})));
document.getElementById(dateRangeId).onclick = function () {
_this.datePicker.show(getElement(dateRangeId));
};
}
},
change: function (args) {
if (_this.triggerChange) {
if (_this.isDatetimeCategory) {
_this.startValue = args.startDate.getTime();
_this.endValue = args.endDate.getTime();
_this.findPeriodValue(_this.startValue, _this.endValue);
}
if (_this.control.rangeSlider && args.event) {
if (_this.rootControl.getModuleName() !== 'stockChart') {
_this.control.rangeNavigatorControl.startValue = _this.isDatetimeCategory ? _this.startValue :
args.startDate.getTime();
_this.control.rangeNavigatorControl.endValue = _this.isDatetimeCategory ? _this.endValue :
args.endDate.getTime();
_this.selectedIndex = undefined;
_this.selectedPeriod = null;
_this.control.rangeNavigatorControl.refresh();
}
_this.control.rangeSlider.performAnimation(_this.isDatetimeCategory ? _this.startValue : args.startDate.getTime(), _this.isDatetimeCategory ?
_this.endValue : args.endDate.getTime(), _this.control.rangeNavigatorControl);
}
else if (args.event) {
_this.rootControl.rangeChanged(_this.isDatetimeCategory ? _this.startValue :
args.startDate.getTime(), _this.isDatetimeCategory ? _this.endValue :
args.endDate.getTime());
}
_this.nodes = _this.toolbar.element.querySelectorAll('.e-toolbar-left')[0];
if (!_this.rootControl.resizeTo && _this.control.rangeSlider && _this.control.rangeSlider.isDrag) {
/**
* Issue: While disabling range navigator console error throws
* Fix:Check with rangeSlider present or not. Then checked with isDrag.
*/
for (var i = 0, length_1 = _this.nodes.childNodes.length; i < length_1; i++) {
_this.nodes.childNodes[i].childNodes[0].classList.remove('e-active');
_this.nodes.childNodes[i].childNodes[0].classList.remove('e-active');
}
}
}
}
});
this.datePicker.appendTo('#' + this.calendarId);
}
};
/**
* To find start and end value
*
* @param startValue
* @param endValue
*/
PeriodSelector.prototype.findPeriodValue = function (startValue, endValue) {
for (var index = 0; index < (this.sortedData).length; index++) {
if ((this.sortedData[index]) >= startValue) {
this.startValue = index;
break;
}
}
for (var index = this.sortedData.length - 1; index >= 0; index--) {
if ((this.sortedData[index]) <= endValue) {
this.endValue = index;
break;
}
}
};
PeriodSelector.prototype.findSelectedIndex = function (startDate, endDate, buttons) {
var daysDiffence = (endDate - startDate) / (1000 * 60 * 60 * 24);
var selectedIndex;
for (var i = 0; i < buttons.length; i++) {
var period = buttons[i];
if (period.intervalType === 'Years' && daysDiffence / 365 === period.interval) {
selectedIndex = i;
}
else if (period.intervalType === 'Months' && (daysDiffence / 30 === period.interval || daysDiffence / 31 === period.interval)) {
selectedIndex = i;
}
else if (period.intervalType === 'Days' && daysDiffence === period.interval) {
selectedIndex = i;
}
else if (period.intervalType === 'Weeks' && daysDiffence / 7 === period.interval) {
selectedIndex = i;
}
else if (period.intervalType === 'Hours' && daysDiffence * 24 === period.interval) {
selectedIndex = i;
}
else if (period.intervalType === 'Seconds' && (daysDiffence * 24 * 3600) === period.interval) {
selectedIndex = i;
}
}
return selectedIndex;
};
PeriodSelector.prototype.updateCustomElement = function () {
var selector = [];
var controlId = this.rootControl.element.id;
var buttonStyles = 'text-transform: none; text-overflow: unset';
var className = 'e-dropdown-btn e-btn e-flat';
if (this.rootControl.getModuleName() === 'stockChart') {
if (this.rootControl.seriesType.length) {
var SeriesElement = createElement('button', { id: controlId + '_seriesType',
styles: buttonStyles,
className: className });
SeriesElement.innerText = 'Series';
selector.push({ template: SeriesElement,
align: 'Left' });
}
if (this.rootControl.indicatorType.length) {
var indicatorElement = createElement('button', {
id: controlId + '_indicatorType',
styles: buttonStyles,
className: className
});
indicatorElement.innerText = 'Indicators';
selector.push({ template: indicatorElement,
align: 'Left' });
}
if (this.rootControl.trendlineType.length) {
var trendlineElement = createElement('button', {
id: controlId + '_trendType',
styles: buttonStyles,
className: className
});
trendlineElement.innerText = 'Trendline';
selector.push({ template: trendlineElement,
align: 'Left' });
}
}
return selector;
};
/**
* To set and remove the period style.
*
* @param buttons
* @param selectedIndex
* @returns {void}
*/
PeriodSelector.prototype.setSelectedStyle = function (selectedIndex) {
for (var i = 0, length_2 = this.nodes.childNodes.length; i < length_2; i++) {
this.nodes.childNodes[i].childNodes[0].classList.remove('e-active');
}
if (!isNullOrUndefined(selectedIndex)) {
this.nodes.childNodes[selectedIndex].childNodes[0].classList.add('e-flat');
this.nodes.childNodes[selectedIndex].childNodes[0].classList.add('e-active');
}
};
/**
* Button click handling.
*
* @param args
* @param control
* @param args
* @param control
*/
PeriodSelector.prototype.buttonClick = function (args, control) {
var _this = this;
var clickedEle = args.item;
var slider = this.control.rangeSlider;
var buttons = this.control.periods;
var button = buttons.filter(function (btn) { return (btn.text === clickedEle.text); });
var updatedStart;
var updatedEnd;
buttons.map(function (period, index) {
if (period.selected && _this.rootControl.getModuleName() !== 'stockChart') {
period.selected = false;
}
if (period.text === args.item.text) {
_this.selectedIndex = (_this.nodes.childNodes.length - buttons.length) + index;
if (_this.rootControl.getModuleName() !== 'stockChart') {
period.selected = true;
}
}
});
if (args.item.text !== '') {
this.setSelectedStyle(this.selectedIndex);
}
if (slider && clickedEle.text) {
slider.selectedPeriod = clickedEle.text;
}
if (clickedEle.text.toLowerCase() === 'all') {
updatedStart = control.seriesXMin;
updatedEnd = control.seriesXMax;
if (slider) {
slider.performAnimation(updatedStart, updatedEnd, this.control.rangeNavigatorControl);
}
else {
this.rootControl.rangeChanged(updatedStart, updatedEnd);
}
}
else if (clickedEle.text.toLowerCase() === 'ytd') {
if (slider) {
updatedStart = this.isDatetimeCategory ?
new Date(new Date(this.sortedData[Math.floor(slider.currentEnd)]).getFullYear().toString()).getTime() :
new Date(new Date(slider.currentEnd).getFullYear().toString()).getTime();
updatedStart = this.isDatetimeCategory ? this.findStartValue(updatedStart, slider.currentEnd) : updatedStart;
updatedEnd = slider.currentEnd;
slider.performAnimation(updatedStart, updatedEnd, this.control.rangeNavigatorControl);
}
else {
updatedStart = this.isDatetimeCategory ? new Date(new Date(this.sortedData[Math.floor(this.rootControl.currentEnd)]).getFullYear().toString()).getTime() :
new Date(new Date(this.rootControl.currentEnd).getFullYear().toString()).getTime();
updatedStart = this.isDatetimeCategory ? this.findStartValue(updatedStart, this.rootControl.currentEnd) :
updatedStart;
updatedEnd = this.rootControl.currentEnd;
this.rootControl.rangeChanged(updatedStart, updatedEnd);
}
}
else if (clickedEle.text.toLowerCase() !== '') {
if (slider) {
updatedStart = this.changedRange(button[0].intervalType, slider.currentEnd, button[0].interval).getTime();
updatedStart = this.isDatetimeCategory ? this.findStartValue(updatedStart, slider.currentEnd) : updatedStart;
updatedEnd = slider.currentEnd;
slider.performAnimation(updatedStart, updatedEnd, this.control.rangeNavigatorControl);
}
else {
updatedStart = this.changedRange(button[0].intervalType, this.rootControl.currentEnd, button[0].interval).getTime();
updatedStart = this.isDatetimeCategory ? this.findStartValue(updatedStart, this.rootControl.currentEnd) :
updatedStart;
updatedEnd = this.rootControl.currentEnd;
this.rootControl.rangeChanged(updatedStart, updatedEnd);
}
}
if (this.rootControl.getModuleName() === 'stockChart') {
this.rootControl.zoomChange = false;
}
if (getElement(this.calendarId + '_popup') && !Browser.isDevice) {
var element = getElement(this.calendarId + '_popup');
element.querySelectorAll('.e-range-header')[0].style.display = 'none';
}
};
/**
* To find the start value.
*
* @param startValue
* @param endValue
*/
PeriodSelector.prototype.findStartValue = function (startValue, endValue) {
for (var index = Math.floor(endValue); index >= 0; index--) {
if (this.sortedData[index] <= startValue) {
return (index + 1);
}
}
return 0;
};
/**
*
* @param type updatedRange for selector
* @param end
* @param interval
*/
PeriodSelector.prototype.changedRange = function (type, end, interval) {
var result = this.isDatetimeCategory ? new Date(this.sortedData[Math.floor(end)]) : new Date(end);
switch (type) {
case 'Quarter':
result.setMonth(result.getMonth() - (3 * interval));
break;
case 'Months':
result.setMonth(result.getMonth() - interval);
break;
case 'Weeks':
result.setDate(result.getDate() - (interval * 7));
break;
case 'Days':
result.setDate(result.getDate() - interval);
break;
case 'Hours':
result.setHours(result.getHours() - interval);
break;
case 'Minutes':
result.setMinutes(result.getMinutes() - interval);
break;
case 'Seconds':
result.setSeconds(result.getSeconds() - interval);
break;
default:
result.setFullYear(result.getFullYear() - interval);
break;
}
return result;
};
/**
* Get module name
*
* @returns {string}
*/
PeriodSelector.prototype.getModuleName = function () {
return 'PeriodSelector';
};
/**
* To destroy the period selector.
*
* @returns {void}
* @private
*/
PeriodSelector.prototype.destroy = function () {
/**
* destroy method
*/
};
return PeriodSelector;
}());
export { PeriodSelector };