createComplexityGraph: function()

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));
        });
    },