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