fnordmetric 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +69 -0
- data/Procfile +2 -0
- data/Rakefile +28 -0
- data/VERSION +1 -0
- data/doc/example_server.rb +56 -0
- data/fnordmetric.gemspec +145 -0
- data/haml/app.haml +48 -0
- data/haml/widget.haml +9 -0
- data/lib/fnordmetric.rb +21 -0
- data/lib/fnordmetric/app.rb +70 -0
- data/lib/fnordmetric/average_metric.rb +7 -0
- data/lib/fnordmetric/cache.rb +20 -0
- data/lib/fnordmetric/combine_metric.rb +7 -0
- data/lib/fnordmetric/core.rb +66 -0
- data/lib/fnordmetric/count_metric.rb +13 -0
- data/lib/fnordmetric/dashboard.rb +30 -0
- data/lib/fnordmetric/engine.rb +3 -0
- data/lib/fnordmetric/event.rb +28 -0
- data/lib/fnordmetric/funnel_widget.rb +2 -0
- data/lib/fnordmetric/metric.rb +80 -0
- data/lib/fnordmetric/metric_api.rb +37 -0
- data/lib/fnordmetric/numbers_widget.rb +18 -0
- data/lib/fnordmetric/report.rb +29 -0
- data/lib/fnordmetric/sum_metric.rb +13 -0
- data/lib/fnordmetric/timeline_widget.rb +17 -0
- data/lib/fnordmetric/widget.rb +75 -0
- data/pub/fnordmetric/fnordmetric.css +53 -0
- data/pub/fnordmetric/fnordmetric.js +44 -0
- data/pub/fnordmetric/widget_numbers.js +71 -0
- data/pub/fnordmetric/widget_timeline.css +0 -0
- data/pub/fnordmetric/widget_timeline.js +110 -0
- data/pub/highcharts/adapters/mootools-adapter.js +12 -0
- data/pub/highcharts/adapters/mootools-adapter.src.js +243 -0
- data/pub/highcharts/adapters/prototype-adapter.js +14 -0
- data/pub/highcharts/adapters/prototype-adapter.src.js +284 -0
- data/pub/highcharts/highcharts.js +170 -0
- data/pub/highcharts/highcharts.src.js +11103 -0
- data/pub/highcharts/modules/exporting.js +22 -0
- data/pub/highcharts/modules/exporting.src.js +703 -0
- data/pub/highcharts/themes/dark-blue.js +268 -0
- data/pub/highcharts/themes/dark-green.js +268 -0
- data/pub/highcharts/themes/gray.js +262 -0
- data/pub/highcharts/themes/grid.js +97 -0
- data/pub/jquery-1.6.1.min.js +18 -0
- data/pub/sprite.png +0 -0
- data/readme.rdoc +274 -0
- data/spec/app_spec.rb +178 -0
- data/spec/cache_spec.rb +53 -0
- data/spec/combine_metric_spec.rb +19 -0
- data/spec/core_spec.rb +50 -0
- data/spec/count_metric_spec.rb +32 -0
- data/spec/dashboard_spec.rb +67 -0
- data/spec/event_spec.rb +46 -0
- data/spec/metric_spec.rb +118 -0
- data/spec/report_spec.rb +87 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/sum_metric_spec.rb +33 -0
- data/spec/widget_spec.rb +107 -0
- metadata +271 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
body, html{ height:100%; padding:0px;}
|
2
|
+
body{ background:#fff; color:#333; margin:0; padding:0; overflow-y:scroll; font: 12px/20px "Helvetica Neue", Helvetica, Arial, sans-serif; }
|
3
|
+
|
4
|
+
#wrap{ margin:0 40px; }
|
5
|
+
|
6
|
+
#tabs{ width:200px; position:fixed; height:100%; margin-top:70px; }
|
7
|
+
#tabs ul{ list-style-type:none; padding:0; margin:0; }
|
8
|
+
#tabs ul li{ height:34px; line-height:35px; border-bottom:1px dotted #ececec; cursor:pointer; color:#666; font-size:13px; }
|
9
|
+
#tabs ul li:after{ content:'›'; display:block; float:right; margin-right:15px; color:#ccc; font-size:16px; line-height:35px; }
|
10
|
+
#tabs ul li .picto{ margin-top:10px; margin-right:7px; }
|
11
|
+
#tabs ul li:hover, #tabs ul li:hover:after{ color:#000; }
|
12
|
+
#tabs ul li:hover .picto{ opacity:1; }
|
13
|
+
|
14
|
+
.picto{ display:block; height:14px; width:14px; float:left; background:url('/fnordmetric/sprite.png') no-repeat 14px 14px; opacity:0.7; }
|
15
|
+
.picto.piechart{ background-position:-42px -173px; width:9px; margin-right:5px; }
|
16
|
+
|
17
|
+
#viewport{ min-height:800px; float:left; margin-left:220px; padding-top:20px; border-right:1px solid #e0e0e0; border-left:1px solid #e0e0e0; }
|
18
|
+
|
19
|
+
.headbar{ height:36px; background:#f2f2f2; border-bottom:1px solid #e2e2e2; }
|
20
|
+
.headbar h2{ margin:8px; line-height:21px; float:left; height:20px; font-size:14px; }
|
21
|
+
.headbar .datepicker{ background:#fff; border:1px solid #999; height:20px; padding:0 7px; float:right; margin:8px -1px; min-width:100px; font-size:11px; font-style:italic; }
|
22
|
+
.headbar .button.mr{ margin-right:16px; }
|
23
|
+
|
24
|
+
|
25
|
+
.headbar .button{
|
26
|
+
margin:8px 0px; height:16px; float:right; display:block;
|
27
|
+
margin-right:-1px;
|
28
|
+
background:url('/fnordmetric/sprite.png') no-repeat 0 -49px #eee;
|
29
|
+
border:1px solid #999;
|
30
|
+
border-bottom-color:#888;
|
31
|
+
-webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, .1);
|
32
|
+
cursor:pointer;
|
33
|
+
|
34
|
+
font-size: 11px;
|
35
|
+
font-weight:bold;
|
36
|
+
line-height:16px;
|
37
|
+
padding:2px 6px;
|
38
|
+
text-align:center;
|
39
|
+
text-decoration:none;
|
40
|
+
vertical-align:top;
|
41
|
+
white-space:nowrap;
|
42
|
+
}
|
43
|
+
|
44
|
+
.headbar .button:hover, .headbar.button.active{background:#ddd;border-bottom-color:#999;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, .05)}
|
45
|
+
|
46
|
+
.numbers_container, .number{ float:left; border-right:1px solid #ececec;}
|
47
|
+
.number{ margin-left:12px; padding-right:20px; margin-right:10px; }
|
48
|
+
.number .value{ color:#333; font-size:30px; display:block; margin-bottom:5px; }
|
49
|
+
.number .desc{ color:#999; font-size:12px; }
|
50
|
+
.number:last-child{ border-right:none; }
|
51
|
+
.numbers_container{ padding-right:0px; width:33.2%; }
|
52
|
+
|
53
|
+
.numbers_container .title{ padding:4px 10px 1px 10px; color:#333; font-size:13px; display:block; background:#f2f2f2; border-bottom:1px solid #e2e2e2; margin-bottom:15px; }
|
@@ -0,0 +1,44 @@
|
|
1
|
+
FnordMetric = {
|
2
|
+
d: document,
|
3
|
+
p: '/fnordmetric/',
|
4
|
+
id: function(id){return FnordMetric.d.getElementById(id)},
|
5
|
+
tag: function(element){return FnordMetric.d.getElementsByTagName(element)},
|
6
|
+
ce: function(element){return FnordMetric.d.createElement(element)},
|
7
|
+
|
8
|
+
init: function(){
|
9
|
+
if(widget_config.path_prefix){ FnordMetric.p = widget_config.path_prefix; }
|
10
|
+
},
|
11
|
+
|
12
|
+
js: function(url, callback){
|
13
|
+
var s = FnordMetric.ce('script');
|
14
|
+
s.type = "text/javascript";
|
15
|
+
s.onload = callback;
|
16
|
+
FnordMetric.init();
|
17
|
+
s.src = FnordMetric.p+url;
|
18
|
+
FnordMetric.tag('head')[0].appendChild(s);
|
19
|
+
},
|
20
|
+
|
21
|
+
css: function(url, callback){
|
22
|
+
var s = FnordMetric.ce('link');
|
23
|
+
s.type = "text/css";
|
24
|
+
s.rel = 'stylesheet';
|
25
|
+
s.href = FnordMetric.p+url;
|
26
|
+
s.onload = callback;
|
27
|
+
FnordMetric.tag('head')[0].appendChild(s);
|
28
|
+
},
|
29
|
+
|
30
|
+
render: function(elem, widget_config){
|
31
|
+
var f = FnordMetric.ce('iframe');
|
32
|
+
f.style.width = '100%'; f.style.height = widget_config.widget_height+'px';
|
33
|
+
f.frameBorder = 'none'; f.scrolling = 'no';
|
34
|
+
FnordMetric.id(elem).appendChild(f);
|
35
|
+
var s = f.contentDocument.createElement('script')
|
36
|
+
s.type = "text/javascript";
|
37
|
+
s.src = FnordMetric.p+'/fnordmetric/fnordmetric.js';
|
38
|
+
widget_config.path_prefix = FnordMetric.p;
|
39
|
+
s.onload = function(){ f.contentWindow.FnordMetric.js(widget_config.widget_url); }
|
40
|
+
f.contentWindow.widget_config = widget_config;
|
41
|
+
f.contentDocument.getElementsByTagName('head')[0].appendChild(s);
|
42
|
+
}
|
43
|
+
|
44
|
+
};
|
@@ -0,0 +1,71 @@
|
|
1
|
+
FnordMetric.css('/fnordmetric/fnordmetric.css', function(){});
|
2
|
+
FnordMetric.js('/jquery-1.6.1.min.js', function(){
|
3
|
+
|
4
|
+
drawLayout();
|
5
|
+
updateDataAndValues();
|
6
|
+
|
7
|
+
window.setInterval(updateDataAndValues, 5000);
|
8
|
+
|
9
|
+
function drawLayout(){
|
10
|
+
for(n in widget_config.metrics){
|
11
|
+
$('body').append(container=$('<div></div>').attr('class', 'numbers_container').attr('rel', widget_config.metrics[n]));
|
12
|
+
container.append($('<div></div>').addClass('title').html(widget_config.metrics[n]));
|
13
|
+
for(var k in widget_config.intervals){
|
14
|
+
container.append($('<div></div>').addClass('number').attr('rel', k).attr('data',0).append(
|
15
|
+
$('<span></span>').addClass('value').html(0)
|
16
|
+
).append(
|
17
|
+
$('<span></span>').addClass('desc').html(k)
|
18
|
+
));
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
function updateDataAndValues(){
|
24
|
+
for(n in widget_config.metrics){
|
25
|
+
for(k in widget_config.intervals){
|
26
|
+
var _url = FnordMetric.p+'/metric/'+widget_config.metrics[n]+'?'+widget_config.intervals[k];
|
27
|
+
$.get(_url, updateSingleNumber(widget_config.metrics[n], k));
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
function updateSingleNumber(metric_name, interval_name){
|
33
|
+
return function(json){
|
34
|
+
var _elem = $('.number[rel="'+interval_name+'"]', $('.numbers_container[rel="'+metric_name+'"]'));
|
35
|
+
_elem.attr('data', json.value);
|
36
|
+
updateValues(4);
|
37
|
+
};
|
38
|
+
}
|
39
|
+
|
40
|
+
function formatValue(value){
|
41
|
+
if(value < 10){ return value.toFixed(2); }
|
42
|
+
if(value > 1000){ return (value/1000.0).toFixed(1) + "k"; }
|
43
|
+
return value.toFixed(0);
|
44
|
+
}
|
45
|
+
|
46
|
+
function updateValues(diff_factor){
|
47
|
+
var still_running = false;
|
48
|
+
$('.number').each(function(){
|
49
|
+
var target_val = parseFloat($(this).attr('data'));
|
50
|
+
var current_val = parseFloat($(this).attr('data-current'));
|
51
|
+
if(!current_val){ current_val=0; }
|
52
|
+
var diff = (target_val-current_val)/diff_factor;
|
53
|
+
if(diff < 1){ diff=1; }
|
54
|
+
if(target_val > current_val){
|
55
|
+
still_running = true;
|
56
|
+
var new_val = current_val+diff;
|
57
|
+
if(new_val > target_val){ new_val = target_val; }
|
58
|
+
$(this).attr('data-current', new_val);
|
59
|
+
$('.value', this).html(formatValue(new_val));
|
60
|
+
}
|
61
|
+
});
|
62
|
+
if(still_running){
|
63
|
+
(function(df){
|
64
|
+
window.setTimeout(function(){ updateValues(df); }, 30);
|
65
|
+
})(diff_factor);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
});
|
File without changes
|
@@ -0,0 +1,110 @@
|
|
1
|
+
FnordMetric.js('/jquery-1.6.1.min.js', function(){
|
2
|
+
FnordMetric.js('/highcharts/highcharts.js', function(){
|
3
|
+
FnordMetric.css('/fnordmetric/fnordmetric.css', function(){});
|
4
|
+
FnordMetric.css('/fnordmetric/widget_timeline.css', function(){});
|
5
|
+
|
6
|
+
|
7
|
+
drawLayout();
|
8
|
+
chart = new Highcharts.Chart({
|
9
|
+
chart: { renderTo: 'container', defaultSeriesType: widget_config.chart_type, height: 270 },
|
10
|
+
series: [],
|
11
|
+
title: { text: '' },
|
12
|
+
xAxis: {
|
13
|
+
type: 'datetime',
|
14
|
+
tickInterval: widget_config.tick * 1000,
|
15
|
+
title: (widget_config.x_title||''),
|
16
|
+
labels: { step: 2 }
|
17
|
+
},
|
18
|
+
yAxis: {
|
19
|
+
title: (widget_config.y_title||''),
|
20
|
+
maxPadding: 0
|
21
|
+
},
|
22
|
+
legend: {
|
23
|
+
layout: 'horizontal',
|
24
|
+
align: 'top',
|
25
|
+
verticalAlign: 'top',
|
26
|
+
x: -5,
|
27
|
+
y: -3,
|
28
|
+
margin: 25,
|
29
|
+
borderWidth: 0
|
30
|
+
},
|
31
|
+
});
|
32
|
+
redrawWithRange(true);
|
33
|
+
|
34
|
+
if(widget_config.autoupdate){
|
35
|
+
window.setInterval(function(){
|
36
|
+
redrawWithRange(false, true);
|
37
|
+
}, 3000);
|
38
|
+
}
|
39
|
+
|
40
|
+
function redrawWithRange(first_time, silent){
|
41
|
+
if(!silent){ $("#container").css('opacity', 0.5); }
|
42
|
+
redrawDatepicker();
|
43
|
+
var _query = '?at='+widget_config.start_timestamp+'-'+widget_config.end_timestamp+
|
44
|
+
'&tick='+widget_config.tick+(widget_config.delta ? '&delta=1' : '');
|
45
|
+
chart.series = [];
|
46
|
+
metrics_completed = 0;
|
47
|
+
for(n in widget_config.metrics){
|
48
|
+
$.ajax({
|
49
|
+
url: FnordMetric.p+'/metric/'+widget_config.metrics[n]+_query,
|
50
|
+
success: redrawMetric(first_time, n)
|
51
|
+
});
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
function redrawMetric(first_time, n){
|
56
|
+
return (function(json){
|
57
|
+
for(i in json.values){ json.values[i][0] = json.values[i][0]*1000; }
|
58
|
+
if(!first_time){
|
59
|
+
chart.get('series-'+n).setData(json.values);
|
60
|
+
} else {
|
61
|
+
chart.addSeries({name: widget_config.metrics[n], data: json.values, id: 'series-'+n });
|
62
|
+
}
|
63
|
+
if((metrics_completed += 1) == widget_config.metrics.length){
|
64
|
+
$("#container").css('opacity', 1);
|
65
|
+
}
|
66
|
+
});
|
67
|
+
}
|
68
|
+
|
69
|
+
function redrawDatepicker(){
|
70
|
+
$('.datepicker').html(
|
71
|
+
Highcharts.dateFormat('%d.%m.%y %H:%M', parseInt(widget_config.start_timestamp)*1000) +
|
72
|
+
' ‐ ' +
|
73
|
+
Highcharts.dateFormat('%d.%m.%y %H:%M', parseInt(widget_config.end_timestamp)*1000)
|
74
|
+
);
|
75
|
+
}
|
76
|
+
|
77
|
+
function moveRange(direction){
|
78
|
+
v = widget_config.tick*direction*8;
|
79
|
+
widget_config.start_timestamp += v;
|
80
|
+
widget_config.end_timestamp += v;
|
81
|
+
redrawWithRange();
|
82
|
+
}
|
83
|
+
|
84
|
+
function drawLayout(){
|
85
|
+
$('body').append( $('<div></div>').attr('class', 'headbar').append(
|
86
|
+
$('<div></div>').attr('class', 'button mr').append($('<span></span>').html('refresh')).click(
|
87
|
+
function(){ redrawWithRange(); }
|
88
|
+
)
|
89
|
+
).append(
|
90
|
+
// $('<div></div>').attr('class', 'button').append($('<span></span>').html('1h'))
|
91
|
+
//).append(
|
92
|
+
// $('<div></div>').attr('class', 'button').append($('<span></span>').html('1d'))
|
93
|
+
//).append(
|
94
|
+
$('<div></div>').attr('class', 'button mr').append($('<span></span>').html('→')).click(
|
95
|
+
function(){ moveRange(1); }
|
96
|
+
)
|
97
|
+
).append(
|
98
|
+
$('<div></div>').attr('class', 'datepicker')
|
99
|
+
).append(
|
100
|
+
$('<div></div>').attr('class', 'button').append($('<span></span>').html('←')).click(
|
101
|
+
function(){ moveRange(-1); }
|
102
|
+
)
|
103
|
+
).append(
|
104
|
+
$('<h2></h2>').html(widget_config.title)
|
105
|
+
) );
|
106
|
+
$('body').append( $('<div></div>').attr('id', 'container') );
|
107
|
+
}
|
108
|
+
|
109
|
+
});
|
110
|
+
});
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/*
|
2
|
+
Highcharts JS v2.1.6 (2011-07-08)
|
3
|
+
MooTools adapter
|
4
|
+
|
5
|
+
(c) 2010-2011 Torstein H?nsi
|
6
|
+
|
7
|
+
License: www.highcharts.com/license
|
8
|
+
*/
|
9
|
+
(function(){var g=window,j=!!g.$merge,h=g.$extend||function(){return Object.append.apply(Object,arguments)};g.HighchartsAdapter={init:function(){var a=Fx.prototype,b=a.start,c=Fx.Morph.prototype,d=c.compute;a.start=function(f){var e=this.element;if(f.d)this.paths=Highcharts.pathAnim.init(e,e.d,this.toD);b.apply(this,arguments);return this};c.compute=function(f,e,k){var i=this.paths;if(i)this.element.attr("d",Highcharts.pathAnim.step(i[0],i[1],k,this.toD));else return d.apply(this,arguments)}},animate:function(a,
|
10
|
+
b,c){var d=a.attr,f=c&&c.complete;if(d&&!a.setStyle){a.getStyle=a.attr;a.setStyle=function(){var e=arguments;a.attr.call(a,e[0],e[1][0])};a.$family=a.uid=true}HighchartsAdapter.stop(a);c=new Fx.Morph(d?a:$(a),h({transition:Fx.Transitions.Quad.easeInOut},c));if(b.d)c.toD=b.d;f&&c.addEvent("complete",f);c.start(b);a.fx=c},each:function(a,b){return j?$each(a,b):a.each(b)},map:function(a,b){return a.map(b)},grep:function(a,b){return a.filter(b)},merge:function(){var a=arguments,b=[{}],c=a.length;if(j)a=
|
11
|
+
$merge.apply(null,a);else{for(;c--;)b[c+1]=a[c];a=Object.merge.apply(Object,b)}return a},addEvent:function(a,b,c){if(typeof b=="string"){if(b=="unload")b="beforeunload";if(!a.addEvent)if(a.nodeName)a=$(a);else h(a,new Events);a.addEvent(b,c)}},removeEvent:function(a,b,c){if(b){if(b=="unload")b="beforeunload";defined(c)?a.removeEvent(b,c):a.removeEvents(b)}else a.removeEvents()},fireEvent:function(a,b,c,d){b=new Event({type:b,target:a});b=h(b,c);b.preventDefault=function(){d=null};a.fireEvent&&a.fireEvent(b.type,
|
12
|
+
b);d&&d(b)},stop:function(a){a.fx&&a.fx.cancel()}}})();
|
@@ -0,0 +1,243 @@
|
|
1
|
+
/**
|
2
|
+
* @license Highcharts JS v2.1.6 (2011-07-08)
|
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 Highcharts, Fx, $, $extend, $each, $merge, Events, Event */
|
12
|
+
|
13
|
+
(function() {
|
14
|
+
|
15
|
+
var win = window,
|
16
|
+
legacy = !!win.$merge,
|
17
|
+
$extend = win.$extend || function() {
|
18
|
+
return Object.append.apply(Object, arguments)
|
19
|
+
};
|
20
|
+
|
21
|
+
win.HighchartsAdapter = {
|
22
|
+
/**
|
23
|
+
* Initialize the adapter. This is run once as Highcharts is first run.
|
24
|
+
*/
|
25
|
+
init: function() {
|
26
|
+
var fxProto = Fx.prototype,
|
27
|
+
fxStart = fxProto.start,
|
28
|
+
morphProto = Fx.Morph.prototype,
|
29
|
+
morphCompute = morphProto.compute;
|
30
|
+
|
31
|
+
// override Fx.start to allow animation of SVG element wrappers
|
32
|
+
fxProto.start = function(from, to) {
|
33
|
+
var fx = this,
|
34
|
+
elem = fx.element;
|
35
|
+
|
36
|
+
// special for animating paths
|
37
|
+
if (from.d) {
|
38
|
+
//this.fromD = this.element.d.split(' ');
|
39
|
+
fx.paths = Highcharts.pathAnim.init(
|
40
|
+
elem,
|
41
|
+
elem.d,
|
42
|
+
fx.toD
|
43
|
+
);
|
44
|
+
}
|
45
|
+
fxStart.apply(fx, arguments);
|
46
|
+
|
47
|
+
return this; // chainable
|
48
|
+
};
|
49
|
+
|
50
|
+
// override Fx.step to allow animation of SVG element wrappers
|
51
|
+
morphProto.compute = function(from, to, delta) {
|
52
|
+
var fx = this,
|
53
|
+
paths = fx.paths;
|
54
|
+
|
55
|
+
if (paths) {
|
56
|
+
fx.element.attr(
|
57
|
+
'd',
|
58
|
+
Highcharts.pathAnim.step(paths[0], paths[1], delta, fx.toD)
|
59
|
+
);
|
60
|
+
} else {
|
61
|
+
return morphCompute.apply(fx, arguments);
|
62
|
+
}
|
63
|
+
};
|
64
|
+
|
65
|
+
},
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Animate a HTML element or SVG element wrapper
|
69
|
+
* @param {Object} el
|
70
|
+
* @param {Object} params
|
71
|
+
* @param {Object} options jQuery-like animation options: duration, easing, callback
|
72
|
+
*/
|
73
|
+
animate: function (el, params, options) {
|
74
|
+
var isSVGElement = el.attr,
|
75
|
+
effect,
|
76
|
+
complete = options && options.complete;
|
77
|
+
|
78
|
+
if (isSVGElement && !el.setStyle) {
|
79
|
+
// add setStyle and getStyle methods for internal use in Moo
|
80
|
+
el.getStyle = el.attr;
|
81
|
+
el.setStyle = function() { // property value is given as array in Moo - break it down
|
82
|
+
var args = arguments;
|
83
|
+
el.attr.call(el, args[0], args[1][0]);
|
84
|
+
}
|
85
|
+
// dirty hack to trick Moo into handling el as an element wrapper
|
86
|
+
el.$family = el.uid = true;
|
87
|
+
}
|
88
|
+
|
89
|
+
// stop running animations
|
90
|
+
HighchartsAdapter.stop(el);
|
91
|
+
|
92
|
+
// define and run the effect
|
93
|
+
effect = new Fx.Morph(
|
94
|
+
isSVGElement ? el : $(el),
|
95
|
+
$extend({
|
96
|
+
transition: Fx.Transitions.Quad.easeInOut
|
97
|
+
}, options)
|
98
|
+
);
|
99
|
+
|
100
|
+
// special treatment for paths
|
101
|
+
if (params.d) {
|
102
|
+
effect.toD = params.d;
|
103
|
+
}
|
104
|
+
|
105
|
+
// jQuery-like events
|
106
|
+
if (complete) {
|
107
|
+
effect.addEvent('complete', complete);
|
108
|
+
}
|
109
|
+
|
110
|
+
// run
|
111
|
+
effect.start(params);
|
112
|
+
|
113
|
+
// record for use in stop method
|
114
|
+
el.fx = effect;
|
115
|
+
},
|
116
|
+
|
117
|
+
/**
|
118
|
+
* MooTool's each function
|
119
|
+
*
|
120
|
+
*/
|
121
|
+
each: function(arr, fn) {
|
122
|
+
return legacy ?
|
123
|
+
$each(arr, fn) :
|
124
|
+
arr.each(fn);
|
125
|
+
},
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Map an array
|
129
|
+
* @param {Array} arr
|
130
|
+
* @param {Function} fn
|
131
|
+
*/
|
132
|
+
map: function (arr, fn){
|
133
|
+
return arr.map(fn);
|
134
|
+
},
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Grep or filter an array
|
138
|
+
* @param {Array} arr
|
139
|
+
* @param {Function} fn
|
140
|
+
*/
|
141
|
+
grep: function(arr, fn) {
|
142
|
+
return arr.filter(fn);
|
143
|
+
},
|
144
|
+
|
145
|
+
/**
|
146
|
+
* Deep merge two objects and return a third
|
147
|
+
*/
|
148
|
+
merge: function() {
|
149
|
+
var args = arguments,
|
150
|
+
args13 = [{}], // MooTools 1.3+
|
151
|
+
i = args.length,
|
152
|
+
ret;
|
153
|
+
|
154
|
+
if (legacy) {
|
155
|
+
ret = $merge.apply(null, args);
|
156
|
+
} else {
|
157
|
+
while (i--) {
|
158
|
+
args13[i + 1] = args[i];
|
159
|
+
}
|
160
|
+
ret = Object.merge.apply(Object, args13);
|
161
|
+
}
|
162
|
+
|
163
|
+
return ret;
|
164
|
+
},
|
165
|
+
|
166
|
+
/**
|
167
|
+
* Add an event listener
|
168
|
+
* @param {Object} el HTML element or custom object
|
169
|
+
* @param {String} type Event type
|
170
|
+
* @param {Function} fn Event handler
|
171
|
+
*/
|
172
|
+
addEvent: function (el, type, fn) {
|
173
|
+
if (typeof type == 'string') { // chart broke due to el being string, type function
|
174
|
+
|
175
|
+
if (type == 'unload') { // Moo self destructs before custom unload events
|
176
|
+
type = 'beforeunload';
|
177
|
+
}
|
178
|
+
|
179
|
+
// if the addEvent method is not defined, el is a custom Highcharts object
|
180
|
+
// like series or point
|
181
|
+
if (!el.addEvent) {
|
182
|
+
if (el.nodeName) {
|
183
|
+
el = $(el); // a dynamically generated node
|
184
|
+
} else {
|
185
|
+
$extend(el, new Events()); // a custom object
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
el.addEvent(type, fn);
|
190
|
+
}
|
191
|
+
},
|
192
|
+
|
193
|
+
removeEvent: function(el, type, fn) {
|
194
|
+
if (type) {
|
195
|
+
if (type == 'unload') { // Moo self destructs before custom unload events
|
196
|
+
type = 'beforeunload';
|
197
|
+
}
|
198
|
+
|
199
|
+
if (defined(fn)) {
|
200
|
+
el.removeEvent(type, fn);
|
201
|
+
} else {
|
202
|
+
el.removeEvents(type);
|
203
|
+
}
|
204
|
+
} else {
|
205
|
+
el.removeEvents();
|
206
|
+
}
|
207
|
+
},
|
208
|
+
|
209
|
+
fireEvent: function(el, event, eventArguments, defaultFunction) {
|
210
|
+
// create an event object that keeps all functions
|
211
|
+
event = new Event({
|
212
|
+
type: event,
|
213
|
+
target: el
|
214
|
+
});
|
215
|
+
event = $extend(event, eventArguments);
|
216
|
+
// override the preventDefault function to be able to use
|
217
|
+
// this for custom events
|
218
|
+
event.preventDefault = function() {
|
219
|
+
defaultFunction = null;
|
220
|
+
};
|
221
|
+
// if fireEvent is not available on the object, there hasn't been added
|
222
|
+
// any events to it above
|
223
|
+
if (el.fireEvent) {
|
224
|
+
el.fireEvent(event.type, event);
|
225
|
+
}
|
226
|
+
|
227
|
+
// fire the default if it is passed and it is not prevented above
|
228
|
+
if (defaultFunction) {
|
229
|
+
defaultFunction(event);
|
230
|
+
}
|
231
|
+
},
|
232
|
+
|
233
|
+
/**
|
234
|
+
* Stop running animations on the object
|
235
|
+
*/
|
236
|
+
stop: function (el) {
|
237
|
+
if (el.fx) {
|
238
|
+
el.fx.cancel();
|
239
|
+
}
|
240
|
+
}
|
241
|
+
}
|
242
|
+
|
243
|
+
})();
|