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.

589 lines
12 KiB

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