4077593939f596ba19690c3000fef87f50f6ca45
[WebKit-https.git] / PerformanceTests / Animometer / resources / debug-runner / graph.js
1 Utilities.extendObject(window.benchmarkController, {
2     updateGraphData: function(graphData)
3     {
4         var element = document.getElementById("test-graph-data");
5         element.innerHTML = "";
6         var margins = new Insets(10, 30, 30, 40);
7         var size = Point.elementClientSize(element).subtract(margins.size);
8
9         var svg = d3.select("#test-graph-data").append("svg")
10             .attr("width", size.width + margins.left + margins.right)
11             .attr("height", size.height + margins.top + margins.bottom)
12             .append("g")
13                 .attr("transform", "translate(" + margins.left + "," + margins.top + ")");
14
15         var axes = graphData.axes;
16         var targetFPS = graphData.targetFPS;
17
18         // Axis scales
19         var x = d3.scale.linear()
20                 .range([0, size.width])
21                 .domain([0, d3.max(graphData.samples, function(s) { return s.time; })]);
22         var yLeft = d3.scale.linear()
23                 .range([size.height, 0])
24                 .domain([0, d3.max(graphData.samples, function(s) { return s.complexity; })]);
25         var yRight = d3.scale.linear()
26                 .range([size.height, 0])
27                 .domain([0, 60]);
28
29         // Axes
30         var xAxis = d3.svg.axis()
31                 .scale(x)
32                 .orient("bottom");
33         var yAxisLeft = d3.svg.axis()
34                 .scale(yLeft)
35                 .orient("left");
36         var yAxisRight = d3.svg.axis()
37                 .scale(yRight)
38                 .orient("right");
39
40         // x-axis
41         svg.append("g")
42             .attr("class", "x axis")
43             .attr("fill", "rgb(235, 235, 235)")
44             .attr("transform", "translate(0," + size.height + ")")
45             .call(xAxis)
46             .append("text")
47                 .attr("class", "label")
48                 .attr("x", size.width)
49                 .attr("y", -6)
50                 .attr("fill", "rgb(235, 235, 235)")
51                 .style("text-anchor", "end")
52                 .text("time");
53
54         // yLeft-axis
55         svg.append("g")
56             .attr("class", "y axis")
57             .attr("fill", "#7ADD49")
58             .call(yAxisLeft)
59             .append("text")
60                 .attr("class", "label")
61                 .attr("transform", "rotate(-90)")
62                 .attr("y", 6)
63                 .attr("fill", "#7ADD49")
64                 .attr("dy", ".71em")
65                 .style("text-anchor", "end")
66                 .text(axes[0]);
67
68         // yRight-axis
69         svg.append("g")
70             .attr("class", "y axis")
71             .attr("fill", "#FA4925")
72             .attr("transform", "translate(" + size.width + ", 0)")
73             .call(yAxisRight)
74             .append("text")
75                 .attr("class", "label")
76                 .attr("transform", "rotate(-90)")
77                 .attr("y", 6)
78                 .attr("fill", "#FA4925")
79                 .attr("dy", ".71em")
80                 .style("text-anchor", "end")
81                 .text(axes[1]);
82
83         // samplingTimeOffset
84         svg.append("line")
85             .attr("x1", x(graphData.samplingTimeOffset))
86             .attr("x2", x(graphData.samplingTimeOffset))
87             .attr("y1", yLeft(0))
88             .attr("y2", yLeft(yAxisLeft.scale().domain()[1]))
89             .attr("class", "sample-time marker");
90
91         // left-mean
92         svg.append("line")
93             .attr("x1", x(0))
94             .attr("x2", size.width)
95             .attr("y1", yLeft(graphData.mean[0]))
96             .attr("y2", yLeft(graphData.mean[0]))
97             .attr("class", "left-mean mean");
98
99         // right-mean
100         svg.append("line")
101             .attr("x1", x(0))
102             .attr("x2", size.width)
103             .attr("y1", yRight(graphData.mean[1]))
104             .attr("y2", yRight(graphData.mean[1]))
105             .attr("class", "right-mean mean");
106
107         // right-target
108         if (targetFPS) {
109             svg.append("line")
110                 .attr("x1", x(0))
111                 .attr("x2", size.width)
112                 .attr("y1", yRight(targetFPS))
113                 .attr("y2", yRight(targetFPS))
114                 .attr("class", "target-fps marker");
115         }
116
117         // Cursor
118         var cursorGroup = svg.append("g").attr("id", "cursor");
119         cursorGroup.append("line")
120             .attr("x1", 0)
121             .attr("x2", 0)
122             .attr("y1", yLeft(0))
123             .attr("y2", yLeft(0));
124
125         // Data
126         var allData = graphData.samples;
127         var filteredData = graphData.samples.filter(function (sample) {
128             return "smoothedFPS" in sample;
129         });
130         var intervalData = graphData.samples.filter(function (sample) {
131             return "intervalFPS" in sample;
132         });
133
134         function addData(name, data, yCoordinateCallback, pointRadius, omitLine) {
135             var svgGroup = svg.append("g").attr("id", name);
136             if (!omitLine) {
137                 svgGroup.append("path")
138                     .datum(data)
139                     .attr("d", d3.svg.line()
140                         .x(function(d) { return x(d.time); })
141                         .y(yCoordinateCallback));
142             }
143             svgGroup.selectAll("circle")
144                 .data(data)
145                 .enter()
146                 .append("circle")
147                 .attr("cx", function(d) { return x(d.time); })
148                 .attr("cy", yCoordinateCallback)
149                 .attr("r", pointRadius);
150
151             cursorGroup.append("circle")
152                 .attr("class", name)
153                 .attr("r", pointRadius + 2);
154         }
155
156         addData("complexity", allData, function(d) { return yLeft(d.complexity); }, 2);
157         addData("rawFPS", allData, function(d) { return yRight(d.fps); }, 1);
158         addData("filteredFPS", filteredData, function(d) { return yRight(d.smoothedFPS); }, 2);
159         addData("intervalFPS", intervalData, function(d) { return yRight(d.intervalFPS); }, 2);
160
161         // Area to handle mouse events
162         var area = svg.append("rect")
163             .attr("fill", "transparent")
164             .attr("x", 0)
165             .attr("y", 0)
166             .attr("width", size.x)
167             .attr("height", size.y);
168
169         var timeBisect = d3.bisector(function(d) { return d.time; }).right;
170         var statsToHighlight = ["complexity", "rawFPS", "filteredFPS", "intervalFPS"];
171         area.on("mouseover", function() {
172             document.getElementById("cursor").classList.remove("hidden");
173             document.querySelector("#test-graph nav").classList.remove("hide-data");
174         }).on("mouseout", function() {
175             document.getElementById("cursor").classList.add("hidden");
176             document.querySelector("#test-graph nav").classList.add("hide-data");
177         }).on("mousemove", function() {
178             var form = document.forms["graph-options"].elements;
179
180             var mx_domain = x.invert(d3.mouse(this)[0]);
181             var index = Math.min(timeBisect(allData, mx_domain), allData.length - 1);
182             var data = allData[index];
183             var cursor_x = x(data.time);
184             var cursor_y = yAxisRight.scale().domain()[1];
185             if (form["rawFPS"].checked)
186                 cursor_y = Math.max(cursor_y, data.fps);
187             cursorGroup.select("line")
188                 .attr("x1", cursor_x)
189                 .attr("x2", cursor_x)
190                 .attr("y2", yRight(cursor_y));
191
192             document.querySelector("#test-graph nav .time").textContent = data.time.toFixed(4) + "s (" + index + ")";
193             statsToHighlight.forEach(function(name) {
194                 var element = document.querySelector("#test-graph nav ." + name);
195                 var content = "";
196                 var data_y = null;
197                 switch (name) {
198                 case "complexity":
199                     content = data.complexity;
200                     data_y = yLeft(data.complexity);
201                     break;
202                 case "rawFPS":
203                     content = data.fps.toFixed(2);
204                     data_y = yRight(data.fps);
205                     break;
206                 case "filteredFPS":
207                     if ("smoothedFPS" in data) {
208                         content = data.smoothedFPS.toFixed(2);
209                         data_y = yRight(data.smoothedFPS);
210                     }
211                     break;
212                 case "intervalFPS":
213                     if ("intervalFPS" in data) {
214                         content = data.intervalFPS.toFixed(2);
215                         data_y = yRight(data.intervalFPS);
216                     }
217                     break;
218                 }
219
220                 element.textContent = content;
221
222                 if (form[name].checked && data_y !== null) {
223                     cursorGroup.select("." + name)
224                         .attr("cx", cursor_x)
225                         .attr("cy", data_y);
226                     document.querySelector("#cursor ." + name).classList.remove("hidden");
227                 } else
228                     document.querySelector("#cursor ." + name).classList.add("hidden");
229             });
230         });
231         this.onGraphOptionsChanged();
232     },
233
234     onGraphOptionsChanged: function() {
235         var form = document.forms["graph-options"].elements;
236
237         function showOrHideNodes(isShown, selector) {
238             var nodeList = document.querySelectorAll(selector);
239             if (isShown) {
240                 for (var i = 0; i < nodeList.length; ++i)
241                     nodeList[i].classList.remove("hidden");
242             } else {
243                 for (var i = 0; i < nodeList.length; ++i)
244                     nodeList[i].classList.add("hidden");
245             }
246         }
247
248         showOrHideNodes(form["markers"].checked, ".marker");
249         showOrHideNodes(form["averages"].checked, ".mean");
250         showOrHideNodes(form["complexity"].checked, "#complexity");
251         showOrHideNodes(form["rawFPS"].checked, "#rawFPS");
252         showOrHideNodes(form["filteredFPS"].checked, "#filteredFPS");
253         showOrHideNodes(form["intervalFPS"].checked, "#intervalFPS");
254     }
255 });