Repository: samza
Updated Branches:
  refs/heads/master ad1f16175 -> b71b253d2


http://git-wip-us.apache.org/repos/asf/samza/blob/b71b253d/samza-shell/src/main/visualizer/js/planToDagre.js
----------------------------------------------------------------------
diff --git a/samza-shell/src/main/visualizer/js/planToDagre.js 
b/samza-shell/src/main/visualizer/js/planToDagre.js
new file mode 100644
index 0000000..8ba198e
--- /dev/null
+++ b/samza-shell/src/main/visualizer/js/planToDagre.js
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+function planToDagre(data) {
+  // Create the input graph
+  var g = new dagreD3.graphlib.Graph()
+      .setGraph({
+        rankdir: "LR"
+      })
+      .setDefaultEdgeLabel(function() { return {}; });
+
+  var allStreams = [data.sourceStreams, data.sinkStreams, 
data.intermediateStreams];
+  var streamClasses = ["source", "sink", "intermediate"];
+  for (var i = 0; i < allStreams.length; i++) {
+    var streams = allStreams[i];
+    for (var streamId in streams) {
+      var stream = streams[streamId];
+      var labelVal = "<div><h3 class=\"topbar\">" + stream.streamSpec.id + 
"</h3><ul class=\"detailBox\" >"
+      labelVal += "<li>SystemName: " + stream.streamSpec.systemName + "</li>"
+      labelVal += "<li>PhysicalName: " + stream.streamSpec.physicalName + 
"</li>"
+      labelVal += "<li>PartitionCount: " + stream.streamSpec.partitionCount + 
"</li>"
+      labelVal += "</ul></div>"
+      g.setNode(streamId,  { label: labelVal, labelType: "html", shape: 
"ellipse", class: streamClasses[i] });
+    }
+  }
+
+  var jobs = data.jobs;
+  for (var i = 0; i < jobs.length; i++) {
+    var canonicalOpIds = jobs[i].operatorGraph.canonicalOpIds;
+    var operators = jobs[i].operatorGraph.operators;
+    for (var opId in operators) {
+      var operator = operators[opId];
+      var labelVal = "<div><h3 class=\"topbar\">" + operator.opCode + 
"</h3><ul class=\"detailBox\">";
+      var opId = operator.opId;
+      if (!(opId in canonicalOpIds)) {
+        canonicalOpIds[opId] = opId.toString();
+      }
+      labelVal +=  "<li>ID: " + opId + "</li>";
+      labelVal +=  "<li>@" + operator.sourceLocation + "</li>";
+
+      var keys = ["opId", "opCode", "sourceLocation", "outputStreamId", 
"nextOperatorIds"];
+      for (var key in operator) {
+        if (keys.indexOf(key) === -1) {
+          labelVal += "<li>" + key + ": " + operator[key] + "</li>";
+        }
+      }
+
+      labelVal += "</ul></div>";
+      g.setNode(canonicalOpIds[opId],  { label: labelVal, labelType: "html", 
rx: 5, ry: 5 });
+    }
+  }
+
+  for (var i = 0; i < jobs.length; i++) {
+    var inputs = jobs[i].operatorGraph.inputStreams;
+    for (var k = 0; k < inputs.length; k++) {
+      var input = inputs[k];
+      for (var m = 0; m < input.nextOperatorIds.length; m++) {
+        g.setEdge(input.streamId, canonicalOpIds[input.nextOperatorIds[m]]);
+      }
+    }
+
+    var operators = jobs[i].operatorGraph.operators;
+    for (var opId in operators) {
+      var operator = operators[opId];
+      for (var j = 0; j < operator.nextOperatorIds.length; j++) {
+        g.setEdge(canonicalOpIds[opId], 
canonicalOpIds[operator.nextOperatorIds[j]]);
+      }
+      if (typeof(operator.outputStreamId) !== 'undefined') {
+        g.setEdge(canonicalOpIds[opId], operator.outputStreamId);
+      }
+    }
+  }
+
+  return g;
+}

http://git-wip-us.apache.org/repos/asf/samza/blob/b71b253d/samza-shell/src/main/visualizer/plan.html
----------------------------------------------------------------------
diff --git a/samza-shell/src/main/visualizer/plan.html 
b/samza-shell/src/main/visualizer/plan.html
new file mode 100644
index 0000000..9fe2e26
--- /dev/null
+++ b/samza-shell/src/main/visualizer/plan.html
@@ -0,0 +1,118 @@
+<!doctype html>
+
+<!--
+   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.
+-->
+
+<meta charset="utf-8">
+<title>SAMZA Visualizer</title>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+
+<script src="js/d3.v3.min.js" charset="utf-8"></script>
+<script type="text/javascript" src="js/dagre-d3.min.js"></script>
+<script type="text/javascript" src="js/planToDagre.js"></script>
+<script type="text/javascript" src="plan.json"></script>
+<script type="text/javascript" src="../plan/plan.json"></script>
+
+<h1>SAMZA Visualizer</h1>
+
+<style id="css">
+  body {
+    font: 300 14px 'Helvetica Neue', Helvetica;
+  }
+
+  svg {
+    margin-top: 30px;
+  }
+
+  .node rect {
+    stroke: #999;
+    fill: #E8E8EE;
+    stroke-width: 1.5px;
+  }
+
+  .node ellipse {
+    stroke: #999;
+    fill: #fff;
+    stroke-width: 1.5px;
+  }
+
+  .edgePath path {
+    stroke: #333;
+    stroke-width: 1.5px;
+  }
+
+  g.source > ellipse {
+    fill: #BDEDFF;
+  }
+
+  g.sink > ellipse {
+    fill: #BDEDFF;
+  }
+
+  g.intermediate > ellipse {
+    fill: #C3FDB8;
+  }
+
+  .topbar {
+    text-align: center;
+    border-bottom: solid;
+    border-bottom-color: #cdcfd2;
+    border-bottom-width: 1px;
+  }
+
+  .detailBox{
+    margin-top: -10px;
+  }
+</style>
+
+<section>
+  <p id="summary"/>
+</section>
+
+<svg id="svg-canvas" width=1200 height=1000><g/></svg>
+
+<script id="js">
+  var data = JSON.parse(plan);
+  var g = planToDagre(data);
+
+  var summary = "A visualization of application <b>" + data.applicationName + 
"-" + data.applicationId + "</b>";
+  summary += ", which consists of " + data.jobs.length + " job(s), ";
+  summary += Object.keys(data.sourceStreams).length + " input stream(s), and ";
+  summary += Object.keys(data.sinkStreams).length + " output stream(s).";
+  document.getElementById("summary").innerHTML = summary;
+
+  // Set up an SVG group so that we can translate the final graph.
+  var svg = d3.select("svg"),
+      inner = svg.select("g");
+
+  // Set up zoom support
+  var zoom = d3.behavior.zoom().on("zoom", function() {
+      inner.attr("transform", "translate(" + d3.event.translate + ")" +
+                                  "scale(" + d3.event.scale + ")");
+    });
+  svg.call(zoom);
+
+  // Create the renderer
+  var render = new dagreD3.render();
+
+  // Run the renderer. This is what draws the final graph.
+  render(inner, g);
+
+  var initialScale = 0.65;
+  zoom.scale(initialScale).event(svg);
+  svg.attr('height', g.graph().height * initialScale + 100);
+</script>

Reply via email to