/** 
 | 
 * @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)); 
 | 
                } 
 | 
            }); 
 | 
        } 
 | 
    } 
 | 
}; 
 | 
}()); 
 |