Files
Sensores/static/lib/Highcharts-10.2.1/es-modules/Stock/StockToolbar.js
2025-04-17 00:35:33 -06:00

569 lines
21 KiB
JavaScript

/* *
*
* GUI generator for Stock tools
*
* (c) 2009-2021 Sebastian Bochan
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import U from '../Core/Utilities.js';
var addEvent = U.addEvent, createElement = U.createElement, css = U.css, fireEvent = U.fireEvent, getStyle = U.getStyle, isArray = U.isArray, merge = U.merge, pick = U.pick;
/* *
*
* Classes
*
* */
/**
* Toolbar Class
*
* @private
* @class
*
* @param {object} options
* Options of toolbar
*
* @param {Highcharts.Dictionary<string>|undefined} langOptions
* Language options
*
* @param {Highcharts.Chart} chart
* Reference to chart
*/
var Toolbar = /** @class */ (function () {
/* *
*
* Constructor
*
* */
function Toolbar(options, langOptions, chart) {
/* *
*
* Properties
*
* */
this.arrowDown = void 0;
this.arrowUp = void 0;
this.arrowWrapper = void 0;
this.listWrapper = void 0;
this.showhideBtn = void 0;
this.submenu = void 0;
this.toolbar = void 0;
this.wrapper = void 0;
this.chart = chart;
this.options = options;
this.lang = langOptions;
// set url for icons.
this.iconsURL = this.getIconsURL();
this.guiEnabled = options.enabled;
this.visible = pick(options.visible, true);
this.placed = pick(options.placed, false);
// General events collection which should be removed upon
// destroy/update:
this.eventsToUnbind = [];
if (this.guiEnabled) {
this.createHTML();
this.init();
this.showHideNavigatorion();
}
fireEvent(this, 'afterInit');
}
/* *
*
* Functions
*
* */
/**
* Initialize the toolbar. Create buttons and submenu for each option
* defined in `stockTools.gui`.
* @private
*/
Toolbar.prototype.init = function () {
var _this = this;
var lang = this.lang, guiOptions = this.options, toolbar = this.toolbar, buttons = guiOptions.buttons, defs = guiOptions.definitions, allButtons = toolbar.childNodes;
// create buttons
buttons.forEach(function (btnName) {
var button = _this.addButton(toolbar, defs, btnName, lang);
_this.eventsToUnbind.push(addEvent(button.buttonWrapper, 'click', function () { return _this.eraseActiveButtons(allButtons, button.buttonWrapper); }));
if (isArray(defs[btnName].items)) {
// create submenu buttons
_this.addSubmenu(button, defs[btnName]);
}
});
};
/**
* Create submenu (list of buttons) for the option. In example main button
* is Line, in submenu will be buttons with types of lines.
*
* @private
*
* @param {Highcharts.Dictionary<Highcharts.HTMLDOMElement>} parentBtn
* Button which has submenu
*
* @param {Highcharts.StockToolsGuiDefinitionsButtonsOptions} button
* List of all buttons
*/
Toolbar.prototype.addSubmenu = function (parentBtn, button) {
var _this = this;
var submenuArrow = parentBtn.submenuArrow, buttonWrapper = parentBtn.buttonWrapper, buttonWidth = getStyle(buttonWrapper, 'width'), wrapper = this.wrapper, menuWrapper = this.listWrapper, allButtons = this.toolbar.childNodes,
// create submenu container
submenuWrapper = this.submenu = createElement('ul', {
className: 'highcharts-submenu-wrapper'
}, void 0, buttonWrapper);
// create submenu buttons and select the first one
this.addSubmenuItems(buttonWrapper, button);
// show / hide submenu
this.eventsToUnbind.push(addEvent(submenuArrow, 'click', function (e) {
e.stopPropagation();
// Erase active class on all other buttons
_this.eraseActiveButtons(allButtons, buttonWrapper);
// hide menu
if (buttonWrapper.className
.indexOf('highcharts-current') >= 0) {
menuWrapper.style.width =
menuWrapper.startWidth + 'px';
buttonWrapper.classList.remove('highcharts-current');
submenuWrapper.style.display = 'none';
}
else {
// show menu
// to calculate height of element
submenuWrapper.style.display = 'block';
var topMargin = submenuWrapper.offsetHeight -
buttonWrapper.offsetHeight - 3;
// calculate position of submenu in the box
// if submenu is inside, reset top margin
if (
// cut on the bottom
!(submenuWrapper.offsetHeight +
buttonWrapper.offsetTop >
wrapper.offsetHeight &&
// cut on the top
buttonWrapper.offsetTop > topMargin)) {
topMargin = 0;
}
// apply calculated styles
css(submenuWrapper, {
top: -topMargin + 'px',
left: buttonWidth + 3 + 'px'
});
buttonWrapper.className += ' highcharts-current';
menuWrapper.startWidth = wrapper.offsetWidth;
menuWrapper.style.width = menuWrapper.startWidth +
getStyle(menuWrapper, 'padding-left') +
submenuWrapper.offsetWidth + 3 + 'px';
}
}));
};
/**
* Create buttons in submenu
*
* @private
*
* @param {Highcharts.HTMLDOMElement} buttonWrapper
* Button where submenu is placed
*
* @param {Highcharts.StockToolsGuiDefinitionsButtonsOptions} button
* List of all buttons options
*/
Toolbar.prototype.addSubmenuItems = function (buttonWrapper, button) {
var _this = this;
var _self = this, submenuWrapper = this.submenu, lang = this.lang, menuWrapper = this.listWrapper, items = button.items;
var submenuBtn;
// add items to submenu
items.forEach(function (btnName) {
// add buttons to submenu
submenuBtn = _this.addButton(submenuWrapper, button, btnName, lang);
_this.eventsToUnbind.push(addEvent(submenuBtn.mainButton, 'click', function () {
_self.switchSymbol(this, buttonWrapper, true);
menuWrapper.style.width =
menuWrapper.startWidth + 'px';
submenuWrapper.style.display = 'none';
}));
});
// select first submenu item
var firstSubmenuItem = submenuWrapper.querySelectorAll('li > .highcharts-menu-item-btn')[0];
// replace current symbol, in main button, with submenu's button style
this.switchSymbol(firstSubmenuItem, false);
};
/**
* Erase active class on all other buttons.
* @private
*/
Toolbar.prototype.eraseActiveButtons = function (buttons, currentButton, submenuItems) {
[].forEach.call(buttons, function (btn) {
if (btn !== currentButton) {
btn.classList.remove('highcharts-current');
btn.classList.remove('highcharts-active');
submenuItems =
btn.querySelectorAll('.highcharts-submenu-wrapper');
// hide submenu
if (submenuItems.length > 0) {
submenuItems[0].style.display = 'none';
}
}
});
};
/**
* Create single button. Consist of HTML elements `li`, `span`, and (if
* exists) submenu container.
*
* @private
*
* @param {Highcharts.HTMLDOMElement} target
* HTML reference, where button should be added
*
* @param {object} options
* All options, by btnName refer to particular button
*
* @param {string} btnName
* Button name of functionality mapped for specific class
*
* @param {Highcharts.Dictionary<string>} lang
* All titles, by btnName refer to particular button
*
* @return {object}
* References to all created HTML elements
*/
Toolbar.prototype.addButton = function (target, options, btnName, lang) {
if (lang === void 0) { lang = {}; }
var btnOptions = options[btnName], items = btnOptions.items, classMapping = Toolbar.prototype.classMapping, userClassName = btnOptions.className || '';
// main button wrapper
var buttonWrapper = createElement('li', {
className: pick(classMapping[btnName], '') + ' ' + userClassName,
title: lang[btnName] || btnName
}, void 0, target);
// single button
var mainButton = createElement('span', {
className: 'highcharts-menu-item-btn'
}, void 0, buttonWrapper);
// submenu
if (items && items.length) {
// arrow is a hook to show / hide submenu
var submenuArrow = createElement('span', {
className: 'highcharts-submenu-item-arrow ' +
'highcharts-arrow-right'
}, void 0, buttonWrapper);
submenuArrow.style.backgroundImage = 'url(' +
this.iconsURL + 'arrow-bottom.svg)';
return {
buttonWrapper: buttonWrapper,
mainButton: mainButton,
submenuArrow: submenuArrow
};
}
mainButton.style.backgroundImage = 'url(' +
this.iconsURL + btnOptions.symbol + ')';
return {
buttonWrapper: buttonWrapper,
mainButton: mainButton
};
};
/**
* Create navigation's HTML elements: container and arrows.
* @private
*/
Toolbar.prototype.addNavigation = function () {
var wrapper = this.wrapper;
// arrow wrapper
this.arrowWrapper = createElement('div', {
className: 'highcharts-arrow-wrapper'
});
this.arrowUp = createElement('div', {
className: 'highcharts-arrow-up'
}, void 0, this.arrowWrapper);
this.arrowUp.style.backgroundImage =
'url(' + this.iconsURL + 'arrow-right.svg)';
this.arrowDown = createElement('div', {
className: 'highcharts-arrow-down'
}, void 0, this.arrowWrapper);
this.arrowDown.style.backgroundImage =
'url(' + this.iconsURL + 'arrow-right.svg)';
wrapper.insertBefore(this.arrowWrapper, wrapper.childNodes[0]);
// attach scroll events
this.scrollButtons();
};
/**
* Add events to navigation (two arrows) which allows user to scroll
* top/down GUI buttons, if container's height is not enough.
* @private
*/
Toolbar.prototype.scrollButtons = function () {
var wrapper = this.wrapper, toolbar = this.toolbar, step = 0.1 * wrapper.offsetHeight; // 0.1 = 10%
var targetY = 0;
this.eventsToUnbind.push(addEvent(this.arrowUp, 'click', function () {
if (targetY > 0) {
targetY -= step;
toolbar.style.marginTop = -targetY + 'px';
}
}));
this.eventsToUnbind.push(addEvent(this.arrowDown, 'click', function () {
if (wrapper.offsetHeight + targetY <=
toolbar.offsetHeight + step) {
targetY += step;
toolbar.style.marginTop = -targetY + 'px';
}
}));
};
/*
* Create stockTools HTML main elements.
*
*/
Toolbar.prototype.createHTML = function () {
var chart = this.chart, guiOptions = this.options, container = chart.container, navigation = chart.options.navigation, bindingsClassName = navigation && navigation.bindingsClassName;
var listWrapper, toolbar;
// create main container
var wrapper = this.wrapper = createElement('div', {
className: 'highcharts-stocktools-wrapper ' +
guiOptions.className + ' ' + bindingsClassName
});
container.appendChild(wrapper);
// Mimic event behaviour of being outside chart.container
[
'mousedown',
'mousemove',
'click',
'touchstart'
].forEach(function (eventType) {
addEvent(wrapper, eventType, function (e) {
return e.stopPropagation();
});
});
addEvent(wrapper, 'mouseover', function (e) {
return chart.pointer.onContainerMouseLeave(e);
});
// toolbar
this.toolbar = toolbar = createElement('ul', {
className: 'highcharts-stocktools-toolbar ' +
guiOptions.toolbarClassName
});
// add container for list of buttons
this.listWrapper = listWrapper = createElement('div', {
className: 'highcharts-menu-wrapper'
});
wrapper.insertBefore(listWrapper, wrapper.childNodes[0]);
listWrapper.insertBefore(toolbar, listWrapper.childNodes[0]);
this.showHideToolbar();
// add navigation which allows user to scroll down / top GUI buttons
this.addNavigation();
};
/**
* Function called in redraw verifies if the navigation should be visible.
* @private
*/
Toolbar.prototype.showHideNavigatorion = function () {
// arrows
// 50px space for arrows
if (this.visible &&
this.toolbar.offsetHeight > (this.wrapper.offsetHeight - 50)) {
this.arrowWrapper.style.display = 'block';
}
else {
// reset margin if whole toolbar is visible
this.toolbar.style.marginTop = '0px';
// hide arrows
this.arrowWrapper.style.display = 'none';
}
};
/**
* Create button which shows or hides GUI toolbar.
* @private
*/
Toolbar.prototype.showHideToolbar = function () {
var chart = this.chart, wrapper = this.wrapper, toolbar = this.listWrapper, submenu = this.submenu,
// Show hide toolbar
showhideBtn = this.showhideBtn = createElement('div', {
className: 'highcharts-toggle-toolbar highcharts-arrow-left'
}, void 0, wrapper);
var visible = this.visible;
showhideBtn.style.backgroundImage =
'url(' + this.iconsURL + 'arrow-right.svg)';
if (!visible) {
// hide
if (submenu) {
submenu.style.display = 'none';
}
showhideBtn.style.left = '0px';
visible = this.visible = false;
toolbar.classList.add('highcharts-hide');
showhideBtn.classList.toggle('highcharts-arrow-right');
wrapper.style.height = showhideBtn.offsetHeight + 'px';
}
else {
wrapper.style.height = '100%';
showhideBtn.style.top = getStyle(toolbar, 'padding-top') + 'px';
showhideBtn.style.left = (wrapper.offsetWidth +
getStyle(toolbar, 'padding-left')) + 'px';
}
// Toggle menu
this.eventsToUnbind.push(addEvent(showhideBtn, 'click', function () {
chart.update({
stockTools: {
gui: {
visible: !visible,
placed: true
}
}
});
}));
};
/*
* In main GUI button, replace icon and class with submenu button's
* class / symbol.
*
* @param {HTMLDOMElement} - submenu button
* @param {Boolean} - true or false
*
*/
Toolbar.prototype.switchSymbol = function (button, redraw) {
var buttonWrapper = button.parentNode, buttonWrapperClass = buttonWrapper.className,
// main button in first level og GUI
mainNavButton = buttonWrapper.parentNode.parentNode;
// if the button is disabled, don't do anything
if (buttonWrapperClass.indexOf('highcharts-disabled-btn') > -1) {
return;
}
// set class
mainNavButton.className = '';
if (buttonWrapperClass) {
mainNavButton.classList.add(buttonWrapperClass.trim());
}
// set icon
mainNavButton
.querySelectorAll('.highcharts-menu-item-btn')[0]
.style.backgroundImage =
button.style.backgroundImage;
// set active class
if (redraw) {
this.toggleButtonActiveClass(mainNavButton);
}
};
/**
* Set select state (active class) on button.
* @private
*/
Toolbar.prototype.toggleButtonActiveClass = function (button) {
var classList = button.classList;
if (classList.contains('highcharts-active')) {
classList.remove('highcharts-active');
}
else {
classList.add('highcharts-active');
}
};
/**
* Remove active class from all buttons except defined.
* @private
*/
Toolbar.prototype.unselectAllButtons = function (button) {
var activeBtns = button.parentNode
.querySelectorAll('.highcharts-active');
[].forEach.call(activeBtns, function (activeBtn) {
if (activeBtn !== button) {
activeBtn.classList.remove('highcharts-active');
}
});
};
/**
* Update GUI with given options.
* @private
*/
Toolbar.prototype.update = function (options, redraw) {
merge(true, this.chart.options.stockTools, options);
this.destroy();
this.chart.setStockTools(options);
// If Stock Tools are updated, then bindings should be updated too:
if (this.chart.navigationBindings) {
this.chart.navigationBindings.update();
}
this.chart.isDirtyBox = true;
if (pick(redraw, true)) {
this.chart.redraw();
}
};
/**
* Destroy all HTML GUI elements.
* @private
*/
Toolbar.prototype.destroy = function () {
var stockToolsDiv = this.wrapper, parent = stockToolsDiv && stockToolsDiv.parentNode;
this.eventsToUnbind.forEach(function (unbinder) { return unbinder(); });
// Remove the empty element
if (parent) {
parent.removeChild(stockToolsDiv);
}
};
/**
* Redraw, GUI requires to verify if the navigation should be visible.
* @private
*/
Toolbar.prototype.redraw = function () {
this.showHideNavigatorion();
};
/**
* @private
*/
Toolbar.prototype.getIconsURL = function () {
return this.chart.options.navigation.iconsURL ||
this.options.iconsURL ||
'https://code.highcharts.com/10.2.1/gfx/stock-icons/';
};
return Toolbar;
}());
Toolbar.prototype.classMapping = {
circle: 'highcharts-circle-annotation',
ellipse: 'highcharts-ellipse-annotation',
rectangle: 'highcharts-rectangle-annotation',
label: 'highcharts-label-annotation',
segment: 'highcharts-segment',
arrowSegment: 'highcharts-arrow-segment',
ray: 'highcharts-ray',
arrowRay: 'highcharts-arrow-ray',
line: 'highcharts-infinity-line',
arrowInfinityLine: 'highcharts-arrow-infinity-line',
verticalLine: 'highcharts-vertical-line',
horizontalLine: 'highcharts-horizontal-line',
crooked3: 'highcharts-crooked3',
crooked5: 'highcharts-crooked5',
elliott3: 'highcharts-elliott3',
elliott5: 'highcharts-elliott5',
pitchfork: 'highcharts-pitchfork',
fibonacci: 'highcharts-fibonacci',
fibonacciTimeZones: 'highcharts-fibonacci-time-zones',
parallelChannel: 'highcharts-parallel-channel',
measureX: 'highcharts-measure-x',
measureY: 'highcharts-measure-y',
measureXY: 'highcharts-measure-xy',
timeCycles: 'highcharts-time-cycles',
verticalCounter: 'highcharts-vertical-counter',
verticalLabel: 'highcharts-vertical-label',
verticalArrow: 'highcharts-vertical-arrow',
currentPriceIndicator: 'highcharts-current-price-indicator',
indicators: 'highcharts-indicators',
flagCirclepin: 'highcharts-flag-circlepin',
flagDiamondpin: 'highcharts-flag-diamondpin',
flagSquarepin: 'highcharts-flag-squarepin',
flagSimplepin: 'highcharts-flag-simplepin',
zoomX: 'highcharts-zoom-x',
zoomY: 'highcharts-zoom-y',
zoomXY: 'highcharts-zoom-xy',
typeLine: 'highcharts-series-type-line',
typeOHLC: 'highcharts-series-type-ohlc',
typeHLC: 'highcharts-series-type-hlc',
typeCandlestick: 'highcharts-series-type-candlestick',
typeHollowCandlestick: 'highcharts-series-type-hollowcandlestick',
typeHeikinAshi: 'highcharts-series-type-heikinashi',
fullScreen: 'highcharts-full-screen',
toggleAnnotations: 'highcharts-toggle-annotations',
saveChart: 'highcharts-save-chart',
separator: 'highcharts-separator'
};
/* *
*
* Default Export
*
* */
export default Toolbar;