| Index: Source/devtools/front_end/profiler/d3js_trace/sequences.js
|
| diff --git a/Source/devtools/front_end/profiler/d3js_trace/sequences.js b/Source/devtools/front_end/profiler/d3js_trace/sequences.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b68ccb3415593cc7bcb1f9287a6a1318db0b7d0b
|
| --- /dev/null
|
| +++ b/Source/devtools/front_end/profiler/d3js_trace/sequences.js
|
| @@ -0,0 +1,331 @@
|
| +function sequences(root) {
|
| +
|
| +// Dimensions of sunburst.
|
| +var width = 1600;
|
| +var height = 800;
|
| +var radius = Math.min(width, height) / 2;
|
| +
|
| +var x = d3.scale.linear()
|
| + .range([0, 2 * Math.PI]);
|
| +
|
| +var y = d3.scale.sqrt()
|
| + .range([0, radius]);
|
| +
|
| +// Breadcrumb dimensions: width, height, spacing, width of tip/tail.
|
| +var b = {
|
| + w: 75, h: 30, s: 3, t: 10
|
| +};
|
| +
|
| +var path ={};
|
| +var nodes = {};
|
| +
|
| +// Mapping of step names to colors.
|
| +var colors = {
|
| + "home": "#5687d1",
|
| + "product": "#7b615c",
|
| + "search": "#de783b",
|
| + "account": "#6ab975",
|
| + "other": "#a173d1",
|
| + "end": "#bbbbbb"
|
| +};
|
| +
|
| +// Total size of all segments; we set this later, after loading the data.
|
| +var totalSize = 0;
|
| +
|
| +var svg = d3.select("#chart").append("svg:svg")
|
| + .attr("width", width)
|
| + .attr("height", height)
|
| + .append("svg:g")
|
| + .attr("id", "container")
|
| + .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
|
| +
|
| +var partition = d3.layout.partition()
|
| + .size([2 * Math.PI, radius * radius])
|
| + .value(function(d) { return d.size; });
|
| +
|
| +var arc = d3.svg.arc()
|
| + .startAngle(function(d) { return d.x; })
|
| + .endAngle(function(d) { return d.x + d.dx; })
|
| + .innerRadius(function(d) { return Math.sqrt(d.y); })
|
| + .outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });
|
| +
|
| +initializePage();
|
| +createVisualization(root);
|
| +
|
| +function initializePage() {
|
| +
|
| + // Basic setup of page elements.
|
| + initializeBreadcrumbTrail();
|
| + drawLegend();
|
| + d3.select("#togglelegend").on("click", toggleLegend);
|
| +
|
| + // Bounding circle underneath the sunburst, to make it easier to detect
|
| + // when the mouse leaves the parent g.
|
| + svg.append("svg:circle")
|
| + .attr("r", radius)
|
| + .style("opacity", 0);
|
| +}
|
| +
|
| +// Main function to draw and set up the visualization, once we have the data.
|
| +function createVisualization(json) {
|
| +
|
| + // For efficiency, filter nodes to keep only those large enough to see.
|
| + nodes = partition.nodes(root)
|
| + .filter(function(d) {
|
| + return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
|
| + });
|
| +
|
| + //var path = svg.data([json]).selectAll("path")
|
| + path = svg.selectAll("path")
|
| + .data(nodes)
|
| + .enter().append("svg:path")
|
| + .attr("display", function(d) { return d.depth ? null : "none"; })
|
| + .attr("d", arc)
|
| + .attr("fill-rule", "evenodd")
|
| + .style("fill", function(d) { return colors[d.name]; })
|
| + .style("opacity", 1)
|
| + .on("mouseover", mouseover)
|
| + .on("click", click);
|
| +
|
| + // Add the mouseleave handler to the bounding circle.
|
| + d3.select("#container").on("mouseleave", mouseleave);
|
| +
|
| + // Get total size of the tree = value of root node from partition.
|
| + totalSize = path.node().__data__.value;
|
| +};
|
| +
|
| +function click(d) {
|
| +
|
| + console.log(d);
|
| +}
|
| +
|
| +// Fade all but the current sequence, and show it in the breadcrumb trail.
|
| +function mouseover(d) {
|
| +
|
| + var percentage = (100 * d.value / totalSize).toPrecision(3);
|
| + var percentageString = percentage + "%";
|
| + if (percentage < 0.1) {
|
| + percentageString = "< 0.1%";
|
| + }
|
| +
|
| + d3.select("#percentage")
|
| + .text(percentageString);
|
| +
|
| + d3.select("#funcname")
|
| + .text(d.name);
|
| +
|
| + d3.select("#explanation")
|
| + .style("visibility", "");
|
| +
|
| + var sequenceArray = getAncestors(d);
|
| + updateBreadcrumbs(sequenceArray, percentageString);
|
| +
|
| + // Fade all the segments.
|
| + d3.selectAll("path")
|
| + .style("opacity", 0.3);
|
| +
|
| + // Then highlight only those that are an ancestor of the current segment.
|
| + svg.selectAll("path")
|
| + .filter(function(node) {
|
| + return (sequenceArray.indexOf(node) >= 0);
|
| + })
|
| + .style("opacity", 1);
|
| +}
|
| +
|
| +// Restore everything to full opacity when moving off the visualization.
|
| +function mouseleave(d) {
|
| +
|
| + // Hide the breadcrumb trail
|
| + d3.select("#trail")
|
| + .style("visibility", "hidden");
|
| +
|
| + // Deactivate all segments during transition.
|
| + d3.selectAll("path").on("mouseover", null);
|
| +
|
| + // Transition each segment to full opacity and then reactivate it.
|
| + d3.selectAll("path")
|
| + .transition()
|
| + .duration(1000)
|
| + .style("opacity", 1)
|
| + .each("end", function() {
|
| + d3.select(this).on("mouseover", mouseover);
|
| + });
|
| +
|
| + d3.select("#explanation")
|
| + .transition()
|
| + .duration(1000)
|
| + .style("visibility", "hidden");
|
| +}
|
| +
|
| +// Given a node in a partition layout, return an array of all of its ancestor
|
| +// nodes, highest first, but excluding the root.
|
| +function getAncestors(node) {
|
| + var path = [];
|
| + var current = node;
|
| + while (current.parent) {
|
| + path.unshift(current);
|
| + current = current.parent;
|
| + }
|
| + return path;
|
| +}
|
| +
|
| +function initializeBreadcrumbTrail() {
|
| + // Add the svg area.
|
| + var trail = d3.select("#sequence").append("svg:svg")
|
| + .attr("width", width)
|
| + .attr("height", 50)
|
| + .attr("id", "trail");
|
| + // Add the label at the end, for the percentage.
|
| + trail.append("svg:text")
|
| + .attr("id", "endlabel")
|
| + .style("fill", "#000");
|
| +}
|
| +
|
| +// Generate a string that describes the points of a breadcrumb polygon.
|
| +function breadcrumbPoints(d, i) {
|
| + var points = [];
|
| + points.push("0,0");
|
| + points.push(b.w + ",0");
|
| + points.push(b.w + b.t + "," + (b.h / 2));
|
| + points.push(b.w + "," + b.h);
|
| + points.push("0," + b.h);
|
| + if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
|
| + points.push(b.t + "," + (b.h / 2));
|
| + }
|
| + return points.join(" ");
|
| +}
|
| +
|
| +// Update the breadcrumb trail to show the current sequence and percentage.
|
| +function updateBreadcrumbs(nodeArray, percentageString) {
|
| +
|
| + // Data join; key function combines name and depth (= position in sequence).
|
| + var g = d3.select("#trail")
|
| + .selectAll("g")
|
| + .data(nodeArray, function(d) { return d.name + d.depth; });
|
| +
|
| + // Add breadcrumb and label for entering nodes.
|
| + var entering = g.enter().append("svg:g");
|
| +
|
| + entering.append("svg:polygon")
|
| + .attr("points", breadcrumbPoints)
|
| + .style("fill", function(d) { return colors[d.name]; });
|
| +
|
| + entering.append("svg:text")
|
| + .attr("x", (b.w + b.t) / 2)
|
| + .attr("y", b.h / 2)
|
| + .attr("dy", "0.35em")
|
| + .attr("text-anchor", "middle")
|
| + .text(function(d) {
|
| + var str = d.name;
|
| + if (str.length > 10) {
|
| + str = str.substr(0, 8) + "...";
|
| + }
|
| + return str;
|
| + });
|
| +
|
| + // Set position for entering and updating nodes.
|
| + g.attr("transform", function(d, i) {
|
| + return "translate(" + i * (b.w + b.s) + ", 0)";
|
| + });
|
| +
|
| + // Remove exiting nodes.
|
| + g.exit().remove();
|
| +
|
| + // Now move and update the percentage at the end.
|
| + d3.select("#trail").select("#endlabel")
|
| + .attr("x", (nodeArray.length + 0.5) * (b.w + b.s))
|
| + .attr("y", b.h / 2)
|
| + .attr("dy", "0.35em")
|
| + .attr("text-anchor", "middle")
|
| + .text(percentageString);
|
| +
|
| + // Make the breadcrumb trail visible, if it's hidden.
|
| + d3.select("#trail")
|
| + .style("visibility", "");
|
| +
|
| +}
|
| +
|
| +function drawLegend() {
|
| +
|
| + // Dimensions of legend item: width, height, spacing, radius of rounded rect.
|
| + var li = {
|
| + w: 75, h: 30, s: 3, r: 3
|
| + };
|
| +
|
| + var legend = d3.select("#legend").append("svg:svg")
|
| + .attr("width", li.w)
|
| + .attr("height", d3.keys(colors).length * (li.h + li.s));
|
| +
|
| + var g = legend.selectAll("g")
|
| + .data(d3.entries(colors))
|
| + .enter().append("svg:g")
|
| + .attr("transform", function(d, i) {
|
| + return "translate(0," + i * (li.h + li.s) + ")";
|
| + });
|
| +
|
| + g.append("svg:rect")
|
| + .attr("rx", li.r)
|
| + .attr("ry", li.r)
|
| + .attr("width", li.w)
|
| + .attr("height", li.h)
|
| + .style("fill", function(d) { return d.value; });
|
| +
|
| + g.append("svg:text")
|
| + .attr("x", li.w / 2)
|
| + .attr("y", li.h / 2)
|
| + .attr("dy", "0.35em")
|
| + .attr("text-anchor", "middle")
|
| + .text(function(d) { return d.key; });
|
| +}
|
| +
|
| +function toggleLegend() {
|
| + var legend = d3.select("#legend");
|
| + if (legend.style("visibility") == "hidden") {
|
| + legend.style("visibility", "");
|
| + } else {
|
| + legend.style("visibility", "hidden");
|
| + }
|
| +}
|
| +
|
| +}
|
| +
|
| +window.addEventListener("message", function(event) {
|
| + var data = {
|
| + name: "Foo",
|
| + size: 20,
|
| + children: [
|
| + {
|
| + name: "Bar1",
|
| + children: [
|
| + {
|
| + name: "Bar11",
|
| + size: 5,
|
| + children: []
|
| + },
|
| + {
|
| + name: "Bar12",
|
| + size: 5,
|
| + children: []
|
| + }
|
| + ]
|
| + },
|
| + {
|
| + name: "Bar2",
|
| + children: [
|
| + {
|
| + name: "Bar21",
|
| + size: 1,
|
| + children: []
|
| + },
|
| + {
|
| + name: "Bar22",
|
| + size: 2,
|
| + children: []
|
| + }
|
| + ]
|
| + }
|
| + ]
|
| + }
|
| +// sequences(data);
|
| + sequences(event.data);
|
| +})
|
|
|