in MotionMark/resources/debug-runner/graph.js [135:304]
createComplexityGraph: function(result, timeRegressions, data, options, margins, size)
{
var svg = d3.select("#test-graph-data").append("svg")
.attr("id", "complexity-graph")
.attr("class", "hidden")
.attr("width", size.width)
.attr("height", size.height)
.append("g")
.attr("transform", "translate(" + margins.left + "," + margins.top + ")");
var timeSamples = data[Strings.json.controller];
var xMin = 100000, xMax = 0;
if (timeRegressions) {
timeRegressions.forEach(function(regression) {
for (var i = regression.startIndex; i <= regression.endIndex; ++i) {
xMin = Math.min(xMin, timeSamples[i].complexity);
xMax = Math.max(xMax, timeSamples[i].complexity);
}
});
} else {
xMin = d3.min(timeSamples, function(s) { return s.complexity; });
xMax = d3.max(timeSamples, function(s) { return s.complexity; });
}
const axisWidth = size.width - margins.left - margins.right;
const axisHeight = size.height - margins.top - margins.bottom;
// The y axis is frameLength in ms, inverted with the axis labels showing fps.
const minFrameRate = this._targetFrameRate / 4;
const maxFrameRate = this._targetFrameRate * 1.5;
const yMin = msPerSecond / minFrameRate;
const yMax = msPerSecond / maxFrameRate;
var xScale = d3.scale.linear()
.range([0, axisWidth])
.domain([xMin, xMax]);
var yScale = d3.scale.linear()
.range([axisHeight, 0])
.domain([yMin, yMax]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.tickValues(this._tickValuesForFrameRate(this._targetFrameRate, minFrameRate, maxFrameRate))
.tickFormat(function(d) { return (msPerSecond / d).toFixed(0); })
.orient("left");
// x-axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + axisHeight + ")")
.call(xAxis);
// y-axis
var yAxisGroup = svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// time result
var mean = svg.append("g")
.attr("class", "mean complexity");
var timeResult = result[Strings.json.controller];
this._addRegressionLine(mean, xScale, yScale, [[timeResult.average, yMin], [timeResult.average, yMax]], timeResult.stdev, true);
// regression
this._addRegression(result[Strings.json.complexity], svg.append("g").attr("class", "regression raw"), xScale, yScale);
var bootstrapResult = result[Strings.json.complexity][Strings.json.bootstrap];
if (bootstrapResult) {
var histogram = d3.layout.histogram()
.bins(xScale.ticks(100))(bootstrapResult.data);
var yBootstrapScale = d3.scale.linear()
.range([axisHeight/2, 0])
.domain([0, d3.max(histogram, function(d) { return d.y; })]);
group = svg.append("g").attr("class", "bootstrap");
var bar = group.selectAll(".bar")
.data(histogram)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yBootstrapScale(d.y) + ")"; });
bar.append("rect")
.attr("x", 1)
.attr("y", axisHeight/2)
.attr("width", xScale(histogram[1].x) - xScale(histogram[0].x) - 1)
.attr("height", function(d) { return axisHeight/2 - yBootstrapScale(d.y); });
group = group.append("g").attr("class", "median");
this._addRegressionLine(group, xScale, yScale, [[bootstrapResult.median, yMin], [bootstrapResult.median, yMax]], [bootstrapResult.confidenceLow, bootstrapResult.confidenceHigh], true);
group.append("circle")
.attr("cx", xScale(bootstrapResult.median))
.attr("cy", yScale(msPerSecond / 60))
.attr("r", 5);
}
// series
group = svg.append("g")
.attr("class", "series raw")
.selectAll("line")
.data(data[Strings.json.complexity])
.enter();
group.append("line")
.attr("x1", function(d) { return xScale(d.complexity) - 3; })
.attr("x2", function(d) { return xScale(d.complexity) + 3; })
.attr("y1", function(d) { return yScale(d.frameLength) - 3; })
.attr("y2", function(d) { return yScale(d.frameLength) + 3; });
group.append("line")
.attr("x1", function(d) { return xScale(d.complexity) - 3; })
.attr("x2", function(d) { return xScale(d.complexity) + 3; })
.attr("y1", function(d) { return yScale(d.frameLength) + 3; })
.attr("y2", function(d) { return yScale(d.frameLength) - 3; });
// Cursor
var cursorGroup = svg.append("g").attr("class", "cursor hidden");
cursorGroup.append("line")
.attr("class", "x")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", yScale(yAxis.scale().domain()[0]) + 10)
.attr("y2", yScale(yAxis.scale().domain()[1]));
cursorGroup.append("line")
.attr("class", "y")
.attr("x1", xScale(xAxis.scale().domain()[0]) - 10)
.attr("x2", xScale(xAxis.scale().domain()[1]))
.attr("y1", 0)
.attr("y2", 0)
cursorGroup.append("text")
.attr("class", "label x")
.attr("x", 0)
.attr("y", yScale(yAxis.scale().domain()[0]) + 15)
.attr("baseline-shift", "-100%")
.attr("text-anchor", "middle");
cursorGroup.append("text")
.attr("class", "label y")
.attr("x", xScale(xAxis.scale().domain()[0]) - 15)
.attr("y", 0)
.attr("baseline-shift", "-30%")
.attr("text-anchor", "end");
// Area to handle mouse events
var area = svg.append("rect")
.attr("fill", "transparent")
.attr("x", 0)
.attr("y", 0)
.attr("width", size.width)
.attr("height", axisHeight);
area.on("mouseover", function() {
document.querySelector("#complexity-graph .cursor").classList.remove("hidden");
}).on("mouseout", function() {
document.querySelector("#complexity-graph .cursor").classList.add("hidden");
}).on("mousemove", function() {
var location = d3.mouse(this);
var location_domain = [xScale.invert(location[0]), yScale.invert(location[1])];
cursorGroup.select("line.x")
.attr("x1", location[0])
.attr("x2", location[0]);
cursorGroup.select("text.x")
.attr("x", location[0])
.text(location_domain[0].toFixed(1));
cursorGroup.select("line.y")
.attr("y1", location[1])
.attr("y2", location[1]);
cursorGroup.select("text.y")
.attr("y", location[1])
.text((msPerSecond / location_domain[1]).toFixed(1));
});
},