You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

607 lines
12 KiB

9 years ago
  1. /**
  2. * @license Highcharts JS v4.1.8 (2015-08-20)
  3. *
  4. * Standalone Highcharts Framework
  5. *
  6. * License: MIT License
  7. */
  8. /*global Highcharts */
  9. var HighchartsAdapter = (function () {
  10. var UNDEFINED,
  11. doc = document,
  12. emptyArray = [],
  13. timers = [],
  14. timerId,
  15. animSetters = {},
  16. Fx;
  17. Math.easeInOutSine = function (t, b, c, d) {
  18. return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
  19. };
  20. /**
  21. * Extend given object with custom events
  22. */
  23. function augment(obj) {
  24. function removeOneEvent(el, type, fn) {
  25. el.removeEventListener(type, fn, false);
  26. }
  27. function IERemoveOneEvent(el, type, fn) {
  28. fn = el.HCProxiedMethods[fn.toString()];
  29. el.detachEvent('on' + type, fn);
  30. }
  31. function removeAllEvents(el, type) {
  32. var events = el.HCEvents,
  33. remove,
  34. types,
  35. len,
  36. n;
  37. if (el.removeEventListener) {
  38. remove = removeOneEvent;
  39. } else if (el.attachEvent) {
  40. remove = IERemoveOneEvent;
  41. } else {
  42. return; // break on non-DOM events
  43. }
  44. if (type) {
  45. types = {};
  46. types[type] = true;
  47. } else {
  48. types = events;
  49. }
  50. for (n in types) {
  51. if (events[n]) {
  52. len = events[n].length;
  53. while (len--) {
  54. remove(el, n, events[n][len]);
  55. }
  56. }
  57. }
  58. }
  59. if (!obj.HCExtended) {
  60. Highcharts.extend(obj, {
  61. HCExtended: true,
  62. HCEvents: {},
  63. bind: function (name, fn) {
  64. var el = this,
  65. events = this.HCEvents,
  66. wrappedFn;
  67. // handle DOM events in modern browsers
  68. if (el.addEventListener) {
  69. el.addEventListener(name, fn, false);
  70. // handle old IE implementation
  71. } else if (el.attachEvent) {
  72. wrappedFn = function (e) {
  73. e.target = e.srcElement || window; // #2820
  74. fn.call(el, e);
  75. };
  76. if (!el.HCProxiedMethods) {
  77. el.HCProxiedMethods = {};
  78. }
  79. // link wrapped fn with original fn, so we can get this in removeEvent
  80. el.HCProxiedMethods[fn.toString()] = wrappedFn;
  81. el.attachEvent('on' + name, wrappedFn);
  82. }
  83. if (events[name] === UNDEFINED) {
  84. events[name] = [];
  85. }
  86. events[name].push(fn);
  87. },
  88. unbind: function (name, fn) {
  89. var events,
  90. index;
  91. if (name) {
  92. events = this.HCEvents[name] || [];
  93. if (fn) {
  94. index = HighchartsAdapter.inArray(fn, events);
  95. if (index > -1) {
  96. events.splice(index, 1);
  97. this.HCEvents[name] = events;
  98. }
  99. if (this.removeEventListener) {
  100. removeOneEvent(this, name, fn);
  101. } else if (this.attachEvent) {
  102. IERemoveOneEvent(this, name, fn);
  103. }
  104. } else {
  105. removeAllEvents(this, name);
  106. this.HCEvents[name] = [];
  107. }
  108. } else {
  109. removeAllEvents(this);
  110. this.HCEvents = {};
  111. }
  112. },
  113. trigger: function (name, args) {
  114. var events = this.HCEvents[name] || [],
  115. target = this,
  116. len = events.length,
  117. i,
  118. preventDefault,
  119. fn;
  120. // Attach a simple preventDefault function to skip default handler if called
  121. preventDefault = function () {
  122. args.defaultPrevented = true;
  123. };
  124. for (i = 0; i < len; i++) {
  125. fn = events[i];
  126. // args is never null here
  127. if (args.stopped) {
  128. return;
  129. }
  130. args.preventDefault = preventDefault;
  131. args.target = target;
  132. // If the type is not set, we're running a custom event (#2297). If it is set,
  133. // we're running a browser event, and setting it will cause en error in
  134. // IE8 (#2465).
  135. if (!args.type) {
  136. args.type = name;
  137. }
  138. // If the event handler return false, prevent the default handler from executing
  139. if (fn.call(this, args) === false) {
  140. args.preventDefault();
  141. }
  142. }
  143. }
  144. });
  145. }
  146. return obj;
  147. }
  148. return {
  149. /**
  150. * Initialize the adapter. This is run once as Highcharts is first run.
  151. */
  152. init: function (pathAnim) {
  153. /**
  154. * Compatibility section to add support for legacy IE. This can be removed if old IE
  155. * support is not needed.
  156. */
  157. if (!doc.defaultView) {
  158. this._getStyle = function (el, prop) {
  159. var val;
  160. if (el.style[prop]) {
  161. return el.style[prop];
  162. } else {
  163. if (prop === 'opacity') {
  164. prop = 'filter';
  165. }
  166. /*jslint unparam: true*/
  167. val = el.currentStyle[prop.replace(/\-(\w)/g, function (a, b) { return b.toUpperCase(); })];
  168. if (prop === 'filter') {
  169. val = val.replace(
  170. /alpha\(opacity=([0-9]+)\)/,
  171. function (a, b) {
  172. return b / 100;
  173. }
  174. );
  175. }
  176. /*jslint unparam: false*/
  177. return val === '' ? 1 : val;
  178. }
  179. };
  180. this.adapterRun = function (elem, method) {
  181. var alias = { width: 'clientWidth', height: 'clientHeight' }[method];
  182. if (alias) {
  183. elem.style.zoom = 1;
  184. return elem[alias] - 2 * parseInt(HighchartsAdapter._getStyle(elem, 'padding'), 10);
  185. }
  186. };
  187. }
  188. if (!Array.prototype.forEach) {
  189. this.each = function (arr, fn) { // legacy
  190. var i = 0,
  191. len = arr.length;
  192. for (; i < len; i++) {
  193. if (fn.call(arr[i], arr[i], i, arr) === false) {
  194. return i;
  195. }
  196. }
  197. };
  198. }
  199. if (!Array.prototype.indexOf) {
  200. this.inArray = function (item, arr) {
  201. var len,
  202. i = 0;
  203. if (arr) {
  204. len = arr.length;
  205. for (; i < len; i++) {
  206. if (arr[i] === item) {
  207. return i;
  208. }
  209. }
  210. }
  211. return -1;
  212. };
  213. }
  214. if (!Array.prototype.filter) {
  215. this.grep = function (elements, callback) {
  216. var ret = [],
  217. i = 0,
  218. length = elements.length;
  219. for (; i < length; i++) {
  220. if (!!callback(elements[i], i)) {
  221. ret.push(elements[i]);
  222. }
  223. }
  224. return ret;
  225. };
  226. }
  227. //--- End compatibility section ---
  228. /**
  229. * Start of animation specific code
  230. */
  231. Fx = function (elem, options, prop) {
  232. this.options = options;
  233. this.elem = elem;
  234. this.prop = prop;
  235. };
  236. Fx.prototype = {
  237. update: function () {
  238. var styles,
  239. paths = this.paths,
  240. elem = this.elem,
  241. elemelem = elem.element; // if destroyed, it is null
  242. // Animation setter defined from outside
  243. if (animSetters[this.prop]) {
  244. animSetters[this.prop](this);
  245. // Animating a path definition on SVGElement
  246. } else if (paths && elemelem) {
  247. elem.attr('d', pathAnim.step(paths[0], paths[1], this.now, this.toD));
  248. // Other animations on SVGElement
  249. } else if (elem.attr) {
  250. if (elemelem) {
  251. elem.attr(this.prop, this.now);
  252. }
  253. // HTML styles
  254. } else {
  255. styles = {};
  256. styles[this.prop] = this.now + this.unit;
  257. Highcharts.css(elem, styles);
  258. }
  259. if (this.options.step) {
  260. this.options.step.call(this.elem, this.now, this);
  261. }
  262. },
  263. custom: function (from, to, unit) {
  264. var self = this,
  265. t = function (gotoEnd) {
  266. return self.step(gotoEnd);
  267. },
  268. i;
  269. this.startTime = +new Date();
  270. this.start = from;
  271. this.end = to;
  272. this.unit = unit;
  273. this.now = this.start;
  274. this.pos = this.state = 0;
  275. t.elem = this.elem;
  276. if (t() && timers.push(t) === 1) {
  277. timerId = setInterval(function () {
  278. for (i = 0; i < timers.length; i++) {
  279. if (!timers[i]()) {
  280. timers.splice(i--, 1);
  281. }
  282. }
  283. if (!timers.length) {
  284. clearInterval(timerId);
  285. }
  286. }, 13);
  287. }
  288. },
  289. step: function (gotoEnd) {
  290. var t = +new Date(),
  291. ret,
  292. done,
  293. options = this.options,
  294. elem = this.elem,
  295. i;
  296. if (elem.stopAnimation || (elem.attr && !elem.element)) { // #2616, element including flag is destroyed
  297. ret = false;
  298. } else if (gotoEnd || t >= options.duration + this.startTime) {
  299. this.now = this.end;
  300. this.pos = this.state = 1;
  301. this.update();
  302. this.options.curAnim[this.prop] = true;
  303. done = true;
  304. for (i in options.curAnim) {
  305. if (options.curAnim[i] !== true) {
  306. done = false;
  307. }
  308. }
  309. if (done) {
  310. if (options.complete) {
  311. options.complete.call(elem);
  312. }
  313. }
  314. ret = false;
  315. } else {
  316. var n = t - this.startTime;
  317. this.state = n / options.duration;
  318. this.pos = options.easing(n, 0, 1, options.duration);
  319. this.now = this.start + ((this.end - this.start) * this.pos);
  320. this.update();
  321. ret = true;
  322. }
  323. return ret;
  324. }
  325. };
  326. /**
  327. * The adapter animate method
  328. */
  329. this.animate = function (el, prop, opt) {
  330. var start,
  331. unit = '',
  332. end,
  333. fx,
  334. args,
  335. name,
  336. PX = 'px';
  337. el.stopAnimation = false; // ready for new
  338. if (typeof opt !== 'object' || opt === null) {
  339. args = arguments;
  340. opt = {
  341. duration: args[2],
  342. easing: args[3],
  343. complete: args[4]
  344. };
  345. }
  346. if (typeof opt.duration !== 'number') {
  347. opt.duration = 400;
  348. }
  349. opt.easing = Math[opt.easing] || Math.easeInOutSine;
  350. opt.curAnim = Highcharts.extend({}, prop);
  351. for (name in prop) {
  352. fx = new Fx(el, opt, name);
  353. end = null;
  354. if (name === 'd') {
  355. fx.paths = pathAnim.init(
  356. el,
  357. el.d,
  358. prop.d
  359. );
  360. fx.toD = prop.d;
  361. start = 0;
  362. end = 1;
  363. } else if (el.attr) {
  364. start = el.attr(name);
  365. } else {
  366. start = parseFloat(HighchartsAdapter._getStyle(el, name)) || 0;
  367. if (name !== 'opacity') {
  368. unit = PX;
  369. }
  370. }
  371. if (!end) {
  372. end = prop[name];
  373. }
  374. if (end.match && end.match(PX)) {
  375. end = end.replace(/px/g, ''); // #4351
  376. }
  377. fx.custom(start, end, unit);
  378. }
  379. };
  380. },
  381. /**
  382. * Internal method to return CSS value for given element and property
  383. */
  384. _getStyle: function (el, prop) {
  385. return window.getComputedStyle(el, undefined).getPropertyValue(prop);
  386. },
  387. /**
  388. * Add an animation setter for a specific property
  389. */
  390. addAnimSetter: function (prop, fn) {
  391. animSetters[prop] = fn;
  392. },
  393. /**
  394. * Downloads a script and executes a callback when done.
  395. * @param {String} scriptLocation
  396. * @param {Function} callback
  397. */
  398. getScript: function (scriptLocation, callback) {
  399. // We cannot assume that Assets class from mootools-more is available so instead insert a script tag to download script.
  400. var head = doc.getElementsByTagName('head')[0],
  401. script = doc.createElement('script');
  402. script.type = 'text/javascript';
  403. script.src = scriptLocation;
  404. script.onload = callback;
  405. head.appendChild(script);
  406. },
  407. /**
  408. * Return the index of an item in an array, or -1 if not found
  409. */
  410. inArray: function (item, arr) {
  411. return arr.indexOf ? arr.indexOf(item) : emptyArray.indexOf.call(arr, item);
  412. },
  413. /**
  414. * A direct link to adapter methods
  415. */
  416. adapterRun: function (elem, method) {
  417. return parseInt(HighchartsAdapter._getStyle(elem, method), 10);
  418. },
  419. /**
  420. * Filter an array
  421. */
  422. grep: function (elements, callback) {
  423. return emptyArray.filter.call(elements, callback);
  424. },
  425. /**
  426. * Map an array
  427. */
  428. map: function (arr, fn) {
  429. var results = [], i = 0, len = arr.length;
  430. for (; i < len; i++) {
  431. results[i] = fn.call(arr[i], arr[i], i, arr);
  432. }
  433. return results;
  434. },
  435. /**
  436. * Get the element's offset position, corrected by overflow:auto. Loosely based on jQuery's offset method.
  437. */
  438. offset: function (el) {
  439. var docElem = document.documentElement,
  440. box = el.getBoundingClientRect();
  441. return {
  442. top: box.top + (window.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0),
  443. left: box.left + (window.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0)
  444. };
  445. },
  446. /**
  447. * Add an event listener
  448. */
  449. addEvent: function (el, type, fn) {
  450. augment(el).bind(type, fn);
  451. },
  452. /**
  453. * Remove event added with addEvent
  454. */
  455. removeEvent: function (el, type, fn) {
  456. augment(el).unbind(type, fn);
  457. },
  458. /**
  459. * Fire an event on a custom object
  460. */
  461. fireEvent: function (el, type, eventArguments, defaultFunction) {
  462. var e;
  463. if (doc.createEvent && (el.dispatchEvent || el.fireEvent)) {
  464. e = doc.createEvent('Events');
  465. e.initEvent(type, true, true);
  466. e.target = el;
  467. Highcharts.extend(e, eventArguments);
  468. if (el.dispatchEvent) {
  469. el.dispatchEvent(e);
  470. } else {
  471. el.fireEvent(type, e);
  472. }
  473. } else if (el.HCExtended === true) {
  474. eventArguments = eventArguments || {};
  475. el.trigger(type, eventArguments);
  476. }
  477. if (eventArguments && eventArguments.defaultPrevented) {
  478. defaultFunction = null;
  479. }
  480. if (defaultFunction) {
  481. defaultFunction(eventArguments);
  482. }
  483. },
  484. washMouseEvent: function (e) {
  485. return e;
  486. },
  487. /**
  488. * Stop running animation
  489. */
  490. stop: function (el) {
  491. el.stopAnimation = true;
  492. },
  493. /**
  494. * Utility for iterating over an array. Parameters are reversed compared to jQuery.
  495. * @param {Array} arr
  496. * @param {Function} fn
  497. */
  498. each: function (arr, fn) { // modern browsers
  499. return Array.prototype.forEach.call(arr, fn);
  500. }
  501. };
  502. }());