| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283 | 
							- /**
 
-  * (c) 2009-2017 Highsoft, Black Label
 
-  *
 
-  * License: www.highcharts.com/license
 
-  */
 
- 'use strict';
 
- import H from '../parts/Globals.js';
 
- import chartNavigationMixin from '../mixins/navigation.js';
 
- var doc = H.doc,
 
-     addEvent = H.addEvent,
 
-     pick = H.pick,
 
-     merge = H.merge,
 
-     extend = H.extend,
 
-     isNumber = H.isNumber,
 
-     fireEvent = H.fireEvent,
 
-     isArray = H.isArray,
 
-     isObject = H.isObject,
 
-     objectEach = H.objectEach,
 
-     PREFIX = 'highcharts-';
 
- /**
 
-  * @private
 
-  * @interface bindingsUtils
 
-  */
 
- var bindingsUtils = {
 
-     /**
 
-      * Update size of background (rect) in some annotations: Measure, Simple
 
-      * Rect.
 
-      *
 
-      * @private
 
-      * @function bindingsUtils.updateRectSize
 
-      *
 
-      * @param {global.Event} event
 
-      *        Normalized browser event
 
-      *
 
-      * @param {Highcharts.Annotation} annotation
 
-      *        Annotation to be updated
 
-      */
 
-     updateRectSize: function (event, annotation) {
 
-         var options = annotation.options.typeOptions,
 
-             x = this.chart.xAxis[0].toValue(event.chartX),
 
-             y = this.chart.yAxis[0].toValue(event.chartY),
 
-             width = x - options.point.x,
 
-             height = options.point.y - y;
 
-         annotation.update({
 
-             typeOptions: {
 
-                 background: {
 
-                     width: width,
 
-                     height: height
 
-                 }
 
-             }
 
-         });
 
-     },
 
-     /**
 
-      * Get field type according to value
 
-      *
 
-      * @private
 
-      * @function bindingsUtils.getFieldType
 
-      *
 
-      * @param {*} value
 
-      *        Atomic type (one of: string, number, boolean)
 
-      *
 
-      * @return {string}
 
-      *         Field type (one of: text, number, checkbox)
 
-      */
 
-     getFieldType: function (value) {
 
-         return {
 
-             'string': 'text',
 
-             'number': 'number',
 
-             'boolean': 'checkbox'
 
-         }[typeof value];
 
-     }
 
- };
 
- H.NavigationBindings = function (chart, options) {
 
-     this.chart = chart;
 
-     this.options = options;
 
-     this.eventsToUnbind = [];
 
-     this.container = doc.getElementsByClassName(
 
-         this.options.bindingsClassName
 
-     );
 
- };
 
- // Define which options from annotations should show up in edit box:
 
- H.NavigationBindings.annotationsEditable = {
 
-     // `typeOptions` are always available
 
-     // Nested and shared options:
 
-     nestedOptions: {
 
-         labelOptions: ['style', 'format', 'backgroundColor'],
 
-         labels: ['style'],
 
-         label: ['style'],
 
-         style: ['fontSize', 'color'],
 
-         background: ['fill', 'strokeWidth', 'stroke'],
 
-         innerBackground: ['fill', 'strokeWidth', 'stroke'],
 
-         outerBackground: ['fill', 'strokeWidth', 'stroke'],
 
-         shapeOptions: ['fill', 'strokeWidth', 'stroke'],
 
-         shapes: ['fill', 'strokeWidth', 'stroke'],
 
-         line: ['strokeWidth', 'stroke'],
 
-         backgroundColors: [true],
 
-         connector: ['fill', 'strokeWidth', 'stroke'],
 
-         crosshairX: ['strokeWidth', 'stroke'],
 
-         crosshairY: ['strokeWidth', 'stroke']
 
-     },
 
-     // Simple shapes:
 
-     circle: ['shapes'],
 
-     verticalLine: [],
 
-     label: ['labelOptions'],
 
-     // Measure
 
-     measure: ['background', 'crosshairY', 'crosshairX'],
 
-     // Others:
 
-     fibonacci: [],
 
-     tunnel: ['background', 'line', 'height'],
 
-     pitchfork: ['innerBackground', 'outerBackground'],
 
-     rect: ['shapes'],
 
-     // Crooked lines, elliots, arrows etc:
 
-     crookedLine: []
 
- };
 
- // Define non editable fields per annotation, for example Rectangle inherits
 
- // options from Measure, but crosshairs are not available
 
- H.NavigationBindings.annotationsNonEditable = {
 
-     rectangle: ['crosshairX', 'crosshairY', 'label']
 
- };
 
