Utilities.js 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754
  1. /* *
  2. *
  3. * (c) 2010-2019 Torstein Honsi
  4. *
  5. * License: www.highcharts.com/license
  6. *
  7. * */
  8. /**
  9. * Reference to the global SVGElement class as a workaround for a name conflict
  10. * in the Highcharts namespace.
  11. *
  12. * @see https://developer.mozilla.org/en-US/docs/Web/API/SVGElement
  13. *
  14. * @global
  15. * @typedef {global.SVGElement} GlobalSVGElement
  16. */
  17. /**
  18. * An animation configuration. Animation configurations can also be defined as
  19. * booleans, where `false` turns off animation and `true` defaults to a duration
  20. * of 500ms.
  21. *
  22. * @interface Highcharts.AnimationOptionsObject
  23. *//**
  24. * A callback function to exectute when the animation finishes.
  25. * @name Highcharts.AnimationOptionsObject#complete
  26. * @type {Function|undefined}
  27. *//**
  28. * The animation duration in milliseconds.
  29. * @name Highcharts.AnimationOptionsObject#duration
  30. * @type {number}
  31. *//**
  32. * The name of an easing function as defined on the `Math` object.
  33. * @name Highcharts.AnimationOptionsObject#easing
  34. * @type {string|undefined}
  35. *//**
  36. * A callback function to execute on each step of each attribute or CSS property
  37. * that's being animated. The first argument contains information about the
  38. * animation and progress.
  39. * @name Highcharts.AnimationOptionsObject#step
  40. * @type {Function|undefined}
  41. */
  42. /**
  43. * A style object with camel case property names to define visual appearance of
  44. * a SVG element or HTML element. The properties can be whatever styles are
  45. * supported on the given SVG or HTML element.
  46. *
  47. * @example
  48. * {
  49. * fontFamily: 'monospace',
  50. * fontSize: '1.2em'
  51. * }
  52. *
  53. * @interface Highcharts.CSSObject
  54. *//**
  55. * @name Highcharts.CSSObject#[key:string]
  56. * @type {boolean|number|string|undefined}
  57. *//**
  58. * Background style for the element.
  59. * @name Highcharts.CSSObject#background
  60. * @type {string|undefined}
  61. *//**
  62. * Background color of the element.
  63. * @name Highcharts.CSSObject#backgroundColor
  64. * @type {Highcharts.ColorString|undefined}
  65. *//**
  66. * Border style for the element.
  67. * @name Highcharts.CSSObject#border
  68. * @type {string|undefined}
  69. *//**
  70. * Radius of the element border.
  71. * @name Highcharts.CSSObject#borderRadius
  72. * @type {number|undefined}
  73. *//**
  74. * Color used in the element. The "contrast" option is a Highcharts custom
  75. * property that results in black or white, depending on the background of the
  76. * element.
  77. * @name Highcharts.CSSObject#color
  78. * @type {"contrast"|Highcharts.ColorString|undefined}
  79. *//**
  80. * Style of the mouse cursor when resting over the element.
  81. * @name Highcharts.CSSObject#cursor
  82. * @type {Highcharts.CursorType|undefined}
  83. *//**
  84. * Font family of the element text. Multiple values have to be in decreasing
  85. * preference order and separated by comma.
  86. * @name Highcharts.CSSObject#fontFamily
  87. * @type {string|undefined}
  88. *//**
  89. * Font size of the element text.
  90. * @name Highcharts.CSSObject#fontSize
  91. * @type {string|undefined}
  92. *//**
  93. * Font weight of the element text.
  94. * @name Highcharts.CSSObject#fontWeight
  95. * @type {string|undefined}
  96. *//**
  97. * Height of the element.
  98. * @name Highcharts.CSSObject#height
  99. * @type {number|undefined}
  100. *//**
  101. * Width of the element border.
  102. * @name Highcharts.CSSObject#lineWidth
  103. * @type {number|undefined}
  104. *//**
  105. * Opacity of the element.
  106. * @name Highcharts.CSSObject#opacity
  107. * @type {number|undefined}
  108. *//**
  109. * Space around the element content.
  110. * @name Highcharts.CSSObject#padding
  111. * @type {string|undefined}
  112. *//**
  113. * Behaviour of the element when the mouse cursor rests over it.
  114. * @name Highcharts.CSSObject#pointerEvents
  115. * @type {string|undefined}
  116. *//**
  117. * Positioning of the element.
  118. * @name Highcharts.CSSObject#position
  119. * @type {string|undefined}
  120. *//**
  121. * Alignment of the element text.
  122. * @name Highcharts.CSSObject#textAlign
  123. * @type {string|undefined}
  124. *//**
  125. * Outline style of the element text.
  126. * @name Highcharts.CSSObject#textOutline
  127. * @type {string|undefined}
  128. *//**
  129. * Additional decoration of the element text.
  130. * @name Highcharts.CSSObject#textDecoration
  131. * @type {string|undefined}
  132. *//**
  133. * Line break style of the element text. Highcharts SVG elements support
  134. * `ellipsis` when a `width` is set.
  135. * @name Highcharts.CSSObject#textOverflow
  136. * @type {string|undefined}
  137. *//**
  138. * Top spacing of the element relative to the parent element.
  139. * @name Highcharts.CSSObject#top
  140. * @type {string|undefined}
  141. *//**
  142. * Animated transition of selected element properties.
  143. * @name Highcharts.CSSObject#transition
  144. * @type {string|undefined}
  145. *//**
  146. * Line break style of the element text.
  147. * @name Highcharts.CSSObject#whiteSpace
  148. * @type {string|undefined}
  149. *//**
  150. * Width of the element.
  151. * @name Highcharts.CSSObject#width
  152. * @type {number|undefined}
  153. */
  154. /**
  155. * All possible cursor styles.
  156. *
  157. * @typedef {"alias"|"all-scroll"|"auto"|"cell"|"col-resize"|"context-menu"|"copy"|"crosshair"|"default"|"e-resize"|"ew-resize"|"grab"|"grabbing"|"help"|"move"|"n-resize"|"ne-resize"|"nesw-resize"|"no-drop"|"none"|"not-allowed"|"ns-resize"|"nw-resize"|"nwse-resize"|"pointer"|"progress"|"row-resize"|"s-resize"|"se-resize"|"sw-resize"|"text"|"vertical-text"|"w-resize"|"wait"|"zoom-in"|"zoom-out"} Highcharts.CursorType
  158. */
  159. /**
  160. * All possible dash styles.
  161. *
  162. * @typedef {"Dash"|"DashDot"|"Dot"|"LongDash"|"LongDashDot"|"LongDashDotDot"|"ShortDash"|"ShortDashDot"|"ShortDashDotDot"|"ShortDot"|"Solid"} Highcharts.DashStyleType
  163. */
  164. /**
  165. * Generic dictionary in TypeScript notation.
  166. *
  167. * @interface Highcharts.Dictionary<T>
  168. *//**
  169. * @name Highcharts.Dictionary<T>#[key:string]
  170. * @type {T}
  171. */
  172. /**
  173. * The function callback to execute when the event is fired. The `this` context
  174. * contains the instance, that fired the event.
  175. *
  176. * @callback Highcharts.EventCallbackFunction<T>
  177. *
  178. * @param {T} this
  179. *
  180. * @param {Highcharts.Dictionary<*>} [eventArguments]
  181. * Event arguments.
  182. */
  183. /**
  184. * The event options for adding function callback.
  185. *
  186. * @interface Highcharts.EventOptionsObject
  187. *//**
  188. * The order the event handler should be called. This opens for having one
  189. * handler be called before another, independent of in which order they were
  190. * added.
  191. * @name Highcharts.EventOptionsObject#order
  192. * @type {number}
  193. */
  194. /**
  195. * Formats data as a string. Usually the data is accessible throught the `this`
  196. * keyword.
  197. *
  198. * @callback Highcharts.FormatterCallbackFunction<T>
  199. *
  200. * @param {T} this
  201. *
  202. * @return {string}
  203. */
  204. /**
  205. * An object of key-value pairs for HTML attributes.
  206. *
  207. * @typedef {Highcharts.Dictionary<boolean|number|string>} Highcharts.HTMLAttributes
  208. */
  209. /**
  210. * An HTML DOM element. The type is a reference to the regular HTMLElement in
  211. * the global scope.
  212. *
  213. * @typedef {global.HTMLElement} Highcharts.HTMLDOMElement
  214. *
  215. * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
  216. */
  217. /**
  218. * The iterator callback.
  219. *
  220. * @callback Highcharts.ObjectEachCallbackFunction
  221. *
  222. * @param {*} value
  223. * The property value.
  224. *
  225. * @param {string} key
  226. * The property key.
  227. *
  228. * @param {*} obj
  229. * The object that objectEach is being applied to.
  230. */
  231. /**
  232. * An object containing `left` and `top` properties for the position in the
  233. * page.
  234. *
  235. * @interface Highcharts.OffsetObject
  236. *//**
  237. * Left distance to the page border.
  238. * @name Highcharts.OffsetObject#left
  239. * @type {number}
  240. *//**
  241. * Top distance to the page border.
  242. * @name Highcharts.OffsetObject#top
  243. * @type {number}
  244. */
  245. /**
  246. * If a number is given, it defines the pixel length. If a percentage string is
  247. * given, like for example `'50%'`, the setting defines a length relative to a
  248. * base size, for example the size of a container.
  249. *
  250. * @typedef {number|string} Highcharts.RelativeSize
  251. */
  252. /**
  253. * An object of key-value pairs for SVG attributes. Attributes in Highcharts
  254. * elements for the most parts correspond to SVG, but some are specific to
  255. * Highcharts, like `zIndex`, `rotation`, `rotationOriginX`,
  256. * `rotationOriginY`, `translateX`, `translateY`, `scaleX` and `scaleY`. SVG
  257. * attributes containing a hyphen are _not_ camel-cased, they should be
  258. * quoted to preserve the hyphen.
  259. *
  260. * @example
  261. * {
  262. * 'stroke': '#ff0000', // basic
  263. * 'stroke-width': 2, // hyphenated
  264. * 'rotation': 45 // custom
  265. * 'd': ['M', 10, 10, 'L', 30, 30, 'z'] // path definition, note format
  266. * }
  267. *
  268. * @interface Highcharts.SVGAttributes
  269. *//**
  270. * @name Highcharts.SVGAttributes#[key:string]
  271. * @type {boolean|number|string|Array<number|string>|undefined}
  272. *//**
  273. * @name Highcharts.SVGAttributes#d
  274. * @type {string|Highcharts.SVGPathArray|undefined}
  275. *//**
  276. * @name Highcharts.SVGAttributes#inverted
  277. * @type {boolean|undefined}
  278. *//**
  279. * @name Highcharts.SVGAttributes#matrix
  280. * @type {Array<number>|undefined}
  281. *//**
  282. * @name Highcharts.SVGAttributes#stroke
  283. * @type {Highcharts.ColorString|undefined}
  284. *//**
  285. * @name Highcharts.SVGAttributes#rotation
  286. * @type {string|undefined}
  287. *//**
  288. * @name Highcharts.SVGAttributes#rotationOriginX
  289. * @type {number|undefined}
  290. *//**
  291. * @name Highcharts.SVGAttributes#rotationOriginY
  292. * @type {number|undefined}
  293. *//**
  294. * @name Highcharts.SVGAttributes#scaleX
  295. * @type {number|undefined}
  296. *//**
  297. * @name Highcharts.SVGAttributes#scaleY
  298. * @type {number|undefined}
  299. *//**
  300. * @name Highcharts.SVGAttributes#translateX
  301. * @type {number|undefined}
  302. *//**
  303. * @name Highcharts.SVGAttributes#translateY
  304. * @type {number|undefined}
  305. *//**
  306. * @name Highcharts.SVGAttributes#zIndex
  307. * @type {number|undefined}
  308. */
  309. /**
  310. * An SVG DOM element. The type is a reference to the regular SVGElement in the
  311. * global scope.
  312. *
  313. * @typedef {globals.GlobalSVGElement} Highcharts.SVGDOMElement
  314. *
  315. * @see https://developer.mozilla.org/en-US/docs/Web/API/SVGElement
  316. */
  317. /**
  318. * Array of path commands, that will go into the `d` attribute of an SVG
  319. * element.
  320. *
  321. * @typedef {Array<number|Highcharts.SVGPathCommand>} Highcharts.SVGPathArray
  322. */
  323. /**
  324. * Possible path commands in a SVG path array.
  325. *
  326. * @typedef {string} Highcharts.SVGPathCommand
  327. * @validvalue ["a","c","h","l","m","q","s","t","v","z","A","C","H","L","M","Q","S","T","V","Z"]
  328. */
  329. 'use strict';
  330. import H from './Globals.js';
  331. /**
  332. * The Highcharts object is the placeholder for all other members, and various
  333. * utility functions. The most important member of the namespace would be the
  334. * chart constructor.
  335. *
  336. * @example
  337. * var chart = Highcharts.chart('container', { ... });
  338. *
  339. * @namespace Highcharts
  340. */
  341. H.timers = [];
  342. var charts = H.charts,
  343. doc = H.doc,
  344. win = H.win;
  345. /**
  346. * Provide error messages for debugging, with links to online explanation. This
  347. * function can be overridden to provide custom error handling.
  348. *
  349. * @sample highcharts/chart/highcharts-error/
  350. * Custom error handler
  351. *
  352. * @function Highcharts.error
  353. *
  354. * @param {number|string} code
  355. * The error code. See
  356. * [errors.xml](https://github.com/highcharts/highcharts/blob/master/errors/errors.xml)
  357. * for available codes. If it is a string, the error message is printed
  358. * directly in the console.
  359. *
  360. * @param {boolean} [stop=false]
  361. * Whether to throw an error or just log a warning in the console.
  362. *
  363. * @param {Highcharts.Chart} [chart]
  364. * Reference to the chart that causes the error. Used in 'debugger'
  365. * module to display errors directly on the chart.
  366. * Important note: This argument is undefined for errors that lack
  367. * access to the Chart instance.
  368. */
  369. H.error = function (code, stop, chart) {
  370. var msg = H.isNumber(code) ?
  371. 'Highcharts error #' + code + ': www.highcharts.com/errors/' + code :
  372. code;
  373. if (chart) {
  374. H.fireEvent(chart, 'displayError', { code: code });
  375. }
  376. if (stop) {
  377. throw new Error(msg);
  378. }
  379. // else ...
  380. if (win.console) {
  381. console.log(msg); // eslint-disable-line no-console
  382. }
  383. };
  384. /**
  385. * An animator object used internally. One instance applies to one property
  386. * (attribute or style prop) on one element. Animation is always initiated
  387. * through {@link SVGElement#animate}.
  388. *
  389. * @example
  390. * var rect = renderer.rect(0, 0, 10, 10).add();
  391. * rect.animate({ width: 100 });
  392. *
  393. * @private
  394. * @class Highcharts.Fx
  395. *
  396. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGElement} elem
  397. * The element to animate.
  398. *
  399. * @param {Highcharts.AnimationOptionsObject} options
  400. * Animation options.
  401. *
  402. * @param {string} prop
  403. * The single attribute or CSS property to animate.
  404. */
  405. H.Fx = function (elem, options, prop) {
  406. this.options = options;
  407. this.elem = elem;
  408. this.prop = prop;
  409. };
  410. H.Fx.prototype = {
  411. /**
  412. * Set the current step of a path definition on SVGElement.
  413. *
  414. * @function Highcharts.Fx#dSetter
  415. */
  416. dSetter: function () {
  417. var start = this.paths[0],
  418. end = this.paths[1],
  419. ret = [],
  420. now = this.now,
  421. i = start.length,
  422. startVal;
  423. // Land on the final path without adjustment points appended in the ends
  424. if (now === 1) {
  425. ret = this.toD;
  426. } else if (i === end.length && now < 1) {
  427. while (i--) {
  428. startVal = parseFloat(start[i]);
  429. ret[i] =
  430. isNaN(startVal) ? // a letter instruction like M or L
  431. end[i] :
  432. now * (parseFloat(end[i] - startVal)) + startVal;
  433. }
  434. // If animation is finished or length not matching, land on right value
  435. } else {
  436. ret = end;
  437. }
  438. this.elem.attr('d', ret, null, true);
  439. },
  440. /**
  441. * Update the element with the current animation step.
  442. *
  443. * @function Highcharts.Fx#update
  444. */
  445. update: function () {
  446. var elem = this.elem,
  447. prop = this.prop, // if destroyed, it is null
  448. now = this.now,
  449. step = this.options.step;
  450. // Animation setter defined from outside
  451. if (this[prop + 'Setter']) {
  452. this[prop + 'Setter']();
  453. // Other animations on SVGElement
  454. } else if (elem.attr) {
  455. if (elem.element) {
  456. elem.attr(prop, now, null, true);
  457. }
  458. // HTML styles, raw HTML content like container size
  459. } else {
  460. elem.style[prop] = now + this.unit;
  461. }
  462. if (step) {
  463. step.call(elem, now, this);
  464. }
  465. },
  466. /**
  467. * Run an animation.
  468. *
  469. * @function Highcharts.Fx#run
  470. *
  471. * @param {number} from
  472. * The current value, value to start from.
  473. *
  474. * @param {number} to
  475. * The end value, value to land on.
  476. *
  477. * @param {string} [unit]
  478. * The property unit, for example `px`.
  479. */
  480. run: function (from, to, unit) {
  481. var self = this,
  482. options = self.options,
  483. timer = function (gotoEnd) {
  484. return timer.stopped ? false : self.step(gotoEnd);
  485. },
  486. requestAnimationFrame =
  487. win.requestAnimationFrame ||
  488. function (step) {
  489. setTimeout(step, 13);
  490. },
  491. step = function () {
  492. for (var i = 0; i < H.timers.length; i++) {
  493. if (!H.timers[i]()) {
  494. H.timers.splice(i--, 1);
  495. }
  496. }
  497. if (H.timers.length) {
  498. requestAnimationFrame(step);
  499. }
  500. };
  501. if (from === to && !this.elem['forceAnimate:' + this.prop]) {
  502. delete options.curAnim[this.prop];
  503. if (options.complete && Object.keys(options.curAnim).length === 0) {
  504. options.complete.call(this.elem);
  505. }
  506. } else { // #7166
  507. this.startTime = +new Date();
  508. this.start = from;
  509. this.end = to;
  510. this.unit = unit;
  511. this.now = this.start;
  512. this.pos = 0;
  513. timer.elem = this.elem;
  514. timer.prop = this.prop;
  515. if (timer() && H.timers.push(timer) === 1) {
  516. requestAnimationFrame(step);
  517. }
  518. }
  519. },
  520. /**
  521. * Run a single step in the animation.
  522. *
  523. * @function Highcharts.Fx#step
  524. *
  525. * @param {boolean} [gotoEnd]
  526. * Whether to go to the endpoint of the animation after abort.
  527. *
  528. * @return {boolean}
  529. * Returns `true` if animation continues.
  530. */
  531. step: function (gotoEnd) {
  532. var t = +new Date(),
  533. ret,
  534. done,
  535. options = this.options,
  536. elem = this.elem,
  537. complete = options.complete,
  538. duration = options.duration,
  539. curAnim = options.curAnim;
  540. if (elem.attr && !elem.element) { // #2616, element is destroyed
  541. ret = false;
  542. } else if (gotoEnd || t >= duration + this.startTime) {
  543. this.now = this.end;
  544. this.pos = 1;
  545. this.update();
  546. curAnim[this.prop] = true;
  547. done = true;
  548. H.objectEach(curAnim, function (val) {
  549. if (val !== true) {
  550. done = false;
  551. }
  552. });
  553. if (done && complete) {
  554. complete.call(elem);
  555. }
  556. ret = false;
  557. } else {
  558. this.pos = options.easing((t - this.startTime) / duration);
  559. this.now = this.start + ((this.end - this.start) * this.pos);
  560. this.update();
  561. ret = true;
  562. }
  563. return ret;
  564. },
  565. /**
  566. * Prepare start and end values so that the path can be animated one to one.
  567. *
  568. * @function Highcharts.Fx#initPath
  569. *
  570. * @param {Highcharts.SVGElement} elem
  571. * The SVGElement item.
  572. *
  573. * @param {string} fromD
  574. * Starting path definition.
  575. *
  576. * @param {Highcharts.SVGPathArray} toD
  577. * Ending path definition.
  578. *
  579. * @return {Array<Highcharts.SVGPathArray>}
  580. * An array containing start and end paths in array form so that
  581. * they can be animated in parallel.
  582. */
  583. initPath: function (elem, fromD, toD) {
  584. fromD = fromD || '';
  585. var shift,
  586. startX = elem.startX,
  587. endX = elem.endX,
  588. bezier = fromD.indexOf('C') > -1,
  589. numParams = bezier ? 7 : 3,
  590. fullLength,
  591. slice,
  592. i,
  593. start = fromD.split(' '),
  594. end = toD.slice(), // copy
  595. isArea = elem.isArea,
  596. positionFactor = isArea ? 2 : 1,
  597. reverse;
  598. /**
  599. * In splines make moveTo and lineTo points have six parameters like
  600. * bezier curves, to allow animation one-to-one.
  601. */
  602. function sixify(arr) {
  603. var isOperator,
  604. nextIsOperator;
  605. i = arr.length;
  606. while (i--) {
  607. // Fill in dummy coordinates only if the next operator comes
  608. // three places behind (#5788)
  609. isOperator = arr[i] === 'M' || arr[i] === 'L';
  610. nextIsOperator = /[a-zA-Z]/.test(arr[i + 3]);
  611. if (isOperator && nextIsOperator) {
  612. arr.splice(
  613. i + 1, 0,
  614. arr[i + 1], arr[i + 2],
  615. arr[i + 1], arr[i + 2]
  616. );
  617. }
  618. }
  619. }
  620. /**
  621. * Insert an array at the given position of another array
  622. */
  623. function insertSlice(arr, subArr, index) {
  624. [].splice.apply(
  625. arr,
  626. [index, 0].concat(subArr)
  627. );
  628. }
  629. /**
  630. * If shifting points, prepend a dummy point to the end path.
  631. */
  632. function prepend(arr, other) {
  633. while (arr.length < fullLength) {
  634. // Move to, line to or curve to?
  635. arr[0] = other[fullLength - arr.length];
  636. // Prepend a copy of the first point
  637. insertSlice(arr, arr.slice(0, numParams), 0);
  638. // For areas, the bottom path goes back again to the left, so we
  639. // need to append a copy of the last point.
  640. if (isArea) {
  641. insertSlice(
  642. arr,
  643. arr.slice(arr.length - numParams), arr.length
  644. );
  645. i--;
  646. }
  647. }
  648. arr[0] = 'M';
  649. }
  650. /**
  651. * Copy and append last point until the length matches the end length.
  652. */
  653. function append(arr, other) {
  654. var i = (fullLength - arr.length) / numParams;
  655. while (i > 0 && i--) {
  656. // Pull out the slice that is going to be appended or inserted.
  657. // In a line graph, the positionFactor is 1, and the last point
  658. // is sliced out. In an area graph, the positionFactor is 2,
  659. // causing the middle two points to be sliced out, since an area
  660. // path starts at left, follows the upper path then turns and
  661. // follows the bottom back.
  662. slice = arr.slice().splice(
  663. (arr.length / positionFactor) - numParams,
  664. numParams * positionFactor
  665. );
  666. // Move to, line to or curve to?
  667. slice[0] = other[fullLength - numParams - (i * numParams)];
  668. // Disable first control point
  669. if (bezier) {
  670. slice[numParams - 6] = slice[numParams - 2];
  671. slice[numParams - 5] = slice[numParams - 1];
  672. }
  673. // Now insert the slice, either in the middle (for areas) or at
  674. // the end (for lines)
  675. insertSlice(arr, slice, arr.length / positionFactor);
  676. if (isArea) {
  677. i--;
  678. }
  679. }
  680. }
  681. if (bezier) {
  682. sixify(start);
  683. sixify(end);
  684. }
  685. // For sideways animation, find out how much we need to shift to get the
  686. // start path Xs to match the end path Xs.
  687. if (startX && endX) {
  688. for (i = 0; i < startX.length; i++) {
  689. // Moving left, new points coming in on right
  690. if (startX[i] === endX[0]) {
  691. shift = i;
  692. break;
  693. // Moving right
  694. } else if (startX[0] ===
  695. endX[endX.length - startX.length + i]) {
  696. shift = i;
  697. reverse = true;
  698. break;
  699. }
  700. }
  701. if (shift === undefined) {
  702. start = [];
  703. }
  704. }
  705. if (start.length && H.isNumber(shift)) {
  706. // The common target length for the start and end array, where both
  707. // arrays are padded in opposite ends
  708. fullLength = end.length + shift * positionFactor * numParams;
  709. if (!reverse) {
  710. prepend(end, start);
  711. append(start, end);
  712. } else {
  713. prepend(start, end);
  714. append(end, start);
  715. }
  716. }
  717. return [start, end];
  718. },
  719. /**
  720. * Handle animation of the color attributes directly.
  721. *
  722. * @function Highcharts.Fx#fillSetter
  723. */
  724. fillSetter: function () {
  725. H.Fx.prototype.strokeSetter.apply(this, arguments);
  726. },
  727. /**
  728. * Handle animation of the color attributes directly.
  729. *
  730. * @function Highcharts.Fx#strokeSetter
  731. */
  732. strokeSetter: function () {
  733. this.elem.attr(
  734. this.prop,
  735. H.color(this.start).tweenTo(H.color(this.end), this.pos),
  736. null,
  737. true
  738. );
  739. }
  740. }; // End of Fx prototype
  741. /**
  742. * Utility function to deep merge two or more objects and return a third object.
  743. * The merge function can also be used with a single object argument to create a
  744. * deep copy of an object.
  745. *
  746. * @function Highcharts.merge
  747. *
  748. * @param {*} a
  749. * The first object to extend. When only this is given, the function
  750. * returns a deep copy.
  751. *
  752. * @param {*} [n]
  753. * An object to merge into the previous one.
  754. *
  755. * @return {*}
  756. * The merged object. If the first argument is true, the return is the
  757. * same as the second argument.
  758. *//**
  759. * Utility function to deep merge two or more objects and return a third object.
  760. * If the first argument is true, the contents of the second object is copied
  761. * into the first object. The merge function can also be used with a single
  762. * object argument to create a deep copy of an object.
  763. *
  764. * @function Highcharts.merge
  765. *
  766. * @param {boolean} extend
  767. * Whether to extend the left-side object (a) or return a whole new
  768. * object.
  769. *
  770. * @param {*} a
  771. * The first object to extend. When only this is given, the function
  772. * returns a deep copy.
  773. *
  774. * @param {*} [n]
  775. * An object to merge into the previous one.
  776. *
  777. * @return {*}
  778. * The merged object. If the first argument is true, the return is the
  779. * same as the second argument.
  780. */
  781. H.merge = function () {
  782. var i,
  783. args = arguments,
  784. len,
  785. ret = {},
  786. doCopy = function (copy, original) {
  787. // An object is replacing a primitive
  788. if (typeof copy !== 'object') {
  789. copy = {};
  790. }
  791. H.objectEach(original, function (value, key) {
  792. // Copy the contents of objects, but not arrays or DOM nodes
  793. if (H.isObject(value, true) &&
  794. !H.isClass(value) &&
  795. !H.isDOMElement(value)
  796. ) {
  797. copy[key] = doCopy(copy[key] || {}, value);
  798. // Primitives and arrays are copied over directly
  799. } else {
  800. copy[key] = original[key];
  801. }
  802. });
  803. return copy;
  804. };
  805. // If first argument is true, copy into the existing object. Used in
  806. // setOptions.
  807. if (args[0] === true) {
  808. ret = args[1];
  809. args = Array.prototype.slice.call(args, 2);
  810. }
  811. // For each argument, extend the return
  812. len = args.length;
  813. for (i = 0; i < len; i++) {
  814. ret = doCopy(ret, args[i]);
  815. }
  816. return ret;
  817. };
  818. /**
  819. * Shortcut for parseInt
  820. *
  821. * @private
  822. * @function Highcharts.pInt
  823. *
  824. * @param {*} s
  825. *
  826. * @param {number} mag
  827. * Magnitude
  828. *
  829. * @return {number}
  830. */
  831. H.pInt = function (s, mag) {
  832. return parseInt(s, mag || 10);
  833. };
  834. /**
  835. * Utility function to check for string type.
  836. *
  837. * @function Highcharts.isString
  838. *
  839. * @param {*} s
  840. * The item to check.
  841. *
  842. * @return {boolean}
  843. * True if the argument is a string.
  844. */
  845. H.isString = function (s) {
  846. return typeof s === 'string';
  847. };
  848. /**
  849. * Utility function to check if an item is an array.
  850. *
  851. * @function Highcharts.isArray
  852. *
  853. * @param {*} obj
  854. * The item to check.
  855. *
  856. * @return {boolean}
  857. * True if the argument is an array.
  858. */
  859. H.isArray = function (obj) {
  860. var str = Object.prototype.toString.call(obj);
  861. return str === '[object Array]' || str === '[object Array Iterator]';
  862. };
  863. /**
  864. * Utility function to check if an item is of type object.
  865. *
  866. * @function Highcharts.isObject
  867. *
  868. * @param {*} obj
  869. * The item to check.
  870. *
  871. * @param {boolean} [strict=false]
  872. * Also checks that the object is not an array.
  873. *
  874. * @return {boolean}
  875. * True if the argument is an object.
  876. */
  877. H.isObject = function (obj, strict) {
  878. return !!obj && typeof obj === 'object' && (!strict || !H.isArray(obj));
  879. };
  880. /**
  881. * Utility function to check if an Object is a HTML Element.
  882. *
  883. * @function Highcharts.isDOMElement
  884. *
  885. * @param {*} obj
  886. * The item to check.
  887. *
  888. * @return {boolean}
  889. * True if the argument is a HTML Element.
  890. */
  891. H.isDOMElement = function (obj) {
  892. return H.isObject(obj) && typeof obj.nodeType === 'number';
  893. };
  894. /**
  895. * Utility function to check if an Object is an class.
  896. *
  897. * @function Highcharts.isClass
  898. *
  899. * @param {*} obj
  900. * The item to check.
  901. *
  902. * @return {boolean}
  903. * True if the argument is an class.
  904. */
  905. H.isClass = function (obj) {
  906. var c = obj && obj.constructor;
  907. return !!(
  908. H.isObject(obj, true) &&
  909. !H.isDOMElement(obj) &&
  910. (c && c.name && c.name !== 'Object')
  911. );
  912. };
  913. /**
  914. * Utility function to check if an item is a number and it is finite (not NaN,
  915. * Infinity or -Infinity).
  916. *
  917. * @function Highcharts.isNumber
  918. *
  919. * @param {*} n
  920. * The item to check.
  921. *
  922. * @return {boolean}
  923. * True if the item is a finite number
  924. */
  925. H.isNumber = function (n) {
  926. return typeof n === 'number' && !isNaN(n) && n < Infinity && n > -Infinity;
  927. };
  928. /**
  929. * Remove the last occurence of an item from an array.
  930. *
  931. * @function Highcharts.erase
  932. *
  933. * @param {Array} arr
  934. * The array.
  935. *
  936. * @param {*} item
  937. * The item to remove.
  938. */
  939. H.erase = function (arr, item) {
  940. var i = arr.length;
  941. while (i--) {
  942. if (arr[i] === item) {
  943. arr.splice(i, 1);
  944. break;
  945. }
  946. }
  947. };
  948. /**
  949. * Check if an object is null or undefined.
  950. *
  951. * @function Highcharts.defined
  952. *
  953. * @param {*} obj
  954. * The object to check.
  955. *
  956. * @return {boolean}
  957. * False if the object is null or undefined, otherwise true.
  958. */
  959. H.defined = function (obj) {
  960. return obj !== undefined && obj !== null;
  961. };
  962. /**
  963. * Set or get an attribute or an object of attributes. To use as a setter, pass
  964. * a key and a value, or let the second argument be a collection of keys and
  965. * values. To use as a getter, pass only a string as the second argument.
  966. *
  967. * @function Highcharts.attr
  968. *
  969. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} elem
  970. * The DOM element to receive the attribute(s).
  971. *
  972. * @param {string|Highcharts.HTMLAttributes|Highcharts.SVGAttributes} [prop]
  973. * The property or an object of key-value pairs.
  974. *
  975. * @param {string} [value]
  976. * The value if a single property is set.
  977. *
  978. * @return {*}
  979. * When used as a getter, return the value.
  980. */
  981. H.attr = function (elem, prop, value) {
  982. var ret;
  983. // if the prop is a string
  984. if (H.isString(prop)) {
  985. // set the value
  986. if (H.defined(value)) {
  987. elem.setAttribute(prop, value);
  988. // get the value
  989. } else if (elem && elem.getAttribute) {
  990. ret = elem.getAttribute(prop);
  991. // IE7 and below cannot get class through getAttribute (#7850)
  992. if (!ret && prop === 'class') {
  993. ret = elem.getAttribute(prop + 'Name');
  994. }
  995. }
  996. // else if prop is defined, it is a hash of key/value pairs
  997. } else if (H.defined(prop) && H.isObject(prop)) {
  998. H.objectEach(prop, function (val, key) {
  999. elem.setAttribute(key, val);
  1000. });
  1001. }
  1002. return ret;
  1003. };
  1004. /**
  1005. * Check if an element is an array, and if not, make it into an array.
  1006. *
  1007. * @function Highcharts.splat
  1008. *
  1009. * @param {*} obj
  1010. * The object to splat.
  1011. *
  1012. * @return {Array}
  1013. * The produced or original array.
  1014. */
  1015. H.splat = function (obj) {
  1016. return H.isArray(obj) ? obj : [obj];
  1017. };
  1018. /**
  1019. * Set a timeout if the delay is given, otherwise perform the function
  1020. * synchronously.
  1021. *
  1022. * @function Highcharts.syncTimeout
  1023. *
  1024. * @param {Function} fn
  1025. * The function callback.
  1026. *
  1027. * @param {number} delay
  1028. * Delay in milliseconds.
  1029. *
  1030. * @param {*} [parameter]
  1031. * An optional parameter to send to the function callback.
  1032. *
  1033. * @return {number}
  1034. * An identifier for the timeout that can later be cleared with
  1035. * Highcharts.clearTimeout.
  1036. */
  1037. H.syncTimeout = function (fn, delay, context) {
  1038. if (delay) {
  1039. return setTimeout(fn, delay, context);
  1040. }
  1041. fn.call(0, context);
  1042. };
  1043. /**
  1044. * Internal clear timeout. The function checks that the `id` was not removed
  1045. * (e.g. by `chart.destroy()`). For the details see
  1046. * [issue #7901](https://github.com/highcharts/highcharts/issues/7901).
  1047. *
  1048. * @function Highcharts.clearTimeout
  1049. *
  1050. * @param {number} id
  1051. * Id of a timeout.
  1052. */
  1053. H.clearTimeout = function (id) {
  1054. if (H.defined(id)) {
  1055. clearTimeout(id);
  1056. }
  1057. };
  1058. /**
  1059. * Utility function to extend an object with the members of another.
  1060. *
  1061. * @function Highcharts.extend
  1062. *
  1063. * @param {Highcharts.Dictionary<*>} a
  1064. * The object to be extended.
  1065. *
  1066. * @param {Highcharts.Dictionary<*>} b
  1067. * The object to add to the first one.
  1068. *
  1069. * @return {Highcharts.Dictionary<*>}
  1070. * Object a, the original object.
  1071. */
  1072. H.extend = function (a, b) {
  1073. var n;
  1074. if (!a) {
  1075. a = {};
  1076. }
  1077. for (n in b) {
  1078. a[n] = b[n];
  1079. }
  1080. return a;
  1081. };
  1082. /**
  1083. * Return the first value that is not null or undefined.
  1084. *
  1085. * @function Highcharts.pick
  1086. *
  1087. * @param {...*} items
  1088. * Variable number of arguments to inspect.
  1089. *
  1090. * @return {*}
  1091. * The value of the first argument that is not null or undefined.
  1092. */
  1093. H.pick = function () {
  1094. var args = arguments,
  1095. i,
  1096. arg,
  1097. length = args.length;
  1098. for (i = 0; i < length; i++) {
  1099. arg = args[i];
  1100. if (arg !== undefined && arg !== null) {
  1101. return arg;
  1102. }
  1103. }
  1104. };
  1105. /**
  1106. * Set CSS on a given element.
  1107. *
  1108. * @function Highcharts.css
  1109. *
  1110. * @param {Highcharts.HTMLDOMElement} el
  1111. * An HTML DOM element.
  1112. *
  1113. * @param {Highcharts.CSSObject} styles
  1114. * Style object with camel case property names.
  1115. */
  1116. H.css = function (el, styles) {
  1117. if (H.isMS && !H.svg) { // #2686
  1118. if (styles && styles.opacity !== undefined) {
  1119. styles.filter = 'alpha(opacity=' + (styles.opacity * 100) + ')';
  1120. }
  1121. }
  1122. H.extend(el.style, styles);
  1123. };
  1124. /**
  1125. * Utility function to create an HTML element with attributes and styles.
  1126. *
  1127. * @function Highcharts.createElement
  1128. *
  1129. * @param {string} tag
  1130. * The HTML tag.
  1131. *
  1132. * @param {Highcharts.HTMLAttributes} [attribs]
  1133. * Attributes as an object of key-value pairs.
  1134. *
  1135. * @param {Highcharts.CSSObject} [styles]
  1136. * Styles as an object of key-value pairs.
  1137. *
  1138. * @param {Highcharts.HTMLDOMElement} [parent]
  1139. * The parent HTML object.
  1140. *
  1141. * @param {boolean} [nopad=false]
  1142. * If true, remove all padding, border and margin.
  1143. *
  1144. * @return {Highcharts.HTMLDOMElement}
  1145. * The created DOM element.
  1146. */
  1147. H.createElement = function (tag, attribs, styles, parent, nopad) {
  1148. var el = doc.createElement(tag),
  1149. css = H.css;
  1150. if (attribs) {
  1151. H.extend(el, attribs);
  1152. }
  1153. if (nopad) {
  1154. css(el, { padding: 0, border: 'none', margin: 0 });
  1155. }
  1156. if (styles) {
  1157. css(el, styles);
  1158. }
  1159. if (parent) {
  1160. parent.appendChild(el);
  1161. }
  1162. return el;
  1163. };
  1164. /**
  1165. * Extend a prototyped class by new members.
  1166. *
  1167. * @function Highcharts.extendClass
  1168. *
  1169. * @param {*} parent
  1170. * The parent prototype to inherit.
  1171. *
  1172. * @param {Highcharts.Dictionary<*>} members
  1173. * A collection of prototype members to add or override compared to the
  1174. * parent prototype.
  1175. *
  1176. * @return {*}
  1177. * A new prototype.
  1178. */
  1179. H.extendClass = function (parent, members) {
  1180. var object = function () {};
  1181. object.prototype = new parent(); // eslint-disable-line new-cap
  1182. H.extend(object.prototype, members);
  1183. return object;
  1184. };
  1185. /**
  1186. * Left-pad a string to a given length by adding a character repetetively.
  1187. *
  1188. * @function Highcharts.pad
  1189. *
  1190. * @param {number} number
  1191. * The input string or number.
  1192. *
  1193. * @param {number} length
  1194. * The desired string length.
  1195. *
  1196. * @param {string} [padder=0]
  1197. * The character to pad with.
  1198. *
  1199. * @return {string}
  1200. * The padded string.
  1201. */
  1202. H.pad = function (number, length, padder) {
  1203. return new Array(
  1204. (length || 2) +
  1205. 1 -
  1206. String(number)
  1207. .replace('-', '')
  1208. .length
  1209. ).join(padder || 0) + number;
  1210. };
  1211. /**
  1212. * Return a length based on either the integer value, or a percentage of a base.
  1213. *
  1214. * @function Highcharts.relativeLength
  1215. *
  1216. * @param {Highcharts.RelativeSize} value
  1217. * A percentage string or a number.
  1218. *
  1219. * @param {number} base
  1220. * The full length that represents 100%.
  1221. *
  1222. * @param {number} [offset=0]
  1223. * A pixel offset to apply for percentage values. Used internally in
  1224. * axis positioning.
  1225. *
  1226. * @return {number}
  1227. * The computed length.
  1228. */
  1229. H.relativeLength = function (value, base, offset) {
  1230. return (/%$/).test(value) ?
  1231. (base * parseFloat(value) / 100) + (offset || 0) :
  1232. parseFloat(value);
  1233. };
  1234. /**
  1235. * Wrap a method with extended functionality, preserving the original function.
  1236. *
  1237. * @function Highcharts.wrap
  1238. *
  1239. * @param {*} obj
  1240. * The context object that the method belongs to. In real cases, this is
  1241. * often a prototype.
  1242. *
  1243. * @param {string} method
  1244. * The name of the method to extend.
  1245. *
  1246. * @param {Function} func
  1247. * A wrapper function callback. This function is called with the same
  1248. * arguments as the original function, except that the original function
  1249. * is unshifted and passed as the first argument.
  1250. */
  1251. H.wrap = function (obj, method, func) {
  1252. var proceed = obj[method];
  1253. obj[method] = function () {
  1254. var args = Array.prototype.slice.call(arguments),
  1255. outerArgs = arguments,
  1256. ctx = this,
  1257. ret;
  1258. ctx.proceed = function () {
  1259. proceed.apply(ctx, arguments.length ? arguments : outerArgs);
  1260. };
  1261. args.unshift(proceed);
  1262. ret = func.apply(this, args);
  1263. ctx.proceed = null;
  1264. return ret;
  1265. };
  1266. };
  1267. /**
  1268. * Recursively converts all Date properties to timestamps.
  1269. *
  1270. * @param {Object} object - any object to convert properties of
  1271. */
  1272. H.datePropsToTimestamps = function (object) {
  1273. H.objectEach(object, function (val, key) {
  1274. if (H.isObject(val) && typeof val.getTime === 'function') {
  1275. object[key] = val.getTime();
  1276. } else if (H.isObject(val) || H.isArray(val)) {
  1277. H.datePropsToTimestamps(val);
  1278. }
  1279. });
  1280. };
  1281. /**
  1282. * Format a single variable. Similar to sprintf, without the % prefix.
  1283. *
  1284. * @example
  1285. * formatSingle('.2f', 5); // => '5.00'.
  1286. *
  1287. * @function Highcharts.formatSingle
  1288. *
  1289. * @param {string} format
  1290. * The format string.
  1291. *
  1292. * @param {*} val
  1293. * The value.
  1294. *
  1295. * @param {Highcharts.Time} [time]
  1296. * A `Time` instance that determines the date formatting, for example
  1297. * for applying time zone corrections to the formatted date.
  1298. *
  1299. * @return {string}
  1300. * The formatted representation of the value.
  1301. */
  1302. H.formatSingle = function (format, val, time) {
  1303. var floatRegex = /f$/,
  1304. decRegex = /\.([0-9])/,
  1305. lang = H.defaultOptions.lang,
  1306. decimals;
  1307. if (floatRegex.test(format)) { // float
  1308. decimals = format.match(decRegex);
  1309. decimals = decimals ? decimals[1] : -1;
  1310. if (val !== null) {
  1311. val = H.numberFormat(
  1312. val,
  1313. decimals,
  1314. lang.decimalPoint,
  1315. format.indexOf(',') > -1 ? lang.thousandsSep : ''
  1316. );
  1317. }
  1318. } else {
  1319. val = (time || H.time).dateFormat(format, val);
  1320. }
  1321. return val;
  1322. };
  1323. /**
  1324. * Format a string according to a subset of the rules of Python's String.format
  1325. * method.
  1326. *
  1327. * @example
  1328. * var s = Highcharts.format(
  1329. * 'The {color} fox was {len:.2f} feet long',
  1330. * { color: 'red', len: Math.PI }
  1331. * );
  1332. * // => The red fox was 3.14 feet long
  1333. *
  1334. * @function Highcharts.format
  1335. *
  1336. * @param {string} str
  1337. * The string to format.
  1338. *
  1339. * @param {*} ctx
  1340. * The context, a collection of key-value pairs where each key is
  1341. * replaced by its value.
  1342. *
  1343. * @param {Highcharts.Time} [time]
  1344. * A `Time` instance that determines the date formatting, for example
  1345. * for applying time zone corrections to the formatted date.
  1346. *
  1347. * @return {string}
  1348. * The formatted string.
  1349. */
  1350. H.format = function (str, ctx, time) {
  1351. var splitter = '{',
  1352. isInside = false,
  1353. segment,
  1354. valueAndFormat,
  1355. path,
  1356. i,
  1357. len,
  1358. ret = [],
  1359. val,
  1360. index;
  1361. while (str) {
  1362. index = str.indexOf(splitter);
  1363. if (index === -1) {
  1364. break;
  1365. }
  1366. segment = str.slice(0, index);
  1367. if (isInside) { // we're on the closing bracket looking back
  1368. valueAndFormat = segment.split(':');
  1369. path = valueAndFormat.shift().split('.'); // get first and leave
  1370. len = path.length;
  1371. val = ctx;
  1372. // Assign deeper paths
  1373. for (i = 0; i < len; i++) {
  1374. if (val) {
  1375. val = val[path[i]];
  1376. }
  1377. }
  1378. // Format the replacement
  1379. if (valueAndFormat.length) {
  1380. val = H.formatSingle(valueAndFormat.join(':'), val, time);
  1381. }
  1382. // Push the result and advance the cursor
  1383. ret.push(val);
  1384. } else {
  1385. ret.push(segment);
  1386. }
  1387. str = str.slice(index + 1); // the rest
  1388. isInside = !isInside; // toggle
  1389. splitter = isInside ? '}' : '{'; // now look for next matching bracket
  1390. }
  1391. ret.push(str);
  1392. return ret.join('');
  1393. };
  1394. /**
  1395. * Get the magnitude of a number.
  1396. *
  1397. * @function Highcharts.getMagnitude
  1398. *
  1399. * @param {number} number
  1400. * The number.
  1401. *
  1402. * @return {number}
  1403. * The magnitude, where 1-9 are magnitude 1, 10-99 magnitude 2 etc.
  1404. */
  1405. H.getMagnitude = function (num) {
  1406. return Math.pow(10, Math.floor(Math.log(num) / Math.LN10));
  1407. };
  1408. /**
  1409. * Take an interval and normalize it to multiples of round numbers.
  1410. *
  1411. * @deprecated
  1412. * @function Highcharts.normalizeTickInterval
  1413. *
  1414. * @param {number} interval
  1415. * The raw, un-rounded interval.
  1416. *
  1417. * @param {Array} [multiples]
  1418. * Allowed multiples.
  1419. *
  1420. * @param {number} [magnitude]
  1421. * The magnitude of the number.
  1422. *
  1423. * @param {boolean} [allowDecimals]
  1424. * Whether to allow decimals.
  1425. *
  1426. * @param {boolean} [hasTickAmount]
  1427. * If it has tickAmount, avoid landing on tick intervals lower than
  1428. * original.
  1429. *
  1430. * @return {number}
  1431. * The normalized interval.
  1432. *
  1433. * @todo
  1434. * Move this function to the Axis prototype. It is here only for historical
  1435. * reasons.
  1436. */
  1437. H.normalizeTickInterval = function (
  1438. interval,
  1439. multiples,
  1440. magnitude,
  1441. allowDecimals,
  1442. hasTickAmount
  1443. ) {
  1444. var normalized,
  1445. i,
  1446. retInterval = interval;
  1447. // round to a tenfold of 1, 2, 2.5 or 5
  1448. magnitude = H.pick(magnitude, 1);
  1449. normalized = interval / magnitude;
  1450. // multiples for a linear scale
  1451. if (!multiples) {
  1452. multiples = hasTickAmount ?
  1453. // Finer grained ticks when the tick amount is hard set, including
  1454. // when alignTicks is true on multiple axes (#4580).
  1455. [1, 1.2, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10] :
  1456. // Else, let ticks fall on rounder numbers
  1457. [1, 2, 2.5, 5, 10];
  1458. // the allowDecimals option
  1459. if (allowDecimals === false) {
  1460. if (magnitude === 1) {
  1461. multiples = multiples.filter(function (num) {
  1462. return num % 1 === 0;
  1463. });
  1464. } else if (magnitude <= 0.1) {
  1465. multiples = [1 / magnitude];
  1466. }
  1467. }
  1468. }
  1469. // normalize the interval to the nearest multiple
  1470. for (i = 0; i < multiples.length; i++) {
  1471. retInterval = multiples[i];
  1472. // only allow tick amounts smaller than natural
  1473. if (
  1474. (
  1475. hasTickAmount &&
  1476. retInterval * magnitude >= interval
  1477. ) ||
  1478. (
  1479. !hasTickAmount &&
  1480. (
  1481. normalized <=
  1482. (
  1483. multiples[i] +
  1484. (multiples[i + 1] || multiples[i])
  1485. ) / 2
  1486. )
  1487. )
  1488. ) {
  1489. break;
  1490. }
  1491. }
  1492. // Multiply back to the correct magnitude. Correct floats to appropriate
  1493. // precision (#6085).
  1494. retInterval = H.correctFloat(
  1495. retInterval * magnitude,
  1496. -Math.round(Math.log(0.001) / Math.LN10)
  1497. );
  1498. return retInterval;
  1499. };
  1500. /**
  1501. * Sort an object array and keep the order of equal items. The ECMAScript
  1502. * standard does not specify the behaviour when items are equal.
  1503. *
  1504. * @function Highcharts.stableSort
  1505. *
  1506. * @param {Array} arr
  1507. * The array to sort.
  1508. *
  1509. * @param {Function} sortFunction
  1510. * The function to sort it with, like with regular Array.prototype.sort.
  1511. */
  1512. H.stableSort = function (arr, sortFunction) {
  1513. var length = arr.length,
  1514. sortValue,
  1515. i;
  1516. // Add index to each item
  1517. for (i = 0; i < length; i++) {
  1518. arr[i].safeI = i; // stable sort index
  1519. }
  1520. arr.sort(function (a, b) {
  1521. sortValue = sortFunction(a, b);
  1522. return sortValue === 0 ? a.safeI - b.safeI : sortValue;
  1523. });
  1524. // Remove index from items
  1525. for (i = 0; i < length; i++) {
  1526. delete arr[i].safeI; // stable sort index
  1527. }
  1528. };
  1529. /**
  1530. * Non-recursive method to find the lowest member of an array. `Math.min` raises
  1531. * a maximum call stack size exceeded error in Chrome when trying to apply more
  1532. * than 150.000 points. This method is slightly slower, but safe.
  1533. *
  1534. * @function Highcharts.arrayMin
  1535. *
  1536. * @param {Array} data
  1537. * An array of numbers.
  1538. *
  1539. * @return {number}
  1540. * The lowest number.
  1541. */
  1542. H.arrayMin = function (data) {
  1543. var i = data.length,
  1544. min = data[0];
  1545. while (i--) {
  1546. if (data[i] < min) {
  1547. min = data[i];
  1548. }
  1549. }
  1550. return min;
  1551. };
  1552. /**
  1553. * Non-recursive method to find the lowest member of an array. `Math.max` raises
  1554. * a maximum call stack size exceeded error in Chrome when trying to apply more
  1555. * than 150.000 points. This method is slightly slower, but safe.
  1556. *
  1557. * @function Highcharts.arrayMax
  1558. *
  1559. * @param {Array} data
  1560. * An array of numbers.
  1561. *
  1562. * @return {number}
  1563. * The highest number.
  1564. */
  1565. H.arrayMax = function (data) {
  1566. var i = data.length,
  1567. max = data[0];
  1568. while (i--) {
  1569. if (data[i] > max) {
  1570. max = data[i];
  1571. }
  1572. }
  1573. return max;
  1574. };
  1575. /**
  1576. * Utility method that destroys any SVGElement instances that are properties on
  1577. * the given object. It loops all properties and invokes destroy if there is a
  1578. * destroy method. The property is then delete.
  1579. *
  1580. * @function Highcharts.destroyObjectProperties
  1581. *
  1582. * @param {*} obj
  1583. * The object to destroy properties on.
  1584. *
  1585. * @param {*} [except]
  1586. * Exception, do not destroy this property, only delete it.
  1587. */
  1588. H.destroyObjectProperties = function (obj, except) {
  1589. H.objectEach(obj, function (val, n) {
  1590. // If the object is non-null and destroy is defined
  1591. if (val && val !== except && val.destroy) {
  1592. // Invoke the destroy
  1593. val.destroy();
  1594. }
  1595. // Delete the property from the object.
  1596. delete obj[n];
  1597. });
  1598. };
  1599. /**
  1600. * Discard a HTML element by moving it to the bin and delete.
  1601. *
  1602. * @function Highcharts.discardElement
  1603. *
  1604. * @param {Highcharts.HTMLDOMElement} element
  1605. * The HTML node to discard.
  1606. */
  1607. H.discardElement = function (element) {
  1608. var garbageBin = H.garbageBin;
  1609. // create a garbage bin element, not part of the DOM
  1610. if (!garbageBin) {
  1611. garbageBin = H.createElement('div');
  1612. }
  1613. // move the node and empty bin
  1614. if (element) {
  1615. garbageBin.appendChild(element);
  1616. }
  1617. garbageBin.innerHTML = '';
  1618. };
  1619. /**
  1620. * Fix JS round off float errors.
  1621. *
  1622. * @function Highcharts.correctFloat
  1623. *
  1624. * @param {number} num
  1625. * A float number to fix.
  1626. *
  1627. * @param {number} [prec=14]
  1628. * The precision.
  1629. *
  1630. * @return {number}
  1631. * The corrected float number.
  1632. */
  1633. H.correctFloat = function (num, prec) {
  1634. return parseFloat(
  1635. num.toPrecision(prec || 14)
  1636. );
  1637. };
  1638. /**
  1639. * Set the global animation to either a given value, or fall back to the given
  1640. * chart's animation option.
  1641. *
  1642. * @function Highcharts.setAnimation
  1643. *
  1644. * @param {boolean|Highcharts.AnimationOptionsObject} animation
  1645. * The animation object.
  1646. *
  1647. * @param {Highcharts.Chart} chart
  1648. * The chart instance.
  1649. *
  1650. * @todo
  1651. * This function always relates to a chart, and sets a property on the renderer,
  1652. * so it should be moved to the SVGRenderer.
  1653. */
  1654. H.setAnimation = function (animation, chart) {
  1655. chart.renderer.globalAnimation = H.pick(
  1656. animation,
  1657. chart.options.chart.animation,
  1658. true
  1659. );
  1660. };
  1661. /**
  1662. * Get the animation in object form, where a disabled animation is always
  1663. * returned as `{ duration: 0 }`.
  1664. *
  1665. * @function Highcharts.animObject
  1666. *
  1667. * @param {boolean|Highcharts.AnimationOptionsObject} animation
  1668. * An animation setting. Can be an object with duration, complete and
  1669. * easing properties, or a boolean to enable or disable.
  1670. *
  1671. * @return {Highcharts.AnimationOptionsObject}
  1672. * An object with at least a duration property.
  1673. */
  1674. H.animObject = function (animation) {
  1675. return H.isObject(animation) ?
  1676. H.merge(animation) :
  1677. { duration: animation ? 500 : 0 };
  1678. };
  1679. /**
  1680. * The time unit lookup
  1681. *
  1682. * @ignore
  1683. */
  1684. H.timeUnits = {
  1685. millisecond: 1,
  1686. second: 1000,
  1687. minute: 60000,
  1688. hour: 3600000,
  1689. day: 24 * 3600000,
  1690. week: 7 * 24 * 3600000,
  1691. month: 28 * 24 * 3600000,
  1692. year: 364 * 24 * 3600000
  1693. };
  1694. /**
  1695. * Format a number and return a string based on input settings.
  1696. *
  1697. * @sample highcharts/members/highcharts-numberformat/
  1698. * Custom number format
  1699. *
  1700. * @function Highcharts.numberFormat
  1701. *
  1702. * @param {number} number
  1703. * The input number to format.
  1704. *
  1705. * @param {number} decimals
  1706. * The amount of decimals. A value of -1 preserves the amount in the
  1707. * input number.
  1708. *
  1709. * @param {string} [decimalPoint]
  1710. * The decimal point, defaults to the one given in the lang options, or
  1711. * a dot.
  1712. *
  1713. * @param {string} [thousandsSep]
  1714. * The thousands separator, defaults to the one given in the lang
  1715. * options, or a space character.
  1716. *
  1717. * @return {string}
  1718. * The formatted number.
  1719. */
  1720. H.numberFormat = function (number, decimals, decimalPoint, thousandsSep) {
  1721. number = +number || 0;
  1722. decimals = +decimals;
  1723. var lang = H.defaultOptions.lang,
  1724. origDec = (number.toString().split('.')[1] || '').split('e')[0].length,
  1725. strinteger,
  1726. thousands,
  1727. ret,
  1728. roundedNumber,
  1729. exponent = number.toString().split('e'),
  1730. fractionDigits;
  1731. if (decimals === -1) {
  1732. // Preserve decimals. Not huge numbers (#3793).
  1733. decimals = Math.min(origDec, 20);
  1734. } else if (!H.isNumber(decimals)) {
  1735. decimals = 2;
  1736. } else if (decimals && exponent[1] && exponent[1] < 0) {
  1737. // Expose decimals from exponential notation (#7042)
  1738. fractionDigits = decimals + +exponent[1];
  1739. if (fractionDigits >= 0) {
  1740. // remove too small part of the number while keeping the notation
  1741. exponent[0] = (+exponent[0]).toExponential(fractionDigits)
  1742. .split('e')[0];
  1743. decimals = fractionDigits;
  1744. } else {
  1745. // fractionDigits < 0
  1746. exponent[0] = exponent[0].split('.')[0] || 0;
  1747. if (decimals < 20) {
  1748. // use number instead of exponential notation (#7405)
  1749. number = (exponent[0] * Math.pow(10, exponent[1]))
  1750. .toFixed(decimals);
  1751. } else {
  1752. // or zero
  1753. number = 0;
  1754. }
  1755. exponent[1] = 0;
  1756. }
  1757. }
  1758. // Add another decimal to avoid rounding errors of float numbers. (#4573)
  1759. // Then use toFixed to handle rounding.
  1760. roundedNumber = (
  1761. Math.abs(exponent[1] ? exponent[0] : number) +
  1762. Math.pow(10, -Math.max(decimals, origDec) - 1)
  1763. ).toFixed(decimals);
  1764. // A string containing the positive integer component of the number
  1765. strinteger = String(H.pInt(roundedNumber));
  1766. // Leftover after grouping into thousands. Can be 0, 1 or 2.
  1767. thousands = strinteger.length > 3 ? strinteger.length % 3 : 0;
  1768. // Language
  1769. decimalPoint = H.pick(decimalPoint, lang.decimalPoint);
  1770. thousandsSep = H.pick(thousandsSep, lang.thousandsSep);
  1771. // Start building the return
  1772. ret = number < 0 ? '-' : '';
  1773. // Add the leftover after grouping into thousands. For example, in the
  1774. // number 42 000 000, this line adds 42.
  1775. ret += thousands ? strinteger.substr(0, thousands) + thousandsSep : '';
  1776. // Add the remaining thousands groups, joined by the thousands separator
  1777. ret += strinteger
  1778. .substr(thousands)
  1779. .replace(/(\d{3})(?=\d)/g, '$1' + thousandsSep);
  1780. // Add the decimal point and the decimal component
  1781. if (decimals) {
  1782. // Get the decimal component
  1783. ret += decimalPoint + roundedNumber.slice(-decimals);
  1784. }
  1785. if (exponent[1] && +ret !== 0) {
  1786. ret += 'e' + exponent[1];
  1787. }
  1788. return ret;
  1789. };
  1790. /**
  1791. * Easing definition
  1792. *
  1793. * @private
  1794. * @function Math.easeInOutSine
  1795. *
  1796. * @param {number} pos
  1797. * Current position, ranging from 0 to 1.
  1798. *
  1799. * @return {number}
  1800. */
  1801. Math.easeInOutSine = function (pos) {
  1802. return -0.5 * (Math.cos(Math.PI * pos) - 1);
  1803. };
  1804. /**
  1805. * Get the computed CSS value for given element and property, only for numerical
  1806. * properties. For width and height, the dimension of the inner box (excluding
  1807. * padding) is returned. Used for fitting the chart within the container.
  1808. *
  1809. * @function Highcharts.getStyle
  1810. *
  1811. * @param {Highcharts.HTMLDOMElement} el
  1812. * An HTML element.
  1813. *
  1814. * @param {string} prop
  1815. * The property name.
  1816. *
  1817. * @param {boolean} [toInt=true]
  1818. * Parse to integer.
  1819. *
  1820. * @return {number}
  1821. * The numeric value.
  1822. */
  1823. H.getStyle = function (el, prop, toInt) {
  1824. var style;
  1825. // For width and height, return the actual inner pixel size (#4913)
  1826. if (prop === 'width') {
  1827. return Math.max(
  1828. 0, // #8377
  1829. (
  1830. Math.min(
  1831. el.offsetWidth,
  1832. el.scrollWidth,
  1833. (
  1834. el.getBoundingClientRect &&
  1835. // #9871, getBoundingClientRect doesn't handle
  1836. // transforms, so avoid that
  1837. H.getStyle(el, 'transform', false) === 'none'
  1838. ) ?
  1839. Math.floor(el.getBoundingClientRect().width) : // #6427
  1840. Infinity
  1841. ) -
  1842. H.getStyle(el, 'padding-left') -
  1843. H.getStyle(el, 'padding-right')
  1844. )
  1845. );
  1846. }
  1847. if (prop === 'height') {
  1848. return Math.max(
  1849. 0, // #8377
  1850. Math.min(el.offsetHeight, el.scrollHeight) -
  1851. H.getStyle(el, 'padding-top') -
  1852. H.getStyle(el, 'padding-bottom')
  1853. );
  1854. }
  1855. if (!win.getComputedStyle) {
  1856. // SVG not supported, forgot to load oldie.js?
  1857. H.error(27, true);
  1858. }
  1859. // Otherwise, get the computed style
  1860. style = win.getComputedStyle(el, undefined);
  1861. if (style) {
  1862. style = style.getPropertyValue(prop);
  1863. if (H.pick(toInt, prop !== 'opacity')) {
  1864. style = H.pInt(style);
  1865. }
  1866. }
  1867. return style;
  1868. };
  1869. /**
  1870. * Search for an item in an array.
  1871. *
  1872. * @function Highcharts.inArray
  1873. *
  1874. * @deprecated
  1875. *
  1876. * @param {*} item
  1877. * The item to search for.
  1878. *
  1879. * @param {Array} arr
  1880. * The array or node collection to search in.
  1881. *
  1882. * @param {number} [fromIndex=0]
  1883. * The index to start searching from.
  1884. *
  1885. * @return {number}
  1886. * The index within the array, or -1 if not found.
  1887. */
  1888. H.inArray = function (item, arr, fromIndex) {
  1889. return arr.indexOf(item, fromIndex);
  1890. };
  1891. /**
  1892. * Return the value of the first element in the array that satisfies the
  1893. * provided testing function.
  1894. *
  1895. * @function Highcharts.find
  1896. *
  1897. * @param {Array} arr
  1898. * The array to test.
  1899. *
  1900. * @param {Function} callback
  1901. * The callback function. The function receives the item as the first
  1902. * argument. Return `true` if this item satisfies the condition.
  1903. *
  1904. * @return {*}
  1905. * The value of the element.
  1906. */
  1907. H.find = Array.prototype.find ?
  1908. function (arr, callback) {
  1909. return arr.find(callback);
  1910. } :
  1911. // Legacy implementation. PhantomJS, IE <= 11 etc. #7223.
  1912. function (arr, fn) {
  1913. var i,
  1914. length = arr.length;
  1915. for (i = 0; i < length; i++) {
  1916. if (fn(arr[i], i)) {
  1917. return arr[i];
  1918. }
  1919. }
  1920. };
  1921. /**
  1922. * Returns an array of a given object's own properties.
  1923. *
  1924. * @function Highcharts.keys
  1925. * @deprecated
  1926. *
  1927. * @param {*} obj
  1928. * The object of which the properties are to be returned.
  1929. *
  1930. * @return {Array<string>}
  1931. * An array of strings that represents all the properties.
  1932. */
  1933. H.keys = Object.keys;
  1934. /**
  1935. * Get the element's offset position, corrected for `overflow: auto`.
  1936. *
  1937. * @function Highcharts.offset
  1938. *
  1939. * @param {Highcharts.HTMLDOMElement} el
  1940. * The HTML element.
  1941. *
  1942. * @return {Highcharts.OffsetObject}
  1943. * An object containing `left` and `top` properties for the position in
  1944. * the page.
  1945. */
  1946. H.offset = function (el) {
  1947. var docElem = doc.documentElement,
  1948. box = (el.parentElement || el.parentNode) ?
  1949. el.getBoundingClientRect() :
  1950. { top: 0, left: 0 };
  1951. return {
  1952. top: box.top + (win.pageYOffset || docElem.scrollTop) -
  1953. (docElem.clientTop || 0),
  1954. left: box.left + (win.pageXOffset || docElem.scrollLeft) -
  1955. (docElem.clientLeft || 0)
  1956. };
  1957. };
  1958. /**
  1959. * Stop running animation.
  1960. *
  1961. * @function Highcharts.stop
  1962. *
  1963. * @param {Highcharts.SVGElement} el
  1964. * The SVGElement to stop animation on.
  1965. *
  1966. * @param {string} [prop]
  1967. * The property to stop animating. If given, the stop method will stop a
  1968. * single property from animating, while others continue.
  1969. *
  1970. * @todo
  1971. * A possible extension to this would be to stop a single property, when
  1972. * we want to continue animating others. Then assign the prop to the timer
  1973. * in the Fx.run method, and check for the prop here. This would be an
  1974. * improvement in all cases where we stop the animation from .attr. Instead of
  1975. * stopping everything, we can just stop the actual attributes we're setting.
  1976. */
  1977. H.stop = function (el, prop) {
  1978. var i = H.timers.length;
  1979. // Remove timers related to this element (#4519)
  1980. while (i--) {
  1981. if (H.timers[i].elem === el && (!prop || prop === H.timers[i].prop)) {
  1982. H.timers[i].stopped = true; // #4667
  1983. }
  1984. }
  1985. };
  1986. /**
  1987. * Iterate over object key pairs in an object.
  1988. *
  1989. * @function Highcharts.objectEach
  1990. *
  1991. * @param {*} obj
  1992. * The object to iterate over.
  1993. *
  1994. * @param {Highcharts.ObjectEachCallbackFunction} fn
  1995. * The iterator callback. It passes three arguments:
  1996. * * value - The property value.
  1997. * * key - The property key.
  1998. * * obj - The object that objectEach is being applied to.
  1999. *
  2000. * @param {*} [ctx]
  2001. * The context.
  2002. */
  2003. H.objectEach = function (obj, fn, ctx) {
  2004. for (var key in obj) {
  2005. if (obj.hasOwnProperty(key)) {
  2006. fn.call(ctx || obj[key], obj[key], key, obj);
  2007. }
  2008. }
  2009. };
  2010. /**
  2011. * Iterate over an array.
  2012. *
  2013. * @deprecated
  2014. * @function Highcharts.each
  2015. *
  2016. * @param {Array<*>} arr
  2017. * The array to iterate over.
  2018. *
  2019. * @param {Function} fn
  2020. * The iterator callback. It passes three arguments:
  2021. * - `item`: The array item.
  2022. * - `index`: The item's index in the array.
  2023. * - `arr`: The array that each is being applied to.
  2024. *
  2025. * @param {*} [ctx]
  2026. * The context.
  2027. */
  2028. /**
  2029. * Filter an array by a callback.
  2030. *
  2031. * @deprecated
  2032. * @function Highcharts.grep
  2033. *
  2034. * @param {Array<*>} arr
  2035. * The array to filter.
  2036. *
  2037. * @param {Function} callback
  2038. * The callback function. The function receives the item as the first
  2039. * argument. Return `true` if the item is to be preserved.
  2040. *
  2041. * @return {Array<*>}
  2042. * A new, filtered array.
  2043. */
  2044. /**
  2045. * Map an array by a callback.
  2046. *
  2047. * @deprecated
  2048. * @function Highcharts.map
  2049. *
  2050. * @param {Array<*>} arr
  2051. * The array to map.
  2052. *
  2053. * @param {Function} fn
  2054. * The callback function. Return the new value for the new array.
  2055. *
  2056. * @return {Array<*>}
  2057. * A new array item with modified items.
  2058. */
  2059. /**
  2060. * Reduce an array to a single value.
  2061. *
  2062. * @deprecated
  2063. * @function Highcharts.reduce
  2064. *
  2065. * @param {Array} arr
  2066. * The array to reduce.
  2067. *
  2068. * @param {Function} fn
  2069. * The callback function. Return the reduced value. Receives 4
  2070. * arguments: Accumulated/reduced value, current value, current array
  2071. * index, and the array.
  2072. *
  2073. * @param {*} initialValue
  2074. * The initial value of the accumulator.
  2075. *
  2076. * @return {*}
  2077. * The reduced value.
  2078. */
  2079. /**
  2080. * Test whether at least one element in the array passes the test implemented by
  2081. * the provided function.
  2082. *
  2083. * @deprecated
  2084. * @function Highcharts.some
  2085. *
  2086. * @param {Array<*>} arr
  2087. * The array to test
  2088. *
  2089. * @param {Function} fn
  2090. * The function to run on each item. Return truty to pass the test.
  2091. * Receives arguments `currentValue`, `index` and `array`.
  2092. *
  2093. * @param {*} ctx
  2094. * The context.
  2095. *
  2096. * @return {boolean}
  2097. */
  2098. H.objectEach({
  2099. map: 'map',
  2100. each: 'forEach',
  2101. grep: 'filter',
  2102. reduce: 'reduce',
  2103. some: 'some'
  2104. }, function (val, key) {
  2105. H[key] = function (arr) {
  2106. return Array.prototype[val].apply(
  2107. arr,
  2108. [].slice.call(arguments, 1)
  2109. );
  2110. };
  2111. });
  2112. /**
  2113. * Add an event listener.
  2114. *
  2115. * @function Highcharts.addEvent<T>
  2116. *
  2117. * @param {T} el
  2118. * The element or object to add a listener to. It can be a
  2119. * {@link HTMLDOMElement}, an {@link SVGElement} or any other object.
  2120. *
  2121. * @param {string} type
  2122. * The event type.
  2123. *
  2124. * @param {Highcharts.EventCallbackFunction<T>} fn
  2125. * The function callback to execute when the event is fired.
  2126. *
  2127. * @param {Highcharts.EventOptionsObject} [options]
  2128. * Options for adding the event.
  2129. *
  2130. * @return {Function}
  2131. * A callback function to remove the added event.
  2132. */
  2133. H.addEvent = function (el, type, fn, options) {
  2134. var events,
  2135. addEventListener = el.addEventListener || H.addEventListenerPolyfill;
  2136. // If we're setting events directly on the constructor, use a separate
  2137. // collection, `protoEvents` to distinguish it from the item events in
  2138. // `hcEvents`.
  2139. if (typeof el === 'function' && el.prototype) {
  2140. events = el.prototype.protoEvents = el.prototype.protoEvents || {};
  2141. } else {
  2142. events = el.hcEvents = el.hcEvents || {};
  2143. }
  2144. // Allow click events added to points, otherwise they will be prevented by
  2145. // the TouchPointer.pinch function after a pinch zoom operation (#7091).
  2146. if (H.Point && el instanceof H.Point && el.series && el.series.chart) {
  2147. el.series.chart.runTrackerClick = true;
  2148. }
  2149. // Handle DOM events
  2150. if (addEventListener) {
  2151. addEventListener.call(el, type, fn, false);
  2152. }
  2153. if (!events[type]) {
  2154. events[type] = [];
  2155. }
  2156. events[type].push(fn);
  2157. // Order the calls
  2158. if (options && H.isNumber(options.order)) {
  2159. fn.order = options.order;
  2160. events[type].sort(function (a, b) {
  2161. return a.order - b.order;
  2162. });
  2163. }
  2164. // Return a function that can be called to remove this event.
  2165. return function () {
  2166. H.removeEvent(el, type, fn);
  2167. };
  2168. };
  2169. /**
  2170. * Remove an event that was added with {@link Highcharts#addEvent}.
  2171. *
  2172. * @function Highcharts.removeEvent<T>
  2173. *
  2174. * @param {T} el
  2175. * The element to remove events on.
  2176. *
  2177. * @param {string} [type]
  2178. * The type of events to remove. If undefined, all events are removed
  2179. * from the element.
  2180. *
  2181. * @param {Highcharts.EventCallbackFunction<T>} [fn]
  2182. * The specific callback to remove. If undefined, all events that match
  2183. * the element and optionally the type are removed.
  2184. */
  2185. H.removeEvent = function (el, type, fn) {
  2186. var events,
  2187. index;
  2188. function removeOneEvent(type, fn) {
  2189. var removeEventListener =
  2190. el.removeEventListener || H.removeEventListenerPolyfill;
  2191. if (removeEventListener) {
  2192. removeEventListener.call(el, type, fn, false);
  2193. }
  2194. }
  2195. function removeAllEvents(eventCollection) {
  2196. var types,
  2197. len;
  2198. if (!el.nodeName) {
  2199. return; // break on non-DOM events
  2200. }
  2201. if (type) {
  2202. types = {};
  2203. types[type] = true;
  2204. } else {
  2205. types = eventCollection;
  2206. }
  2207. H.objectEach(types, function (val, n) {
  2208. if (eventCollection[n]) {
  2209. len = eventCollection[n].length;
  2210. while (len--) {
  2211. removeOneEvent(n, eventCollection[n][len]);
  2212. }
  2213. }
  2214. });
  2215. }
  2216. ['protoEvents', 'hcEvents'].forEach(function (coll) {
  2217. var eventCollection = el[coll];
  2218. if (eventCollection) {
  2219. if (type) {
  2220. events = eventCollection[type] || [];
  2221. if (fn) {
  2222. index = events.indexOf(fn);
  2223. if (index > -1) {
  2224. events.splice(index, 1);
  2225. eventCollection[type] = events;
  2226. }
  2227. removeOneEvent(type, fn);
  2228. } else {
  2229. removeAllEvents(eventCollection);
  2230. eventCollection[type] = [];
  2231. }
  2232. } else {
  2233. removeAllEvents(eventCollection);
  2234. el[coll] = {};
  2235. }
  2236. }
  2237. });
  2238. };
  2239. /**
  2240. * Fire an event that was registered with {@link Highcharts#addEvent}.
  2241. *
  2242. * @function Highcharts.fireEvent
  2243. *
  2244. * @param {*} el
  2245. * The object to fire the event on. It can be a {@link HTMLDOMElement},
  2246. * an {@link SVGElement} or any other object.
  2247. *
  2248. * @param {string} type
  2249. * The type of event.
  2250. *
  2251. * @param {Highcharts.Dictionary<*>} [eventArguments]
  2252. * Custom event arguments that are passed on as an argument to the event
  2253. * handler.
  2254. *
  2255. * @param {Function} [defaultFunction]
  2256. * The default function to execute if the other listeners haven't
  2257. * returned false.
  2258. */
  2259. H.fireEvent = function (el, type, eventArguments, defaultFunction) {
  2260. var e,
  2261. events,
  2262. len,
  2263. i,
  2264. fn;
  2265. eventArguments = eventArguments || {};
  2266. if (doc.createEvent && (el.dispatchEvent || el.fireEvent)) {
  2267. e = doc.createEvent('Events');
  2268. e.initEvent(type, true, true);
  2269. H.extend(e, eventArguments);
  2270. if (el.dispatchEvent) {
  2271. el.dispatchEvent(e);
  2272. } else {
  2273. el.fireEvent(type, e);
  2274. }
  2275. } else {
  2276. ['protoEvents', 'hcEvents'].forEach(function (coll) {
  2277. if (el[coll]) {
  2278. events = el[coll][type] || [];
  2279. len = events.length;
  2280. if (!eventArguments.target) { // We're running a custom event
  2281. H.extend(eventArguments, {
  2282. // Attach a simple preventDefault function to skip
  2283. // default handler if called. The built-in
  2284. // defaultPrevented property is not overwritable (#5112)
  2285. preventDefault: function () {
  2286. eventArguments.defaultPrevented = true;
  2287. },
  2288. // Setting target to native events fails with clicking
  2289. // the zoom-out button in Chrome.
  2290. target: el,
  2291. // If the type is not set, we're running a custom event
  2292. // (#2297). If it is set, we're running a browser event,
  2293. // and setting it will cause en error in IE8 (#2465).
  2294. type: type
  2295. });
  2296. }
  2297. for (i = 0; i < len; i++) {
  2298. fn = events[i];
  2299. // If the event handler return false, prevent the default
  2300. // handler from executing
  2301. if (fn && fn.call(el, eventArguments) === false) {
  2302. eventArguments.preventDefault();
  2303. }
  2304. }
  2305. }
  2306. });
  2307. }
  2308. // Run the default if not prevented
  2309. if (defaultFunction && !eventArguments.defaultPrevented) {
  2310. defaultFunction.call(el, eventArguments);
  2311. }
  2312. };
  2313. /**
  2314. * The global animate method, which uses Fx to create individual animators.
  2315. *
  2316. * @function Highcharts.animate
  2317. *
  2318. * @param {Highcharts.HTMLDOMElement|Highcharts.SVGElement} el
  2319. * The element to animate.
  2320. *
  2321. * @param {Highcharts.HTMLAttributes|Highcharts.SVGAttributes} params
  2322. * An object containing key-value pairs of the properties to animate.
  2323. * Supports numeric as pixel-based CSS properties for HTML objects and
  2324. * attributes for SVGElements.
  2325. *
  2326. * @param {Highcharts.AnimationOptionsObject} [opt]
  2327. * Animation options.
  2328. */
  2329. H.animate = function (el, params, opt) {
  2330. var start,
  2331. unit = '',
  2332. end,
  2333. fx,
  2334. args;
  2335. if (!H.isObject(opt)) { // Number or undefined/null
  2336. args = arguments;
  2337. opt = {
  2338. duration: args[2],
  2339. easing: args[3],
  2340. complete: args[4]
  2341. };
  2342. }
  2343. if (!H.isNumber(opt.duration)) {
  2344. opt.duration = 400;
  2345. }
  2346. opt.easing = typeof opt.easing === 'function' ?
  2347. opt.easing :
  2348. (Math[opt.easing] || Math.easeInOutSine);
  2349. opt.curAnim = H.merge(params);
  2350. H.objectEach(params, function (val, prop) {
  2351. // Stop current running animation of this property
  2352. H.stop(el, prop);
  2353. fx = new H.Fx(el, opt, prop);
  2354. end = null;
  2355. if (prop === 'd') {
  2356. fx.paths = fx.initPath(
  2357. el,
  2358. el.d,
  2359. params.d
  2360. );
  2361. fx.toD = params.d;
  2362. start = 0;
  2363. end = 1;
  2364. } else if (el.attr) {
  2365. start = el.attr(prop);
  2366. } else {
  2367. start = parseFloat(H.getStyle(el, prop)) || 0;
  2368. if (prop !== 'opacity') {
  2369. unit = 'px';
  2370. }
  2371. }
  2372. if (!end) {
  2373. end = val;
  2374. }
  2375. if (end && end.match && end.match('px')) {
  2376. end = end.replace(/px/g, ''); // #4351
  2377. }
  2378. fx.run(start, end, unit);
  2379. });
  2380. };
  2381. /**
  2382. * Factory to create new series prototypes.
  2383. *
  2384. * @function Highcharts.seriesType
  2385. *
  2386. * @param {string} type
  2387. * The series type name.
  2388. *
  2389. * @param {string} parent
  2390. * The parent series type name. Use `line` to inherit from the basic
  2391. * {@link Series} object.
  2392. *
  2393. * @param {*} options
  2394. * The additional default options that is merged with the parent's
  2395. * options.
  2396. *
  2397. * @param {*} props
  2398. * The properties (functions and primitives) to set on the new
  2399. * prototype.
  2400. *
  2401. * @param {*} [pointProps]
  2402. * Members for a series-specific extension of the {@link Point}
  2403. * prototype if needed.
  2404. *
  2405. * @return {Highcharts.Series}
  2406. * The newly created prototype as extended from {@link Series} or its
  2407. * derivatives.
  2408. */
  2409. // docs: add to API + extending Highcharts
  2410. H.seriesType = function (type, parent, options, props, pointProps) {
  2411. var defaultOptions = H.getOptions(),
  2412. seriesTypes = H.seriesTypes;
  2413. // Merge the options
  2414. defaultOptions.plotOptions[type] = H.merge(
  2415. defaultOptions.plotOptions[parent],
  2416. options
  2417. );
  2418. // Create the class
  2419. seriesTypes[type] = H.extendClass(seriesTypes[parent] ||
  2420. function () {}, props);
  2421. seriesTypes[type].prototype.type = type;
  2422. // Create the point class if needed
  2423. if (pointProps) {
  2424. seriesTypes[type].prototype.pointClass =
  2425. H.extendClass(H.Point, pointProps);
  2426. }
  2427. return seriesTypes[type];
  2428. };
  2429. /**
  2430. * Get a unique key for using in internal element id's and pointers. The key is
  2431. * composed of a random hash specific to this Highcharts instance, and a
  2432. * counter.
  2433. *
  2434. * @example
  2435. * var id = H.uniqueKey(); // => 'highcharts-x45f6hp-0'
  2436. *
  2437. * @function Highcharts.uniqueKey
  2438. *
  2439. * @return {string}
  2440. * A unique key.
  2441. */
  2442. H.uniqueKey = (function () {
  2443. var uniqueKeyHash = Math.random().toString(36).substring(2, 9),
  2444. idCounter = 0;
  2445. return function () {
  2446. return 'highcharts-' + uniqueKeyHash + '-' + idCounter++;
  2447. };
  2448. }());
  2449. H.isFunction = function (obj) {
  2450. return typeof obj === 'function';
  2451. };
  2452. // Register Highcharts as a plugin in jQuery
  2453. if (win.jQuery) {
  2454. /**
  2455. * Highcharts-extended JQuery.
  2456. *
  2457. * @external JQuery
  2458. */
  2459. /**
  2460. * Helper function to return the chart of the current JQuery selector
  2461. * element.
  2462. *
  2463. * @function external:JQuery#highcharts
  2464. *
  2465. * @return {Highcharts.Chart}
  2466. * The chart that is linked to the JQuery selector element.
  2467. *//**
  2468. * Factory function to create a chart in the current JQuery selector
  2469. * element.
  2470. *
  2471. * @function external:JQuery#highcharts
  2472. *
  2473. * @param {"Chart"|"Map"|"StockChart"|string} [className]
  2474. * Name of the factory class in the Highcharts namespace.
  2475. *
  2476. * @param {Highcharts.Options} [options]
  2477. * The chart options structure.
  2478. *
  2479. * @param {Highcharts.ChartCallbackFunction} [callback]
  2480. * Function to run when the chart has loaded and and all external
  2481. * images are loaded. Defining a
  2482. * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
  2483. * handler is equivalent.
  2484. *
  2485. * @return {JQuery}
  2486. * The current JQuery selector.
  2487. */
  2488. win.jQuery.fn.highcharts = function () {
  2489. var args = [].slice.call(arguments);
  2490. if (this[0]) { // this[0] is the renderTo div
  2491. // Create the chart
  2492. if (args[0]) {
  2493. new H[ // eslint-disable-line no-new
  2494. // Constructor defaults to Chart
  2495. H.isString(args[0]) ? args.shift() : 'Chart'
  2496. ](this[0], args[0], args[1]);
  2497. return this;
  2498. }
  2499. // When called without parameters or with the return argument,
  2500. // return an existing chart
  2501. return charts[H.attr(this[0], 'data-highcharts-chart')];
  2502. }
  2503. };
  2504. }