Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require.config({
- paths : {
- "app" : "../app",
- "d3" : "../app/search/d3.v3.min"
- }
- });
- require([
- "jquery",
- "underscore",
- "splunkjs/mvc",
- "d3",
- "app/search/d3.tip",
- "splunkjs/mvc/simplexml/ready!"
- ],
- function (
- $,
- _,
- mvc,
- d3,
- d3tooltip) {
- var search = splunkjs.mvc.Components.get("columnSearch"); // Get the search manager
- var results = search.data("results"); // Get its results
- // A node within the JSON tree with reference to its parents to calculate their value
- function Node(name, parentNode) {
- this.children = [];
- this.name = name;
- this.value = 0;
- this.parentNode = parentNode;
- // Adding value to a node also adds this value to its parents
- this.addValue = function (value) {
- this.value += parseInt(value);
- if (this.parentNode != null) {
- this.parentNode.addValue(value);
- }
- };
- // Method to check if node by given name is already in child nodes
- this.hasChildNamed = function (name) {
- for (var child = 0; child < this.children.length; child++) {
- if (this.children[child].name == name) {
- return this.children[child];
- }
- }
- return null;
- };
- };
- // As soon as search returns results, parse them
- results.on("data", function () {
- if (!results.hasData())
- return;
- var collection = results.collection().toJSON();
- var levels = results.collection().raw.fields; // Assuming first fields are level names,
- var valueLabel = levels.pop(); // last field represents value
- var nestedJSON = new Node('root', null); // This contains the object given to the viz at the end
- // Go over each result row
- for (var resultIndex = 0; resultIndex < collection.length; resultIndex++) {
- var result = collection[resultIndex];
- var currentNode = nestedJSON;
- // And over each column in these results
- for (var levelIndex = 0; levelIndex < levels.length; levelIndex++) {
- var level = levels[levelIndex];
- var name = result[levels[levelIndex]];
- // See if current node has a child by the name of the current result, add if not
- var treePosition = currentNode.hasChildNamed(name);
- if (treePosition) {
- currentNode = treePosition;
- } else {
- var newNode = new Node(name, currentNode);
- currentNode.children.push(newNode);
- currentNode = newNode;
- if (levelIndex == levels.length - 1 || result[levels[levelIndex + 1]] == "-") {
- newNode.addValue(result[valueLabel]);
- break;
- }
- }
- }
- }
- // Done parsing, render viz
- d3.select("#flameTarget")
- .datum(nestedJSON)
- .call(flameGraph);
- });
- var flameGraph = flameGraph()
- .height(150) // adjust to needs, will clip if too little
- .width(960)
- .cellHeight(20)
- .transitionDuration(750)
- .transitionEase('cubic-in-out')
- .sort(true)
- //Example to sort in reverse order
- //.sort(function(a,b){ return d3.descending(a.name, b.name);})
- .title("");
- // Copied Code for flame graph, kept in here for simplicity (should be moved to separate file one day)
- function flameGraph() {
- var w = 960, // graph width
- h = 540, // graph height
- c = 18, // cell height
- selection = null, // selection
- tooltip = true, // enable tooltip
- title = "", // graph title
- transitionDuration = 750,
- transitionEase = "cubic-in-out", // tooltip offset
- sort = true,
- reversed = false, // reverse the graph direction
- clickHandler = null;
- var tip = d3tooltip()
- .direction("s")
- .offset([8, 0])
- .attr('class', 'd3-flame-graph-tip')
- .html(function (d) {
- return label(d);
- });
- var labelFormat = function (d) {
- return d.name + " (" + d3.round(100 * d.dx, 3) + "%, " + d.value + " samples)";
- };
- function setDetails(t) {
- var details = document.getElementById("details");
- if (details)
- details.innerHTML = t;
- }
- function label(d) {
- if (!d.dummy) {
- return labelFormat(d);
- } else {
- return "";
- }
- }
- function name(d) {
- return d.name;
- }
- var colorMapper = function (d) {
- return d.highlight ? "#E600E6" : colorHash(d.name);
- };
- function generateHash(name) {
- // Return a vector (0.0->1.0) that is a hash of the input string.
- // The hash is computed to favor early characters over later ones, so
- // that strings with similar starts have similar vectors. Only the first
- // 6 characters are considered.
- var hash = 0,
- weight = 1,
- max_hash = 0,
- mod = 10,
- max_char = 6;
- if (name) {
- for (var i = 0; i < name.length; i++) {
- if (i > max_char) {
- break;
- }
- hash += weight * (name.charCodeAt(i) % mod);
- max_hash += weight * (mod - 1);
- weight *= 0.70;
- }
- if (max_hash > 0) {
- hash = hash / max_hash;
- }
- }
- return hash;
- }
- function colorHash(name) {
- // Return an rgb() color string that is a hash of the provided name,
- // and with a warm palette.
- var vector = 0;
- if (name) {
- name = name.replace(/.*`/, ""); // drop module name if present
- name = name.replace(/\(.*/, ""); // drop extra info
- vector = generateHash(name);
- }
- var r = 200 + Math.round(55 * vector);
- var g = 0 + Math.round(230 * (1 - vector));
- var b = 0 + Math.round(55 * (1 - vector));
- return "rgb(" + r + "," + g + "," + b + ")";
- }
- function augment(data) {
- // Augment partitioning layout with "dummy" nodes so that internal nodes'
- // values dictate their width. Annoying, but seems to be least painful
- // option. https://github.com/mbostock/d3/pull/574
- if (data.children && (data.children.length > 0)) {
- data.children.forEach(augment);
- var childValues = 0;
- data.children.forEach(function (child) {
- childValues += child.value;
- });
- if (childValues < data.value) {
- data.children.push({
- "name" : "",
- "value" : data.value - childValues,
- "dummy" : true
- });
- }
- }
- }
- function hide(d) {
- if (!d.original) {
- d.original = d.value;
- }
- d.value = 0;
- if (d.children) {
- d.children.forEach(hide);
- }
- }
- function show(d) {
- d.fade = false;
- if (d.original) {
- d.value = d.original;
- }
- if (d.children) {
- d.children.forEach(show);
- }
- }
- function getSiblings(d) {
- var siblings = [];
- if (d.parent) {
- var me = d.parent.children.indexOf(d);
- siblings = d.parent.children.slice(0);
- siblings.splice(me, 1);
- }
- return siblings;
- }
- function hideSiblings(d) {
- var siblings = getSiblings(d);
- siblings.forEach(function (s) {
- hide(s);
- });
- if (d.parent) {
- hideSiblings(d.parent);
- }
- }
- function fadeAncestors(d) {
- if (d.parent) {
- d.parent.fade = true;
- fadeAncestors(d.parent);
- }
- }
- function getRoot(d) {
- if (d.parent) {
- return getRoot(d.parent);
- }
- return d;
- }
- function zoom(d) {
- tip.hide(d);
- hideSiblings(d);
- show(d);
- fadeAncestors(d);
- update();
- if (typeof clickHandler === 'function') {
- clickHandler(d);
- }
- }
- function searchTree(d, term) {
- var re = new RegExp(term),
- searchResults = [];
- function searchInner(d) {
- var label = d.name;
- if (d.children) {
- d.children.forEach(function (child) {
- searchInner(child);
- });
- }
- if (label.match(re)) {
- d.highlight = true;
- searchResults.push(d);
- } else {
- d.highlight = false;
- }
- }
- searchInner(d);
- return searchResults;
- }
- function clear(d) {
- d.highlight = false;
- if (d.children) {
- d.children.forEach(function (child) {
- clear(child);
- });
- }
- }
- function doSort(a, b) {
- if (typeof sort === 'function') {
- return sort(a, b);
- } else if (sort) {
- return d3.ascending(a.name, b.name);
- } else {
- return 0;
- }
- }
- var partition = d3.layout.partition()
- .sort(doSort)
- .value(function (d) {
- return d.v || d.value;
- })
- .children(function (d) {
- return d.c || d.children;
- });
- function update() {
- selection.each(function (data) {
- var x = d3.scale.linear().range([0, w]),
- y = d3.scale.linear().range([0, c]);
- var nodes = partition(data);
- var kx = w / data.dx;
- var g = d3.select(this).select("svg").selectAll("g").data(nodes);
- g.transition()
- .duration(transitionDuration)
- .ease(transitionEase)
- .attr("transform", function (d) {
- return "translate(" + x(d.x) + ","
- + (reversed ? y(d.depth) : (h - y(d.depth) - c)) + ")";
- });
- g.select("rect").transition()
- .duration(transitionDuration)
- .ease(transitionEase)
- .attr("width", function (d) {
- return d.dx * kx;
- });
- var node = g.enter()
- .append("svg:g")
- .attr("transform", function (d) {
- return "translate(" + x(d.x) + ","
- + (reversed ? y(d.depth) : (h - y(d.depth) - c)) + ")";
- });
- node.append("svg:rect")
- .attr("width", function (d) {
- return d.dx * kx;
- });
- if (!tooltip)
- node.append("svg:title");
- node.append("foreignObject")
- .append("xhtml:div");
- g.attr("width", function (d) {
- return d.dx * kx;
- })
- .attr("height", function (d) {
- return c;
- })
- .attr("name", function (d) {
- return d.name;
- })
- .attr("class", function (d) {
- return d.fade ? "frame fade" : "frame";
- });
- g.select("rect")
- .attr("height", function (d) {
- return c;
- })
- .attr("fill", function (d) {
- return colorMapper(d);
- })
- .style("visibility", function (d) {
- return d.dummy ? "hidden" : "visible";
- });
- if (!tooltip)
- g.select("title")
- .text(label);
- g.select("foreignObject")
- .attr("width", function (d) {
- return d.dx * kx;
- })
- .attr("height", function (d) {
- return c;
- })
- .select("div")
- .attr("class", "flamegraph-label")
- .style("display", function (d) {
- return (d.dx * kx < 35) || d.dummy ? "none" : "block";
- })
- .text(name);
- g.on('click', zoom);
- g.exit().remove();
- g.on('mouseover', function (d) {
- if (!d.dummy) {
- if (tooltip)
- tip.show(d);
- setDetails(label(d));
- }
- }).on('mouseout', function (d) {
- if (!d.dummy) {
- if (tooltip)
- tip.hide(d);
- setDetails("");
- }
- });
- });
- }
- function merge(data, samples) {
- samples.forEach(function (sample) {
- var node = _.find(data, function (element) {
- return element.name === sample.name;
- });
- if (node) {
- node.value += sample.value;
- if (sample.children) {
- if (!node.children) {
- node.children = [];
- }
- merge(node.children, sample.children)
- }
- } else {
- data.push(sample);
- }
- });
- }
- function chart(s) {
- selection = s;
- if (!arguments.length)
- return chart;
- selection.each(function (data) {
- var svg = d3.select(this)
- .append("svg:svg")
- .attr("width", w)
- .attr("height", h)
- .attr("class", "partition d3-flame-graph")
- .call(tip);
- svg.append("svg:text")
- .attr("class", "title")
- .attr("text-anchor", "middle")
- .attr("y", "25")
- .attr("x", w / 2)
- .attr("fill", "#808080")
- .text(title);
- augment(data);
- // "creative" fix for node ordering when partition is called for the first time
- partition(data);
- });
- // first draw
- update();
- }
- chart.height = function (_) {
- if (!arguments.length) {
- return h;
- }
- h = _;
- return chart;
- };
- chart.width = function (_) {
- if (!arguments.length) {
- return w;
- }
- w = _;
- return chart;
- };
- chart.cellHeight = function (_) {
- if (!arguments.length) {
- return c;
- }
- c = _;
- return chart;
- };
- chart.tooltip = function (_) {
- if (!arguments.length) {
- return tooltip;
- }
- if (typeof _ === "function") {
- tip = _;
- }
- tooltip = true;
- return chart;
- };
- chart.title = function (_) {
- if (!arguments.length) {
- return title;
- }
- title = _;
- return chart;
- };
- chart.transitionDuration = function (_) {
- if (!arguments.length) {
- return transitionDuration;
- }
- transitionDuration = _;
- return chart;
- };
- chart.transitionEase = function (_) {
- if (!arguments.length) {
- return transitionEase;
- }
- transitionEase = _;
- return chart;
- };
- chart.sort = function (_) {
- if (!arguments.length) {
- return sort;
- }
- sort = _;
- return chart;
- };
- chart.reversed = function (_) {
- if (!arguments.length) {
- return reversed;
- }
- reversed = _;
- return chart;
- };
- chart.label = function (_) {
- if (!arguments.length) {
- return labelFormat;
- }
- labelFormat = _;
- return chart;
- };
- chart.search = function (term) {
- var searchResults = [];
- selection.each(function (data) {
- searchResults = searchTree(data, term);
- update();
- });
- return searchResults;
- };
- chart.clear = function () {
- selection.each(function (data) {
- clear(data);
- update();
- });
- };
- chart.zoomTo = function (d) {
- zoom(d);
- };
- chart.resetZoom = function () {
- selection.each(function (data) {
- zoom(data); // zoom to root
- });
- };
- chart.onClick = function (_) {
- if (!arguments.length) {
- return clickHandler;
- }
- clickHandler = _;
- return chart;
- };
- chart.merge = function (samples) {
- selection.each(function (data) {
- merge([data], [samples]);
- augment(data);
- });
- update();
- }
- chart.color = function (_) {
- if (!arguments.length) {
- return colorMapper;
- }
- colorMapper = _;
- return chart;
- };
- return chart;
- }
- });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement