Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Unified Diff: Source/devtools/front_end/profiler/d3js_trace/sequences.js

Issue 887673002: DevTools: CPU profiler sunburst view (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/devtools/front_end/profiler/d3js_trace/sequences.css ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
+})
« no previous file with comments | « Source/devtools/front_end/profiler/d3js_trace/sequences.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698