Repository: incubator-htrace Updated Branches: refs/heads/master 2f86d169e -> 8f2c9576c
HTRACE-131. Port spans.js in htrace-hbase to htraced (Masatake Iwasaki via Colin P. McCabe) Project: http://git-wip-us.apache.org/repos/asf/incubator-htrace/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-htrace/commit/8f2c9576 Tree: http://git-wip-us.apache.org/repos/asf/incubator-htrace/tree/8f2c9576 Diff: http://git-wip-us.apache.org/repos/asf/incubator-htrace/diff/8f2c9576 Branch: refs/heads/master Commit: 8f2c9576cb5eb4cff11a640c132cc9b835430936 Parents: 2f86d16 Author: Colin Patrick Mccabe <[email protected]> Authored: Mon Mar 16 17:06:13 2015 -0700 Committer: Colin P. Mccabe <[email protected]> Committed: Mon Mar 16 17:09:17 2015 -0700 ---------------------------------------------------------------------- htrace-core/src/web/app/setup.js | 13 +- .../src/web/app/views/details/details.js | 8 + .../src/web/app/views/swimlane/swimlane.js | 178 +++++++++++++++++++ htrace-core/src/web/index.html | 13 ++ 4 files changed, 211 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/8f2c9576/htrace-core/src/web/app/setup.js ---------------------------------------------------------------------- diff --git a/htrace-core/src/web/app/setup.js b/htrace-core/src/web/app/setup.js index d210ea6..90915e3 100644 --- a/htrace-core/src/web/app/setup.js +++ b/htrace-core/src/web/app/setup.js @@ -29,7 +29,9 @@ var Router = Backbone.Marionette.AppRouter.extend({ "routes": { "": "init", "!/search(/:query)": "search", - "!/spans/:id": "span" + "!/spans/:id": "span", + "!/swimlane/:id": "swimlane", + "!/swimlane/:id:?:lim": "swimlane" }, "initialize": function() { @@ -131,6 +133,15 @@ var Router = Backbone.Marionette.AppRouter.extend({ "el": top.content.$el[0], "id": "span-" + id })); + }, + + "swimlane": function(id, lim) { + var top = new app.SwimlaneView(); + app.root.app.show(top); + top.swimlane.show(new app.SwimlaneGraphView({ + "spanId": id, + "lim": lim + })); } }); http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/8f2c9576/htrace-core/src/web/app/views/details/details.js ---------------------------------------------------------------------- diff --git a/htrace-core/src/web/app/views/details/details.js b/htrace-core/src/web/app/views/details/details.js index 2a2b9f4..2f79e1b 100644 --- a/htrace-core/src/web/app/views/details/details.js +++ b/htrace-core/src/web/app/views/details/details.js @@ -35,5 +35,13 @@ app.SpanDetailsView = Backbone.Marionette.ItemView.extend({ }; context["span"]["duration"] = this.model.duration(); return context; + }, + + "events": { + "click": "swimlane" + }, + "swimlane": function() { + Backbone.history.navigate("!/swimlane/" + this.model.get("spanId"), + {"trigger": true}); } }); http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/8f2c9576/htrace-core/src/web/app/views/swimlane/swimlane.js ---------------------------------------------------------------------- diff --git a/htrace-core/src/web/app/views/swimlane/swimlane.js b/htrace-core/src/web/app/views/swimlane/swimlane.js new file mode 100644 index 0000000..878e2d0 --- /dev/null +++ b/htrace-core/src/web/app/views/swimlane/swimlane.js @@ -0,0 +1,178 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +app.SwimlaneView = Backbone.Marionette.LayoutView.extend({ + "template": "#swimlane-layout-template", + "regions": { + "swimlane": "div[role='complementary']", + "content": "div[role='main']" + } +}); + +app.SwimlaneGraphView = Backbone.Marionette.View.extend({ + className: "swimlane", + + initialize: function() { + this.spans = this.getSpans(0, [], + this.getJsonSync("/span/" + this.options.spanId), + this.options.lim || "lim=100", + this.getJsonSync); + }, + + render: function() { + this.appendSVG(this.spans); + }, + + getSpans: function getSpans(depth, spans, span, lim, getJSON) { + span.depth = depth; + spans.push(span); + var children = []; + getJSON("/span/" + span.s + "/children?" + lim).forEach(function(childId) { + children.push(getJSON("/span/" + childId)); + }); + children.sort(function(x, y) { + return x.b < y.b ? -1 : x.b > y.b ? 1 : 0; + }); + children.forEach(function(child) { + spans = getSpans(depth + 1, spans, child, lim, getJSON); + }); + return spans; + }, + + getJsonSync: function getJsonSync(url) { + return $.ajax({ + type: "GET", + url: url, + async: false, + dataType: "json" + }).responseJSON; + }, + + appendSVG: function appendSVG(spans) { + const height_span = 20; + const width_span = 700; + const size_tl = 6; + const margin = {top: 50, bottom: 50, left: 20, right: 1000, process: 300}; + + var height_screen = spans.length * height_span; + var dmax = d3.max(spans, function(s) { return s.depth; }); + var tmin = d3.min(spans, function(s) { return s.b; }); + var tmax = d3.max(spans, function(s) { return s.e; }); + var xscale = d3.time.scale() + .domain([new Date(tmin), new Date(tmax)]).range([0, width_span]); + + var svg = d3.select("div[role='main']").append("svg") + .attr("width", width_span + margin.process + margin.left + margin.right) + .attr("height", height_screen + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + var bars = svg.append("g") + .attr("id", "bars") + .attr("width", width_span) + .attr("height", height_screen) + .attr("transform", "translate(" + (10 * dmax + margin.process) + ", 0)"); + + var span_g = bars.selectAll("g.span") + .data(spans) + .enter() + .append("g") + .attr("transform", function(s, i) { + return "translate(0, " + (i * height_span + 5) + ")"; + }) + .classed("timeline", function(d) { return d.t; }); + + span_g.append("text") + .text(function(s) { return s.r; }) + .style("alignment-baseline", "hanging") + .style("font-size", "14px") + .attr("transform", function(s) { + return "translate(" + (s.depth * 10 - margin.process - 10 * dmax) + ", 0)"; + }); + + var rect_g = span_g.append("g") + .attr("transform", function(s) { + return "translate(" + xscale(new Date(s.b)) + ", 0)"; + }); + + rect_g.append("rect") + .attr("height", height_span - 1) + .attr("width", function (s) { + return (width_span * (s.e - s.b)) / (tmax - tmin) + 1; + }) + .style("fill", "lightblue") + .attr("class", "span") + + rect_g.append("text") + .text(function(s){ return s.d; }) + .style("alignment-baseline", "hanging") + .style("font-size", "14px"); + + rect_g.append("text") + .text(function(s){ return s.e - s.b; }) + .style("alignment-baseline", "baseline") + .style("text-anchor", "end") + .style("font-size", "10px") + .attr("transform", function(s, i) { return "translate(0, 10)"; }); + + bars.selectAll("g.timeline").selectAll("rect.timeline") + .data(function(s) { return s.t; }) + .enter() + .append("rect") + .style("fill", "red") + .attr("height", size_tl) + .attr("width", size_tl) + .attr("transform", function(t) { + return "translate(" + xscale(t.t) + "," + (height_span - 1 - size_tl) + ")"; + }) + .classed("timeline"); + + var popup = d3.select("div[role='main']").append("div") + .attr("class", "popup") + .style("opacity", 0); + + bars.selectAll("g.timeline") + .on("mouseover", function(d) { + popup.transition().duration(300).style("opacity", .95); + var text = "<table>"; + d.t.forEach(function (t) { + text += "<tr><td>" + (t.t - tmin) + "</td>"; + text += "<td> : " + t.m + "<td/></tr>"; + }); + text += "</table>" + popup.html(text) + .style("left", (document.body.scrollLeft + 50) + "px") + .style("top", (document.body.scrollTop + 70) + "px") + .style("width", "700px") + .style("background", "orange") + .style("position", "absolute"); + }) + .on("mouseout", function(d) { + popup.transition().duration(300).style("opacity", 0); + }); + + var axis = d3.svg.axis() + .scale(xscale) + .orient("top") + .tickValues(xscale.domain()) + .tickFormat(d3.time.format("%x %X.%L")) + .tickSize(6, 3); + + bars.append("g").attr("class", "axis").call(axis); + } +}); http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/8f2c9576/htrace-core/src/web/index.html ---------------------------------------------------------------------- diff --git a/htrace-core/src/web/index.html b/htrace-core/src/web/index.html index ecb0d7e..bcfea19 100644 --- a/htrace-core/src/web/index.html +++ b/htrace-core/src/web/index.html @@ -164,6 +164,18 @@ </table> </script> + <script id="swimlane-layout-template" type="text/html"> + <div class="container-fluid" id="list" role="application"> + <div class="row"> + <div class="col-md-12" role="main"></div> + </div> + + <div class="row"> + <div class="col-md-12" role="complementary"></div> + </div> + </div> + </script> + <script src="lib/js/jquery-2.1.3.min.js" type="text/javascript"></script> <script src="lib/js/d3-3.5.5.js" type="text/javascript"></script> <script src="lib/bootstrap-3.3.1/js/bootstrap.min.js" type="text/javascript"></script> @@ -182,6 +194,7 @@ <script src="app/views/search/field.js" type="text/javascript"></script> <script src="app/views/search/search.js" type="text/javascript"></script> <script src="app/views/details/details.js" type="text/javascript"></script> + <script src="app/views/swimlane/swimlane.js" type="text/javascript"></script> <script src="app/setup.js" type="text/javascript"></script> </body> </html>
