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>
