visage-app 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +9 -0
- data/README.md +138 -0
- data/Rakefile +33 -0
- data/VERSION +1 -0
- data/bin/visage +17 -0
- data/config.ru +7 -0
- data/features/json.feature +66 -0
- data/features/site.feature +9 -0
- data/features/step_definitions/form_steps.rb +6 -0
- data/features/step_definitions/json_steps.rb +79 -0
- data/features/step_definitions/result_steps.rb +19 -0
- data/features/step_definitions/site_steps.rb +4 -0
- data/features/step_definitions/visage_steps.rb +20 -0
- data/features/step_definitions/webrat_steps.rb +42 -0
- data/features/support/env.rb +36 -0
- data/features/visage.feature +11 -0
- data/lib/visage/collectd/json.rb +142 -0
- data/lib/visage/collectd/profile.rb +36 -0
- data/lib/visage/config/fallback-colors.yaml +82 -0
- data/lib/visage/config/init.rb +33 -0
- data/lib/visage/config/plugin-colors.yaml +63 -0
- data/lib/visage/config/profiles.yaml +35 -0
- data/lib/visage/config/profiles.yaml.sample +33 -0
- data/lib/visage/config.rb +51 -0
- data/lib/visage/patches.rb +18 -0
- data/lib/visage/public/favicon.gif +0 -0
- data/lib/visage/public/javascripts/application.js +4 -0
- data/lib/visage/public/javascripts/g.line.js +217 -0
- data/lib/visage/public/javascripts/g.raphael.js +7 -0
- data/lib/visage/public/javascripts/graph.js +510 -0
- data/lib/visage/public/javascripts/mootools-1.2.3-core.js +4036 -0
- data/lib/visage/public/javascripts/mootools-1.2.3.1-more.js +104 -0
- data/lib/visage/public/javascripts/raphael-min.js +7 -0
- data/lib/visage/public/javascripts/raphael.js +3215 -0
- data/lib/visage/public/stylesheets/screen.css +96 -0
- data/lib/visage/views/index.haml +48 -0
- data/lib/visage/views/layout.haml +22 -0
- data/lib/visage/views/single.haml +43 -0
- data/lib/visage-app.rb +81 -0
- metadata +142 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
class CollectdProfile
|
7
|
+
|
8
|
+
def initialize(opts={})
|
9
|
+
@profile = opts[:profile]
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
attr_accessor :profiles
|
15
|
+
|
16
|
+
def get(id)
|
17
|
+
id.gsub!(/\s+/, '+')
|
18
|
+
if found = @profiles.find {|p| p[1]["splat"] == id }
|
19
|
+
OpenStruct.new(found[1])
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def all
|
26
|
+
# here be ugliness
|
27
|
+
profiles = @profiles.to_a.sort_by { |profile|
|
28
|
+
profile[1]["order"]
|
29
|
+
}.map { |profile|
|
30
|
+
OpenStruct.new(profile[1].merge({'name' => profile[0]}))
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
---
|
2
|
+
Aluminium 1:
|
3
|
+
color: "#eeeeec"
|
4
|
+
fallback_order: 20
|
5
|
+
Aluminium 2:
|
6
|
+
color: "#d3d7cf"
|
7
|
+
fallback_order: 20
|
8
|
+
Aluminium 3:
|
9
|
+
color: "#babdb6"
|
10
|
+
fallback_order: 15
|
11
|
+
Aluminium 4:
|
12
|
+
color: "#888a85"
|
13
|
+
fallback_order: 20
|
14
|
+
Aluminium 5:
|
15
|
+
color: "#555753"
|
16
|
+
fallback_order: 20
|
17
|
+
Aluminium 6:
|
18
|
+
color: "#2e3436"
|
19
|
+
fallback_order: 7
|
20
|
+
Butter 1:
|
21
|
+
color: "#fce94f"
|
22
|
+
fallback_order: 12
|
23
|
+
Butter 2:
|
24
|
+
color: "#edd400"
|
25
|
+
fallback_order: 4
|
26
|
+
Butter 3:
|
27
|
+
color: "#c4a000"
|
28
|
+
fallback_order: 20
|
29
|
+
Chameleon 1:
|
30
|
+
color: "#8ae234"
|
31
|
+
fallback_order: 11
|
32
|
+
Chameleon 2:
|
33
|
+
color: "#73d216"
|
34
|
+
fallback_order: 1
|
35
|
+
Chameleon 3:
|
36
|
+
color: "#4e9a06"
|
37
|
+
fallback_order: 20
|
38
|
+
Chocolate 1:
|
39
|
+
color: "#e9b96e"
|
40
|
+
fallback_order: 14
|
41
|
+
Chocolate 2:
|
42
|
+
color: "#c17d11"
|
43
|
+
fallback_order: 5
|
44
|
+
Chocolate 3:
|
45
|
+
color: "#8f5902"
|
46
|
+
fallback_order: 20
|
47
|
+
Orange 1:
|
48
|
+
color: "#fcaf3e"
|
49
|
+
fallback_order: 13
|
50
|
+
Orange 2:
|
51
|
+
color: "#f57900"
|
52
|
+
fallback_order: 5
|
53
|
+
Orange 3:
|
54
|
+
color: "#ce5c00"
|
55
|
+
fallback_order: 20
|
56
|
+
Plum 1:
|
57
|
+
color: "#ad7fa8"
|
58
|
+
fallback_order: 9
|
59
|
+
Plum 2:
|
60
|
+
color: "#5c3566"
|
61
|
+
fallback_order: 20
|
62
|
+
Plum 3:
|
63
|
+
color: "#5c3566"
|
64
|
+
fallback_order: 1
|
65
|
+
Scarlet Red 1:
|
66
|
+
color: "#ef2929"
|
67
|
+
fallback_order: 8
|
68
|
+
Scarlet Red 2:
|
69
|
+
color: "#cc0000"
|
70
|
+
fallback_order: 0
|
71
|
+
Scarlet Red 3:
|
72
|
+
color: "#a40000"
|
73
|
+
fallback_order: 20
|
74
|
+
Sky Blue 1:
|
75
|
+
color: "#729fcf"
|
76
|
+
fallback_order: 10
|
77
|
+
Sky Blue 2:
|
78
|
+
color: "#3465a4"
|
79
|
+
fallback_order: 2
|
80
|
+
Sky Blue 3:
|
81
|
+
color: "#204a87"
|
82
|
+
fallback_order: 20
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
__DIR__ = File.expand_path(File.dirname(__FILE__))
|
4
|
+
require File.join(__DIR__, '..', 'config')
|
5
|
+
|
6
|
+
Visage::Config.use do |c|
|
7
|
+
c['fallback_colors'] = YAML::load(File.read(File.join(__DIR__, 'fallback-colors.yaml')))
|
8
|
+
|
9
|
+
profile_filename = File.join(__DIR__, 'profiles.yaml')
|
10
|
+
unless File.exists?(profile_filename)
|
11
|
+
puts "You need to specify a list of profiles in config/profile.yaml!"
|
12
|
+
puts "Check out config/profiles.yaml.sample for an example."
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
YAML::load(File.read(profile_filename)).each_pair do |key, value|
|
16
|
+
c[key] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
plugin_colors_filename = File.join(__DIR__, 'plugin-colors.yaml')
|
20
|
+
unless File.exists?(plugin_colors_filename)
|
21
|
+
puts "It's highly recommended you specify graph line colors in config/plugin-colors.yaml!"
|
22
|
+
end
|
23
|
+
YAML::load(File.read(plugin_colors_filename)).each_pair do |key, value|
|
24
|
+
c[key] = value
|
25
|
+
end
|
26
|
+
|
27
|
+
# Location of collectd's RRD - you may want to edit this!
|
28
|
+
c['rrddir'] = "/var/lib/collectd/rrd"
|
29
|
+
|
30
|
+
# whether to shade in graphs
|
31
|
+
c['shade'] = false
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
---
|
2
|
+
plugin_colors:
|
3
|
+
memory:
|
4
|
+
memory-used:
|
5
|
+
value: "#cc0000"
|
6
|
+
memory-buffered:
|
7
|
+
value: "#edd400"
|
8
|
+
memory-cached:
|
9
|
+
value: "#3465a4"
|
10
|
+
memory-free:
|
11
|
+
value: "#73d216"
|
12
|
+
cpu:
|
13
|
+
cpu-idle:
|
14
|
+
value: "#eeeeec"
|
15
|
+
cpu-wait:
|
16
|
+
value: "#edd400"
|
17
|
+
cpu-user:
|
18
|
+
value: "#3465a4"
|
19
|
+
cpu-system:
|
20
|
+
value: "#cc0000"
|
21
|
+
cpu-nice:
|
22
|
+
value: "#73d216"
|
23
|
+
cpu-softirq:
|
24
|
+
value: "#ad7fa8"
|
25
|
+
cpu-interrupt:
|
26
|
+
value: "#5c3566"
|
27
|
+
cpu-steal:
|
28
|
+
value: "#2e3436"
|
29
|
+
swap:
|
30
|
+
swap-used:
|
31
|
+
value: "#cc0000"
|
32
|
+
swap-free:
|
33
|
+
value: "#73d216"
|
34
|
+
swap-cached:
|
35
|
+
value: "#3465a4"
|
36
|
+
load:
|
37
|
+
load:
|
38
|
+
longterm: "#ef2929"
|
39
|
+
shortterm: "#73d216"
|
40
|
+
midterm: "#3465a4"
|
41
|
+
df:
|
42
|
+
df:
|
43
|
+
used: "#cc0000"
|
44
|
+
free: "#73d216"
|
45
|
+
disk:
|
46
|
+
disk_merged:
|
47
|
+
read: "#8ae234"
|
48
|
+
write: "#ef2929"
|
49
|
+
disk_time:
|
50
|
+
read: "#729fcf"
|
51
|
+
write: "#fcaf3e"
|
52
|
+
disk_ops:
|
53
|
+
read: "#ad7fa8"
|
54
|
+
write: "#fce94f"
|
55
|
+
disk_octets:
|
56
|
+
read: "#c17d11"
|
57
|
+
write: "#888a85"
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
---
|
2
|
+
profiles:
|
3
|
+
CPU + Load:
|
4
|
+
plugins:
|
5
|
+
- cpu-0/cpu-user/cpu-system/cpu-idle/cpu-wait/cpu-interrupt
|
6
|
+
- cpu-1
|
7
|
+
- load/load
|
8
|
+
- battery-0
|
9
|
+
splat: cpu+load
|
10
|
+
order: 1
|
11
|
+
Memory:
|
12
|
+
plugins:
|
13
|
+
- memory
|
14
|
+
- swap
|
15
|
+
splat: memory
|
16
|
+
order: 2
|
17
|
+
Disk Usage:
|
18
|
+
plugins:
|
19
|
+
- df/df-root
|
20
|
+
- disk-sda
|
21
|
+
splat: disk+usage
|
22
|
+
order: 3
|
23
|
+
Networking:
|
24
|
+
plugins:
|
25
|
+
- tcpconns-9393-local
|
26
|
+
- tcpconns-80-local
|
27
|
+
- tcpconns-22-local
|
28
|
+
splat: network
|
29
|
+
order: 4
|
30
|
+
Processes:
|
31
|
+
plugins:
|
32
|
+
- processes
|
33
|
+
- processes-collectd
|
34
|
+
splat: processes
|
35
|
+
order: 5
|
@@ -0,0 +1,33 @@
|
|
1
|
+
---
|
2
|
+
profiles:
|
3
|
+
cpu+load:
|
4
|
+
plugins:
|
5
|
+
- cpu-0
|
6
|
+
- cpu-1
|
7
|
+
- load/load
|
8
|
+
- battery-0
|
9
|
+
name: CPU + Load
|
10
|
+
order: 1
|
11
|
+
memory:
|
12
|
+
plugins:
|
13
|
+
- memory
|
14
|
+
- swap
|
15
|
+
name: Memory
|
16
|
+
order: 2
|
17
|
+
disk+usage:
|
18
|
+
plugins:
|
19
|
+
- df/df-root
|
20
|
+
- disk-sda
|
21
|
+
name: Disk Usage
|
22
|
+
order: 3
|
23
|
+
network:
|
24
|
+
plugins:
|
25
|
+
- tcpconns-9393-local
|
26
|
+
- tcpconns-80-local
|
27
|
+
name: Networking
|
28
|
+
order: 4
|
29
|
+
processes:
|
30
|
+
plugins:
|
31
|
+
- processes
|
32
|
+
name: Processes
|
33
|
+
order: 5
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Visage
|
2
|
+
class Config
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def use
|
6
|
+
@configuration ||= {}
|
7
|
+
yield @configuration
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(method, *args)
|
12
|
+
if method.to_s[-1,1] == '='
|
13
|
+
@configuration[method.to_s.tr('=','')] = *args
|
14
|
+
else
|
15
|
+
@configuration[method.to_s]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hash
|
20
|
+
@configuration
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Profiles
|
25
|
+
class << self
|
26
|
+
require 'ostruct'
|
27
|
+
|
28
|
+
attr_accessor :profiles
|
29
|
+
|
30
|
+
def get(id)
|
31
|
+
id.gsub!(/\s+/, '+')
|
32
|
+
if found = @profiles.find {|p| p[1]["splat"] == id }
|
33
|
+
OpenStruct.new(found[1])
|
34
|
+
else
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def all
|
40
|
+
# here be ugliness
|
41
|
+
profiles = @profiles.to_a.sort_by { |profile|
|
42
|
+
profile[1]["order"]
|
43
|
+
}.map { |profile|
|
44
|
+
OpenStruct.new(profile[1].merge({'name' => profile[0]}))
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# extracted from Extlib.
|
2
|
+
# FIXME: what's the licensing here?
|
3
|
+
class String
|
4
|
+
def camel_case
|
5
|
+
return self if self !~ /_/ && self =~ /[A-Z]+.*/
|
6
|
+
split('_').map{|e| e.capitalize}.join
|
7
|
+
end
|
8
|
+
|
9
|
+
def blank?
|
10
|
+
strip.empty?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class NilClass
|
15
|
+
def blank?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
Binary file
|
@@ -0,0 +1,217 @@
|
|
1
|
+
/*
|
2
|
+
* g.Raphael 0.4 - Charting library, based on Raphaël
|
3
|
+
*
|
4
|
+
* Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
|
5
|
+
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
|
6
|
+
*/
|
7
|
+
Raphael.fn.g.linechart = function (x, y, width, height, valuesx, valuesy, opts) {
|
8
|
+
function shrink(values, dim) {
|
9
|
+
var k = values.length / dim,
|
10
|
+
j = 0,
|
11
|
+
l = k,
|
12
|
+
sum = 0,
|
13
|
+
res = [];
|
14
|
+
while (j < values.length) {
|
15
|
+
l--;
|
16
|
+
if (l < 0) {
|
17
|
+
sum += values[j] * (1 + l);
|
18
|
+
res.push(sum / k);
|
19
|
+
sum = values[j++] * -l;
|
20
|
+
l += k;
|
21
|
+
} else {
|
22
|
+
sum += values[j++];
|
23
|
+
}
|
24
|
+
}
|
25
|
+
return res;
|
26
|
+
}
|
27
|
+
opts = opts || {};
|
28
|
+
if (!this.raphael.is(valuesx[0], "array")) {
|
29
|
+
valuesx = [valuesx];
|
30
|
+
}
|
31
|
+
if (!this.raphael.is(valuesy[0], "array")) {
|
32
|
+
valuesy = [valuesy];
|
33
|
+
}
|
34
|
+
var allx = Array.prototype.concat.apply([], valuesx),
|
35
|
+
ally = Array.prototype.concat.apply([], valuesy),
|
36
|
+
xdim = this.g.snapEnds(Math.min.apply(Math, allx), Math.max.apply(Math, allx), valuesx[0].length - 1),
|
37
|
+
minx = xdim.from,
|
38
|
+
maxx = xdim.to,
|
39
|
+
gutter = opts.gutter || 10,
|
40
|
+
kx = (width - gutter * 2) / (maxx - minx),
|
41
|
+
ydim = this.g.snapEnds(Math.min.apply(Math, ally), Math.max.apply(Math, ally), valuesy[0].length - 1),
|
42
|
+
miny = ydim.from,
|
43
|
+
maxy = ydim.to,
|
44
|
+
ky = (height - gutter * 2) / (maxy - miny),
|
45
|
+
len = Math.max(valuesx[0].length, valuesy[0].length),
|
46
|
+
symbol = opts.symbol || "",
|
47
|
+
colors = opts.colors || Raphael.fn.g.colors,
|
48
|
+
that = this,
|
49
|
+
columns = null,
|
50
|
+
dots = null,
|
51
|
+
chart = this.set(),
|
52
|
+
path = [];
|
53
|
+
|
54
|
+
for (var i = 0, ii = valuesy.length; i < ii; i++) {
|
55
|
+
len = Math.max(len, valuesy[i].length);
|
56
|
+
}
|
57
|
+
var shades = this.set();
|
58
|
+
for (var i = 0, ii = valuesy.length; i < ii; i++) {
|
59
|
+
if (opts.shade) {
|
60
|
+
shades.push(this.path().attr({stroke: "none", fill: colors[i], opacity: opts.nostroke ? 1 : .3}));
|
61
|
+
}
|
62
|
+
if (valuesy[i].length > width - 2 * gutter) {
|
63
|
+
valuesy[i] = shrink(valuesy[i], width - 2 * gutter);
|
64
|
+
len = width - 2 * gutter;
|
65
|
+
}
|
66
|
+
if (valuesx[i] && valuesx[i].length > width - 2 * gutter) {
|
67
|
+
valuesx[i] = shrink(valuesx[i], width - 2 * gutter);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
var axis = this.set();
|
71
|
+
if (opts.axis) {
|
72
|
+
var ax = (opts.axis + "").split(/[,\s]+/);
|
73
|
+
+ax[0] && axis.push(this.g.axis(x + gutter, y + gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 2));
|
74
|
+
+ax[1] && axis.push(this.g.axis(x + width - gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 3));
|
75
|
+
+ax[2] && axis.push(this.g.axis(x + gutter, y + height - gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 0));
|
76
|
+
+ax[3] && axis.push(this.g.axis(x + gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 1));
|
77
|
+
}
|
78
|
+
var lines = this.set(),
|
79
|
+
symbols = this.set(),
|
80
|
+
line;
|
81
|
+
for (var i = 0, ii = valuesy.length; i < ii; i++) {
|
82
|
+
if (!opts.nostroke) {
|
83
|
+
lines.push(line = this.path().attr({
|
84
|
+
stroke: colors[i],
|
85
|
+
"stroke-width": opts.width || 2,
|
86
|
+
"stroke-linejoin": "round",
|
87
|
+
"stroke-linecap": "round",
|
88
|
+
"stroke-dasharray": opts.dash || ""
|
89
|
+
}));
|
90
|
+
}
|
91
|
+
var sym = this.raphael.is(symbol, "array") ? symbol[i] : symbol,
|
92
|
+
symset = this.set();
|
93
|
+
path = [];
|
94
|
+
for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
|
95
|
+
var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx;
|
96
|
+
var Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
|
97
|
+
(Raphael.is(sym, "array") ? sym[j] : sym) && symset.push(this.g[Raphael.fn.g.markers[this.raphael.is(sym, "array") ? sym[j] : sym]](X, Y, (opts.width || 2) * 3).attr({fill: colors[i], stroke: "none"}));
|
98
|
+
path = path.concat([j ? "L" : "M", X, Y]);
|
99
|
+
}
|
100
|
+
symbols.push(symset);
|
101
|
+
if (opts.shade) {
|
102
|
+
shades[i].attr({path: path.concat(["L", X, y + height - gutter, "L", x + gutter + ((valuesx[i] || valuesx[0])[0] - minx) * kx, y + height - gutter, "z"]).join(",")});
|
103
|
+
}
|
104
|
+
!opts.nostroke && line.attr({path: path.join(",")});
|
105
|
+
}
|
106
|
+
function createColumns(f) {
|
107
|
+
// unite Xs together
|
108
|
+
var Xs = [];
|
109
|
+
for (var i = 0, ii = valuesx.length; i < ii; i++) {
|
110
|
+
Xs = Xs.concat(valuesx[i]);
|
111
|
+
}
|
112
|
+
Xs.sort();
|
113
|
+
// remove duplicates
|
114
|
+
var Xs2 = [],
|
115
|
+
xs = [];
|
116
|
+
for (var i = 0, ii = Xs.length; i < ii; i++) {
|
117
|
+
Xs[i] != Xs[i - 1] && Xs2.push(Xs[i]) && xs.push(x + gutter + (Xs[i] - minx) * kx);
|
118
|
+
}
|
119
|
+
Xs = Xs2;
|
120
|
+
ii = Xs.length;
|
121
|
+
var cvrs = f || that.set();
|
122
|
+
for (var i = 0; i < ii; i++) {
|
123
|
+
var X = xs[i] - (xs[i] - (xs[i - 1] || x)) / 2,
|
124
|
+
w = ((xs[i + 1] || x + width) - xs[i]) / 2 + (xs[i] - (xs[i - 1] || x)) / 2,
|
125
|
+
C;
|
126
|
+
f ? (C = {}) : cvrs.push(C = that.rect(X - 1, y, Math.max(w + 1, 1), height).attr({stroke: "none", fill: "#000", opacity: 0}));
|
127
|
+
C.values = [];
|
128
|
+
C.symbols = that.set();
|
129
|
+
C.y = [];
|
130
|
+
C.x = xs[i];
|
131
|
+
C.axis = Xs[i];
|
132
|
+
for (var j = 0, jj = valuesy.length; j < jj; j++) {
|
133
|
+
Xs2 = valuesx[j] || valuesx[0];
|
134
|
+
for (var k = 0, kk = Xs2.length; k < kk; k++) {
|
135
|
+
if (Xs2[k] == Xs[i]) {
|
136
|
+
C.values.push(valuesy[j][k]);
|
137
|
+
C.y.push(y + height - gutter - (valuesy[j][k] - miny) * ky);
|
138
|
+
C.symbols.push(chart.symbols[j][k]);
|
139
|
+
}
|
140
|
+
}
|
141
|
+
}
|
142
|
+
f && f.call(C);
|
143
|
+
}
|
144
|
+
!f && (columns = cvrs);
|
145
|
+
}
|
146
|
+
function createDots(f) {
|
147
|
+
var cvrs = f || that.set(),
|
148
|
+
C;
|
149
|
+
for (var i = 0, ii = valuesy.length; i < ii; i++) {
|
150
|
+
for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
|
151
|
+
var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx,
|
152
|
+
nearX = x + gutter + ((valuesx[i] || valuesx[0])[j ? j - 1 : 1] - minx) * kx,
|
153
|
+
Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
|
154
|
+
f ? (C = {}) : cvrs.push(C = that.circle(X, Y, Math.abs(nearX - X) / 2).attr({stroke: "none", fill: "#000", opacity: 0}));
|
155
|
+
C.x = X;
|
156
|
+
C.y = Y;
|
157
|
+
C.value = valuesy[i][j];
|
158
|
+
C.line = chart.lines[i];
|
159
|
+
C.shade = chart.shades[i];
|
160
|
+
C.symbol = chart.symbols[i][j];
|
161
|
+
C.symbols = chart.symbols[i];
|
162
|
+
C.axis = (valuesx[i] || valuesx[0])[j];
|
163
|
+
f && f.call(C);
|
164
|
+
}
|
165
|
+
}
|
166
|
+
!f && (dots = cvrs);
|
167
|
+
}
|
168
|
+
chart.push(lines, shades, symbols, axis, columns, dots);
|
169
|
+
chart.lines = lines;
|
170
|
+
chart.shades = shades;
|
171
|
+
chart.symbols = symbols;
|
172
|
+
chart.axis = axis;
|
173
|
+
chart.hoverColumn = function (fin, fout) {
|
174
|
+
!columns && createColumns();
|
175
|
+
columns.mouseover(fin).mouseout(fout);
|
176
|
+
return this;
|
177
|
+
};
|
178
|
+
chart.clickColumn = function (f) {
|
179
|
+
!columns && createColumns();
|
180
|
+
columns.click(f);
|
181
|
+
return this;
|
182
|
+
};
|
183
|
+
chart.hrefColumn = function (cols) {
|
184
|
+
var hrefs = that.raphael.is(arguments[0], "array") ? arguments[0] : arguments;
|
185
|
+
if (!(arguments.length - 1) && typeof cols == "object") {
|
186
|
+
for (var x in cols) {
|
187
|
+
for (var i = 0, ii = columns.length; i < ii; i++) if (columns[i].axis == x) {
|
188
|
+
columns[i].attr("href", cols[x]);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
192
|
+
!columns && createColumns();
|
193
|
+
for (var i = 0, ii = hrefs.length; i < ii; i++) {
|
194
|
+
columns[i] && columns[i].attr("href", hrefs[i]);
|
195
|
+
}
|
196
|
+
return this;
|
197
|
+
};
|
198
|
+
chart.hover = function (fin, fout) {
|
199
|
+
!dots && createDots();
|
200
|
+
dots.mouseover(fin).mouseout(fout);
|
201
|
+
return this;
|
202
|
+
};
|
203
|
+
chart.click = function (f) {
|
204
|
+
!dots && createDots();
|
205
|
+
dots.click(f);
|
206
|
+
return this;
|
207
|
+
};
|
208
|
+
chart.each = function (f) {
|
209
|
+
createDots(f);
|
210
|
+
return this;
|
211
|
+
};
|
212
|
+
chart.eachColumn = function (f) {
|
213
|
+
createColumns(f);
|
214
|
+
return this;
|
215
|
+
};
|
216
|
+
return chart;
|
217
|
+
};
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/*
|
2
|
+
* g.Raphael 0.4 - Charting library, based on Raphaël
|
3
|
+
*
|
4
|
+
* Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
|
5
|
+
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
|
6
|
+
*/
|
7
|
+
(function(){Raphael.fn.g=Raphael.fn.g||{};Raphael.fn.g.markers={disc:"disc",o:"disc",flower:"flower",f:"flower",diamond:"diamond",d:"diamond",square:"square",s:"square",triangle:"triangle",t:"triangle",star:"star","*":"star",cross:"cross",x:"cross",plus:"plus","+":"plus",arrow:"arrow","->":"arrow"};Raphael.fn.g.shim={stroke:"none",fill:"#000","fill-opacity":0};Raphael.fn.g.txtattr={font:"12px Arial, sans-serif"};Raphael.fn.g.colors=[];var b=[0.6,0.2,0.05,0.1333,0.75,0];for(var a=0;a<10;a++){if(a<b.length){Raphael.fn.g.colors.push("hsb("+b[a]+", .75, .75)");}else{Raphael.fn.g.colors.push("hsb("+b[a-b.length]+", 1, .5)");}}Raphael.fn.g.text=function(c,f,e){return this.text(c,f,e).attr(this.g.txtattr);};Raphael.fn.g.labelise=function(c,f,e){if(c){return(c+"").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g,function(g,i,h){if(i){return(+f).toFixed(i.replace(/^#+\.?/g,"").length);}if(h){return(f*100/e).toFixed(h.replace(/^%+\.?/g,"").length)+"%";}});}else{return(+f).toFixed(0);}};Raphael.fn.g.finger=function(j,i,e,k,f,g,h){if((f&&!k)||(!f&&!e)){return h?"":this.path();}g={square:"square",sharp:"sharp",soft:"soft"}[g]||"round";var m;k=Math.round(k);e=Math.round(e);j=Math.round(j);i=Math.round(i);switch(g){case"round":if(!f){var c=Math.floor(k/2);if(e<c){c=e;m=["M",j+0.5,i+0.5-Math.floor(k/2),"l",0,0,"a",c,Math.floor(k/2),0,0,1,0,k,"l",0,0,"z"];}else{m=["M",j+0.5,i+0.5-c,"l",e-c,0,"a",c,c,0,1,1,0,k,"l",c-e,0,"z"];}}else{var c=Math.floor(e/2);if(k<c){c=k;m=["M",j-Math.floor(e/2),i,"l",0,0,"a",Math.floor(e/2),c,0,0,1,e,0,"l",0,0,"z"];}else{m=["M",j-c,i,"l",0,c-k,"a",c,c,0,1,1,e,0,"l",0,k-c,"z"];}}break;case"sharp":if(!f){var l=Math.floor(k/2);m=["M",j,i+l,"l",0,-k,Math.max(e-l,0),0,Math.min(l,e),l,-Math.min(l,e),l+(l*2<k),"z"];}else{var l=Math.floor(e/2);m=["M",j+l,i,"l",-e,0,0,-Math.max(k-l,0),l,-Math.min(l,k),l,Math.min(l,k),l,"z"];}break;case"square":if(!f){m=["M",j,i+Math.floor(k/2),"l",0,-k,e,0,0,k,"z"];}else{m=["M",j+Math.floor(e/2),i,"l",1-e,0,0,-k,e-1,0,"z"];}break;case"soft":var c;if(!f){c=Math.min(e,Math.round(k/5));m=["M",j+0.5,i+0.5-Math.floor(k/2),"l",e-c,0,"a",c,c,0,0,1,c,c,"l",0,k-c*2,"a",c,c,0,0,1,-c,c,"l",c-e,0,"z"];}else{c=Math.min(Math.round(e/5),k);m=["M",j-Math.floor(e/2),i,"l",0,c-k,"a",c,c,0,0,1,c,-c,"l",e-2*c,0,"a",c,c,0,0,1,c,c,"l",0,k-c,"z"];}}if(h){return m.join(",");}else{return this.path(m);}};Raphael.fn.g.disc=function(c,f,e){return this.circle(c,f,e);};Raphael.fn.g.line=function(c,f,e){return this.rect(c-e,f-e/5,2*e,2*e/5);};Raphael.fn.g.square=function(c,f,e){e=e*0.7;return this.rect(c-e,f-e,2*e,2*e);};Raphael.fn.g.triangle=function(c,f,e){e*=1.75;return this.path("M".concat(c,",",f,"m0-",e*0.58,"l",e*0.5,",",e*0.87,"-",e,",0z"));};Raphael.fn.g.diamond=function(c,f,e){return this.path(["M",c,f-e,"l",e,e,-e,e,-e,-e,e,-e,"z"]);};Raphael.fn.g.flower=function(g,f,c,e){c=c*1.25;var l=c,k=l*0.5;e=+e<3||!e?5:e;var m=["M",g,f+k,"Q"],j;for(var h=1;h<e*2+1;h++){j=h%2?l:k;m=m.concat([+(g+j*Math.sin(h*Math.PI/e)).toFixed(3),+(f+j*Math.cos(h*Math.PI/e)).toFixed(3)]);}m.push("z");return this.path(m.join(","));};Raphael.fn.g.star=function(c,k,j,e){e=e||j*0.5;var h=["M",c,k+e,"L"],g;for(var f=1;f<10;f++){g=f%2?j:e;h=h.concat([(c+g*Math.sin(f*Math.PI*0.2)).toFixed(3),(k+g*Math.cos(f*Math.PI*0.2)).toFixed(3)]);}h.push("z");return this.path(h.join(","));};Raphael.fn.g.cross=function(c,f,e){e=e/2.5;return this.path("M".concat(c-e,",",f,"l",[-e,-e,e,-e,e,e,e,-e,e,e,-e,e,e,e,-e,e,-e,-e,-e,e,-e,-e,"z"]));};Raphael.fn.g.plus=function(c,f,e){e=e/2;return this.path("M".concat(c-e/2,",",f-e/2,"l",[0,-e,e,0,0,e,e,0,0,e,-e,0,0,e,-e,0,0,-e,-e,0,0,-e,"z"]));};Raphael.fn.g.arrow=function(c,f,e){return this.path("M".concat(c-e*0.7,",",f-e*0.4,"l",[e*0.6,0,0,-e*0.4,e,e*0.8,-e,e*0.8,0,-e*0.4,-e*0.6,0],"z"));};Raphael.fn.g.tag=function(c,k,j,i,g){i=i||0;g=g==null?5:g;j=j==null?"$9.99":j;var f=0.5522*g,e=this.set(),h=3;e.push(this.path().attr({fill:"#000",stroke:"none"}));e.push(this.text(c,k,j).attr(this.g.txtattr).attr({fill:"#fff"}));e.update=function(){this.rotate(0,c,k);var m=this[1].getBBox();if(m.height>=g*2){this[0].attr({path:["M",c,k+g,"a",g,g,0,1,1,0,-g*2,g,g,0,1,1,0,g*2,"m",0,-g*2-h,"a",g+h,g+h,0,1,0,0,(g+h)*2,"L",c+g+h,k+m.height/2+h,"l",m.width+2*h,0,0,-m.height-2*h,-m.width-2*h,0,"L",c,k-g-h].join(",")});}else{var l=Math.sqrt(Math.pow(g+h,2)-Math.pow(m.height/2+h,2));this[0].attr({path:["M",c,k+g,"c",-f,0,-g,f-g,-g,-g,0,-f,g-f,-g,g,-g,f,0,g,g-f,g,g,0,f,f-g,g,-g,g,"M",c+l,k-m.height/2-h,"a",g+h,g+h,0,1,0,0,m.height+2*h,"l",g+h-l+m.width+2*h,0,0,-m.height-2*h,"L",c+l,k-m.height/2-h].join(",")});}this[1].attr({x:c+g+h+m.width/2,y:k});i=(360-i)%360;this.rotate(i,c,k);i>90&&i<270&&this[1].attr({x:c-g-h-m.width/2,y:k,rotation:[180+i,c,k]});return this;};e.update();return e;};Raphael.fn.g.popupit=function(j,i,k,e,q){e=e==null?2:e;q=q||5;j=Math.round(j)+0.5;i=Math.round(i)+0.5;var g=k.getBBox(),l=Math.round(g.width/2),f=Math.round(g.height/2),o=[0,l+q*2,0,-l-q*2],m=[-f*2-q*3,-f-q,0,-f-q],c=["M",j-o[e],i-m[e],"l",-q,(e==2)*-q,-Math.max(l-q,0),0,"a",q,q,0,0,1,-q,-q,"l",0,-Math.max(f-q,0),(e==3)*-q,-q,(e==3)*q,-q,0,-Math.max(f-q,0),"a",q,q,0,0,1,q,-q,"l",Math.max(l-q,0),0,q,!e*-q,q,!e*q,Math.max(l-q,0),0,"a",q,q,0,0,1,q,q,"l",0,Math.max(f-q,0),(e==1)*q,q,(e==1)*-q,q,0,Math.max(f-q,0),"a",q,q,0,0,1,-q,q,"l",-Math.max(l-q,0),0,"z"].join(","),n=[{x:j,y:i+q*2+f},{x:j-q*2-l,y:i},{x:j,y:i-q*2-f},{x:j+q*2+l,y:i}][e];k.translate(n.x-l-g.x,n.y-f-g.y);return this.path(c).attr({fill:"#000",stroke:"none"}).insertBefore(k.node?k:k[0]);};Raphael.fn.g.popup=function(c,j,i,e,g){e=e==null?2:e;g=g||5;i=i||"$9.99";var f=this.set(),h=3;f.push(this.path().attr({fill:"#000",stroke:"none"}));f.push(this.text(c,j,i).attr(this.g.txtattr).attr({fill:"#fff"}));f.update=function(m,l,n){m=m||c;l=l||j;var q=this[1].getBBox(),s=q.width/2,o=q.height/2,v=[0,s+g*2,0,-s-g*2],t=[-o*2-g*3,-o-g,0,-o-g],k=["M",m-v[e],l-t[e],"l",-g,(e==2)*-g,-Math.max(s-g,0),0,"a",g,g,0,0,1,-g,-g,"l",0,-Math.max(o-g,0),(e==3)*-g,-g,(e==3)*g,-g,0,-Math.max(o-g,0),"a",g,g,0,0,1,g,-g,"l",Math.max(s-g,0),0,g,!e*-g,g,!e*g,Math.max(s-g,0),0,"a",g,g,0,0,1,g,g,"l",0,Math.max(o-g,0),(e==1)*g,g,(e==1)*-g,g,0,Math.max(o-g,0),"a",g,g,0,0,1,-g,g,"l",-Math.max(s-g,0),0,"z"].join(","),u=[{x:m,y:l+g*2+o},{x:m-g*2-s,y:l},{x:m,y:l-g*2-o},{x:m+g*2+s,y:l}][e];if(n){this[0].animate({path:k},500,">");this[1].animate(u,500,">");}else{this[0].attr({path:k});this[1].attr(u);}return this;};return f.update(c,j);};Raphael.fn.g.flag=function(c,i,h,g){g=g||0;h=h||"$9.99";var e=this.set(),f=3;e.push(this.path().attr({fill:"#000",stroke:"none"}));e.push(this.text(c,i,h).attr(this.g.txtattr).attr({fill:"#fff"}));e.update=function(j,m){this.rotate(0,j,m);var l=this[1].getBBox(),k=l.height/2;this[0].attr({path:["M",j,m,"l",k+f,-k-f,l.width+2*f,0,0,l.height+2*f,-l.width-2*f,0,"z"].join(",")});this[1].attr({x:j+k+f+l.width/2,y:m});g=360-g;this.rotate(g,j,m);g>90&&g<270&&this[1].attr({x:j-r-f-l.width/2,y:m,rotation:[180+g,j,m]});return this;};return e.update(c,i);};Raphael.fn.g.label=function(c,g,f){var e=this.set();e.push(this.rect(c,g,10,10).attr({stroke:"none",fill:"#000"}));e.push(this.text(c,g,f).attr(this.g.txtattr).attr({fill:"#fff"}));e.update=function(){var i=this[1].getBBox(),h=Math.min(i.width+10,i.height+10)/2;this[0].attr({x:i.x-h/2,y:i.y-h/2,width:i.width+h,height:i.height+h,r:h});};e.update();return e;};Raphael.fn.g.labelit=function(f){var e=f.getBBox(),c=Math.min(20,e.width+10,e.height+10)/2;return this.rect(e.x-c/2,e.y-c/2,e.width+c,e.height+c,c).attr({stroke:"none",fill:"#000"}).insertBefore(f[0]);};Raphael.fn.g.drop=function(c,i,h,f,g){f=f||30;g=g||0;var e=this.set();e.push(this.path(["M",c,i,"l",f,0,"A",f*0.4,f*0.4,0,1,0,c+f*0.7,i-f*0.7,"z"]).attr({fill:"#000",stroke:"none",rotation:[22.5-g,c,i]}));g=(g+90)*Math.PI/180;e.push(this.text(c+f*Math.sin(g),i+f*Math.cos(g),h).attr(this.g.txtattr).attr({"font-size":f*12/30,fill:"#fff"}));e.drop=e[0];e.text=e[1];return e;};Raphael.fn.g.blob=function(e,k,j,i,g){i=(+i+1?i:45)+90;g=g||12;var c=Math.PI/180,h=g*12/12;var f=this.set();f.push(this.path().attr({fill:"#000",stroke:"none"}));f.push(this.text(e+g*Math.sin((i)*c),k+g*Math.cos((i)*c)-h/2,j).attr(this.g.txtattr).attr({"font-size":h,fill:"#fff"}));f.update=function(q,p,v){q=q||e;p=p||k;var y=this[1].getBBox(),B=Math.max(y.width+h,g*25/12),x=Math.max(y.height+h,g*25/12),m=q+g*Math.sin((i-22.5)*c),z=p+g*Math.cos((i-22.5)*c),o=q+g*Math.sin((i+22.5)*c),A=p+g*Math.cos((i+22.5)*c),D=(o-m)/2,C=(A-z)/2,n=B/2,l=x/2,u=-Math.sqrt(Math.abs(n*n*l*l-n*n*C*C-l*l*D*D)/(n*n*C*C+l*l*D*D)),t=u*n*C/l+(o+m)/2,s=u*-l*D/n+(A+z)/2;if(v){this.animate({x:t,y:s,path:["M",e,k,"L",o,A,"A",n,l,0,1,1,m,z,"z"].join(",")},500,">");}else{this.attr({x:t,y:s,path:["M",e,k,"L",o,A,"A",n,l,0,1,1,m,z,"z"].join(",")});}return this;};f.update(e,k);return f;};Raphael.fn.g.colorValue=function(g,f,e,c){return"hsb("+[Math.min((1-g/f)*0.4,1),e||0.75,c||0.75]+")";};Raphael.fn.g.snapEnds=function(l,m,k){var h=l,n=m;if(h==n){return{from:h,to:n,power:0};}function o(f){return Math.abs(f-0.5)<0.25?Math.floor(f)+0.5:Math.round(f);}var j=(n-h)/k,c=Math.floor(j),g=c,e=0;if(c){while(g){e--;g=Math.floor(j*Math.pow(10,e))/Math.pow(10,e);}e++;}else{while(!c){e=e||1;c=Math.floor(j*Math.pow(10,e))/Math.pow(10,e);e++;}e&&e--;}var n=o(m*Math.pow(10,e))/Math.pow(10,e);if(n<m){n=o((m+0.5)*Math.pow(10,e))/Math.pow(10,e);}var h=o((l-(e>0?0:0.5))*Math.pow(10,e))/Math.pow(10,e);return{from:h,to:n,power:e};};Raphael.fn.g.axis=function(s,q,m,E,h,H,k,J,l,c){c=c==null?2:c;l=l||"t";H=H||10;var D=l=="|"||l==" "?["M",s+0.5,q,"l",0,0.001]:k==1||k==3?["M",s+0.5,q,"l",0,-m]:["M",s,q+0.5,"l",m,0],v=this.g.snapEnds(E,h,H),I=v.from,z=v.to,G=v.power,F=0,A=this.set();d=(z-I)/H;var p=I,o=G>0?G:0;u=m/H;if(+k==1||+k==3){var e=q,w=(k-1?1:-1)*(c+3+!!(k-1));while(e>=q-m){l!="-"&&l!=" "&&(D=D.concat(["M",s-(l=="+"||l=="|"?c:!(k-1)*c*2),e+0.5,"l",c*2+1,0]));A.push(this.text(s+w,e,(J&&J[F++])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr).attr({"text-anchor":k-1?"start":"end"}));p+=d;e-=u;}if(Math.round(e+u-(q-m))){l!="-"&&l!=" "&&(D=D.concat(["M",s-(l=="+"||l=="|"?c:!(k-1)*c*2),q-m+0.5,"l",c*2+1,0]));A.push(this.text(s+w,q-m,(J&&J[F])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr).attr({"text-anchor":k-1?"start":"end"}));}}else{var g=s,p=I,o=G>0?G:0,w=(k?-1:1)*(c+9+!k),u=m/H,B=0,C=0;while(g<=s+m){l!="-"&&l!=" "&&(D=D.concat(["M",g+0.5,q-(l=="+"?c:!!k*c*2),"l",0,c*2+1]));A.push(B=this.text(g,q+w,(J&&J[F++])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr));var n=B.getBBox();if(C>=n.x-5){A.pop(A.length-1).remove();}else{C=n.x+n.width;}p+=d;g+=u;}if(Math.round(g-u-s-m)){l!="-"&&l!=" "&&(D=D.concat(["M",s+m+0.5,q-(l=="+"?c:!!k*c*2),"l",0,c*2+1]));A.push(this.text(s+m,q+w,(J&&J[F])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr));}}var K=this.path(D);K.text=A;K.all=this.set([K,A]);K.remove=function(){this.text.remove();this.constructor.prototype.remove.call(this);};return K;};Raphael.el.lighter=function(e){e=e||2;var c=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[c[0],c[1]];c[0]=Raphael.rgb2hsb(Raphael.getRGB(c[0]).hex);c[1]=Raphael.rgb2hsb(Raphael.getRGB(c[1]).hex);c[0].b=Math.min(c[0].b*e,1);c[0].s=c[0].s/e;c[1].b=Math.min(c[1].b*e,1);c[1].s=c[1].s/e;this.attr({fill:"hsb("+[c[0].h,c[0].s,c[0].b]+")",stroke:"hsb("+[c[1].h,c[1].s,c[1].b]+")"});};Raphael.el.darker=function(e){e=e||2;var c=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[c[0],c[1]];c[0]=Raphael.rgb2hsb(Raphael.getRGB(c[0]).hex);c[1]=Raphael.rgb2hsb(Raphael.getRGB(c[1]).hex);c[0].s=Math.min(c[0].s*e,1);c[0].b=c[0].b/e;c[1].s=Math.min(c[1].s*e,1);c[1].b=c[1].b/e;this.attr({fill:"hsb("+[c[0].h,c[0].s,c[0].b]+")",stroke:"hsb("+[c[1].h,c[1].s,c[1].b]+")"});};Raphael.el.original=function(){if(this.fs){this.attr({fill:this.fs[0],stroke:this.fs[1]});delete this.fs;}};})();
|