rack-mini-profiler 0.1.20 → 0.1.25
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.
Potentially problematic release.
This version of rack-mini-profiler might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/Ruby/CHANGELOG +130 -0
- data/{README.md → Ruby/README.md} +40 -9
- data/Ruby/lib/html/flamegraph.html +325 -0
- data/Ruby/lib/html/includes.css +451 -0
- data/{lib → Ruby/lib}/html/includes.js +135 -24
- data/{lib → Ruby/lib}/html/includes.less +38 -35
- data/{lib → Ruby/lib}/html/includes.tmpl +40 -15
- data/{lib → Ruby/lib}/html/jquery.1.7.1.js +1 -1
- data/{lib → Ruby/lib}/html/jquery.tmpl.js +1 -1
- data/{lib → Ruby/lib}/html/list.css +0 -0
- data/{lib → Ruby/lib}/html/list.js +7 -6
- data/{lib → Ruby/lib}/html/list.tmpl +0 -0
- data/Ruby/lib/html/profile_handler.js +1 -0
- data/{lib → Ruby/lib}/html/share.html +0 -0
- data/{lib → Ruby/lib}/mini_profiler/client_settings.rb +0 -0
- data/{lib → Ruby/lib}/mini_profiler/client_timer_struct.rb +1 -1
- data/{lib → Ruby/lib}/mini_profiler/config.rb +57 -52
- data/{lib → Ruby/lib}/mini_profiler/context.rb +11 -10
- data/Ruby/lib/mini_profiler/custom_timer_struct.rb +22 -0
- data/Ruby/lib/mini_profiler/flame_graph.rb +54 -0
- data/Ruby/lib/mini_profiler/gc_profiler.rb +107 -0
- data/{lib → Ruby/lib}/mini_profiler/page_timer_struct.rb +7 -2
- data/{lib → Ruby/lib}/mini_profiler/profiler.rb +206 -196
- data/{lib → Ruby/lib}/mini_profiler/profiling_methods.rb +131 -100
- data/{lib → Ruby/lib}/mini_profiler/request_timer_struct.rb +20 -1
- data/{lib → Ruby/lib}/mini_profiler/sql_timer_struct.rb +0 -0
- data/{lib → Ruby/lib}/mini_profiler/storage/abstract_store.rb +31 -27
- data/{lib → Ruby/lib}/mini_profiler/storage/file_store.rb +111 -109
- data/Ruby/lib/mini_profiler/storage/memcache_store.rb +53 -0
- data/{lib → Ruby/lib}/mini_profiler/storage/memory_store.rb +65 -63
- data/Ruby/lib/mini_profiler/storage/redis_store.rb +54 -0
- data/{lib → Ruby/lib}/mini_profiler/timer_struct.rb +0 -0
- data/Ruby/lib/mini_profiler/version.rb +5 -0
- data/{lib → Ruby/lib}/mini_profiler_rails/railtie.rb +3 -2
- data/Ruby/lib/patches/net_patches.rb +14 -0
- data/{lib → Ruby/lib}/patches/sql_patches.rb +89 -48
- data/{lib → Ruby/lib}/rack-mini-profiler.rb +2 -1
- data/rack-mini-profiler.gemspec +8 -6
- metadata +56 -65
- data/CHANGELOG +0 -93
- data/lib/html/includes.css +0 -75
- data/lib/html/profile_handler.js +0 -62
- data/lib/mini_profiler/storage/redis_store.rb +0 -44
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0b5ea4acbaf4d5efec150414455d875c5503fca4
|
4
|
+
data.tar.gz: 536e12f73b856176c7c30ef90e208f7612348d89
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5cff4678b233ae68fd4d1c92b2549bdcd78c9771d47970330fce8067543dd2894313e985310aeda89e07d28b53b708182714fd4ee3ac45d5126da0cf99c93e6f
|
7
|
+
data.tar.gz: 84d598d7329983f0d92931e05c2306df30ee02ff580e6d8f1cd5c7a633cbf542a3acf353ca9bb87cf67259ccb8bf838ef18b01e7ba1b4387f63f3426a03a9c75
|
data/Ruby/CHANGELOG
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
28-June-2012 - Sam
|
2
|
+
|
3
|
+
* Started change log
|
4
|
+
* Corrected profiler so it properly captures POST requests (was supressing non 200s)
|
5
|
+
* Amended Rack.MiniProfiler.config[:user_provider] to use ip addres for identity
|
6
|
+
* Fixed bug where unviewed missing ids never got cleared
|
7
|
+
* Supress all '/assets/' in the rails tie (makes debugging easier)
|
8
|
+
* record_sql was mega buggy
|
9
|
+
* added MemcacheStore
|
10
|
+
|
11
|
+
9-July-2012 - Sam
|
12
|
+
|
13
|
+
* Cleaned up mechanism for profiling in production, all you need to do now
|
14
|
+
is call Rack::MiniProfiler.authorize_request to get profiling working in
|
15
|
+
production
|
16
|
+
* Added option to display full backtraces pp=full-backtrace
|
17
|
+
* Cleaned up railties, got rid of the post authorize callback
|
18
|
+
* Version 0.1.3
|
19
|
+
|
20
|
+
12-July-2012 - Sam
|
21
|
+
|
22
|
+
* Fixed incorrect profiling steps (was not indenting or measuring start time right
|
23
|
+
* Implemented native PG and MySql2 interceptors, this gives way more accurate times
|
24
|
+
* Refactored context so its a proper class and not a hash
|
25
|
+
* Added some more client probing built in to rails
|
26
|
+
* More tests
|
27
|
+
|
28
|
+
18-July-2012 - Sam
|
29
|
+
|
30
|
+
* Added First Paint time for chrome
|
31
|
+
* Bug fix to ensure non Rails installs have mini profiler
|
32
|
+
* Version 0.1.7
|
33
|
+
|
34
|
+
30-July-2012 - Sam
|
35
|
+
|
36
|
+
* Made compliant with ancient versions of Rack (including Rack used by Rails2)
|
37
|
+
* Fixed broken share link
|
38
|
+
* Fixed crashes on startup (in MemoryStore and FileStore)
|
39
|
+
* Version 0.1.8
|
40
|
+
* Unicode fix
|
41
|
+
* Version 0.1.9
|
42
|
+
|
43
|
+
7-August-2012 - Sam
|
44
|
+
|
45
|
+
* Added option to disable profiler for the current session (pp=disable / pp=enable)
|
46
|
+
* yajl compatability contributed by Sven Riedel
|
47
|
+
|
48
|
+
10-August-2012 - Sam
|
49
|
+
|
50
|
+
* Added basic prepared statement profiling for postgres
|
51
|
+
|
52
|
+
20-August-2012 - Sam
|
53
|
+
|
54
|
+
* 1.12.pre
|
55
|
+
* Cap X-MiniProfiler-Ids at 10, otherwise the header can get killed
|
56
|
+
|
57
|
+
3-September-2012 - Sam
|
58
|
+
|
59
|
+
* 1.13.pre
|
60
|
+
* pg gem prepared statements were not being logged correctly
|
61
|
+
* added setting config.backtrace_ignores = [] - an array of regexes that match on caller lines that get ignored
|
62
|
+
* added setting config.backtrace_includes = [] - an array of regexes that get included in the trace by default
|
63
|
+
* cleaned up the way client settings are stored
|
64
|
+
* made pp=full-backtrace "sticky"
|
65
|
+
* added pp=normal-backtrace to clear the "sticky" state
|
66
|
+
* change "pp=sample" to work with "caller" no need for stack trace gem
|
67
|
+
|
68
|
+
4-September-2012 - Sam
|
69
|
+
|
70
|
+
* 1.15.pre
|
71
|
+
* fixed annoying bug where client settings were not sticking
|
72
|
+
* fixed long standing issue with Rack::ConditionalGet stopping MiniProfiler from working properly
|
73
|
+
|
74
|
+
5-September-2012 - Sam
|
75
|
+
|
76
|
+
* 1.16
|
77
|
+
* fixed long standing problem specs (issue with memory store)
|
78
|
+
* fixed issue where profiler would be dumped when you got a 404 in production (and any time rails is bypassed)
|
79
|
+
* implemented stacktrace properly
|
80
|
+
|
81
|
+
9-September-2012 - Sam
|
82
|
+
|
83
|
+
* 1.17
|
84
|
+
* pp=sample was bust unless stacktrace was installed
|
85
|
+
|
86
|
+
10-September-2012 - Sam
|
87
|
+
|
88
|
+
* 1.19
|
89
|
+
* fix compat issue with 1.8.7
|
90
|
+
|
91
|
+
12-September-2012 - Sam
|
92
|
+
|
93
|
+
* 1.20
|
94
|
+
* Added pp=profile-gc , it allows you to profile the GC in Ruby 1.9.3
|
95
|
+
|
96
|
+
17-September-2012
|
97
|
+
* 1.21
|
98
|
+
* New MemchacedStore
|
99
|
+
* Rails 4 support
|
100
|
+
|
101
|
+
17-September-2012
|
102
|
+
* Allow rack-mini-profiler to be sourced from github
|
103
|
+
* Extracted the pp=profile-gc-time out, the object space profiler needs to disable gc
|
104
|
+
|
105
|
+
20-September-2012
|
106
|
+
* 1.22
|
107
|
+
* Fix permission issue in the gem
|
108
|
+
|
109
|
+
8-April-2013
|
110
|
+
* 1.24
|
111
|
+
* Flame Graph Support see: http://samsaffron.com/archive/2013/03/19/flame-graphs-in-ruby-miniprofiler
|
112
|
+
* Fix file retention leak in file_store
|
113
|
+
* New toggle_shortcut and start_hidden options
|
114
|
+
* Fix for AngularJS support and MooTools
|
115
|
+
* More robust gc profiling
|
116
|
+
* Mongoid support
|
117
|
+
* Fix for html5 implicit body tags
|
118
|
+
* script tag initialized via data-attributes
|
119
|
+
* new - Rack::MiniProfiler.counter counter_name {}
|
120
|
+
* Allow usage of existing jQuery if its already loaded
|
121
|
+
* Fix pp=enable
|
122
|
+
* 1.8.7 support ... grrr
|
123
|
+
* Net:HTTP profiling
|
124
|
+
* pre authorize to run in all non development? and production? modes
|
125
|
+
|
126
|
+
8-April-2013
|
127
|
+
* 1.25
|
128
|
+
* Missed flamegraph.html from build
|
129
|
+
|
130
|
+
|
@@ -15,7 +15,7 @@ All you have to do is include the Gem and you're good to go in development.
|
|
15
15
|
|
16
16
|
rack-mini-profiler is designed with production profiling in mind. To enable that just run `Rack::MiniProfiler.authorize_request` once you know a request is allowed to profile.
|
17
17
|
|
18
|
-
|
18
|
+
Using Rails:
|
19
19
|
|
20
20
|
```ruby
|
21
21
|
# A hook in your ApplicationController
|
@@ -47,23 +47,53 @@ class MyApp < Sinatra::Base
|
|
47
47
|
end
|
48
48
|
```
|
49
49
|
|
50
|
+
## Database profiling
|
51
|
+
|
52
|
+
Currently supports Mysql2, Postgres, and Mongoid3 (with fallback support to ActiveRecord)
|
53
|
+
|
50
54
|
## Storage
|
51
55
|
|
52
|
-
|
56
|
+
rack-mini-profiler stores it's results so they can be shared later and aren't lost at the end of the request.
|
57
|
+
|
58
|
+
There are 4 storage options: `MemoryStore`, `RedisStore`, `MemcacheStore`, and `FileStore`.
|
59
|
+
|
60
|
+
`FileStore` is the default in Rails environments and will write files to `tmp/miniprofiler/*`. `MemoryStore` is the default otherwise.
|
61
|
+
|
62
|
+
To change the default you can create a file in `config/initializers/mini_profiler.rb`
|
53
63
|
|
54
64
|
```ruby
|
55
|
-
#
|
65
|
+
# set MemoryStore
|
56
66
|
Rack::MiniProfiler.config.storage = Rack::MiniProfiler::MemoryStore
|
57
|
-
```
|
58
67
|
|
59
|
-
|
68
|
+
# set RedisStore
|
69
|
+
if Rails.env.production?
|
70
|
+
uri = URI.parse(ENV["REDIS_SERVER_URL"])
|
71
|
+
Rack::MiniProfiler.config.storage_options = { :host => uri.host, :port => uri.port, :password => uri.password }
|
72
|
+
Rack::MiniProfiler.config.storage = Rack::MiniProfiler::RedisStore
|
73
|
+
end
|
74
|
+
```
|
60
75
|
|
61
|
-
MemoryStore
|
76
|
+
MemoryStore stores results in a processes heap - something that does not work well in a multi process environment.
|
62
77
|
FileStore stores results in the file system - something that may not work well in a multi machine environment.
|
78
|
+
RedisStore/MemcacheStore work in multi process and multi machine environments (RedisStore only saves results for up to 24 hours so it won't continue to fill up Redis).
|
63
79
|
|
64
80
|
Additionally you may implement an AbstractStore for your own provider.
|
65
81
|
|
66
|
-
|
82
|
+
## User result segregation
|
83
|
+
|
84
|
+
MiniProfiler will attempt to keep all user results isolated, out-of-the-box the user provider uses the ip address:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
Rack::MiniProfiler.config.user_provider = Proc.new{|env| Rack::Request.new(env).ip}
|
88
|
+
```
|
89
|
+
|
90
|
+
You can override (something that is very important in a multi-machine production setup):
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
Rack::MiniProfiler.config.user_provider = Proc.new{ |env| CurrentUser.get(env) }
|
94
|
+
```
|
95
|
+
|
96
|
+
The string this function returns should be unique for each user on the system (for anonymous you may need to fall back to ip address)
|
67
97
|
|
68
98
|
## Running the Specs
|
69
99
|
|
@@ -120,11 +150,12 @@ end
|
|
120
150
|
* pre_authorize_cb - A lambda callback you can set to determine whether or not mini_profiler should be visible on a given request. Default in a Rails environment is only on in development mode. If in a Rack app, the default is always on.
|
121
151
|
* position - Can either be 'right' or 'left'. Default is 'left'.
|
122
152
|
* skip_schema_queries - Whether or not you want to log the queries about the schema of your tables. Default is 'false', 'true' in rails development.
|
123
|
-
* use_existing_jquery - Use the version of jQuery on the page as opposed to the self contained one
|
124
153
|
* auto_inject (default true) - when false the miniprofiler script is not injected in the page
|
125
154
|
* backtrace_filter - a regex you can use to filter out unwanted lines from the backtraces
|
155
|
+
* toggle_shortcut (default Alt+P) - a jquery.hotkeys.js-style keyboard shortcut, used to toggle the mini_profiler's visibility. See http://code.google.com/p/js-hotkeys/ for more info.
|
156
|
+
* start_hidden (default false) - Whether or not you want the mini_profiler to be visible when loading a page
|
126
157
|
|
127
158
|
## Special query strings
|
128
159
|
|
129
|
-
If you include the query string `pp=help` at the end of your request you will see the various
|
160
|
+
If you include the query string `pp=help` at the end of your request you will see the various options available. You can use these options to extend or contract the amount of diagnostics rack-mini-profiler gathers.
|
130
161
|
|
@@ -0,0 +1,325 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
|
5
|
+
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.0.8/d3.min.js"></script>
|
6
|
+
<!-- <script src="http://cdnjs.cloudflare.com/ajax/libs/sugar/1.3.8/sugar.min.js"></script> -->
|
7
|
+
<meta charset=utf-8 />
|
8
|
+
<title>Flame Graph of Page</title>
|
9
|
+
<style>
|
10
|
+
.info {height: 40px;}
|
11
|
+
.legend div {
|
12
|
+
display: block;
|
13
|
+
float: left;
|
14
|
+
width: 150px;
|
15
|
+
margin: 0 8px 8px;
|
16
|
+
padding: 4px;
|
17
|
+
height: 50px;
|
18
|
+
}
|
19
|
+
</style>
|
20
|
+
</head>
|
21
|
+
<body>
|
22
|
+
<div class="graph"></div>
|
23
|
+
<div class="info"></div>
|
24
|
+
<div class="legend"></div>
|
25
|
+
|
26
|
+
<script>
|
27
|
+
|
28
|
+
var data = /*DATA*/;
|
29
|
+
var maxX = 0;
|
30
|
+
var maxY = 0;
|
31
|
+
|
32
|
+
debounce = function(func, wait, trickle) {
|
33
|
+
var timeout;
|
34
|
+
|
35
|
+
timeout = null;
|
36
|
+
return function() {
|
37
|
+
var args, context, currentWait, later;
|
38
|
+
context = this;
|
39
|
+
args = arguments;
|
40
|
+
later = function() {
|
41
|
+
timeout = null;
|
42
|
+
return func.apply(context, args);
|
43
|
+
};
|
44
|
+
|
45
|
+
if (timeout && trickle) {
|
46
|
+
// already queued, let it through
|
47
|
+
return;
|
48
|
+
}
|
49
|
+
|
50
|
+
if (typeof wait === "function") {
|
51
|
+
currentWait = wait();
|
52
|
+
} else {
|
53
|
+
currentWait = wait;
|
54
|
+
}
|
55
|
+
|
56
|
+
if (timeout) {
|
57
|
+
clearTimeout(timeout);
|
58
|
+
}
|
59
|
+
|
60
|
+
timeout = setTimeout(later, currentWait);
|
61
|
+
return timeout;
|
62
|
+
};
|
63
|
+
};
|
64
|
+
|
65
|
+
|
66
|
+
var guessGem = function(frame)
|
67
|
+
{
|
68
|
+
var split = frame.split('/gems/');
|
69
|
+
if(split.length == 1) {
|
70
|
+
split = frame.split('/app/');
|
71
|
+
if(split.length == 1) {
|
72
|
+
split = frame.split('/lib/');
|
73
|
+
}
|
74
|
+
|
75
|
+
split = split[Math.max(split.length-2,0)].split('/');
|
76
|
+
return split[split.length-1];
|
77
|
+
}
|
78
|
+
else
|
79
|
+
{
|
80
|
+
return split[split.length -1].split('/')[0];
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
var guessMethod = function(frame) {
|
85
|
+
var split = frame.split('`');
|
86
|
+
if(split.length == 2) {
|
87
|
+
return split[1].split("'")[0];
|
88
|
+
}
|
89
|
+
return '?';
|
90
|
+
}
|
91
|
+
|
92
|
+
var guessFile = function(frame) {
|
93
|
+
var split = frame.split(".rb:");
|
94
|
+
if(split.length == 2) {
|
95
|
+
split = split[0].split('/');
|
96
|
+
return split[split.length - 1];
|
97
|
+
}
|
98
|
+
return "";
|
99
|
+
}
|
100
|
+
|
101
|
+
$.each(data, function(){
|
102
|
+
maxX = Math.max(maxX, this.x + this.width);
|
103
|
+
maxY = Math.max(maxY, this.y);
|
104
|
+
this.shortName = /* guessGem(this.frame) + " " + guessFile(this.frame) + " " */ guessMethod(this.frame);
|
105
|
+
});
|
106
|
+
|
107
|
+
var width = $(window).width();
|
108
|
+
var height = $(window).height() / 1.2;
|
109
|
+
|
110
|
+
$('.graph').width(width).height(height);
|
111
|
+
|
112
|
+
var xScale = d3.scale.linear()
|
113
|
+
.domain([0, maxX])
|
114
|
+
.range([0, width]);
|
115
|
+
|
116
|
+
var yScale = d3.scale.linear()
|
117
|
+
.domain([0, maxY])
|
118
|
+
.range([0,height]);
|
119
|
+
|
120
|
+
var realHeight = 0;
|
121
|
+
var debouncedHeightCheck = debounce(function(){
|
122
|
+
if (realHeight > 15) {
|
123
|
+
svg.selectAll('text').attr('display','show');
|
124
|
+
} else {
|
125
|
+
svg.selectAll('text').attr('display','none');
|
126
|
+
}
|
127
|
+
}, 200);
|
128
|
+
|
129
|
+
function zoom()
|
130
|
+
{
|
131
|
+
svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
|
132
|
+
|
133
|
+
realHeight = yScale(1) * d3.event.scale;
|
134
|
+
debouncedHeightCheck();
|
135
|
+
}
|
136
|
+
|
137
|
+
var svg = d3.select(".graph")
|
138
|
+
.append("svg")
|
139
|
+
.attr("width", "100%")
|
140
|
+
.attr("height", "100%")
|
141
|
+
.attr("pointer-events", "all")
|
142
|
+
.append('svg:g')
|
143
|
+
.call(d3.behavior.zoom().on("zoom", zoom))
|
144
|
+
.append('svg:g');
|
145
|
+
|
146
|
+
|
147
|
+
// so zoom works everywhere
|
148
|
+
svg.append("rect")
|
149
|
+
.attr("x",function(d) { return xScale(0); })
|
150
|
+
.attr("y",function(d) { return yScale(0);})
|
151
|
+
.attr("width", function(d){return xScale(maxX);})
|
152
|
+
.attr("height", yScale(maxY))
|
153
|
+
.attr("fill", "white");
|
154
|
+
|
155
|
+
var color = function() {
|
156
|
+
var r = parseInt(205 + Math.random() * 50);
|
157
|
+
var g = parseInt(Math.random() * 230);
|
158
|
+
var b = parseInt(Math.random() * 55);
|
159
|
+
return "rgb(" + r + "," + g + "," + b + ")";
|
160
|
+
}
|
161
|
+
var info = {};
|
162
|
+
|
163
|
+
// http://stackoverflow.com/questions/1960473/unique-values-in-an-array
|
164
|
+
Array.prototype.getUnique = function() {
|
165
|
+
var o = {}, a = []
|
166
|
+
for (var i = 0; i < this.length; i++) o[this[i]] = 1
|
167
|
+
for (var e in o) a.push(e)
|
168
|
+
return a
|
169
|
+
}
|
170
|
+
|
171
|
+
var samplePercent = function(samples){
|
172
|
+
return "(" + samples +
|
173
|
+
" sample" + (samples == 1 ? "" : "s") + " - " +
|
174
|
+
((samples / maxX) * 100).toFixed(2) + "%)";
|
175
|
+
}
|
176
|
+
|
177
|
+
var mouseover = function(d) {
|
178
|
+
var i = info[d.frame];
|
179
|
+
$('.info').text( d.frame + " " + samplePercent(i.samples.length));
|
180
|
+
d3.selectAll(i.nodes)
|
181
|
+
.attr('opacity',0.5);
|
182
|
+
};
|
183
|
+
|
184
|
+
var mouseout = function(d) {
|
185
|
+
var i = info[d.frame];
|
186
|
+
$('.info').text("");
|
187
|
+
d3.selectAll(i.nodes)
|
188
|
+
.attr('opacity',1);
|
189
|
+
};
|
190
|
+
|
191
|
+
// http://stackoverflow.com/a/7419630
|
192
|
+
var rainbow = function(numOfSteps, step) {
|
193
|
+
// This function generates vibrant, "evenly spaced" colours (i.e. no clustering). This is ideal for creating easily distiguishable vibrant markers in Google Maps and other apps.
|
194
|
+
// Adam Cole, 2011-Sept-14
|
195
|
+
// HSV to RBG adapted from: http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
|
196
|
+
var r, g, b;
|
197
|
+
var h = step / numOfSteps;
|
198
|
+
var i = ~~(h * 6);
|
199
|
+
var f = h * 6 - i;
|
200
|
+
var q = 1 - f;
|
201
|
+
switch(i % 6){
|
202
|
+
case 0: r = 1, g = f, b = 0; break;
|
203
|
+
case 1: r = q, g = 1, b = 0; break;
|
204
|
+
case 2: r = 0, g = 1, b = f; break;
|
205
|
+
case 3: r = 0, g = q, b = 1; break;
|
206
|
+
case 4: r = f, g = 0, b = 1; break;
|
207
|
+
case 5: r = 1, g = 0, b = q; break;
|
208
|
+
}
|
209
|
+
var c = "#" + ("00" + (~ ~(r * 255)).toString(16)).slice(-2) + ("00" + (~ ~(g * 255)).toString(16)).slice(-2) + ("00" + (~ ~(b * 255)).toString(16)).slice(-2);
|
210
|
+
return (c);
|
211
|
+
}
|
212
|
+
|
213
|
+
// assign some colors, analyze samples per gem
|
214
|
+
var gemStats = {}
|
215
|
+
|
216
|
+
$.each(data, function(){
|
217
|
+
|
218
|
+
var gem = guessGem(this.frame);
|
219
|
+
var stat = gemStats[gem];
|
220
|
+
|
221
|
+
if(!stat) {
|
222
|
+
gemStats[gem] = stat = {samples: [], frames: []};
|
223
|
+
}
|
224
|
+
|
225
|
+
stat.frames.push(this.frame);
|
226
|
+
for(var j=0; j < this.width; j++){
|
227
|
+
stat.samples.push(this.x + j);
|
228
|
+
}
|
229
|
+
});
|
230
|
+
|
231
|
+
var totalGems = 0;
|
232
|
+
$.each(gemStats, function(){totalGems++;});
|
233
|
+
|
234
|
+
|
235
|
+
var currentIndex = 0;
|
236
|
+
$.each(gemStats, function(k,stat){
|
237
|
+
|
238
|
+
stat.color = rainbow(totalGems, currentIndex);
|
239
|
+
stat.samples = stat.samples.getUnique();
|
240
|
+
|
241
|
+
for(var x=0; x < stat.frames.length; x++) {
|
242
|
+
info[stat.frames[x]] = {nodes: [], samples: [], color: stat.color};
|
243
|
+
}
|
244
|
+
|
245
|
+
currentIndex += 1;
|
246
|
+
});
|
247
|
+
|
248
|
+
|
249
|
+
// see: http://bl.ocks.org/mundhradevang/1387786
|
250
|
+
function fontSize(d,i) {
|
251
|
+
var size = yScale(1) / 3;
|
252
|
+
// var words = d.shortName.split(' ');
|
253
|
+
var word = d.shortName; // words[0];
|
254
|
+
var width = xScale(d.width+100);
|
255
|
+
var height = yScale(1);
|
256
|
+
var length = 0;
|
257
|
+
d3.select(this).style("font-size", size + "px").text(word);
|
258
|
+
while(((this.getBBox().width >= width) || (this.getBBox().height >= height)) && (size > 12))
|
259
|
+
{
|
260
|
+
size -= 0.1;
|
261
|
+
d3.select(this).style("font-size", size + "px");
|
262
|
+
}
|
263
|
+
|
264
|
+
d3.select(this).attr("dy", size);
|
265
|
+
}
|
266
|
+
|
267
|
+
svg.selectAll("g")
|
268
|
+
.data(data)
|
269
|
+
.enter()
|
270
|
+
.append("g")
|
271
|
+
.each(function(){
|
272
|
+
d3.select(this)
|
273
|
+
.append("rect")
|
274
|
+
.attr("x",function(d) { return xScale(d.x-1); })
|
275
|
+
.attr("y",function(d) { return yScale(maxY - d.y);})
|
276
|
+
.attr("width", function(d){return xScale(d.width);})
|
277
|
+
.attr("height", yScale(1))
|
278
|
+
.attr("fill", function(d){
|
279
|
+
var i = info[d.frame];
|
280
|
+
if(!i) {
|
281
|
+
info[d.frame] = i = {nodes: [], samples: [], color: color()};
|
282
|
+
}
|
283
|
+
i.nodes.push(this);
|
284
|
+
for(var j=0; j < d.width; j++){
|
285
|
+
i.samples.push(d.x + j);
|
286
|
+
}
|
287
|
+
return i.color;
|
288
|
+
})
|
289
|
+
.on("mouseover", mouseover)
|
290
|
+
.on("mouseout", mouseout);
|
291
|
+
|
292
|
+
d3.select(this)
|
293
|
+
.append("text")
|
294
|
+
.attr("x",function(d) { return xScale(d.x - 0.98); })
|
295
|
+
.attr("y",function(d) { return yScale(maxY - d.y);})
|
296
|
+
.on("mouseover", mouseover)
|
297
|
+
.on("mouseout", mouseout)
|
298
|
+
.each(fontSize)
|
299
|
+
.attr("display", "none");
|
300
|
+
|
301
|
+
});
|
302
|
+
|
303
|
+
|
304
|
+
// Samples may overlap on the same line
|
305
|
+
for (var r in info) {
|
306
|
+
if (info[r].samples) {
|
307
|
+
info[r].samples = info[r].samples.getUnique();
|
308
|
+
}
|
309
|
+
};
|
310
|
+
|
311
|
+
|
312
|
+
// render the legend
|
313
|
+
$.each(gemStats, function(k,v){
|
314
|
+
var node = $("<div></div>")
|
315
|
+
.css("background-color", v.color)
|
316
|
+
.text(k + " " + samplePercent(v.samples.length)) ;
|
317
|
+
$('.legend').append(node);
|
318
|
+
});
|
319
|
+
|
320
|
+
|
321
|
+
|
322
|
+
</script>
|
323
|
+
</body>
|
324
|
+
</html>
|
325
|
+
|