- extend(H.NavigationBindings.prototype, {
 
-     // Private properties added by bindings:
 
-     // Active (selected) annotation that is editted through popup/forms
 
-     // activeAnnotation: Annotation
 
-     // Holder for current step, used on mouse move to update bound object
 
-     // mouseMoveEvent: function () {}
 
-     // Next event in `step` array to be called on chart's click
 
-     // nextEvent: function () {}
 
-     // Index in the `step` array of the current event
 
-     // stepIndex: 0
 
-     // Flag to determine if current binding has steps
 
-     // steps: true|false
 
-     // Bindings holder for all events
 
-     // selectedButton: {}
 
-     // Holder for user options, returned from `start` event, and passed on to
 
-     // `step`'s' and `end`.
 
-     // currentUserDetails: {}
 
-     /**
 
-      * Initi all events conencted to NavigationBindings.
 
-      *
 
-      * @private
 
-      * @function Highcharts.NavigationBindings#initEvents
 
-      */
 
-     initEvents: function () {
 
-         var navigation = this,
 
-             chart = navigation.chart,
 
-             bindingsContainer = navigation.container,
 
-             options = navigation.options;
 
-         // Shorthand object for getting events for buttons:
 
-         navigation.boundClassNames = {};
 
-         objectEach(options.bindings, function (value) {
 
-             navigation.boundClassNames[value.className] = value;
 
-         });
 
-         // Handle multiple containers with the same class names:
 
-         [].forEach.call(bindingsContainer, function (subContainer) {
 
-             navigation.eventsToUnbind.push(
 
-                 addEvent(
 
-                     subContainer,
 
-                     'click',
 
-                     function (event) {
 
-                         var bindings = navigation.getButtonEvents(
 
-                             bindingsContainer,
 
-                             event
 
-                         );
 
-                         if (bindings) {
 
-                             navigation.bindingsButtonClick(
 
-                                 bindings.button,
 
-                                 bindings.events,
 
-                                 event
 
-                             );
 
-                         }
 
-                     }
 
-                 )
 
-             );
 
-         });
 
-         objectEach(options.events || {}, function (callback, eventName) {
 
-             navigation.eventsToUnbind.push(
 
-                 addEvent(
 
-                     navigation,
 
-                     eventName,
 
-                     callback
 
-                 )
 
-             );
 
-         });
 
-         navigation.eventsToUnbind.push(
 
-             addEvent(chart.container, 'click', function (e) {
 
-                 if (
 
-                     !chart.cancelClick &&
 
-                     chart.isInsidePlot(
 
-                         e.chartX - chart.plotLeft,
 
-                         e.chartY - chart.plotTop
 
-                     )
 
-                 ) {
 
-                     navigation.bindingsChartClick(this, e);
 
-                 }
 
-             })
 
-         );
 
-         navigation.eventsToUnbind.push(
 
-             addEvent(chart.container, 'mousemove', function (e) {
 
-                 navigation.bindingsContainerMouseMove(this, e);
 
-             })
 
-         );
 
-     },
 
-     /**
 
-      * Common chart.update() delegation, shared between bindings and exporting.
 
-      *
 
-      * @private
 
-      * @function Highcharts.NavigationBindings#initUpdate
 
-      */
 
-     initUpdate: function () {
 
-         var navigation = this;
 
-         chartNavigationMixin.addUpdate(
 
-             function (options) {
 
-                 navigation.update(options);
 
-             },
 
-             this.chart
 
-         );
 
-     },
 
-     /**
 
-      * Hook for click on a button, method selcts/unselects buttons,
 
-      * then calls `bindings.init` callback.
 
-      *
 
-      * @private
 
-      * @function Highcharts.NavigationBindings#bindingsButtonClick
 
-      *
 
-      * @param {Highcharts.HTMLDOMElement} [button]
 
-      *        Clicked button
 
-      *
 
-      * @param {object} [events]
 
-      *        Events passed down from bindings (`init`, `start`, `step`, `end`)
 
-      *
 
-      * @param {global.Event} [clickEvent]
 
-      *        Browser's click event
 
-      */
 
-     bindingsButtonClick: function (button, events, clickEvent) {
 
-         var navigation = this,
 
-             chart = navigation.chart;
 
-         if (navigation.selectedButtonElement) {
 
-             fireEvent(
 
-                 navigation,
 
-                 'deselectButton',
 
-                 { button: navigation.selectedButtonElement }
 
-             );
 
-             if (navigation.nextEvent) {
 
-                 // Remove in-progress annotations adders:
 
-                 if (
 
-                     navigation.currentUserDetails &&
 
-                     navigation.currentUserDetails.coll === 'annotations'
 
-                 ) {
 
-                     chart.removeAnnotation(navigation.currentUserDetails);
 
-                 }
 
-                 navigation.mouseMoveEvent = navigation.nextEvent = false;
 
-             }
 
-         }
 
-         navigation.selectedButton = events;
 
-         navigation.selectedButtonElement = button;
 
-         fireEvent(navigation, 'selectButton', { button: button });
 
-         // Call "init" event, for example to open modal window
 
-         if (events.init) {
 
-             events.init.call(navigation, button, clickEvent);
 
-         }
 
-         if (events.start || events.steps) {
 
-             chart.renderer.boxWrapper.addClass(PREFIX + 'draw-mode');
 
-         }
 
-     },
 
-     /**
 
-      * Hook for click on a chart, first click on a chart calls `start` event,
 
-      * then on all subsequent clicks iterate over `steps` array.
 
-      * When finished, calls `end` event.
 
-      *
 
-      * @private
 
-      * @function Highcharts.NavigationBindings#bindingsChartClick
 
-      *
 
-      * @param {Highcharts.Chart} chart
 
-      *        Chart that click was performed on.
 
-      *
 
-      * @param {global.Event} clickEvent
 
-      *        Browser's click event.
 
-      */
 
-     bindingsChartClick: function (chartContainer, clickEvent) {
 
-         var navigation = this,
 
-             chart = navigation.chart,
 
-             selectedButton = navigation.selectedButton,
 
-             svgContainer = chart.renderer.boxWrapper;
 
-         if (
 
-             navigation.activeAnnotation &&
 
-             !clickEvent.activeAnnotation &&
 
-             // Element could be removed in the child action, e.g. button
 
-             clickEvent.target.parentNode &&
 
-             // TO DO: Polyfill for IE11?
 
-             !clickEvent.target.closest('.' + PREFIX + 'popup')
 
-         ) {
 
-             fireEvent(navigation, 'closePopup');
 
-             navigation.deselectAnnotation();
 
-         }
 
-         if (!selectedButton || !selectedButton.start) {
 
-             return;
 
-         }
 
-         if (!navigation.nextEvent) {
 
-             // Call init method:
 
-             navigation.currentUserDetails = selectedButton.start.call(
 
-                 navigation,
 
-                 clickEvent
 
-             );
 
-             // If steps exists (e.g. Annotations), bind them:
 
-             if (selectedButton.steps) {
 
-                 navigation.stepIndex = 0;
 
-                 navigation.steps = true;
 
-                 navigation.mouseMoveEvent = navigation.nextEvent =
 
-                     selectedButton.steps[navigation.stepIndex];
 
-             } else {
 
-                 fireEvent(
 
-                     navigation,
 
-                     'deselectButton',
 
-                     { button: navigation.selectedButtonElement }
 
-                 );
 
-                 svgContainer.removeClass(PREFIX + 'draw-mode');
 
-                 navigation.steps = false;
 
-                 navigation.selectedButton = null;
 
-                 // First click is also the last one:
 
-                 if (selectedButton.end) {
 
-                     selectedButton.end.call(
 
-                         navigation,
 
-                         clickEvent,
 
-                         navigation.currentUserDetails
 
-                     );
 
-                 }
 
-             }
 
-         } else {
 
-             navigation.nextEvent(
 
-                 clickEvent,
 
-                 navigation.currentUserDetails
 
-             );
 
-             if (navigation.steps) {
 
-                 navigation.stepIndex++;
 
-                 if (selectedButton.steps[navigation.stepIndex]) {
 
-                     // If we have more steps, bind them one by one:
 
-                     navigation.mouseMoveEvent = navigation.nextEvent =
 
-                         selectedButton.steps[navigation.stepIndex];
 
-                 } else {
 
-                     fireEvent(
 
-                         navigation,
 
-                         'deselectButton',
 
-                         { button: navigation.selectedButtonElement }
 
-                     );
 
-                     svgContainer.removeClass(PREFIX + 'draw-mode');
 
-                     // That was the last step, call end():
 
-                     if (selectedButton.end) {
 
-                         selectedButton.end.call(
 
-                             navigation,
 
-                             clickEvent,
 
-                             navigation.currentUserDetails
 
-                         );
 
-                     }
 
-                     navigation.nextEvent = false;
 
-                     navigation.mouseMoveEvent = false;
 
-                     navigation.selectedButton = null;
 
-                 }
 
-             }
 
-         }
 
-     },
 
-     /**
 
-      * Hook for mouse move on a chart's container. It calls current step.
 
-      *
 
-      * @private
 
-      * @function Highcharts.NavigationBindings#bindingsContainerMouseMove
 
-      *
 
-      * @param {Highcharts.HTMLDOMElement} container
 
-      *        Chart's container.
 
-      *
 
-      * @param {global.Event} moveEvent
 
-      *        Browser's move event.
 
-      */
 
-     bindingsContainerMouseMove: function (container, moveEvent) {
 
-         if (this.mouseMoveEvent) {
 
-             this.mouseMoveEvent(
 
-                 moveEvent,
 
-                 this.currentUserDetails
 
-             );
 
-         }
 
-     },
 
-     /**
 
-      * Translate fields (e.g. `params.period` or `marker.styles.color`) to
 
-      * Highcharts options object (e.g. `{ params: { period } }`).
 
-      *
 
-      * @private
 
-      * @function Highcharts.NavigationBindings#fieldsToOptions
 
-      *
 
-      * @param {object} fields
 
-      *        Fields from popup form.
 
-      *
 
-      * @param {object} config
 
-      *        Default config to be modified.
 
-      *
 
-      * @return {object}
 
-      *         Modified config
 
-      */
 
-     fieldsToOptions: function (fields, config) {
 
-         objectEach(fields, function (value, field) {
 
-             var parsedValue = parseFloat(value),
 
-                 path = field.split('.'),
 
-                 parent = config,
 
-                 pathLength = path.length - 1;
 
-             // If it's a number (not "forma" options), parse it:
 
-             if (
 
-                 isNumber(parsedValue) &&
 
-                 !value.match(/px/g) &&
 
-                 !field.match(/format/g)
 
-             ) {
 
-                 value = parsedValue;
 
-             }
 
-             // Remove empty strings or values like 0
 
-             if (value !== '' && value !== 'undefined') {
 
-                 path.forEach(function (name, index) {
 
-                     var nextName = pick(path[index + 1], '');
 
-                     if (pathLength === index) {
 
-                         // Last index, put value:
 
-                         parent[name] = value;
 
-                     } else if (!parent[name]) {
 
-                         // Create middle property:
 
-                         parent[name] = nextName.match(/\d/g) ? [] : {};
 
-                         parent = parent[name];
 
-                     } else {
 
-                         // Jump into next property
 
-                         parent = parent[name];
 
-                     }
 
-                 });
 
-             }
 
-         });
 
-         return config;
 
-     },
 
-     /**
 
-      * Shorthand method to deselect an annotation.
 
-      *
 
-      * @function Highcharts.NavigationBindings#deselectAnnotation
 
-      */
 
-     deselectAnnotation: function () {
 
-         if (this.activeAnnotation) {
 
-             this.activeAnnotation.setControlPointsVisibility(false);
 
-             this.activeAnnotation = false;
 
-         }
 
-     },
 
-     /**
 
-      * Generates API config for popup in the same format as options for
 
-      * Annotation object.
 
-      *
 
-      * @function Highcharts.NavigationBindings#annotationToFields
 
-      *
 
-      * @param {Highcharts.Annotation} annotation
 
-      *        Annotations object
 
-      *
 
-      * @return {object}
 
-      *         Annotation options to be displayed in popup box
 
-      */
 
-     annotationToFields: function (annotation) {
 
-         var options = annotation.options,
 
-             editables = H.NavigationBindings.annotationsEditable,
 
-             nestedEditables = editables.nestedOptions,
 
-             getFieldType = this.utils.getFieldType,
 
-             type = pick(
 
-                 options.type,
 
-                 options.shapes && options.shapes[0] &&
 
-                     options.shapes[0].type,
 
-                 options.labels && options.labels[0] &&
 
-                     options.labels[0].itemType,
 
-                 'label'
 
-             ),
 
-             nonEditables = H.NavigationBindings
 
-                 .annotationsNonEditable[options.langKey] || [],
 
-             visualOptions = {
 
-                 langKey: options.langKey,
 
-                 type: type
 
-             };
 
-         /**
 
-          * Nested options traversing. Method goes down to the options and copies
 
-          * allowed options (with values) to new object, which is last parameter:
 
-          * "parent".
 
-          *
 
-          * @private
 
-          * @function Highcharts.NavigationBindings#annotationToFields.traverse
 
-          *
 
-          * @param {*} option
 
-          *        Atomic type or object/array
 
-          *
 
-          * @param {string} key
 
-          *        Option name, for example "visible" or "x", "y"
 
-          *
 
-          * @param {object} allowed
 
-          *        Editables from H.NavigationBindings.annotationsEditable
 
-          *
 
-          * @param {object} parent
 
-          *        Where new options will be assigned
 
-          */
 
-         function traverse(option, key, parentEditables, parent) {
 
-             var nextParent;
 
-             if (
 
-                 parentEditables &&
 
-                 nonEditables.indexOf(key) === -1 &&
 
-                 (
 
-                     (
 
-                         parentEditables.indexOf &&
 
-                         parentEditables.indexOf(key)
 
-                     ) >= 0 ||
 
-                     parentEditables[key] || // nested array
 
-                     parentEditables === true // simple array
 
-                 )
 
-             ) {
 
-                 // Roots:
 
-                 if (isArray(option)) {
 
-                     parent[key] = [];
 
-                     option.forEach(function (arrayOption, i) {
 
-                         if (!isObject(arrayOption)) {
 
-                             // Simple arrays, e.g. [String, Number, Boolean]
 
-                             traverse(
 
-                                 arrayOption,
 
-                                 0,
 
-                                 nestedEditables[key],
 
-                                 parent[key]
 
-                             );
 
-                         } else {
 
-                             // Advanced arrays, e.g. [Object, Object]
 
-                             parent[key][i] = {};
 
-                             objectEach(
 
-                                 arrayOption,
 
-                                 function (nestedOption, nestedKey) {
 
-                                     traverse(
 
-                                         nestedOption,
 
-                                         nestedKey,
 
-                                         nestedEditables[key],
 
-                                         parent[key][i]
 
-                                     );
 
-                                 }
 
-                             );
 
-                         }
 
-                     });
 
-                 } else if (isObject(option)) {
 
-                     nextParent = {};
 
-                     if (isArray(parent)) {
 
-                         parent.push(nextParent);
 
-                         nextParent[key] = {};
 
-                         nextParent = nextParent[key];
 
-                     } else {
 
-                         parent[key] = nextParent;
 
-                     }
 
-                     objectEach(option, function (nestedOption, nestedKey) {
 
-                         traverse(
 
-                             nestedOption,
 
-                             nestedKey,
 
-                             key === 0 ? parentEditables : nestedEditables[key],
 
-                             nextParent
 
-                         );
 
-                     });
 
-                 } else {
 
-                     // Leaf:
 
-                     if (key === 'format') {
 
-                         parent[key] = [
 
-                             H.format(
 
-                                 option,
 
-                                 annotation.labels[0].points[0]
 
-                             ).toString(),
 
-                             'text'
 
-                         ];
 
-                     } else if (isArray(parent)) {
 
-                         parent.push([option, getFieldType(option)]);
 
-                     } else {
 
-                         parent[key] = [option, getFieldType(option)];
 
-                     }
 
-                 }
 
-             }
 
-         }
 
-         objectEach(options, function (option, key) {
 
-             if (key === 'typeOptions') {
 
-                 visualOptions[key] = {};
 
-                 objectEach(options[key], function (typeOption, typeKey) {
 
-                     traverse(
 
-                         typeOption,
 
-                         typeKey,
 
-                         nestedEditables,
 
-                         visualOptions[key],
 
-                         true
 
-                     );
 
-                 });
 
-             } else {
 
-                 traverse(option, key, editables[type], visualOptions);
 
-             }
 
-         });
 
-         return visualOptions;
 
-     },
 
-     /**
 
-      * Get all class names for all parents in the element. Iterates until finds
 
-      * main container.
 
-      *
 
-      * @function Highcharts.NavigationBindings#getClickedClassNames
 
-      *
 
-      * @param {Highcharts.HTMLDOMElement}
 
-      *        Container that event is bound to.
 
-      *
 
-      * @param {global.Event} event
 
-      *        Browser's event.
 
-      *
 
-      * @return {Array<string>}
 
-      *         Array of class names with corresponding elements
 
-      */
 
-     getClickedClassNames: function (container, event) {
 
-         var element = event.target,
 
-             classNames = [],
 
-             elemClassName;
 
-         while (element) {
 
-             elemClassName = H.attr(element, 'class');
 
-             if (elemClassName) {
 
-                 classNames = classNames.concat(
 
-                     elemClassName.split(' ').map(
 
-                         function (name) { // eslint-disable-line no-loop-func
 
-                             return [
 
-                                 name,
 
-                                 element
 
-                             ];
 
-                         }
 
-                     )
 
-                 );
 
-             }
 
-             element = element.parentNode;
 
-             if (element === container) {
 
-                 return classNames;
 
-             }
 
-         }
 
-         return classNames;
 
-     },
 
-     /**
 
-      * Get events bound to a button. It's a custom event delegation to find all
 
-      * events connected to the element.
 
-      *
 
-      * @function Highcharts.NavigationBindings#getButtonEvents
 
-      *
 
-      * @param {Highcharts.HTMLDOMElement}
 
-      *        Container that event is bound to.
 
-      *
 
-      * @param {global.Event} event
 
-      *        Browser's event.
 
-      *
 
-      * @return {object}
 
-      *         Oject with events (init, start, steps, and end)
 
-      */
 
-     getButtonEvents: function (container, event) {
 
-         var navigation = this,
 
-             classNames = this.getClickedClassNames(container, event),
 
-             bindings;
 
-         classNames.forEach(function (className) {
 
-             if (navigation.boundClassNames[className[0]] && !bindings) {
 
-                 bindings = {
 
-                     events: navigation.boundClassNames[className[0]],
 
-                     button: className[1]
 
-                 };
 
-             }
 
-         });
 
-         return bindings;
 
-     },
 
-     /**
 
-      * Bindings are just events, so the whole update process is simply
 
-      * removing old events and adding new ones.
 
-      *
 
-      * @private
 
-      * @function Highcharts.NavigationBindings#update
 
-      */
 
-     update: function (options) {
 
-         this.options = merge(true, this.options, options);
 
-         this.removeEvents();
 
-         this.initEvents();
 
-     },
 
-     /**
 
-      * Remove all events created in the navigation.
 
-      *
 
-      * @private
 
-      * @function Highcharts.NavigationBindings#removeEvents
 
-      */
 
-     removeEvents: function () {
 
-         this.eventsToUnbind.forEach(function (unbinder) {
 
-             unbinder();
 
-         });
 
-     },
 
-     destroy: function () {
 
-         this.removeEvents();
 
-     },
 
-     /**
 
-      * General utils for bindings
 
-      *
 
-      * @private
 
-      * @name Highcharts.NavigationBindings#utils
 
-      * @type {bindingsUtils}
 
-      */
 
-     utils: bindingsUtils
 
- });
 
