var seldate = $("#selecteddate").val(); var paramDateL = getUrlParameter("startDate"); if (typeof paramDateL !== 'undefined') { try { seldate = new Date(parseFloat(paramDateL)).yyyymmdd(); $("#selecteddate").val(seldate) } catch (err) { } } if (typeof seldate === 'undefined' || seldate === "") { seldate = new Date().yyyymmdd(); } setStartEndDates(seldate); $("#datetimepickerstart").datetimepicker({ format : 'Y-m-d H:i', closeOnDateSelect : true, onChangeDateTime : function(ct, input) { $('#startDateValue').text(ct.getTime()); var endTime = parseFloat($('#endDateValue').text()); if (ct.getTime() >= endTime) { // Add 12 hours var endDate = new Date(ct.getTime() + (12 * 60 * 60 *1000)); writeStartEndDatesFull(ct, endDate); } } }); $("#datetimepickerend").datetimepicker({ format : 'Y-m-d H:i', closeOnDateSelect : true, onChangeDateTime : function(ct, $input) { $('#endDateValue').text(ct.getTime()); var startTime = parseFloat($('#startDateValue').text()); if (ct.getTime() <= startTime) { // add 12 hours var endDate = new Date(ct.getTime() + (12 * 60 * 60 *1000)); writeStartEndDatesFull(ct, endDate); } } }); $("#startQuery").click(function() { var script = $('#performance_script').val(); var sample = $('#performance_samplesize').val(); if (!script) return false; $("#startQuery").prop("disabled", true); $('#performanceGraph').text('Loading...'); var tenant = $("#tenants :selected").text(); var apiurl = "/monitorapi?cmd=performanceTree&tenant=" + encodeURIComponent(tenant); apiurl = apiurl + "&script=" + encodeURIComponent(script); apiurl = apiurl + "&start=" + $('#startDateValue').text(); apiurl = apiurl + "&end=" + $('#endDateValue').text(); apiurl = apiurl + "&sample=" + encodeURIComponent(sample); $.ajax({ url : apiurl, dataType : "json", async : true, success : function(data) { $('#performanceGraph').html(''); $("#startQuery").prop("disabled", false); var treeData = rewriteData(data); loadGraph(treeData); } }); return false; }); function initPage() { } function rewriteData(jsonData) { var result = []; var rootScript = jsonData.rpcName; var children = [] var root = { "name": rootScript, "parent": "null", "calls": jsonData.calls, "sumProcTime": jsonData.sumProcTime, "children": children}; if (jsonData.children) rewriteDataChildren(jsonData.children, children, rootScript) result.push(root); console.log(result) return result; } function rewriteDataChildren(jsonData, parentChildren, parent) { for (var i = 0; i < jsonData.length; i++) { var elem = jsonData[i]; var script = elem.rpcName; var children = [] var root = { "name": script, "parent": parent, "calls": elem.calls, "sumProcTime": elem.sumProcTime, "children": children}; if (elem.children) rewriteDataChildren(elem.children, children, script); parentChildren.push(root); } } function round(n, d) { return (Math.round(n * (10 ^ d)) / (10 ^ d)).toFixed(d); } function reloadPage() { initPage(); } function loadGraph(treeData) { // ************** Generate the tree diagram ***************** var margin = {top: 20, right: 120, bottom: 20, left: 120}, width = 960 - margin.right - margin.left, height = 500 - margin.top - margin.bottom; var i = 0, duration = 750, root; var tree = d3.layout.tree() .size([height, width]); var diagonal = d3.svg.diagonal() .projection(function(d) { return [d.y, d.x]; }); var svg = d3.select("#performanceGraph") .append("svg") .attr("width", "100%") .attr("height", "100%") .call(d3.behavior.zoom().on("zoom", function () { svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")") })) .append("g") root = treeData[0]; root.x0 = height / 2; root.y0 = 0; update(root); d3.select(self.frameElement).style("height", "500px"); function update(source) { // Compute the new tree layout. var nodes = tree.nodes(root).reverse(), links = tree.links(nodes); // Normalize for fixed-depth. nodes.forEach(function(d) { d.y = d.depth * 180; }); // Update the nodes… var node = svg.selectAll("g.node") .data(nodes, function(d) { return d.id || (d.id = ++i); }); // Enter any new nodes at the parent's previous position. var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) .on("click", click); nodeEnter.append("circle") .attr("r", 1e-6) .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); nodeEnter.append("text") .attr("x", function(d) { return d.children || d._children ? -13 : 13; }) .attr("dy", ".35em") .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) .text(function(d) { return d.name }) .style("fill-opacity", 1e-6); nodeEnter.append("text") .attr("x", function(d) { return d.children || d._children ? -13 : 13; }) .attr("dy", "1.5em") .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) .text(function(d) { return d.calls + " calls" }) .style("fill-opacity", 1); nodeEnter.append("text") .attr("x", function(d) { return d.children || d._children ? -13 : 13; }) .attr("dy", "2.6em") .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) .text(function(d) { if (!d.sumProcTime || d.sumProcTime == 0) {return null}; return (round(d.sumProcTime / d.calls, 0)) + " ms" }) .style("fill-opacity", 1); // Transition nodes to their new position. var nodeUpdate = node.transition() .duration(duration) .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); nodeUpdate.select("circle") .attr("r", 10) .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); nodeUpdate.select("text") .style("fill-opacity", 1); // Transition exiting nodes to the parent's new position. var nodeExit = node.exit().transition() .duration(duration) .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) .remove(); nodeExit.select("circle") .attr("r", 1e-6); nodeExit.select("text") .style("fill-opacity", 1e-6); // Update the links… var link = svg.selectAll("path.link") .data(links, function(d) { return d.target.id; }); // Enter any new links at the parent's previous position. link.enter().insert("path", "g") .attr("class", "link") .attr("d", function(d) { var o = {x: source.x0, y: source.y0}; return diagonal({source: o, target: o}); }); // Transition links to their new position. link.transition() .duration(duration) .attr("d", diagonal); // Transition exiting nodes to the parent's new position. link.exit().transition() .duration(duration) .attr("d", function(d) { var o = {x: source.x, y: source.y}; return diagonal({source: o, target: o}); }) .remove(); // Stash the old positions for transition. nodes.forEach(function(d) { d.x0 = d.x; d.y0 = d.y; }); } // Toggle children on click. function click(d) { if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } update(d); } } function setStartEndDates(seldate) { // Use moment.js for consistent date parsing var startDate = moment(seldate + 'T00:00:00'+timezoneOffsetString, "YYYY-MM-DDTHH:mm:ssZ").toDate(); var endDate = moment(seldate + 'T00:00:00'+timezoneOffsetString, "YYYY-MM-DDTHH:mm:ssZ").toDate(); endDate.setDate(startDate.getDate() + 1); writeStartEndDates(startDate, endDate); } function writeStartEndDatesFull(startDate, endDate) { $('#startDateValue').text(startDate.getTime()); $('#endDateValue').text(endDate.getTime()); $("#datetimepickerstart").val(startDate.yyyymmdd() + ' ' + addZero(startDate.getHours()) + ':' + addZero(startDate.getMinutes())); $("#datetimepickerend").val( endDate.yyyymmdd() + ' ' + addZero(endDate.getHours()) + ':' + addZero(endDate.getMinutes())); } function writeStartEndDates(startDate, endDate) { $('#startDateValue').text(startDate.getTime()); $('#endDateValue').text(endDate.getTime()); $("#datetimepickerstart").val(startDate.yyyymmdd() + ' 00:00'); $("#datetimepickerend").val(endDate.yyyymmdd() + ' 00:00'); }