b02b31210d659ea75761663486b53a0837b51b37.svn-base 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /**
  2. * @license Highcharts JS v3.0.6 (2013-10-04)
  3. * Prototype adapter
  4. *
  5. * @author Michael Nelson, Torstein Hønsi.
  6. *
  7. * Feel free to use and modify this script.
  8. * Highcharts license: www.highcharts.com/license.
  9. */
  10. // JSLint options:
  11. /*global Effect, Class, Event, Element, $, $$, $A */
  12. // Adapter interface between prototype and the Highcharts charting library
  13. var HighchartsAdapter = (function () {
  14. var hasEffect = typeof Effect !== 'undefined';
  15. return {
  16. /**
  17. * Initialize the adapter. This is run once as Highcharts is first run.
  18. * @param {Object} pathAnim The helper object to do animations across adapters.
  19. */
  20. init: function (pathAnim) {
  21. if (hasEffect) {
  22. /**
  23. * Animation for Highcharts SVG element wrappers only
  24. * @param {Object} element
  25. * @param {Object} attribute
  26. * @param {Object} to
  27. * @param {Object} options
  28. */
  29. Effect.HighchartsTransition = Class.create(Effect.Base, {
  30. initialize: function (element, attr, to, options) {
  31. var from,
  32. opts;
  33. this.element = element;
  34. this.key = attr;
  35. from = element.attr ? element.attr(attr) : $(element).getStyle(attr);
  36. // special treatment for paths
  37. if (attr === 'd') {
  38. this.paths = pathAnim.init(
  39. element,
  40. element.d,
  41. to
  42. );
  43. this.toD = to;
  44. // fake values in order to read relative position as a float in update
  45. from = 0;
  46. to = 1;
  47. }
  48. opts = Object.extend((options || {}), {
  49. from: from,
  50. to: to,
  51. attribute: attr
  52. });
  53. this.start(opts);
  54. },
  55. setup: function () {
  56. HighchartsAdapter._extend(this.element);
  57. // If this is the first animation on this object, create the _highcharts_animation helper that
  58. // contain pointers to the animation objects.
  59. if (!this.element._highchart_animation) {
  60. this.element._highchart_animation = {};
  61. }
  62. // Store a reference to this animation instance.
  63. this.element._highchart_animation[this.key] = this;
  64. },
  65. update: function (position) {
  66. var paths = this.paths,
  67. element = this.element,
  68. obj;
  69. if (paths) {
  70. position = pathAnim.step(paths[0], paths[1], position, this.toD);
  71. }
  72. if (element.attr) { // SVGElement
  73. if (element.element) { // If not, it has been destroyed (#1405)
  74. element.attr(this.options.attribute, position);
  75. }
  76. } else { // HTML, #409
  77. obj = {};
  78. obj[this.options.attribute] = position;
  79. $(element).setStyle(obj);
  80. }
  81. },
  82. finish: function () {
  83. // Delete the property that holds this animation now that it is finished.
  84. // Both canceled animations and complete ones gets a 'finish' call.
  85. if (this.element && this.element._highchart_animation) { // #1405
  86. delete this.element._highchart_animation[this.key];
  87. }
  88. }
  89. });
  90. }
  91. },
  92. /**
  93. * Run a general method on the framework, following jQuery syntax
  94. * @param {Object} el The HTML element
  95. * @param {String} method Which method to run on the wrapped element
  96. */
  97. adapterRun: function (el, method) {
  98. // This currently works for getting inner width and height. If adding
  99. // more methods later, we need a conditional implementation for each.
  100. return parseInt($(el).getStyle(method), 10);
  101. },
  102. /**
  103. * Downloads a script and executes a callback when done.
  104. * @param {String} scriptLocation
  105. * @param {Function} callback
  106. */
  107. getScript: function (scriptLocation, callback) {
  108. var head = $$('head')[0]; // Returns an array, so pick the first element.
  109. if (head) {
  110. // Append a new 'script' element, set its type and src attributes, add a 'load' handler that calls the callback
  111. head.appendChild(new Element('script', { type: 'text/javascript', src: scriptLocation}).observe('load', callback));
  112. }
  113. },
  114. /**
  115. * Custom events in prototype needs to be namespaced. This method adds a namespace 'h:' in front of
  116. * events that are not recognized as native.
  117. */
  118. addNS: function (eventName) {
  119. var HTMLEvents = /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
  120. MouseEvents = /^(?:click|mouse(?:down|up|over|move|out))$/;
  121. return (HTMLEvents.test(eventName) || MouseEvents.test(eventName)) ?
  122. eventName :
  123. 'h:' + eventName;
  124. },
  125. // el needs an event to be attached. el is not necessarily a dom element
  126. addEvent: function (el, event, fn) {
  127. if (el.addEventListener || el.attachEvent) {
  128. Event.observe($(el), HighchartsAdapter.addNS(event), fn);
  129. } else {
  130. HighchartsAdapter._extend(el);
  131. el._highcharts_observe(event, fn);
  132. }
  133. },
  134. // motion makes things pretty. use it if effects is loaded, if not... still get to the end result.
  135. animate: function (el, params, options) {
  136. var key,
  137. fx;
  138. // default options
  139. options = options || {};
  140. options.delay = 0;
  141. options.duration = (options.duration || 500) / 1000;
  142. options.afterFinish = options.complete;
  143. // animate wrappers and DOM elements
  144. if (hasEffect) {
  145. for (key in params) {
  146. // The fx variable is seemingly thrown away here, but the Effect.setup will add itself to the _highcharts_animation object
  147. // on the element itself so its not really lost.
  148. fx = new Effect.HighchartsTransition($(el), key, params[key], options);
  149. }
  150. } else {
  151. if (el.attr) { // #409 without effects
  152. for (key in params) {
  153. el.attr(key, params[key]);
  154. }
  155. }
  156. if (options.complete) {
  157. options.complete();
  158. }
  159. }
  160. if (!el.attr) { // HTML element, #409
  161. $(el).setStyle(params);
  162. }
  163. },
  164. // this only occurs in higcharts 2.0+
  165. stop: function (el) {
  166. var key;
  167. if (el._highcharts_extended && el._highchart_animation) {
  168. for (key in el._highchart_animation) {
  169. // Cancel the animation
  170. // The 'finish' function in the Effect object will remove the reference
  171. el._highchart_animation[key].cancel();
  172. }
  173. }
  174. },
  175. // um.. each
  176. each: function (arr, fn) {
  177. $A(arr).each(fn);
  178. },
  179. inArray: function (item, arr, from) {
  180. return arr ? arr.indexOf(item, from) : -1;
  181. },
  182. /**
  183. * Get the cumulative offset relative to the top left of the page. This method, unlike its
  184. * jQuery and MooTools counterpart, still suffers from issue #208 regarding the position
  185. * of a chart within a fixed container.
  186. */
  187. offset: function (el) {
  188. return $(el).cumulativeOffset();
  189. },
  190. // fire an event based on an event name (event) and an object (el).
  191. // again, el may not be a dom element
  192. fireEvent: function (el, event, eventArguments, defaultFunction) {
  193. if (el.fire) {
  194. el.fire(HighchartsAdapter.addNS(event), eventArguments);
  195. } else if (el._highcharts_extended) {
  196. eventArguments = eventArguments || {};
  197. el._highcharts_fire(event, eventArguments);
  198. }
  199. if (eventArguments && eventArguments.defaultPrevented) {
  200. defaultFunction = null;
  201. }
  202. if (defaultFunction) {
  203. defaultFunction(eventArguments);
  204. }
  205. },
  206. removeEvent: function (el, event, handler) {
  207. if ($(el).stopObserving) {
  208. if (event) {
  209. event = HighchartsAdapter.addNS(event);
  210. }
  211. $(el).stopObserving(event, handler);
  212. } if (window === el) {
  213. Event.stopObserving(el, event, handler);
  214. } else {
  215. HighchartsAdapter._extend(el);
  216. el._highcharts_stop_observing(event, handler);
  217. }
  218. },
  219. washMouseEvent: function (e) {
  220. return e;
  221. },
  222. // um, grep
  223. grep: function (arr, fn) {
  224. return arr.findAll(fn);
  225. },
  226. // um, map
  227. map: function (arr, fn) {
  228. return arr.map(fn);
  229. },
  230. // extend an object to handle highchart events (highchart objects, not svg elements).
  231. // this is a very simple way of handling events but whatever, it works (i think)
  232. _extend: function (object) {
  233. if (!object._highcharts_extended) {
  234. Object.extend(object, {
  235. _highchart_events: {},
  236. _highchart_animation: null,
  237. _highcharts_extended: true,
  238. _highcharts_observe: function (name, fn) {
  239. this._highchart_events[name] = [this._highchart_events[name], fn].compact().flatten();
  240. },
  241. _highcharts_stop_observing: function (name, fn) {
  242. if (name) {
  243. if (fn) {
  244. this._highchart_events[name] = [this._highchart_events[name]].compact().flatten().without(fn);
  245. } else {
  246. delete this._highchart_events[name];
  247. }
  248. } else {
  249. this._highchart_events = {};
  250. }
  251. },
  252. _highcharts_fire: function (name, args) {
  253. var target = this;
  254. (this._highchart_events[name] || []).each(function (fn) {
  255. // args is never null here
  256. if (args.stopped) {
  257. return; // "throw $break" wasn't working. i think because of the scope of 'this'.
  258. }
  259. // Attach a simple preventDefault function to skip default handler if called
  260. args.preventDefault = function () {
  261. args.defaultPrevented = true;
  262. };
  263. args.target = target;
  264. // If the event handler return false, prevent the default handler from executing
  265. if (fn.bind(this)(args) === false) {
  266. args.preventDefault();
  267. }
  268. }
  269. .bind(this));
  270. }
  271. });
  272. }
  273. }
  274. };
  275. }());