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