- H.Chart.prototype.initNavigationBindings = function () {
 
-     var chart = this,
 
-         options = chart.options;
 
-     if (options && options.navigation && options.navigation.bindings) {
 
-         chart.navigationBindings = new H.NavigationBindings(
 
-             chart,
 
-             options.navigation
 
-         );
 
-         chart.navigationBindings.initEvents();
 
-         chart.navigationBindings.initUpdate();
 
-     }
 
- };
 
- addEvent(H.Chart, 'load', function () {
 
-     this.initNavigationBindings();
 
- });
 
- addEvent(H.Chart, 'destroy', function () {
 
-     if (this.navigationBindings) {
 
-         this.navigationBindings.destroy();
 
-     }
 
- });
 
- addEvent(H.NavigationBindings, 'deselectButton', function () {
 
-     this.selectedButtonElement = null;
 
- });
 
- // Show edit-annotation form:
 
- function selectableAnnotation(annotationType) {
 
-     var originalClick = annotationType.prototype.defaultOptions.events &&
 
-             annotationType.prototype.defaultOptions.events.click;
 
-     function selectAndshowPopup(event) {
 
-         var annotation = this,
 
-             navigation = annotation.chart.navigationBindings,
 
-             prevAnnotation = navigation.activeAnnotation;
 
-         if (originalClick) {
 
-             originalClick.click.call(annotation, event);
 
-         }
 
-         if (prevAnnotation !== annotation) {
 
-             // Select current:
 
-             navigation.deselectAnnotation();
 
-             navigation.activeAnnotation = annotation;
 
-             annotation.setControlPointsVisibility(true);
 
-             fireEvent(
 
-                 navigation,
 
-                 'showPopup',
 
-                 {
 
-                     annotation: annotation,
 
-                     formType: 'annotation-toolbar',
 
-                     options: navigation.annotationToFields(annotation),
 
-                     onSubmit: function (data) {
 
-                         var config = {},
 
-                             typeOptions;
 
-                         if (data.actionType === 'remove') {
 
-                             navigation.activeAnnotation = false;
 
-                             navigation.chart.removeAnnotation(annotation);
 
-                         } else {
 
-                             navigation.fieldsToOptions(data.fields, config);
 
-                             navigation.deselectAnnotation();
 
-                             typeOptions = config.typeOptions;
 
-                             if (annotation.options.type === 'measure') {
 
-                                 // Manually disable crooshars according to
 
-                                 // stroke width of the shape:
 
-                                 typeOptions.crosshairY.enabled =
 
-                                     typeOptions.crosshairY.strokeWidth !== 0;
 
-                                 typeOptions.crosshairX.enabled =
 
-                                     typeOptions.crosshairX.strokeWidth !== 0;
 
-                             }
 
-                             annotation.update(config);
 
-                         }
 
-                     }
 
-                 }
 
-             );
 
-         } else {
 
-             // Deselect current:
 
-             navigation.deselectAnnotation();
 
-             fireEvent(navigation, 'closePopup');
 
-         }
 
-         // Let bubble event to chart.click:
 
-         event.activeAnnotation = true;
 
-     }
 
-     H.merge(
 
-         true,
 
-         annotationType.prototype.defaultOptions.events,
 
-         {
 
-             click: selectAndshowPopup
 
-         }
 
-     );
 
- }
 
