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