1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456 |
- /**
- * GUI generator for Stock tools
- *
- * (c) 2009-2017 Sebastian Bochan
- *
- * License: www.highcharts.com/license
- */
- 'use strict';
- import H from '../parts/Globals.js';
- var addEvent = H.addEvent,
- createElement = H.createElement,
- pick = H.pick,
- isArray = H.isArray,
- fireEvent = H.fireEvent,
- getStyle = H.getStyle,
- merge = H.merge,
- css = H.css,
- win = H.win,
- DIV = 'div',
- SPAN = 'span',
- UL = 'ul',
- LI = 'li',
- PREFIX = 'highcharts-',
- activeClass = PREFIX + 'active';
- H.setOptions({
- /**
- * @optionparent lang
- */
- lang: {
- /**
- * Configure the stockTools GUI titles(hints) in the chart. Requires
- * the `stock-tools.js` module to be loaded.
- *
- * @product highstock
- * @since 7.0.0
- * @type {Object}
- */
- stockTools: {
- gui: {
- // Main buttons:
- simpleShapes: 'Simple shapes',
- lines: 'Lines',
- crookedLines: 'Crooked lines',
- measure: 'Measure',
- advanced: 'Advanced',
- toggleAnnotations: 'Toggle annotations',
- verticalLabels: 'Vertical labels',
- flags: 'Flags',
- zoomChange: 'Zoom change',
- typeChange: 'Type change',
- saveChart: 'Save chart',
- indicators: 'Indicators',
- currentPriceIndicator: 'Current Price Indicators',
- // Other features:
- zoomX: 'Zoom X',
- zoomY: 'Zoom Y',
- zoomXY: 'Zooom XY',
- fullScreen: 'Fullscreen',
- typeOHLC: 'OHLC',
- typeLine: 'Line',
- typeCandlestick: 'Candlestick',
- // Basic shapes:
- circle: 'Circle',
- label: 'Label',
- rectangle: 'Rectangle',
- // Flags:
- flagCirclepin: 'Flag circle',
- flagDiamondpin: 'Flag diamond',
- flagSquarepin: 'Flag square',
- flagSimplepin: 'Flag simple',
- // Measures:
- measureXY: 'Measure XY',
- measureX: 'Measure X',
- measureY: 'Measure Y',
- // Segment, ray and line:
- segment: 'Segment',
- arrowSegment: 'Arrow segment',
- ray: 'Ray',
- arrowRay: 'Arrow ray',
- line: 'Line',
- arrowLine: 'Arrow line',
- horizontalLine: 'Horizontal line',
- verticalLine: 'Vertical line',
- infinityLine: 'Infinity line',
- // Crooked lines:
- crooked3: 'Crooked 3 line',
- crooked5: 'Crooked 5 line',
- elliott3: 'Elliott 3 line',
- elliott5: 'Elliott 5 line',
- // Counters:
- verticalCounter: 'Vertical counter',
- verticalLabel: 'Vertical label',
- verticalArrow: 'Vertical arrow',
- // Advanced:
- fibonacci: 'Fibonacci',
- pitchfork: 'Pitchfork',
- parallelChannel: 'Parallel channel'
- }
- },
- navigation: {
- popup: {
- // Annotations:
- circle: 'Circle',
- rectangle: 'Rectangle',
- label: 'Label',
- segment: 'Segment',
- arrowSegment: 'Arrow segment',
- ray: 'Ray',
- arrowRay: 'Arrow ray',
- line: 'Line',
- arrowLine: 'Arrow line',
- horizontalLine: 'Horizontal line',
- verticalLine: 'Vertical line',
- crooked3: 'Crooked 3 line',
- crooked5: 'Crooked 5 line',
- elliott3: 'Elliott 3 line',
- elliott5: 'Elliott 5 line',
- verticalCounter: 'Vertical counter',
- verticalLabel: 'Vertical label',
- verticalArrow: 'Vertical arrow',
- fibonacci: 'Fibonacci',
- pitchfork: 'Pitchfork',
- parallelChannel: 'Parallel channel',
- infinityLine: 'Infinity line',
- measure: 'Measure',
- measureXY: 'Measure XY',
- measureX: 'Measure X',
- measureY: 'Measure Y',
- // Flags:
- flags: 'Flags',
- // GUI elements:
- addButton: 'add',
- saveButton: 'save',
- editButton: 'edit',
- removeButton: 'remove',
- series: 'Series',
- volume: 'Volume',
- connector: 'Connector',
- // Field names:
- innerBackground: 'Inner background',
- outerBackground: 'Outer background',
- crosshairX: 'Crosshair X',
- crosshairY: 'Crosshair Y',
- tunnel: 'Tunnel',
- background: 'Background'
- }
- }
- },
- /**
- * Configure the stockTools gui strings in the chart. Requires the
- * [stockTools module]() to be loaded. For a description of the module
- * and information on its features, see [Highcharts StockTools]().
- *
- * @product highstock
- *
- * @sample stock/demo/stock-tools-gui Stock Tools GUI
- *
- * @sample stock/demo/stock-tools-custom-gui Stock Tools customized GUI
- *
- * @since 7.0.0
- * @type {Object}
- * @optionparent stockTools
- */
- stockTools: {
- /**
- * Definitions of buttons in Stock Tools GUI.
- */
- gui: {
- /**
- * Enable or disable the stockTools gui.
- *
- * @type {boolean}
- * @default true
- */
- enabled: true,
- /**
- * A CSS class name to apply to the stocktools' div,
- * allowing unique CSS styling for each chart.
- *
- * @type {string}
- * @default 'highcharts-bindings-wrapper'
- *
- */
- className: 'highcharts-bindings-wrapper',
- /**
- * A CSS class name to apply to the container of buttons,
- * allowing unique CSS styling for each chart.
- *
- * @type {string}
- * @default 'stocktools-toolbar'
- *
- */
- toolbarClassName: 'stocktools-toolbar',
- /**
- * Path where Highcharts will look for icons. Change this to use
- * icons from a different server.
- */
- iconsURL: 'https://code.highcharts.com/@product.version@/gfx/stock-icons/',
- /**
- * A collection of strings pointing to config options for the
- * toolbar items. Each name refers to unique key from definitions
- * object.
- *
- * @type {array}
- *
- * @default [
- * 'indicators',
- * 'separator',
- * 'simpleShapes',
- * 'lines',
- * 'crookedLines',
- * 'measure',
- * 'advanced',
- * 'toggleAnnotations',
- * 'separator',
- * 'verticalLabels',
- * 'flags',
- * 'separator',
- * 'zoomChange',
- * 'fullScreen',
- * 'typeChange',
- * 'separator',
- * 'currentPriceIndicator',
- * 'saveChart'
- * ]
- */
- buttons: [
- 'indicators',
- 'separator',
- 'simpleShapes',
- 'lines',
- 'crookedLines',
- 'measure',
- 'advanced',
- 'toggleAnnotations',
- 'separator',
- 'verticalLabels',
- 'flags',
- 'separator',
- 'zoomChange',
- 'fullScreen',
- 'typeChange',
- 'separator',
- 'currentPriceIndicator',
- 'saveChart'
- ],
- /**
- * An options object of the buttons definitions. Each name refers to
- * unique key from buttons array.
- *
- * @type {object}
- *
- */
- definitions: {
- separator: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'separator.svg'
- },
- simpleShapes: {
- /**
- * A collection of strings pointing to config options for
- * the items.
- *
- * @type {array}
- * @default [
- * 'label',
- * 'circle',
- * 'rectangle'
- * ]
- *
- */
- items: [
- 'label',
- 'circle',
- 'rectangle'
- ],
- circle: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- *
- */
- symbol: 'circle.svg'
- },
- rectangle: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- *
- */
- symbol: 'rectangle.svg'
- },
- label: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- *
- */
- symbol: 'label.svg'
- }
- },
- flags: {
- /**
- * A collection of strings pointing to config options for
- * the items.
- *
- * @type {array}
- * @default [
- * 'flagCirclepin',
- * 'flagDiamondpin',
- * 'flagSquarepin',
- * 'flagSimplepin'
- * ]
- *
- */
- items: [
- 'flagCirclepin',
- 'flagDiamondpin',
- 'flagSquarepin',
- 'flagSimplepin'
- ],
- flagSimplepin: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- *
- */
- symbol: 'flag-basic.svg'
- },
- flagDiamondpin: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- *
- */
- symbol: 'flag-diamond.svg'
- },
- flagSquarepin: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'flag-trapeze.svg'
- },
- flagCirclepin: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'flag-elipse.svg'
- }
- },
- lines: {
- /**
- * A collection of strings pointing to config options for
- * the items.
- *
- * @type {array}
- * @default [
- * 'segment',
- * 'arrowSegment',
- * 'ray',
- * 'arrowRay',
- * 'line',
- * 'arrowLine',
- * 'horizontalLine',
- * 'verticalLine'
- * ]
- */
- items: [
- 'segment',
- 'arrowSegment',
- 'ray',
- 'arrowRay',
- 'line',
- 'arrowLine',
- 'horizontalLine',
- 'verticalLine'
- ],
- segment: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'segment.svg'
- },
- arrowSegment: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'arrow-segment.svg'
- },
- ray: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'ray.svg'
- },
- arrowRay: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'arrow-ray.svg'
- },
- line: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'line.svg'
- },
- arrowLine: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'arrow-line.svg'
- },
- verticalLine: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'vertical-line.svg'
- },
- horizontalLine: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'horizontal-line.svg'
- }
- },
- crookedLines: {
- /**
- * A collection of strings pointing to config options for
- * the items.
- *
- * @type {array}
- * @default [
- * 'elliott3',
- * 'elliott5',
- * 'crooked3',
- * 'crooked5'
- * ]
- *
- */
- items: [
- 'elliott3',
- 'elliott5',
- 'crooked3',
- 'crooked5'
- ],
- crooked3: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'crooked-3.svg'
- },
- crooked5: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'crooked-5.svg'
- },
- elliott3: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'elliott-3.svg'
- },
- elliott5: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'elliott-5.svg'
- }
- },
- verticalLabels: {
- /**
- * A collection of strings pointing to config options for
- * the items.
- *
- * @type {array}
- * @default [
- * 'verticalCounter',
- * 'verticalLabel',
- * 'verticalArrow'
- * ]
- */
- items: [
- 'verticalCounter',
- 'verticalLabel',
- 'verticalArrow'
- ],
- verticalCounter: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'vertical-counter.svg'
- },
- verticalLabel: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'vertical-label.svg'
- },
- verticalArrow: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'vertical-arrow.svg'
- }
- },
- advanced: {
- /**
- * A collection of strings pointing to config options for
- * the items.
- *
- * @type {array}
- * @default [
- * 'fibonacci',
- * 'pitchfork',
- * 'parallelChannel'
- * ]
- */
- items: [
- 'fibonacci',
- 'pitchfork',
- 'parallelChannel'
- ],
- pitchfork: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'pitchfork.svg'
- },
- fibonacci: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'fibonacci.svg'
- },
- parallelChannel: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'parallel-channel.svg'
- }
- },
- measure: {
- /**
- * A collection of strings pointing to config options for
- * the items.
- *
- * @type {array}
- * @default [
- * 'measureXY',
- * 'measureX',
- * 'measureY'
- * ]
- */
- items: [
- 'measureXY',
- 'measureX',
- 'measureY'
- ],
- measureX: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'measure-x.svg'
- },
- measureY: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'measure-y.svg'
- },
- measureXY: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'measure-xy.svg'
- }
- },
- toggleAnnotations: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'annotations-visible.svg'
- },
- currentPriceIndicator: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'current-price-show.svg'
- },
- indicators: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'indicators.svg'
- },
- zoomChange: {
- /**
- * A collection of strings pointing to config options for
- * the items.
- *
- * @type {array}
- * @default [
- * 'zoomX',
- * 'zoomY',
- * 'zoomXY'
- * ]
- */
- items: [
- 'zoomX',
- 'zoomY',
- 'zoomXY'
- ],
- zoomX: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'zoom-x.svg'
- },
- zoomY: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'zoom-y.svg'
- },
- zoomXY: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'zoom-xy.svg'
- }
- },
- typeChange: {
- /**
- * A collection of strings pointing to config options for
- * the items.
- *
- * @type {array}
- * @default [
- * 'typeOHLC',
- * 'typeLine',
- * 'typeCandlestick'
- * ]
- */
- items: [
- 'typeOHLC',
- 'typeLine',
- 'typeCandlestick'
- ],
- typeOHLC: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'series-ohlc.svg'
- },
- typeLine: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'series-line.svg'
- },
- typeCandlestick: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'series-candlestick.svg'
- }
- },
- fullScreen: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'fullscreen.svg'
- },
- saveChart: {
- /**
- * A predefined background symbol for the button.
- *
- * @type {string}
- */
- symbol: 'save-chart.svg'
- }
- }
- }
- }
- });
- // Run HTML generator
- addEvent(H.Chart, 'afterGetContainer', function () {
- this.setStockTools();
- });
- addEvent(H.Chart, 'getMargins', function () {
- var offsetWidth = (
- this.stockTools &&
- this.stockTools.listWrapper &&
- this.stockTools.listWrapper.offsetWidth
- );
- if (offsetWidth && offsetWidth < this.plotWidth) {
- this.plotLeft += offsetWidth;
- }
- });
- addEvent(H.Chart, 'destroy', function () {
- if (this.stockTools) {
- this.stockTools.destroy();
- }
- });
- addEvent(H.Chart, 'redraw', function () {
- if (this.stockTools && this.stockTools.guiEnabled) {
- this.stockTools.redraw();
- }
- });
- /*
- * Toolbar Class
- *
- * @param {Object} - options of toolbar
- * @param {Chart} - Reference to chart
- *
- */
- H.Toolbar = function (options, langOptions, chart) {
- this.chart = chart;
- this.options = options;
- this.lang = langOptions;
- 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');
- };
- H.extend(H.Chart.prototype, {
- /*
- * Verify if Toolbar should be added.
- *
- * @param {Object} - chart options
- *
- */
- setStockTools: function (options) {
- var chartOptions = this.options,
- lang = chartOptions.lang,
- guiOptions = merge(
- chartOptions.stockTools && chartOptions.stockTools.gui,
- options && options.gui
- ),
- langOptions = lang.stockTools && lang.stockTools.gui;
- this.stockTools = new H.Toolbar(guiOptions, langOptions, this);
- if (this.stockTools.guiEnabled) {
- this.isDirtyBox = true;
- }
- }
- });
- H.Toolbar.prototype = {
- /*
- * Initialize the toolbar. Create buttons and submenu for each option
- * defined in `stockTools.gui`.
- *
- */
- init: function () {
- var _self = this,
- lang = this.lang,
- guiOptions = this.options,
- toolbar = this.toolbar,
- addSubmenu = _self.addSubmenu,
- buttons = guiOptions.buttons,
- defs = guiOptions.definitions,
- allButtons = toolbar.childNodes,
- inIframe = this.inIframe(),
- button;
- // create buttons
- buttons.forEach(function (btnName) {
- button = _self.addButton(toolbar, defs, btnName, lang);
- if (inIframe && btnName === 'fullScreen') {
- button.buttonWrapper.className += ' ' + PREFIX + 'disabled-btn';
- }
- ['click', 'touchstart'].forEach(function (eventName) {
- addEvent(button.buttonWrapper, eventName, function () {
- _self.eraseActiveButtons(
- allButtons,
- button.buttonWrapper
- );
- });
- });
- if (isArray(defs[btnName].items)) {
- // create submenu buttons
- addSubmenu.call(_self, 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.
- *
- * @param {Object} - button which has submenu
- * @param {Array} - list of all buttons
- *
- */
- addSubmenu: function (parentBtn, button) {
- var _self = this,
- submenuArrow = parentBtn.submenuArrow,
- buttonWrapper = parentBtn.buttonWrapper,
- buttonWidth = getStyle(buttonWrapper, 'width'),
- wrapper = this.wrapper,
- menuWrapper = this.listWrapper,
- allButtons = this.toolbar.childNodes,
- topMargin = 0,
- submenuWrapper;
- // create submenu container
- this.submenu = submenuWrapper = createElement(UL, {
- className: PREFIX + 'submenu-wrapper'
- }, null, buttonWrapper);
- // create submenu buttons and select the first one
- this.addSubmenuItems(buttonWrapper, button);
- // show / hide submenu
- ['click', 'touchstart'].forEach(function (eventName) {
- addEvent(submenuArrow, eventName, function (e) {
- e.stopPropagation();
- // Erase active class on all other buttons
- _self.eraseActiveButtons(allButtons, buttonWrapper);
- // hide menu
- if (buttonWrapper.className.indexOf(PREFIX + 'current') >= 0) {
- menuWrapper.style.width = menuWrapper.startWidth + 'px';
- buttonWrapper.classList.remove(PREFIX + 'current');
- submenuWrapper.style.display = 'none';
- } else {
- // show menu
- // to calculate height of element
- submenuWrapper.style.display = 'block';
- 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 += ' ' + PREFIX + 'current';
- menuWrapper.startWidth = wrapper.offsetWidth;
- menuWrapper.style.width = menuWrapper.startWidth +
- H.getStyle(menuWrapper, 'padding-left') +
- submenuWrapper.offsetWidth + 3 + 'px';
- }
- });
- });
- },
- /*
- * Create buttons in submenu
- *
- * @param {HTMLDOMElement} - button where submenu is placed
- * @param {Array} - list of all buttons options
- *
- */
- addSubmenuItems: function (buttonWrapper, button) {
- var _self = this,
- submenuWrapper = this.submenu,
- lang = this.lang,
- menuWrapper = this.listWrapper,
- items = button.items,
- firstSubmenuItem,
- submenuBtn;
- // add items to submenu
- items.forEach(function (btnName) {
- // add buttons to submenu
- submenuBtn = _self.addButton(
- submenuWrapper,
- button,
- btnName,
- lang
- );
- ['click', 'touchstart'].forEach(function (eventName) {
- addEvent(submenuBtn.mainButton, eventName, function () {
- _self.switchSymbol(this, buttonWrapper, true);
- menuWrapper.style.width = menuWrapper.startWidth + 'px';
- submenuWrapper.style.display = 'none';
- });
- });
- });
- // select first submenu item
- firstSubmenuItem = submenuWrapper
- .querySelectorAll('li > .' + PREFIX + 'menu-item-btn')[0];
- // replace current symbol, in main button, with submenu's button style
- _self.switchSymbol(firstSubmenuItem, false);
- },
- /*
- * Erase active class on all other buttons.
- *
- * @param {Array} - Array of HTML buttons
- * @param {HTMLDOMElement} - Current HTML button
- *
- */
- eraseActiveButtons: function (buttons, currentButton, submenuItems) {
- [].forEach.call(buttons, function (btn) {
- if (btn !== currentButton) {
- btn.classList.remove(PREFIX + 'current');
- btn.classList.remove(PREFIX + 'active');
- submenuItems =
- btn.querySelectorAll('.' + PREFIX + 'submenu-wrapper');
- // hide submenu
- if (submenuItems.length > 0) {
- submenuItems[0].style.display = 'none';
- }
- }
- });
- },
- /*
- * Create single button. Consist of `<li>` , `<span>` and (if exists)
- * submenu container.
- *
- * @param {HTMLDOMElement} - HTML reference, where button should be added
- * @param {Object} - all options, by btnName refer to particular button
- * @param {String} - name of functionality mapped for specific class
- * @param {Object} - All titles, by btnName refer to particular button
- *
- * @return {Object} - references to all created HTML elements
- */
- addButton: function (target, options, btnName, lang) {
- var guiOptions = this.options,
- btnOptions = options[btnName],
- items = btnOptions.items,
- classMapping = H.Toolbar.prototype.classMapping,
- userClassName = btnOptions.className || '',
- mainButton,
- submenuArrow,
- buttonWrapper;
- // main button wrapper
- buttonWrapper = createElement(LI, {
- className: pick(classMapping[btnName], '') + ' ' + userClassName,
- title: lang[btnName] || btnName
- }, null, target);
- // single button
- mainButton = createElement(SPAN, {
- className: PREFIX + 'menu-item-btn'
- }, null, buttonWrapper);
- // submenu
- if (items && items.length > 1) {
- // arrow is a hook to show / hide submenu
- submenuArrow = createElement(SPAN, {
- className: PREFIX + 'submenu-item-arrow ' +
- PREFIX + 'arrow-right'
- }, null, buttonWrapper);
- } else {
- mainButton.style['background-image'] = 'url(' +
- guiOptions.iconsURL + btnOptions.symbol + ')';
- }
- return {
- buttonWrapper: buttonWrapper,
- mainButton: mainButton,
- submenuArrow: submenuArrow
- };
- },
- /*
- * Create navigation's HTML elements: container and arrows.
- *
- */
- addNavigation: function () {
- var stockToolbar = this,
- wrapper = stockToolbar.wrapper;
- // arrow wrapper
- stockToolbar.arrowWrapper = createElement(DIV, {
- className: PREFIX + 'arrow-wrapper'
- });
- stockToolbar.arrowUp = createElement(DIV, {
- className: PREFIX + 'arrow-up'
- }, null, stockToolbar.arrowWrapper);
- stockToolbar.arrowDown = createElement(DIV, {
- className: PREFIX + 'arrow-down'
- }, null, stockToolbar.arrowWrapper);
- wrapper.insertBefore(
- stockToolbar.arrowWrapper,
- wrapper.childNodes[0]
- );
- // attach scroll events
- stockToolbar.scrollButtons();
- },
- /*
- * Add events to navigation (two arrows) which allows user to scroll
- * top/down GUI buttons, if container's height is not enough.
- *
- */
- scrollButtons: function () {
- var targetY = 0,
- _self = this,
- wrapper = _self.wrapper,
- toolbar = _self.toolbar,
- step = 0.1 * wrapper.offsetHeight; // 0.1 = 10%
- ['click', 'touchstart'].forEach(function (eventName) {
- addEvent(_self.arrowUp, eventName, function () {
- if (targetY > 0) {
- targetY -= step;
- toolbar.style['margin-top'] = -targetY + 'px';
- }
- });
- addEvent(_self.arrowDown, eventName, function () {
- if (
- wrapper.offsetHeight + targetY <=
- toolbar.offsetHeight + step
- ) {
- targetY += step;
- toolbar.style['margin-top'] = -targetY + 'px';
- }
- });
- });
- },
- /*
- * Create stockTools HTML main elements.
- *
- */
- createHTML: function () {
- var stockToolbar = this,
- chart = stockToolbar.chart,
- guiOptions = stockToolbar.options,
- container = chart.container,
- listWrapper,
- toolbar,
- wrapper;
- // create main container
- stockToolbar.wrapper = wrapper = createElement(DIV, {
- className: PREFIX + 'stocktools-wrapper ' +
- guiOptions.className
- });
- container.parentNode.insertBefore(wrapper, container);
- // toolbar
- stockToolbar.toolbar = toolbar = createElement(UL, {
- className: PREFIX + 'stocktools-toolbar ' +
- guiOptions.toolbarClassName
- });
- // add container for list of buttons
- stockToolbar.listWrapper = listWrapper = createElement(DIV, {
- className: PREFIX + 'menu-wrapper'
- });
- wrapper.insertBefore(listWrapper, wrapper.childNodes[0]);
- listWrapper.insertBefore(toolbar, listWrapper.childNodes[0]);
- stockToolbar.showHideToolbar();
- // add navigation which allows user to scroll down / top GUI buttons
- stockToolbar.addNavigation();
- },
- /*
- * Function called in redraw verifies if the navigation should be visible.
- *
- */
- 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.
- *
- */
- showHideToolbar: function () {
- var stockToolbar = this,
- chart = this.chart,
- wrapper = stockToolbar.wrapper,
- toolbar = this.listWrapper,
- submenu = this.submenu,
- visible = this.visible,
- showhideBtn;
- // Show hide toolbar
- this.showhideBtn = showhideBtn = createElement(DIV, {
- className: PREFIX + 'toggle-toolbar ' + PREFIX + 'arrow-left'
- }, null, wrapper);
- if (!visible) {
- // hide
- if (submenu) {
- submenu.style.display = 'none';
- }
- showhideBtn.style.left = '0px';
- stockToolbar.visible = visible = false;
- toolbar.classList.add(PREFIX + 'hide');
- showhideBtn.classList.toggle(PREFIX + 'arrow-right');
- } else {
- showhideBtn.style.top = H.getStyle(toolbar, 'padding-top') + 'px';
- showhideBtn.style.left = (
- wrapper.offsetWidth +
- H.getStyle(toolbar, 'padding-left')
- ) + 'px';
- }
- // toggle menu
- ['click', 'touchstart'].forEach(function (eventName) {
- addEvent(showhideBtn, eventName, 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
- *
- */
- switchSymbol: function (button, redraw) {
- var buttonWrapper = button.parentNode,
- buttonWrapperClass = buttonWrapper.classList.value,
- // main button in first level og GUI
- mainNavButton = buttonWrapper.parentNode.parentNode;
- // set class
- mainNavButton.className = '';
- if (buttonWrapperClass) {
- mainNavButton.classList.add(buttonWrapperClass.trim());
- }
- // set icon
- mainNavButton.querySelectorAll('.' + PREFIX + 'menu-item-btn')[0]
- .style['background-image'] = button.style['background-image'];
- // set active class
- if (redraw) {
- this.selectButton(mainNavButton);
- }
- },
- /*
- * Set select state (active class) on button.
- *
- * @param {HTMLDOMElement} - button
- *
- */
- selectButton: function (btn) {
- if (btn.className.indexOf(activeClass) >= 0) {
- btn.classList.remove(activeClass);
- } else {
- btn.classList.add(activeClass);
- }
- },
- /*
- * Remove active class from all buttons except defined.
- *
- * @param {HTMLDOMElement} - button which should not be deactivated
- *
- */
- unselectAllButtons: function (btn) {
- var activeButtons = btn.parentNode.querySelectorAll('.' + activeClass);
- [].forEach.call(activeButtons, function (activeBtn) {
- if (activeBtn !== btn) {
- activeBtn.classList.remove(activeClass);
- }
- });
- },
- /*
- * Verify if chart is in iframe.
- *
- * @return {Object} - elements translations.
- */
- inIframe: function () {
- try {
- return win.self !== win.top;
- } catch (e) {
- return true;
- }
- },
- /*
- * Update GUI with given options.
- *
- * @param {Object} - general options for Stock Tools
- */
- update: function (options) {
- 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();
- }
- },
- /*
- * Destroy all HTML GUI elements.
- *
- */
- destroy: function () {
- var stockToolsDiv = this.wrapper,
- parent = stockToolsDiv && stockToolsDiv.parentNode;
- this.eventsToUnbind.forEach(function (unbinder) {
- unbinder();
- });
- // Remove the empty element
- if (parent) {
- parent.removeChild(stockToolsDiv);
- }
- // redraw
- this.chart.isDirtyBox = true;
- this.chart.redraw();
- },
- /*
- * Redraw, GUI requires to verify if the navigation should be visible.
- *
- */
- redraw: function () {
- this.showHideNavigatorion();
- },
- /*
- * Mapping JSON fields to CSS classes.
- *
- */
- classMapping: {
- circle: PREFIX + 'circle-annotation',
- rectangle: PREFIX + 'rectangle-annotation',
- label: PREFIX + 'label-annotation',
- segment: PREFIX + 'segment',
- arrowSegment: PREFIX + 'arrow-segment',
- ray: PREFIX + 'ray',
- arrowRay: PREFIX + 'arrow-ray',
- line: PREFIX + 'infinity-line',
- arrowLine: PREFIX + 'arrow-infinity-line',
- verticalLine: PREFIX + 'vertical-line',
- horizontalLine: PREFIX + 'horizontal-line',
- crooked3: PREFIX + 'crooked3',
- crooked5: PREFIX + 'crooked5',
- elliott3: PREFIX + 'elliott3',
- elliott5: PREFIX + 'elliott5',
- pitchfork: PREFIX + 'pitchfork',
- fibonacci: PREFIX + 'fibonacci',
- parallelChannel: PREFIX + 'parallel-channel',
- measureX: PREFIX + 'measure-x',
- measureY: PREFIX + 'measure-y',
- measureXY: PREFIX + 'measure-xy',
- verticalCounter: PREFIX + 'vertical-counter',
- verticalLabel: PREFIX + 'vertical-label',
- verticalArrow: PREFIX + 'vertical-arrow',
- currentPriceIndicator: PREFIX + 'current-price-indicator',
- indicators: PREFIX + 'indicators',
- flagCirclepin: PREFIX + 'flag-circlepin',
- flagDiamondpin: PREFIX + 'flag-diamondpin',
- flagSquarepin: PREFIX + 'flag-squarepin',
- flagSimplepin: PREFIX + 'flag-simplepin',
- zoomX: PREFIX + 'zoom-x',
- zoomY: PREFIX + 'zoom-y',
- zoomXY: PREFIX + 'zoom-xy',
- typeLine: PREFIX + 'series-type-line',
- typeOHLC: PREFIX + 'series-type-ohlc',
- typeCandlestick: PREFIX + 'series-type-candlestick',
- fullScreen: PREFIX + 'full-screen',
- toggleAnnotations: PREFIX + 'toggle-annotations',
- saveChart: PREFIX + 'save-chart',
- separator: PREFIX + 'separator'
- }
- };
- // Comunication with bindings:
- addEvent(H.NavigationBindings, 'selectButton', function (event) {
- var button = event.button,
- className = PREFIX + 'submenu-wrapper',
- gui = this.chart.stockTools;
- if (gui && gui.guiEnabled) {
- // Unslect other active buttons
- gui.unselectAllButtons(event.button);
- // If clicked on a submenu, select state for it's parent
- if (button.parentNode.className.indexOf(className) >= 0) {
- button = button.parentNode.parentNode;
- }
- // Set active class on the current button
- gui.selectButton(button);
- }
- });
- addEvent(H.NavigationBindings, 'deselectButton', function (event) {
- var button = event.button,
- className = PREFIX + 'submenu-wrapper',
- gui = this.chart.stockTools;
- if (gui && gui.guiEnabled) {
- // If deselecting a button from a submenu, select state for it's parent
- if (button.parentNode.className.indexOf(className) >= 0) {
- button = button.parentNode.parentNode;
- }
- gui.selectButton(button);
- }
- });
|