...

Source file src/pkg/cmd/vendor/github.com/google/pprof/third_party/d3flamegraph/d3_flame_graph.go

     1	// A D3.js plugin that produces flame graphs from hierarchical data.
     2	// https://github.com/spiermar/d3-flame-graph
     3	// Version 2.0.0-alpha4
     4	// See LICENSE file for license details
     5	
     6	package d3flamegraph
     7	
     8	// JSSource returns the d3-flamegraph.js file
     9	const JSSource = `
    10	(function (global, factory) {
    11		typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3')) :
    12		typeof define === 'function' && define.amd ? define(['exports', 'd3'], factory) :
    13		(factory((global.d3 = global.d3 || {}),global.d3));
    14	}(this, (function (exports,d3) { 'use strict';
    15	
    16	var d3__default = 'default' in d3 ? d3['default'] : d3;
    17	
    18	var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
    19	
    20	
    21	
    22	
    23	
    24	function createCommonjsModule(fn, module) {
    25		return module = { exports: {} }, fn(module, module.exports), module.exports;
    26	}
    27	
    28	var d3Tip = createCommonjsModule(function (module) {
    29	// d3.tip
    30	// Copyright (c) 2013 Justin Palmer
    31	//
    32	// Tooltips for d3.js SVG visualizations
    33	
    34	(function (root, factory) {
    35	  if (typeof undefined === 'function' && undefined.amd) {
    36	    // AMD. Register as an anonymous module with d3 as a dependency.
    37	    undefined(['d3'], factory);
    38	  } else if ('object' === 'object' && module.exports) {
    39	    // CommonJS
    40	    var d3$$1 = d3__default;
    41	    module.exports = factory(d3$$1);
    42	  } else {
    43	    // Browser global.
    44	    root.d3.tip = factory(root.d3);
    45	  }
    46	}(commonjsGlobal, function (d3$$1) {
    47	
    48	  // Public - contructs a new tooltip
    49	  //
    50	  // Returns a tip
    51	  return function() {
    52	    var direction = d3_tip_direction,
    53	        offset    = d3_tip_offset,
    54	        html      = d3_tip_html,
    55	        node      = initNode(),
    56	        svg       = null,
    57	        point     = null,
    58	        target    = null;
    59	
    60	    function tip(vis) {
    61	      svg = getSVGNode(vis);
    62	      point = svg.createSVGPoint();
    63	      document.body.appendChild(node);
    64	    }
    65	
    66	    // Public - show the tooltip on the screen
    67	    //
    68	    // Returns a tip
    69	    tip.show = function() {
    70	      var args = Array.prototype.slice.call(arguments);
    71	      if(args[args.length - 1] instanceof SVGElement) target = args.pop();
    72	
    73	      var content = html.apply(this, args),
    74	          poffset = offset.apply(this, args),
    75	          dir     = direction.apply(this, args),
    76	          nodel   = getNodeEl(),
    77	          i       = directions.length,
    78	          coords,
    79	          scrollTop  = document.documentElement.scrollTop || document.body.scrollTop,
    80	          scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
    81	
    82	      nodel.html(content)
    83	        .style('opacity', 1).style('pointer-events', 'all');
    84	
    85	      while(i--) nodel.classed(directions[i], false);
    86	      coords = direction_callbacks.get(dir).apply(this);
    87	      nodel.classed(dir, true)
    88	      	.style('top', (coords.top +  poffset[0]) + scrollTop + 'px')
    89	      	.style('left', (coords.left + poffset[1]) + scrollLeft + 'px');
    90	
    91	      return tip;
    92	    };
    93	
    94	    // Public - hide the tooltip
    95	    //
    96	    // Returns a tip
    97	    tip.hide = function() {
    98	      var nodel = getNodeEl();
    99	      nodel.style('opacity', 0).style('pointer-events', 'none');
   100	      return tip
   101	    };
   102	
   103	    // Public: Proxy attr calls to the d3 tip container.  Sets or gets attribute value.
   104	    //
   105	    // n - name of the attribute
   106	    // v - value of the attribute
   107	    //
   108	    // Returns tip or attribute value
   109	    tip.attr = function(n, v) {
   110	      if (arguments.length < 2 && typeof n === 'string') {
   111	        return getNodeEl().attr(n)
   112	      } else {
   113	        var args =  Array.prototype.slice.call(arguments);
   114	        d3$$1.selection.prototype.attr.apply(getNodeEl(), args);
   115	      }
   116	
   117	      return tip
   118	    };
   119	
   120	    // Public: Proxy style calls to the d3 tip container.  Sets or gets a style value.
   121	    //
   122	    // n - name of the property
   123	    // v - value of the property
   124	    //
   125	    // Returns tip or style property value
   126	    tip.style = function(n, v) {
   127	      if (arguments.length < 2 && typeof n === 'string') {
   128	        return getNodeEl().style(n)
   129	      } else {
   130	        var args = Array.prototype.slice.call(arguments);
   131	        d3$$1.selection.prototype.style.apply(getNodeEl(), args);
   132	      }
   133	
   134	      return tip
   135	    };
   136	
   137	    // Public: Set or get the direction of the tooltip
   138	    //
   139	    // v - One of n(north), s(south), e(east), or w(west), nw(northwest),
   140	    //     sw(southwest), ne(northeast) or se(southeast)
   141	    //
   142	    // Returns tip or direction
   143	    tip.direction = function(v) {
   144	      if (!arguments.length) return direction
   145	      direction = v == null ? v : functor(v);
   146	
   147	      return tip
   148	    };
   149	
   150	    // Public: Sets or gets the offset of the tip
   151	    //
   152	    // v - Array of [x, y] offset
   153	    //
   154	    // Returns offset or
   155	    tip.offset = function(v) {
   156	      if (!arguments.length) return offset
   157	      offset = v == null ? v : functor(v);
   158	
   159	      return tip
   160	    };
   161	
   162	    // Public: sets or gets the html value of the tooltip
   163	    //
   164	    // v - String value of the tip
   165	    //
   166	    // Returns html value or tip
   167	    tip.html = function(v) {
   168	      if (!arguments.length) return html
   169	      html = v == null ? v : functor(v);
   170	
   171	      return tip
   172	    };
   173	
   174	    // Public: destroys the tooltip and removes it from the DOM
   175	    //
   176	    // Returns a tip
   177	    tip.destroy = function() {
   178	      if(node) {
   179	        getNodeEl().remove();
   180	        node = null;
   181	      }
   182	      return tip;
   183	    };
   184	
   185	    function d3_tip_direction() { return 'n' }
   186	    function d3_tip_offset() { return [0, 0] }
   187	    function d3_tip_html() { return ' ' }
   188	
   189	    var direction_callbacks = d3$$1.map({
   190	      n:  direction_n,
   191	      s:  direction_s,
   192	      e:  direction_e,
   193	      w:  direction_w,
   194	      nw: direction_nw,
   195	      ne: direction_ne,
   196	      sw: direction_sw,
   197	      se: direction_se
   198	    }),
   199	
   200	    directions = direction_callbacks.keys();
   201	
   202	    function direction_n() {
   203	      var bbox = getScreenBBox();
   204	      return {
   205	        top:  bbox.n.y - node.offsetHeight,
   206	        left: bbox.n.x - node.offsetWidth / 2
   207	      }
   208	    }
   209	
   210	    function direction_s() {
   211	      var bbox = getScreenBBox();
   212	      return {
   213	        top:  bbox.s.y,
   214	        left: bbox.s.x - node.offsetWidth / 2
   215	      }
   216	    }
   217	
   218	    function direction_e() {
   219	      var bbox = getScreenBBox();
   220	      return {
   221	        top:  bbox.e.y - node.offsetHeight / 2,
   222	        left: bbox.e.x
   223	      }
   224	    }
   225	
   226	    function direction_w() {
   227	      var bbox = getScreenBBox();
   228	      return {
   229	        top:  bbox.w.y - node.offsetHeight / 2,
   230	        left: bbox.w.x - node.offsetWidth
   231	      }
   232	    }
   233	
   234	    function direction_nw() {
   235	      var bbox = getScreenBBox();
   236	      return {
   237	        top:  bbox.nw.y - node.offsetHeight,
   238	        left: bbox.nw.x - node.offsetWidth
   239	      }
   240	    }
   241	
   242	    function direction_ne() {
   243	      var bbox = getScreenBBox();
   244	      return {
   245	        top:  bbox.ne.y - node.offsetHeight,
   246	        left: bbox.ne.x
   247	      }
   248	    }
   249	
   250	    function direction_sw() {
   251	      var bbox = getScreenBBox();
   252	      return {
   253	        top:  bbox.sw.y,
   254	        left: bbox.sw.x - node.offsetWidth
   255	      }
   256	    }
   257	
   258	    function direction_se() {
   259	      var bbox = getScreenBBox();
   260	      return {
   261	        top:  bbox.se.y,
   262	        left: bbox.e.x
   263	      }
   264	    }
   265	
   266	    function initNode() {
   267	      var node = d3$$1.select(document.createElement('div'));
   268	      node.style('position', 'absolute').style('top', 0).style('opacity', 0)
   269	      	.style('pointer-events', 'none').style('box-sizing', 'border-box');
   270	
   271	      return node.node()
   272	    }
   273	
   274	    function getSVGNode(el) {
   275	      el = el.node();
   276	      if(el.tagName.toLowerCase() === 'svg')
   277	        return el
   278	
   279	      return el.ownerSVGElement
   280	    }
   281	
   282	    function getNodeEl() {
   283	      if(node === null) {
   284	        node = initNode();
   285	        // re-add node to DOM
   286	        document.body.appendChild(node);
   287	      }
   288	      return d3$$1.select(node);
   289	    }
   290	
   291	    // Private - gets the screen coordinates of a shape
   292	    //
   293	    // Given a shape on the screen, will return an SVGPoint for the directions
   294	    // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
   295	    // sw(southwest).
   296	    //
   297	    //    +-+-+
   298	    //    |   |
   299	    //    +   +
   300	    //    |   |
   301	    //    +-+-+
   302	    //
   303	    // Returns an Object {n, s, e, w, nw, sw, ne, se}
   304	    function getScreenBBox() {
   305	      var targetel   = target || d3$$1.event.target;
   306	
   307	      while ('undefined' === typeof targetel.getScreenCTM && 'undefined' === targetel.parentNode) {
   308	          targetel = targetel.parentNode;
   309	      }
   310	
   311	      var bbox       = {},
   312	          matrix     = targetel.getScreenCTM(),
   313	          tbbox      = targetel.getBBox(),
   314	          width      = tbbox.width,
   315	          height     = tbbox.height,
   316	          x          = tbbox.x,
   317	          y          = tbbox.y;
   318	
   319	      point.x = x;
   320	      point.y = y;
   321	      bbox.nw = point.matrixTransform(matrix);
   322	      point.x += width;
   323	      bbox.ne = point.matrixTransform(matrix);
   324	      point.y += height;
   325	      bbox.se = point.matrixTransform(matrix);
   326	      point.x -= width;
   327	      bbox.sw = point.matrixTransform(matrix);
   328	      point.y -= height / 2;
   329	      bbox.w  = point.matrixTransform(matrix);
   330	      point.x += width;
   331	      bbox.e = point.matrixTransform(matrix);
   332	      point.x -= width / 2;
   333	      point.y -= height / 2;
   334	      bbox.n = point.matrixTransform(matrix);
   335	      point.y += height;
   336	      bbox.s = point.matrixTransform(matrix);
   337	
   338	      return bbox
   339	    }
   340	    
   341	    // Private - replace D3JS 3.X d3.functor() function
   342	    function functor(v) {
   343	    	return typeof v === "function" ? v : function() {
   344	        return v
   345	    	}
   346	    }
   347	
   348	    return tip
   349	  };
   350	
   351	}));
   352	});
   353	
   354	var flamegraph = function () {
   355	  var w = 960; // graph width
   356	  var h = null; // graph height
   357	  var c = 18; // cell height
   358	  var selection = null; // selection
   359	  var tooltip = true; // enable tooltip
   360	  var title = ''; // graph title
   361	  var transitionDuration = 750;
   362	  var transitionEase = d3.easeCubic; // tooltip offset
   363	  var sort = false;
   364	  var inverted = false; // invert the graph direction
   365	  var clickHandler = null;
   366	  var minFrameSize = 0;
   367	  var details = null;
   368	
   369	  var tip = d3Tip()
   370	    .direction('s')
   371	    .offset([8, 0])
   372	    .attr('class', 'd3-flame-graph-tip')
   373	    .html(function (d) { return label(d) });
   374	
   375	  var svg;
   376	
   377	  function name (d) {
   378	    return d.data.n || d.data.name
   379	  }
   380	
   381	  function libtype (d) {
   382	    return d.data.l || d.data.libtype
   383	  }
   384	
   385	  function children (d) {
   386	    return d.c || d.children
   387	  }
   388	
   389	  function value (d) {
   390	    return d.v || d.value
   391	  }
   392	
   393	  var label = function (d) {
   394	    return name(d) + ' (' + d3.format('.3f')(100 * (d.x1 - d.x0), 3) + '%, ' + value(d) + ' samples)'
   395	  };
   396	
   397	  function setDetails (t) {
   398	    if (details) { details.innerHTML = t; }
   399	  }
   400	
   401	  var colorMapper = function (d) {
   402	    return d.highlight ? '#E600E6' : colorHash(name(d), libtype(d))
   403	  };
   404	
   405	  function generateHash (name) {
   406	    // Return a vector (0.0->1.0) that is a hash of the input string.
   407	    // The hash is computed to favor early characters over later ones, so
   408	    // that strings with similar starts have similar vectors. Only the first
   409	    // 6 characters are considered.
   410	    const MAX_CHAR = 6;
   411	
   412	    var hash = 0;
   413	    var maxHash = 0;
   414	    var weight = 1;
   415	    var mod = 10;
   416	
   417	    if (name) {
   418	      for (var i = 0; i < name.length; i++) {
   419	        if (i > MAX_CHAR) { break }
   420	        hash += weight * (name.charCodeAt(i) % mod);
   421	        maxHash += weight * (mod - 1);
   422	        weight *= 0.70;
   423	      }
   424	      if (maxHash > 0) { hash = hash / maxHash; }
   425	    }
   426	    return hash
   427	  }
   428	
   429	  function colorHash (name, libtype) {
   430	    // Return a color for the given name and library type. The library type
   431	    // selects the hue, and the name is hashed to a color in that hue.
   432	
   433	    var r;
   434	    var g;
   435	    var b;
   436	
   437	    // Select hue. Order is important.
   438	    var hue;
   439	    if (typeof libtype === 'undefined' || libtype === '') {
   440	      // default when libtype is not in use
   441	      hue = 'warm';
   442	    } else {
   443	      hue = 'red';
   444	      if (name.match(/::/)) {
   445	        hue = 'yellow';
   446	      }
   447	      if (libtype === 'kernel') {
   448	        hue = 'orange';
   449	      } else if (libtype === 'jit') {
   450	        hue = 'green';
   451	      } else if (libtype === 'inlined') {
   452	        hue = 'aqua';
   453	      }
   454	    }
   455	
   456	    // calculate hash
   457	    var vector = 0;
   458	    if (name) {
   459	      var nameArr = name.split('` + "`" + `');
   460	      if (nameArr.length > 1) {
   461	        name = nameArr[nameArr.length - 1]; // drop module name if present
   462	      }
   463	      name = name.split('(')[0]; // drop extra info
   464	      vector = generateHash(name);
   465	    }
   466	
   467	    // calculate color
   468	    if (hue === 'red') {
   469	      r = 200 + Math.round(55 * vector);
   470	      g = 50 + Math.round(80 * vector);
   471	      b = g;
   472	    } else if (hue === 'orange') {
   473	      r = 190 + Math.round(65 * vector);
   474	      g = 90 + Math.round(65 * vector);
   475	      b = 0;
   476	    } else if (hue === 'yellow') {
   477	      r = 175 + Math.round(55 * vector);
   478	      g = r;
   479	      b = 50 + Math.round(20 * vector);
   480	    } else if (hue === 'green') {
   481	      r = 50 + Math.round(60 * vector);
   482	      g = 200 + Math.round(55 * vector);
   483	      b = r;
   484	    } else if (hue === 'aqua') {
   485	      r = 50 + Math.round(60 * vector);
   486	      g = 165 + Math.round(55 * vector);
   487	      b = g;
   488	    } else {
   489	      // original warm palette
   490	      r = 200 + Math.round(55 * vector);
   491	      g = 0 + Math.round(230 * (1 - vector));
   492	      b = 0 + Math.round(55 * (1 - vector));
   493	    }
   494	
   495	    return 'rgb(' + r + ',' + g + ',' + b + ')'
   496	  }
   497	
   498	  function hide (d) {
   499	    d.data.hide = true;
   500	    if (children(d)) {
   501	      children(d).forEach(hide);
   502	    }
   503	  }
   504	
   505	  function show (d) {
   506	    d.data.fade = false;
   507	    d.data.hide = false;
   508	    if (children(d)) {
   509	      children(d).forEach(show);
   510	    }
   511	  }
   512	
   513	  function getSiblings (d) {
   514	    var siblings = [];
   515	    if (d.parent) {
   516	      var me = d.parent.children.indexOf(d);
   517	      siblings = d.parent.children.slice(0);
   518	      siblings.splice(me, 1);
   519	    }
   520	    return siblings
   521	  }
   522	
   523	  function hideSiblings (d) {
   524	    var siblings = getSiblings(d);
   525	    siblings.forEach(function (s) {
   526	      hide(s);
   527	    });
   528	    if (d.parent) {
   529	      hideSiblings(d.parent);
   530	    }
   531	  }
   532	
   533	  function fadeAncestors (d) {
   534	    if (d.parent) {
   535	      d.parent.data.fade = true;
   536	      fadeAncestors(d.parent);
   537	    }
   538	  }
   539	
   540	  // function getRoot (d) {
   541	  //   if (d.parent) {
   542	  //     return getRoot(d.parent)
   543	  //   }
   544	  //   return d
   545	  // }
   546	
   547	  function zoom (d) {
   548	    tip.hide(d);
   549	    hideSiblings(d);
   550	    show(d);
   551	    fadeAncestors(d);
   552	    update();
   553	    if (typeof clickHandler === 'function') {
   554	      clickHandler(d);
   555	    }
   556	  }
   557	
   558	  function searchTree (d, term) {
   559	    var re = new RegExp(term);
   560	    var searchResults = [];
   561	
   562	    function searchInner (d) {
   563	      var label = name(d);
   564	
   565	      if (children(d)) {
   566	        children(d).forEach(function (child) {
   567	          searchInner(child);
   568	        });
   569	      }
   570	
   571	      if (label.match(re)) {
   572	        d.highlight = true;
   573	        searchResults.push(d);
   574	      } else {
   575	        d.highlight = false;
   576	      }
   577	    }
   578	
   579	    searchInner(d);
   580	    return searchResults
   581	  }
   582	
   583	  function clear (d) {
   584	    d.highlight = false;
   585	    if (children(d)) {
   586	      children(d).forEach(function (child) {
   587	        clear(child);
   588	      });
   589	    }
   590	  }
   591	
   592	  function doSort (a, b) {
   593	    if (typeof sort === 'function') {
   594	      return sort(a, b)
   595	    } else if (sort) {
   596	      return d3.ascending(name(a), name(b))
   597	    }
   598	  }
   599	
   600	  var p = d3.partition();
   601	
   602	  function filterNodes (root) {
   603	    var nodeList = root.descendants();
   604	    if (minFrameSize > 0) {
   605	      var kx = w / (root.x1 - root.x0);
   606	      nodeList = nodeList.filter(function (el) {
   607	        return ((el.x1 - el.x0) * kx) > minFrameSize
   608	      });
   609	    }
   610	    return nodeList
   611	  }
   612	
   613	  function update () {
   614	    selection.each(function (root) {
   615	      var x = d3.scaleLinear().range([0, w]);
   616	      var y = d3.scaleLinear().range([0, c]);
   617	
   618	      if (sort) root.sort(doSort);
   619	      root.sum(function (d) {
   620	        if (d.fade || d.hide) {
   621	          return 0
   622	        }
   623	        // The node's self value is its total value minus all children.
   624	        var v = value(d);
   625	        if (children(d)) {
   626	          var c = children(d);
   627	          for (var i = 0; i < c.length; i++) {
   628	            v -= value(c[i]);
   629	          }
   630	        }
   631	        return v
   632	      });
   633	      p(root);
   634	
   635	      var kx = w / (root.x1 - root.x0);
   636	      function width (d) { return (d.x1 - d.x0) * kx }
   637	
   638	      var descendants = filterNodes(root);
   639	      var g = d3.select(this).select('svg').selectAll('g').data(descendants, function (d) { return d.id });
   640	
   641	      g.transition()
   642	        .duration(transitionDuration)
   643	        .ease(transitionEase)
   644	        .attr('transform', function (d) { return 'translate(' + x(d.x0) + ',' + (inverted ? y(d.depth) : (h - y(d.depth) - c)) + ')' });
   645	
   646	      g.select('rect')
   647	        .attr('width', width);
   648	
   649	      var node = g.enter()
   650	        .append('svg:g')
   651	        .attr('transform', function (d) { return 'translate(' + x(d.x0) + ',' + (inverted ? y(d.depth) : (h - y(d.depth) - c)) + ')' });
   652	
   653	      node.append('svg:rect')
   654	        .transition()
   655	        .delay(transitionDuration / 2)
   656	        .attr('width', width);
   657	
   658	      if (!tooltip) { node.append('svg:title'); }
   659	
   660	      node.append('foreignObject')
   661	        .append('xhtml:div');
   662	
   663	      // Now we have to re-select to see the new elements (why?).
   664	      g = d3.select(this).select('svg').selectAll('g').data(descendants, function (d) { return d.id });
   665	
   666	      g.attr('width', width)
   667	        .attr('height', function (d) { return c })
   668	        .attr('name', function (d) { return name(d) })
   669	        .attr('class', function (d) { return d.data.fade ? 'frame fade' : 'frame' });
   670	
   671	      g.select('rect')
   672	        .attr('height', function (d) { return c })
   673	        .attr('fill', function (d) { return colorMapper(d) });
   674	
   675	      if (!tooltip) {
   676	        g.select('title')
   677	          .text(label);
   678	      }
   679	
   680	      g.select('foreignObject')
   681	        .attr('width', width)
   682	        .attr('height', function (d) { return c })
   683	        .select('div')
   684	        .attr('class', 'd3-flame-graph-label')
   685	        .style('display', function (d) { return (width(d) < 35) ? 'none' : 'block' })
   686	        .transition()
   687	        .delay(transitionDuration)
   688	        .text(name);
   689	
   690	      g.on('click', zoom);
   691	
   692	      g.exit()
   693	        .remove();
   694	
   695	      g.on('mouseover', function (d) {
   696	        if (tooltip) tip.show(d, this);
   697	        setDetails(label(d));
   698	      }).on('mouseout', function (d) {
   699	        if (tooltip) tip.hide(d);
   700	        setDetails('');
   701	      });
   702	    });
   703	  }
   704	
   705	  function merge (data, samples) {
   706	    samples.forEach(function (sample) {
   707	      var node = data.find(function (element) {
   708	        return (element.name === sample.name)
   709	      });
   710	
   711	      if (node) {
   712	        if (node.original) {
   713	          node.original += sample.value;
   714	        } else {
   715	          node.value += sample.value;
   716	        }
   717	        if (sample.children) {
   718	          if (!node.children) {
   719	            node.children = [];
   720	          }
   721	          merge(node.children, sample.children);
   722	        }
   723	      } else {
   724	        data.push(sample);
   725	      }
   726	    });
   727	  }
   728	
   729	  function s4 () {
   730	    return Math.floor((1 + Math.random()) * 0x10000)
   731	      .toString(16)
   732	      .substring(1)
   733	  }
   734	
   735	  function injectIds (node) {
   736	    node.id = s4() + '-' + s4() + '-' + '-' + s4() + '-' + s4();
   737	    var children = node.c || node.children || [];
   738	    for (var i = 0; i < children.length; i++) {
   739	      injectIds(children[i]);
   740	    }
   741	  }
   742	
   743	  function chart (s) {
   744	    var root = d3.hierarchy(
   745	      s.datum(), function (d) { return children(d) }
   746	    );
   747	    injectIds(root);
   748	    selection = s.datum(root);
   749	
   750	    if (!arguments.length) return chart
   751	
   752	    if (!h) {
   753	      h = (root.height + 2) * c;
   754	    }
   755	
   756	    selection.each(function (data) {
   757	      if (!svg) {
   758	        svg = d3.select(this)
   759	          .append('svg:svg')
   760	          .attr('width', w)
   761	          .attr('height', h)
   762	          .attr('class', 'partition d3-flame-graph')
   763	          .call(tip);
   764	
   765	        svg.append('svg:text')
   766	          .attr('class', 'title')
   767	          .attr('text-anchor', 'middle')
   768	          .attr('y', '25')
   769	          .attr('x', w / 2)
   770	          .attr('fill', '#808080')
   771	          .text(title);
   772	      }
   773	    });
   774	
   775	    // first draw
   776	    update();
   777	  }
   778	
   779	  chart.height = function (_) {
   780	    if (!arguments.length) { return h }
   781	    h = _;
   782	    return chart
   783	  };
   784	
   785	  chart.width = function (_) {
   786	    if (!arguments.length) { return w }
   787	    w = _;
   788	    return chart
   789	  };
   790	
   791	  chart.cellHeight = function (_) {
   792	    if (!arguments.length) { return c }
   793	    c = _;
   794	    return chart
   795	  };
   796	
   797	  chart.tooltip = function (_) {
   798	    if (!arguments.length) { return tooltip }
   799	    if (typeof _ === 'function') {
   800	      tip = _;
   801	    }
   802	    tooltip = !!_;
   803	    return chart
   804	  };
   805	
   806	  chart.title = function (_) {
   807	    if (!arguments.length) { return title }
   808	    title = _;
   809	    return chart
   810	  };
   811	
   812	  chart.transitionDuration = function (_) {
   813	    if (!arguments.length) { return transitionDuration }
   814	    transitionDuration = _;
   815	    return chart
   816	  };
   817	
   818	  chart.transitionEase = function (_) {
   819	    if (!arguments.length) { return transitionEase }
   820	    transitionEase = _;
   821	    return chart
   822	  };
   823	
   824	  chart.sort = function (_) {
   825	    if (!arguments.length) { return sort }
   826	    sort = _;
   827	    return chart
   828	  };
   829	
   830	  chart.inverted = function (_) {
   831	    if (!arguments.length) { return inverted }
   832	    inverted = _;
   833	    return chart
   834	  };
   835	
   836	  chart.label = function (_) {
   837	    if (!arguments.length) { return label }
   838	    label = _;
   839	    return chart
   840	  };
   841	
   842	  chart.search = function (term) {
   843	    var searchResults = [];
   844	    selection.each(function (data) {
   845	      searchResults = searchTree(data, term);
   846	      update();
   847	    });
   848	    return searchResults
   849	  };
   850	
   851	  chart.clear = function () {
   852	    selection.each(function (data) {
   853	      clear(data);
   854	      update();
   855	    });
   856	  };
   857	
   858	  chart.zoomTo = function (d) {
   859	    zoom(d);
   860	  };
   861	
   862	  chart.resetZoom = function () {
   863	    selection.each(function (data) {
   864	      zoom(data); // zoom to root
   865	    });
   866	  };
   867	
   868	  chart.onClick = function (_) {
   869	    if (!arguments.length) {
   870	      return clickHandler
   871	    }
   872	    clickHandler = _;
   873	    return chart
   874	  };
   875	
   876	  chart.merge = function (samples) {
   877	    var newRoot; // Need to re-create hierarchy after data changes.
   878	    selection.each(function (root) {
   879	      merge([root.data], [samples]);
   880	      newRoot = d3.hierarchy(root.data, function (d) { return children(d) });
   881	      injectIds(newRoot);
   882	    });
   883	    selection = selection.datum(newRoot);
   884	    update();
   885	  };
   886	
   887	  chart.color = function (_) {
   888	    if (!arguments.length) { return colorMapper }
   889	    colorMapper = _;
   890	    return chart
   891	  };
   892	
   893	  chart.minFrameSize = function (_) {
   894	    if (!arguments.length) { return minFrameSize }
   895	    minFrameSize = _;
   896	    return chart
   897	  };
   898	
   899	  chart.details = function (_) {
   900	    if (!arguments.length) { return details }
   901	    details = _;
   902	    return chart
   903	  };
   904	
   905	  return chart
   906	};
   907	
   908	exports.flamegraph = flamegraph;
   909	
   910	Object.defineProperty(exports, '__esModule', { value: true });
   911	
   912	})));
   913	`
   914	
   915	// CSSSource returns the d3-flamegraph.css file
   916	const CSSSource = `
   917	.d3-flame-graph rect {
   918	  stroke: #EEEEEE;
   919	  fill-opacity: .8;
   920	}
   921	
   922	.d3-flame-graph rect:hover {
   923	  stroke: #474747;
   924	  stroke-width: 0.5;
   925	  cursor: pointer;
   926	}
   927	
   928	.d3-flame-graph-label {
   929	  pointer-events: none;
   930	  white-space: nowrap;
   931	  text-overflow: ellipsis;
   932	  overflow: hidden;
   933	  font-size: 12px;
   934	  font-family: Verdana;
   935	  margin-left: 4px;
   936	  margin-right: 4px;
   937	  line-height: 1.5;
   938	  padding: 0 0 0;
   939	  font-weight: 400;
   940	  color: black;
   941	  text-align: left;
   942	}
   943	
   944	.d3-flame-graph .fade {
   945	  opacity: 0.6 !important;
   946	}
   947	
   948	.d3-flame-graph .title {
   949	  font-size: 20px;
   950	  font-family: Verdana;
   951	}
   952	
   953	.d3-flame-graph-tip {
   954	  line-height: 1;
   955	  font-family: Verdana;
   956	  font-size: 12px;
   957	  padding: 12px;
   958	  background: rgba(0, 0, 0, 0.8);
   959	  color: #fff;
   960	  border-radius: 2px;
   961	  pointer-events: none;
   962	}
   963	
   964	/* Creates a small triangle extender for the tooltip */
   965	.d3-flame-graph-tip:after {
   966	  box-sizing: border-box;
   967	  display: inline;
   968	  font-size: 10px;
   969	  width: 100%;
   970	  line-height: 1;
   971	  color: rgba(0, 0, 0, 0.8);
   972	  position: absolute;
   973	  pointer-events: none;
   974	}
   975	
   976	/* Northward tooltips */
   977	.d3-flame-graph-tip.n:after {
   978	  content: "\25BC";
   979	  margin: -1px 0 0 0;
   980	  top: 100%;
   981	  left: 0;
   982	  text-align: center;
   983	}
   984	
   985	/* Eastward tooltips */
   986	.d3-flame-graph-tip.e:after {
   987	  content: "\25C0";
   988	  margin: -4px 0 0 0;
   989	  top: 50%;
   990	  left: -8px;
   991	}
   992	
   993	/* Southward tooltips */
   994	.d3-flame-graph-tip.s:after {
   995	  content: "\25B2";
   996	  margin: 0 0 1px 0;
   997	  top: -8px;
   998	  left: 0;
   999	  text-align: center;
  1000	}
  1001	
  1002	/* Westward tooltips */
  1003	.d3-flame-graph-tip.w:after {
  1004	  content: "\25B6";
  1005	  margin: -4px 0 0 -1px;
  1006	  top: 50%;
  1007	  left: 100%;
  1008	}
  1009	`
  1010	

View as plain text