- if (H.Annotation) {
 
-     // Basic shapes:
 
-     selectableAnnotation(H.Annotation);
 
-     // Advanced annotations:
 
-     H.objectEach(H.Annotation.types, function (annotationType) {
 
-         selectableAnnotation(annotationType);
 
-     });
 
- }
 
- H.setOptions({
 
-     /**
 
-      * @optionparent lang
 
-      */
 
-     lang: {
 
-         /**
 
-          * Configure the Popup strings in the chart. Requires the
 
-          * `annotations.js` or `annotations-advanced.src.js` module to be
 
-          * loaded.
 
-          *
 
-          * @since           7.0.0
 
-          * @type            {Object}
 
-          * @product         highcharts highstock
 
-          */
 
-         navigation: {
 
-             /**
 
-              * Translations for all field names used in popup.
 
-              *
 
-              * @product         highcharts highstock
 
-              * @type            {Object}
 
-              */
 
-             popup: {
 
-                 simpleShapes: 'Simple shapes',
 
-                 lines: 'Lines',
 
-                 circle: 'Circle',
 
-                 rectangle: 'Rectangle',
 
-                 label: 'Label',
 
-                 shapeOptions: 'Shape options',
 
-                 typeOptions: 'Details',
 
-                 fill: 'Fill',
 
-                 format: 'Text',
 
-                 strokeWidth: 'Line width',
 
-                 stroke: 'Line color',
 
-                 title: 'Title',
 
-                 name: 'Name',
 
-                 labelOptions: 'Label options',
 
-                 labels: 'Labels',
 
-                 backgroundColor: 'Background color',
 
-                 backgroundColors: 'Background colors',
 
-                 borderColor: 'Border color',
 
-                 borderRadius: 'Border radius',
 
-                 borderWidth: 'Border width',
 
-                 style: 'Style',
 
-                 padding: 'Padding',
 
-                 fontSize: 'Font size',
 
-                 color: 'Color',
 
-                 height: 'Height',
 
-                 shapes: 'Shape options'
 
-             }
 
-         }
 
-     },
 
-     /**
 
-      * @optionparent navigation
 
-      * @product      highcharts highstock
 
-      */
 
-     navigation: {
 
-         /**
 
-          * A CSS class name where all bindings will be attached to. Multiple
 
-          * charts on the same page should have separate class names to prevent
 
-          * duplicating events.
 
-          *
 
-          * @since     7.0.0
 
-          * @type      {string}
 
-          */
 
-         bindingsClassName: 'highcharts-bindings-wrapper',
 
-         /**
 
-          * Bindings definitions for custom HTML buttons. Each binding implements
 
-          * simple event-driven interface:
 
-          *
 
-          * - `className`: classname used to bind event to
 
-          *
 
-          * - `init`: initial event, fired on button click
 
-          *
 
-          * - `start`: fired on first click on a chart
 
-          *
 
-          * - `steps`: array of sequential events fired one after another on each
 
-          *   of users clicks
 
-          *
 
-          * - `end`: last event to be called after last step event
 
-          *
 
-          * @type         {Highcharts.Dictionary<Highcharts.StockToolsBindingsObject>|*}
 
-          * @sample       stock/stocktools/stocktools-thresholds
 
-          *               Custom bindings in Highstock
 
-          * @since        7.0.0
 
-          * @product      highcharts highstock
 
-          */
 
-         bindings: {
 
-             /**
 
-              * A circle annotation bindings. Includes `start` and one event in
 
-              * `steps` array.
 
-              *
 
-              * @type    {Highcharts.StockToolsBindingsObject}
 
-              * @default {"className": "highcharts-circle-annotation", "start": function() {}, "steps": [function() {}]}
 
-              */
 
-             circleAnnotation: {
 
-                 /** @ignore */
 
-                 className: 'highcharts-circle-annotation',
 
-                 /** @ignore */
 
-                 start: function (e) {
 
-                     var x = this.chart.xAxis[0].toValue(e.chartX),
 
-                         y = this.chart.yAxis[0].toValue(e.chartY),
 
-                         annotation;
 
-                     annotation = this.chart.addAnnotation({
 
-                         langKey: 'circle',
 
-                         shapes: [{
 
-                             type: 'circle',
 
-                             point: {
 
-                                 xAxis: 0,
 
-                                 yAxis: 0,
 
-                                 x: x,
 
-                                 y: y
 
-                             },
 
-                             r: 5,
 
-                             controlPoints: [{
 
-                                 positioner: function (target) {
 
-                                     var xy = H.Annotation.MockPoint
 
-                                             .pointToPixels(
 
-                                                 target.points[0]
 
-                                             ),
 
-                                         r = target.options.r;
 
-                                     return {
 
-                                         x: xy.x + r * Math.cos(Math.PI / 4) -
 
-                                             this.graphic.width / 2,
 
-                                         y: xy.y + r * Math.sin(Math.PI / 4) -
 
-                                             this.graphic.height / 2
 
-                                     };
 
-                                 },
 
-                                 events: {
 
-                                     // TRANSFORM RADIUS ACCORDING TO Y
 
-                                     // TRANSLATION
 
-                                     drag: function (e, target) {
 
-                                         var annotation = target.annotation,
 
-                                             position = this
 
-                                                 .mouseMoveToTranslation(e);
 
-                                         target.setRadius(
 
-                                             Math.max(
 
-                                                 target.options.r +
 
-                                                     position.y /
 
-                                                     Math.sin(Math.PI / 4),
 
-                                                 5
 
-                                             )
 
-                                         );
 
-                                         annotation.options.shapes[0] =
 
-                                             annotation.userOptions.shapes[0] =
 
-                                             target.options;
 
-                                         target.redraw(false);
 
-                                     }
 
-                                 }
 
-                             }]
 
-                         }]
 
-                     });
 
-                     return annotation;
 
-                 },
 
-                 /** @ignore */
 
-                 steps: [
 
-                     function (e, annotation) {
 
-                         var point = annotation.options.shapes[0].point,
 
-                             x = this.chart.xAxis[0].toPixels(point.x),
 
-                             y = this.chart.yAxis[0].toPixels(point.y),
 
-                             distance = Math.max(
 
-                                 Math.sqrt(
 
-                                     Math.pow(x - e.chartX, 2) +
 
-                                     Math.pow(y - e.chartY, 2)
 
-                                 ),
 
-                                 5
 
-                             );
 
-                         annotation.update({
 
-                             shapes: [{
 
-                                 r: distance
 
-                             }]
 
-                         });
 
-                     }
 
-                 ]
 
-             },
 
-             /**
 
-              * A rectangle annotation bindings. Includes `start` and one event
 
-              * in `steps` array.
 
-              *
 
-              * @type    {Highcharts.StockToolsBindingsObject}
 
-              * @default {"className": "highcharts-rectangle-annotation", "start": function() {}, "steps": [function() {}]}
 
-              */
 
-             rectangleAnnotation: {
 
-                 /** @ignore */
 
-                 className: 'highcharts-rectangle-annotation',
 
-                 /** @ignore */
 
-                 start: function (e) {
 
-                     var x = this.chart.xAxis[0].toValue(e.chartX),
 
-                         y = this.chart.yAxis[0].toValue(e.chartY),
 
-                         options = {
 
-                             langKey: 'rectangle',
 
-                             shapes: [{
 
-                                 type: 'rect',
 
-                                 point: {
 
-                                     x: x,
 
-                                     y: y,
 
-                                     xAxis: 0,
 
-                                     yAxis: 0
 
-                                 },
 
-                                 width: 5,
 
-                                 height: 5,
 
-                                 controlPoints: [{
 
-                                     positioner: function (target) {
 
-                                         var xy = H.Annotation.MockPoint
 
-                                             .pointToPixels(
 
-                                                 target.points[0]
 
-                                             );
 
-                                         return {
 
-                                             x: xy.x + target.options.width - 4,
 
-                                             y: xy.y + target.options.height - 4
 
-                                         };
 
-                                     },
 
-                                     events: {
 
-                                         drag: function (e, target) {
 
-                                             var annotation = target.annotation,
 
-                                                 xy = this
 
-                                                     .mouseMoveToTranslation(e);
 
-                                             target.options.width = Math.max(
 
-                                                 target.options.width + xy.x,
 
-                                                 5
 
-                                             );
 
-                                             target.options.height = Math.max(
 
-                                                 target.options.height + xy.y,
 
-                                                 5
 
-                                             );
 
-                                             annotation.options.shapes[0] =
 
-                                                 target.options;
 
-                                             annotation.userOptions.shapes[0] =
 
-                                                 target.options;
 
-                                             target.redraw(false);
 
-                                         }
 
-                                     }
 
-                                 }]
 
-                             }]
 
-                         };
 
-                     return this.chart.addAnnotation(options);
 
-                 },
 
-                 /** @ignore */
 
-                 steps: [
 
-                     function (e, annotation) {
 
-                         var xAxis = this.chart.xAxis[0],
 
-                             yAxis = this.chart.yAxis[0],
 
-                             point = annotation.options.shapes[0].point,
 
-                             x = xAxis.toPixels(point.x),
 
-                             y = yAxis.toPixels(point.y),
 
-                             width = Math.max(e.chartX - x, 5),
 
-                             height = Math.max(e.chartY - y, 5);
 
-                         annotation.update({
 
-                             shapes: [{
 
-                                 width: width,
 
-                                 height: height,
 
-                                 point: {
 
-                                     x: point.x,
 
-                                     y: point.y
 
-                                 }
 
-                             }]
 
-                         });
 
-                     }
 
-                 ]
 
-             },
 
-             /**
 
-              * A label annotation bindings. Includes `start` event only.
 
-              *
 
-              * @type    {Highcharts.StockToolsBindingsObject}
 
-              * @default {"className": "highcharts-label-annotation", "start": function() {}, "steps": [function() {}]}
 
-              */
 
-             labelAnnotation: {
 
-                 /** @ignore */
 
-                 className: 'highcharts-label-annotation',
 
-                 /** @ignore */
 
-                 start: function (e) {
 
-                     var x = this.chart.xAxis[0].toValue(e.chartX),
 
-                         y = this.chart.yAxis[0].toValue(e.chartY);
 
-                     this.chart.addAnnotation({
 
-                         langKey: 'label',
 
-                         labelOptions: {
 
-                             format: '{y:.2f}'
 
-                         },
 
-                         labels: [{
 
-                             point: {
 
-                                 x: x,
 
-                                 y: y,
 
-                                 xAxis: 0,
 
-                                 yAxis: 0
 
-                             },
 
-                             controlPoints: [{
 
-                                 symbol: 'triangle-down',
 
-                                 positioner: function (target) {
 
-                                     if (!target.graphic.placed) {
 
-                                         return {
 
-                                             x: 0,
 
-                                             y: -9e7
 
-                                         };
 
-                                     }
 
-                                     var xy = H.Annotation.MockPoint
 
-                                         .pointToPixels(
 
-                                             target.points[0]
 
-                                         );
 
-                                     return {
 
-                                         x: xy.x - this.graphic.width / 2,
 
-                                         y: xy.y - this.graphic.height / 2
 
-                                     };
 
-                                 },
 
-                                 // TRANSLATE POINT/ANCHOR
 
-                                 events: {
 
-                                     drag: function (e, target) {
 
-                                         var xy = this.mouseMoveToTranslation(e);
 
-                                         target.translatePoint(xy.x, xy.y);
 
-                                         target.annotation.labels[0].options =
 
-                                             target.options;
 
-                                         target.redraw(false);
 
-                                     }
 
-                                 }
 
-                             }, {
 
-                                 symbol: 'square',
 
-                                 positioner: function (target) {
 
-                                     if (!target.graphic.placed) {
 
-                                         return {
 
-                                             x: 0,
 
-                                             y: -9e7
 
-                                         };
 
-                                     }
 
-                                     return {
 
-                                         x: target.graphic.alignAttr.x -
 
-                                             this.graphic.width / 2,
 
-                                         y: target.graphic.alignAttr.y -
 
-                                             this.graphic.height / 2
 
-                                     };
 
-                                 },
 
-                                 // TRANSLATE POSITION WITHOUT CHANGING THE
 
-                                 // ANCHOR
 
-                                 events: {
 
-                                     drag: function (e, target) {
 
-                                         var xy = this.mouseMoveToTranslation(e);
 
-                                         target.translate(xy.x, xy.y);
 
-                                         target.annotation.labels[0].options =
 
-                                             target.options;
 
-                                         target.redraw(false);
 
-                                     }
 
-                                 }
 
-                             }],
 
-                             overflow: 'none',
 
-                             crop: true
 
-                         }]
 
-                     });
 
-                 }
 
-             }
 
-         },
 
-         /**
 
-          * A `showPopup` event. Fired when selecting for example an annotation.
 
-          *
 
-          * @type      {Function}
 
-          * @apioption navigation.events.showPopup
 
-          */
 
-         /**
 
-          * A `hidePopop` event. Fired when Popup should be hidden, for exampole
 
-          * when clicking on an annotation again.
 
-          *
 
-          * @type      {Function}
 
-          * @apioption navigation.events.hidePopup
 
-          */
 
-         /**
 
-          * Event fired on a button click.
 
-          *
 
-          * @type      {Function}
 
-          * @sample    highcharts/annotations/gui/
 
-          *            Change icon in a dropddown on event
 
-          * @sample    highcharts/annotations/gui-buttons/
 
-          *            Change button class on event
 
-          * @apioption navigation.events.selectButton
 
-          */
 
-         /**
 
-          * Event fired when button state should change, for example after
 
-          * adding an annotation.
 
-          *
 
-          * @type      {Function}
 
-          * @sample    highcharts/annotations/gui/
 
-          *            Change icon in a dropddown on event
 
-          * @sample    highcharts/annotations/gui-buttons/
 
-          *            Change button class on event
 
-          * @apioption navigation.events.deselectButton
 
-          */
 
-         /**
 
-          * Events to communicate between Stock Tools and custom GUI.
 
-          *
 
-          * @since        7.0.0
 
-          * @product      highcharts highstock
 
-          * @optionparent navigation.events
 
-          */
 
-         events: {}
 
-     }
 
- });
 
 
  |