highcharts-js-rails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/LICENSE +7 -0
- data/README.md +85 -0
- data/Rakefile +1 -0
- data/highcharts-js-rails.gemspec +26 -0
- data/lib/highcharts.rb +8 -0
- data/lib/highcharts/axis.rb +48 -0
- data/lib/highcharts/base.rb +19 -0
- data/lib/highcharts/chart.rb +80 -0
- data/lib/highcharts/legend.rb +15 -0
- data/lib/highcharts/plot_options.rb +23 -0
- data/lib/highcharts/rails.rb +6 -0
- data/lib/highcharts/series.rb +19 -0
- data/lib/highcharts/version.rb +3 -0
- data/vendor/.DS_Store +0 -0
- data/vendor/assets/javascripts/.DS_Store +0 -0
- data/vendor/assets/javascripts/adapters/mootools.js +298 -0
- data/vendor/assets/javascripts/adapters/prototype.js +358 -0
- data/vendor/assets/javascripts/highcharts.js +13291 -0
- data/vendor/assets/javascripts/modules/canvas-tools.js +3114 -0
- data/vendor/assets/javascripts/modules/exporting.js +734 -0
- data/vendor/assets/javascripts/themes/dark-blue.js +263 -0
- data/vendor/assets/javascripts/themes/dark-green.js +263 -0
- data/vendor/assets/javascripts/themes/gray.js +262 -0
- data/vendor/assets/javascripts/themes/grid.js +95 -0
- data/vendor/assets/javascripts/themes/skies.js +89 -0
- metadata +128 -0
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (C) 2011 Alex Robbin
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
Highcharts JS Rails
|
2
|
+
===================
|
3
|
+
|
4
|
+
Easily configure a Highcharts JS chart for use in a Rails application.
|
5
|
+
|
6
|
+
Currently you are able to do the following:
|
7
|
+
|
8
|
+
* Configure multiple axes and series on a single chart
|
9
|
+
* Set a specific graph type for each individual series of data (available options include area, areaspline, bar, column, line, pie, scatter or spline) - default is line
|
10
|
+
* Customize the tooltip for the graph
|
11
|
+
* Configure the location and design of the legend
|
12
|
+
* Set the tick interval for a specific axis
|
13
|
+
|
14
|
+
Options
|
15
|
+
-------
|
16
|
+
|
17
|
+
To instantiate a new chart:
|
18
|
+
|
19
|
+
`chart = Highcharts::Chart.new`
|
20
|
+
|
21
|
+
The Highcharts::Chart class can receive a hash of the following options:
|
22
|
+
|
23
|
+
* container: string (required)
|
24
|
+
* title: string (required)
|
25
|
+
* subtitle: string
|
26
|
+
* xAxes: hash or array of hashes (required)
|
27
|
+
* yAxes: hash or array of hashes (required)
|
28
|
+
* legend: hash
|
29
|
+
* series: hash or array of hashes (required)
|
30
|
+
* tooltip: string
|
31
|
+
|
32
|
+
Both the `xAxes` and `yAxes` options can be either a single hash (meaning there is only one axis) or an array of hashes (for multiple-axis charts). Each hash can include the following options:
|
33
|
+
|
34
|
+
* title: string
|
35
|
+
* categories: array
|
36
|
+
* tickInterval: integer
|
37
|
+
* min: integer
|
38
|
+
* max: integer
|
39
|
+
* labels: hash
|
40
|
+
* opposite: boolean
|
41
|
+
|
42
|
+
The `categories` option's array of values will be automatically formatted based on its class.
|
43
|
+
The `tickInterval` option is only necessary if you want to override automatic tickInterval creation. If the option is not passed, the tickInterval will be calculated based on the amount of data passed to the attached `series`.
|
44
|
+
The `labels` option can receive a set of options that includes `prepend` and `append`.
|
45
|
+
|
46
|
+
The `legend` option for the Highcharts::Chart class can receive a hash of the following options:
|
47
|
+
|
48
|
+
* layout: string (possible values can be horizontal or vertical - default is horizontal)
|
49
|
+
* align: string
|
50
|
+
* verticalAlign: string
|
51
|
+
* x: integer
|
52
|
+
* y: integer
|
53
|
+
* borderWidth: integer
|
54
|
+
|
55
|
+
The `series` option for the Highcharts::Chart class can receive a hash of the following options:
|
56
|
+
|
57
|
+
* name: string
|
58
|
+
* type: string (possible values can be area, areaspline, bar, column, line, pie, scatter or spline - default is line)
|
59
|
+
* xAxis: integer (the index of the xAxis this series should be attached to)
|
60
|
+
* yAxis: integer (the index of the yAxis this series should be attached to)
|
61
|
+
* data: array
|
62
|
+
|
63
|
+
The `data` option's array of values will be automatically formatted as a float, if necessary.
|
64
|
+
|
65
|
+
Example
|
66
|
+
--------
|
67
|
+
|
68
|
+
Ruby:
|
69
|
+
|
70
|
+
```
|
71
|
+
chart = Highcharts::Chart.new(
|
72
|
+
:container => 'graph',
|
73
|
+
:title => "Highcharts Example",
|
74
|
+
:xAxes => {:categories => ['October 12', 'October 13', 'October 14']},
|
75
|
+
:yAxes => [{:title => 'Impressions', :min => 0}],
|
76
|
+
:series => [{:name => 'Impressions', :yAxis => 0, :type => 'line', :data => [100000, 122000, 127000]}],
|
77
|
+
:legend => {:layout => 'vertical', :align => 'right', :verticalAlign => 'top', :x => -10, :y => 100, :borderWidth => 0},
|
78
|
+
:tooltip => "'<b>' + this.series.name + '</b><br/>' + this.x + ': ' + this.y"
|
79
|
+
)
|
80
|
+
<%= chart %>
|
81
|
+
```
|
82
|
+
|
83
|
+
HTML/ERB:
|
84
|
+
|
85
|
+
`<div id="graph" style="width: 400px; height: 200px;"></div>`
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'highcharts/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'highcharts-js-rails'
|
7
|
+
s.version = Highcharts::VERSION
|
8
|
+
s.authors = ['Alex Robbin']
|
9
|
+
s.email = ['agrobbin@gmail.com']
|
10
|
+
s.homepage = 'http://github.com/agrobbin/highcharts-js-rails'
|
11
|
+
s.summary = %q{Easily configure a Highcharts JS chart for use in a Rails application}
|
12
|
+
s.description = s.summary
|
13
|
+
|
14
|
+
s.rubyforge_project = 'highcharts-js-rails'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
|
21
|
+
s.add_development_dependency 'bundler'
|
22
|
+
s.add_development_dependency 'simplecov'
|
23
|
+
s.add_development_dependency 'rake'
|
24
|
+
s.add_development_dependency 'rspec'
|
25
|
+
s.add_dependency 'actionpack', '~> 3.0'
|
26
|
+
end
|
data/lib/highcharts.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Highcharts
|
2
|
+
class Axis < Base
|
3
|
+
|
4
|
+
attr_accessor :title, :categories, :tickInterval, :min, :max, :labels, :opposite
|
5
|
+
|
6
|
+
def to_s
|
7
|
+
"{" +
|
8
|
+
[render_title, render_categories, render_tickInterval, render_options(:objects => 'min max opposite'), render_labels].flatten.compact.join(',') +
|
9
|
+
"}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_title
|
13
|
+
title.present? ? "title: {text: '#{title}'}" : nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def render_categories
|
17
|
+
return nil unless categories.present?
|
18
|
+
"categories: [#{categories.collect {|c| "'#{format_category(c)}'"}.join(', ')}]" # need to encapsulate each category in quotes and format it before joining them with a comma
|
19
|
+
end
|
20
|
+
|
21
|
+
def render_tickInterval
|
22
|
+
return tickInterval if tickInterval.present?
|
23
|
+
return nil unless categories.present?
|
24
|
+
"tickInterval: #{(Math.sqrt(categories.length) < 5 ? 1 : Math.sqrt(categories.length)).floor}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def format_category(category)
|
28
|
+
case category
|
29
|
+
when Date
|
30
|
+
category.strftime("%b. %d")
|
31
|
+
when Time
|
32
|
+
category.strftime("%H:%M")
|
33
|
+
when DateTime
|
34
|
+
category.strftime("%b. %d, %H:%M")
|
35
|
+
else
|
36
|
+
category.to_s
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def render_labels
|
41
|
+
return nil unless labels.present?
|
42
|
+
"labels: {" +
|
43
|
+
"formatter: function(){ return '#{labels[:prepend]}' + this.value + '#{labels[:append]}'; }" +
|
44
|
+
"}"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Highcharts
|
2
|
+
class Base < ActionView::Base
|
3
|
+
|
4
|
+
def initialize(*args)
|
5
|
+
args.extract_options!.each {|arg, value| self.send("#{arg}=", value)}
|
6
|
+
end
|
7
|
+
|
8
|
+
def render_options(args)
|
9
|
+
attrs = []
|
10
|
+
args.each do |t, a|
|
11
|
+
a.split.each do |option|
|
12
|
+
attrs << "#{option}: #{t == :objects ? send(option) : "'#{send(option)}'"}" if send(option).present?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
attrs
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Highcharts
|
2
|
+
class Chart < Base
|
3
|
+
include ActionView::Helpers
|
4
|
+
|
5
|
+
attr_accessor :container, :title, :subtitle, :plot_options, :xAxes, :yAxes, :legend, :series, :tooltip
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
check_required_fields
|
9
|
+
|
10
|
+
javascript_tag do
|
11
|
+
safe_concat("$(function(){" +
|
12
|
+
"new Highcharts.Chart({" +
|
13
|
+
render_all +
|
14
|
+
"})" +
|
15
|
+
"});")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def render_all
|
20
|
+
content = [render_container, render_titles, render_plot_options, render_axes, render_series, render_legend, render_tooltip].flatten.compact.join(",")
|
21
|
+
if Rails.env.production?
|
22
|
+
content
|
23
|
+
else
|
24
|
+
content.gsub(/(,|{|\[)/, "\\1\n").gsub(/(}|])/, "\n\\1")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_required_fields
|
29
|
+
%w(container title series).each do |required_argument|
|
30
|
+
raise ArgumentError, ":#{required_argument} must be passed" if send(required_argument).blank? || (send(required_argument).is_a?(Array) && send(required_argument).length == 0)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def render_container
|
35
|
+
"chart: {renderTo: '#{container}'}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def render_titles
|
39
|
+
%w(title subtitle).collect do |t|
|
40
|
+
"#{t}: {text: '#{send(t)}'}" if send(t).present?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def render_plot_options
|
45
|
+
return nil unless plot_options.present?
|
46
|
+
"plotOptions: {" +
|
47
|
+
Array.wrap(plot_options).collect {|po| PlotOptions.new(po)}.join(',') +
|
48
|
+
"}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def render_axes
|
52
|
+
result = %w(x y).collect do |axis|
|
53
|
+
return nil unless send("#{axis}Axes").present?
|
54
|
+
"#{axis}Axis: [" +
|
55
|
+
Array.wrap(send("#{axis}Axes")).collect {|a| Axis.new(a)}.join(',') +
|
56
|
+
"]"
|
57
|
+
end
|
58
|
+
result.compact.join(",")
|
59
|
+
end
|
60
|
+
|
61
|
+
def render_legend
|
62
|
+
return nil unless legend.present?
|
63
|
+
Legend.new(legend)
|
64
|
+
end
|
65
|
+
|
66
|
+
def render_series
|
67
|
+
"series: [" +
|
68
|
+
Array.wrap(series).collect {|s| Series.new(s)}.join(',') +
|
69
|
+
"]"
|
70
|
+
end
|
71
|
+
|
72
|
+
def render_tooltip
|
73
|
+
return nil unless tooltip.present?
|
74
|
+
"tooltip: {" +
|
75
|
+
"formatter: function(){ return #{tooltip}; }" +
|
76
|
+
"}"
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Highcharts
|
2
|
+
class Legend < Base
|
3
|
+
|
4
|
+
attr_accessor :layout, :align, :verticalAlign, :x, :y, :borderWidth
|
5
|
+
|
6
|
+
def to_s
|
7
|
+
rendered_options = render_options(:strings => 'layout align verticalAlign', :objects => 'x y borderWidth')
|
8
|
+
return nil if rendered_options.length == 0
|
9
|
+
"legend: {" +
|
10
|
+
rendered_options.join(',') +
|
11
|
+
"}"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Highcharts
|
2
|
+
class PlotOptions < Base
|
3
|
+
|
4
|
+
attr_accessor :type, :data_labels, :legend
|
5
|
+
|
6
|
+
def to_s
|
7
|
+
"#{type}: {" +
|
8
|
+
[render_data_labels, render_legend].flatten.compact.join(',') +
|
9
|
+
"}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_data_labels
|
13
|
+
"dataLabels: {" +
|
14
|
+
"enabled: #{data_labels == false ? 'false' : 'true'}" +
|
15
|
+
"}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def render_legend
|
19
|
+
"showInLegend: #{legend ? 'true' : 'false'}"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Highcharts
|
2
|
+
class Series < Base
|
3
|
+
|
4
|
+
attr_accessor :name, :type, :xAxis, :yAxis, :data
|
5
|
+
|
6
|
+
def to_s
|
7
|
+
rendered_options = render_options(:strings => 'name type', :objects => 'xAxis yAxis')
|
8
|
+
return nil if rendered_options.length == 0
|
9
|
+
"{" +
|
10
|
+
[rendered_options, render_data].flatten.compact.join(',') +
|
11
|
+
"}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_data
|
15
|
+
"data: #{data.first.is_a?(Array) ? data : data.collect(&:to_f)}"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/vendor/.DS_Store
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,298 @@
|
|
1
|
+
/**
|
2
|
+
* @license Highcharts JS v2.2.0 (2012-02-16)
|
3
|
+
* MooTools adapter
|
4
|
+
*
|
5
|
+
* (c) 2010-2011 Torstein Hønsi
|
6
|
+
*
|
7
|
+
* License: www.highcharts.com/license
|
8
|
+
*/
|
9
|
+
|
10
|
+
// JSLint options:
|
11
|
+
/*global Fx, $, $extend, $each, $merge, Events, Event, DOMEvent */
|
12
|
+
|
13
|
+
(function () {
|
14
|
+
|
15
|
+
var win = window,
|
16
|
+
doc = document,
|
17
|
+
mooVersion = win.MooTools.version.substring(0, 3), // Get the first three characters of the version number
|
18
|
+
legacy = mooVersion === '1.2' || mooVersion === '1.1', // 1.1 && 1.2 considered legacy, 1.3 is not.
|
19
|
+
legacyEvent = legacy || mooVersion === '1.3', // In versions 1.1 - 1.3 the event class is named Event, in newer versions it is named DOMEvent.
|
20
|
+
$extend = win.$extend || function () {
|
21
|
+
return Object.append.apply(Object, arguments);
|
22
|
+
};
|
23
|
+
|
24
|
+
win.HighchartsAdapter = {
|
25
|
+
/**
|
26
|
+
* Initialize the adapter. This is run once as Highcharts is first run.
|
27
|
+
* @param {Object} pathAnim The helper object to do animations across adapters.
|
28
|
+
*/
|
29
|
+
init: function (pathAnim) {
|
30
|
+
var fxProto = Fx.prototype,
|
31
|
+
fxStart = fxProto.start,
|
32
|
+
morphProto = Fx.Morph.prototype,
|
33
|
+
morphCompute = morphProto.compute;
|
34
|
+
|
35
|
+
// override Fx.start to allow animation of SVG element wrappers
|
36
|
+
/*jslint unparam: true*//* allow unused parameters in fx functions */
|
37
|
+
fxProto.start = function (from, to) {
|
38
|
+
var fx = this,
|
39
|
+
elem = fx.element;
|
40
|
+
|
41
|
+
// special for animating paths
|
42
|
+
if (from.d) {
|
43
|
+
//this.fromD = this.element.d.split(' ');
|
44
|
+
fx.paths = pathAnim.init(
|
45
|
+
elem,
|
46
|
+
elem.d,
|
47
|
+
fx.toD
|
48
|
+
);
|
49
|
+
}
|
50
|
+
fxStart.apply(fx, arguments);
|
51
|
+
|
52
|
+
return this; // chainable
|
53
|
+
};
|
54
|
+
|
55
|
+
// override Fx.step to allow animation of SVG element wrappers
|
56
|
+
morphProto.compute = function (from, to, delta) {
|
57
|
+
var fx = this,
|
58
|
+
paths = fx.paths;
|
59
|
+
|
60
|
+
if (paths) {
|
61
|
+
fx.element.attr(
|
62
|
+
'd',
|
63
|
+
pathAnim.step(paths[0], paths[1], delta, fx.toD)
|
64
|
+
);
|
65
|
+
} else {
|
66
|
+
return morphCompute.apply(fx, arguments);
|
67
|
+
}
|
68
|
+
};
|
69
|
+
/*jslint unparam: false*/
|
70
|
+
},
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Downloads a script and executes a callback when done.
|
74
|
+
* @param {String} scriptLocation
|
75
|
+
* @param {Function} callback
|
76
|
+
*/
|
77
|
+
getScript: function (scriptLocation, callback) {
|
78
|
+
// We cannot assume that Assets class from mootools-more is available so instead insert a script tag to download script.
|
79
|
+
var head = doc.getElementsByTagName('head')[0];
|
80
|
+
var script = doc.createElement('script');
|
81
|
+
|
82
|
+
script.type = 'text/javascript';
|
83
|
+
script.src = scriptLocation;
|
84
|
+
script.onload = callback;
|
85
|
+
|
86
|
+
head.appendChild(script);
|
87
|
+
},
|
88
|
+
|
89
|
+
/**
|
90
|
+
* Animate a HTML element or SVG element wrapper
|
91
|
+
* @param {Object} el
|
92
|
+
* @param {Object} params
|
93
|
+
* @param {Object} options jQuery-like animation options: duration, easing, callback
|
94
|
+
*/
|
95
|
+
animate: function (el, params, options) {
|
96
|
+
var isSVGElement = el.attr,
|
97
|
+
effect,
|
98
|
+
complete = options && options.complete;
|
99
|
+
|
100
|
+
if (isSVGElement && !el.setStyle) {
|
101
|
+
// add setStyle and getStyle methods for internal use in Moo
|
102
|
+
el.getStyle = el.attr;
|
103
|
+
el.setStyle = function () { // property value is given as array in Moo - break it down
|
104
|
+
var args = arguments;
|
105
|
+
el.attr.call(el, args[0], args[1][0]);
|
106
|
+
};
|
107
|
+
// dirty hack to trick Moo into handling el as an element wrapper
|
108
|
+
el.$family = function () { return true; };
|
109
|
+
}
|
110
|
+
|
111
|
+
// stop running animations
|
112
|
+
win.HighchartsAdapter.stop(el);
|
113
|
+
|
114
|
+
// define and run the effect
|
115
|
+
effect = new Fx.Morph(
|
116
|
+
isSVGElement ? el : $(el),
|
117
|
+
$extend({
|
118
|
+
transition: Fx.Transitions.Quad.easeInOut
|
119
|
+
}, options)
|
120
|
+
);
|
121
|
+
|
122
|
+
// Make sure that the element reference is set when animating svg elements
|
123
|
+
if (isSVGElement) {
|
124
|
+
effect.element = el;
|
125
|
+
}
|
126
|
+
|
127
|
+
// special treatment for paths
|
128
|
+
if (params.d) {
|
129
|
+
effect.toD = params.d;
|
130
|
+
}
|
131
|
+
|
132
|
+
// jQuery-like events
|
133
|
+
if (complete) {
|
134
|
+
effect.addEvent('complete', complete);
|
135
|
+
}
|
136
|
+
|
137
|
+
// run
|
138
|
+
effect.start(params);
|
139
|
+
|
140
|
+
// record for use in stop method
|
141
|
+
el.fx = effect;
|
142
|
+
},
|
143
|
+
|
144
|
+
/**
|
145
|
+
* MooTool's each function
|
146
|
+
*
|
147
|
+
*/
|
148
|
+
each: function (arr, fn) {
|
149
|
+
return legacy ?
|
150
|
+
$each(arr, fn) :
|
151
|
+
Array.each(arr, fn);
|
152
|
+
},
|
153
|
+
|
154
|
+
/**
|
155
|
+
* Map an array
|
156
|
+
* @param {Array} arr
|
157
|
+
* @param {Function} fn
|
158
|
+
*/
|
159
|
+
map: function (arr, fn) {
|
160
|
+
return arr.map(fn);
|
161
|
+
},
|
162
|
+
|
163
|
+
/**
|
164
|
+
* Grep or filter an array
|
165
|
+
* @param {Array} arr
|
166
|
+
* @param {Function} fn
|
167
|
+
*/
|
168
|
+
grep: function (arr, fn) {
|
169
|
+
return arr.filter(fn);
|
170
|
+
},
|
171
|
+
|
172
|
+
/**
|
173
|
+
* Deep merge two objects and return a third
|
174
|
+
*/
|
175
|
+
merge: function () {
|
176
|
+
var args = arguments,
|
177
|
+
args13 = [{}], // MooTools 1.3+
|
178
|
+
i = args.length,
|
179
|
+
ret;
|
180
|
+
|
181
|
+
if (legacy) {
|
182
|
+
ret = $merge.apply(null, args);
|
183
|
+
} else {
|
184
|
+
while (i--) {
|
185
|
+
// Boolean argumens should not be merged.
|
186
|
+
// JQuery explicitly skips this, so we do it here as well.
|
187
|
+
if (typeof args[i] !== 'boolean') {
|
188
|
+
args13[i + 1] = args[i];
|
189
|
+
}
|
190
|
+
}
|
191
|
+
ret = Object.merge.apply(Object, args13);
|
192
|
+
}
|
193
|
+
|
194
|
+
return ret;
|
195
|
+
},
|
196
|
+
|
197
|
+
/**
|
198
|
+
* Get the offset of an element relative to the top left corner of the web page
|
199
|
+
*/
|
200
|
+
offset: function (el) {
|
201
|
+
var offsets = $(el).getOffsets();
|
202
|
+
return {
|
203
|
+
left: offsets.x,
|
204
|
+
top: offsets.y
|
205
|
+
};
|
206
|
+
},
|
207
|
+
|
208
|
+
/**
|
209
|
+
* Extends an object with Events, if its not done
|
210
|
+
*/
|
211
|
+
extendWithEvents: function (el) {
|
212
|
+
// if the addEvent method is not defined, el is a custom Highcharts object
|
213
|
+
// like series or point
|
214
|
+
if (!el.addEvent) {
|
215
|
+
if (el.nodeName) {
|
216
|
+
el = $(el); // a dynamically generated node
|
217
|
+
} else {
|
218
|
+
$extend(el, new Events()); // a custom object
|
219
|
+
}
|
220
|
+
}
|
221
|
+
},
|
222
|
+
|
223
|
+
/**
|
224
|
+
* Add an event listener
|
225
|
+
* @param {Object} el HTML element or custom object
|
226
|
+
* @param {String} type Event type
|
227
|
+
* @param {Function} fn Event handler
|
228
|
+
*/
|
229
|
+
addEvent: function (el, type, fn) {
|
230
|
+
if (typeof type === 'string') { // chart broke due to el being string, type function
|
231
|
+
|
232
|
+
if (type === 'unload') { // Moo self destructs before custom unload events
|
233
|
+
type = 'beforeunload';
|
234
|
+
}
|
235
|
+
|
236
|
+
win.HighchartsAdapter.extendWithEvents(el);
|
237
|
+
|
238
|
+
el.addEvent(type, fn);
|
239
|
+
}
|
240
|
+
},
|
241
|
+
|
242
|
+
removeEvent: function (el, type, fn) {
|
243
|
+
if (typeof el === 'string') {
|
244
|
+
// el.removeEvents below apperantly calls this method again. Do not quite understand why, so for now just bail out.
|
245
|
+
return;
|
246
|
+
}
|
247
|
+
win.HighchartsAdapter.extendWithEvents(el);
|
248
|
+
if (type) {
|
249
|
+
if (type === 'unload') { // Moo self destructs before custom unload events
|
250
|
+
type = 'beforeunload';
|
251
|
+
}
|
252
|
+
|
253
|
+
if (fn) {
|
254
|
+
el.removeEvent(type, fn);
|
255
|
+
} else {
|
256
|
+
el.removeEvents(type);
|
257
|
+
}
|
258
|
+
} else {
|
259
|
+
el.removeEvents();
|
260
|
+
}
|
261
|
+
},
|
262
|
+
|
263
|
+
fireEvent: function (el, event, eventArguments, defaultFunction) {
|
264
|
+
var eventArgs = {
|
265
|
+
type: event,
|
266
|
+
target: el
|
267
|
+
};
|
268
|
+
// create an event object that keeps all functions
|
269
|
+
event = legacyEvent ? new Event(eventArgs) : new DOMEvent(eventArgs);
|
270
|
+
event = $extend(event, eventArguments);
|
271
|
+
// override the preventDefault function to be able to use
|
272
|
+
// this for custom events
|
273
|
+
event.preventDefault = function () {
|
274
|
+
defaultFunction = null;
|
275
|
+
};
|
276
|
+
// if fireEvent is not available on the object, there hasn't been added
|
277
|
+
// any events to it above
|
278
|
+
if (el.fireEvent) {
|
279
|
+
el.fireEvent(event.type, event);
|
280
|
+
}
|
281
|
+
|
282
|
+
// fire the default if it is passed and it is not prevented above
|
283
|
+
if (defaultFunction) {
|
284
|
+
defaultFunction(event);
|
285
|
+
}
|
286
|
+
},
|
287
|
+
|
288
|
+
/**
|
289
|
+
* Stop running animations on the object
|
290
|
+
*/
|
291
|
+
stop: function (el) {
|
292
|
+
if (el.fx) {
|
293
|
+
el.fx.cancel();
|
294
|
+
}
|
295
|
+
}
|
296
|
+
};
|
297
|
+
|
298
|
+
}());
|