Creates the d3 x and y axis, setting orientations
@private
502742
function buildAxis() {
            if (isHorizontal) {
                xAxis = d3Axis.axisBottom(xScale)
                    .ticks(xTicks, numberFormat)
                    .tickSizeInner([-chartHeight]);

                yAxis = d3Axis.axisLeft(yScale);
            } else {
                xAxis = d3Axis.axisBottom(xScale);

                yAxis = d3Axis.axisLeft(yScale)
                    .ticks(yTicks, numberFormat)
            }
        }
686209
function(opts){
    var options = flotr.clone(flotr.defaultOptions);
    options.x2axis = _.extend(_.clone(options.xaxis), options.x2axis);
    options.y2axis = _.extend(_.clone(options.yaxis), options.y2axis);
    this.options = flotr.merge(opts || {}, options);

    if (this.options.grid.minorVerticalLines === null &&
      this.options.xaxis.scaling === 'logarithmic') {
      this.options.grid.minorVerticalLines = true;
    }
    if (this.options.grid.minorHorizontalLines === null &&
      this.options.yaxis.scaling === 'logarithmic') {
      this.options.grid.minorHorizontalLines = true;
    }

    E.fire(this.el, 'flotr:afterinitoptions', [this]);

    this.axes = flotr.Axis.getAxes(this.options);

    // Initialize some variables used throughout this function.
    var assignedColors = [],
        colors = [],
        ln = this.series.length,
        neededColors = this.series.length,
        oc = this.options.colors,
        usedColors = [],
        variation = 0,
        c, i, j, s;

    // Collect user-defined colors from series.
    for(i = neededColors - 1; i > -1; --i){
      c = this.series[i].color;
      if(c){
        --neededColors;
        if(_.isNumber(c)) assignedColors.push(c);
        else usedColors.push(flotr.Color.parse(c));
      }
    }

    // Calculate the number of colors that need to be generated.
    for(i = assignedColors.length - 1; i > -1; --i)
      neededColors = Math.max(neededColors, assignedColors[i] + 1);

    // Generate needed number of colors.
    for(i = 0; colors.length < neededColors;){
      c = (oc.length == i) ? new flotr.Color(100, 100, 100) : flotr.Color.parse(oc[i]);

      // Make sure each serie gets a different color.
      var sign = variation % 2 == 1 ? -1 : 1,
          factor = 1 + sign * Math.ceil(variation / 2) * 0.2;
      c.scale(factor, factor, factor);

      /**
       * @todo if we're getting too close to something else, we should probably skip this one
       */
      colors.push(c);

      if(++i >= oc.length){
        i = 0;
        ++variation;
      }
    }

    // Fill the options with the generated colors.
    for(i = 0, j = 0; i < ln; ++i){
      s = this.series[i];

      // Assign the color.
      if (!s.color){
        s.color = colors[j++].toString();
      }else if(_.isNumber(s.color)){
        s.color = colors[s.color].toString();
      }

      // Every series needs an axis
      if (!s.xaxis) s.xaxis = this.axes.x;
           if (s.xaxis == 1) s.xaxis = this.axes.x;
      else if (s.xaxis == 2) s.xaxis = this.axes.x2;

      if (!s.yaxis) s.yaxis = this.axes.y;
           if (s.yaxis == 1) s.yaxis = this.axes.y;
      else if (s.yaxis == 2) s.yaxis = this.axes.y2;

      // Apply missing options to the series.
      for (var t in flotr.graphTypes){
        s[t] = _.extend(_.clone(this.options[t]), s[t]);
      }
      s.mouse = _.extend(_.clone(this.options.mouse), s.mouse);

      if (_.isUndefined(s.shadowSize)) s.shadowSize = this.options.shadowSize;
    }
  }
98931
function KDE( canvas, width, height, left, top ) {

		var graph, data, area, rug, edges, axes, annotations, title, text;

		// [1] Instantiate a new graph generator and configure:
		graph = xfig.graph( canvas )
			.width( width )
			.height( height )
			.position({
				'left': left,
				'top': top
			})
			.xMin( 0 )
			.xMax( 1 )
			.yMin( 0 );

		// Create the graph:
		graph.create( 'kde' );

		// Get data:
		d3.json( 'data/kde.data.json', function ( error, json ) {

			var max;

			// [2] Instantiate a new data generator and configure:
			data = xfig.data( json )
				.accessors( 'x', function ( d ) {
					return d[ 0 ];
				})
				.accessors( 'y', function ( d ) {
					return d[ 1 ];
				});

			// Format the data and calculate the KDE:
			data.format( [ 'x', 'y' ] )
				.kde(
					function ( d ) {
						return d[ 1 ];
					}, 0, 1
				);

			// Bind the data instance to the graph:
			max = data.max( function ( d ) {
				return d[ 1 ];
			});
			max += max * 0.05;
			graph.data( data )
				.yMax( max );

			// [3] Instantiate a new area chart generator and configure:
			area = xfig.area( graph )
				.labels( [ 'data 0' ] );

			// Create the area chart:
			area.create();

			// [4] Instantiate a new data generator and configure:
			data = xfig.data( json )
				.accessors( 'x', function ( d ) {
					return d[ 0 ];
				})
				.accessors( 'y', function ( d ) {
					return d[ 1 ];
				});

			// Format the data:
			data.format( [ 'x', 'y' ] )
				.extract( function ( d ) {
					return d[ 1 ];
				});

			// Bind the data instance to the graph:
			graph.data( data );

			// [5] Instantiate a new rug chart generator and configure:
			rug = xfig.rug( graph )
				.labels( [ 'data 0' ] );

			// Create the rug chart:
			rug.create();

			// [6] Instantiate a new axes generator and configure:
			axes = xfig.axes( graph )
				.yLabel( 'density' );

			// Create the axes:
			axes.create();

			// [7] Instantiate a new annotations generator and configure:
			annotations = xfig.annotations( graph );

			// Create the annotations element:
			annotations.create();

			// [7.1] Instantiate a new title instance and configure:
			title = annotations.title()
				.top( -30 )
				.left( 250 );

			// Add a (sub)title:
			title.create( 'KDE' );

			// [7.2] Instantiate a new text instance and configure:
			text = annotations.text()
				.width( 200 )
				.height( 100 )
				.top( 50 )
				.left( 310 );

			// Add a text annotation:
			text.create( 'This is another text annotation, which may run multiple lines.' );

		});

	}
975688
function() {

        var planes = {
            'px': createPlane('px', this.depthSegments, this.heightSegments),
            'nx': createPlane('nx', this.depthSegments, this.heightSegments),
            'py': createPlane('py', this.widthSegments, this.depthSegments),
            'ny': createPlane('ny', this.widthSegments, this.depthSegments),
            'pz': createPlane('pz', this.widthSegments, this.heightSegments),
            'nz': createPlane('nz', this.widthSegments, this.heightSegments),
        };

        var attrList = ['position', 'texcoord0', 'normal'];
        var vertexNumber = 0;
        var faceNumber = 0;
        for (var pos in planes) {
            vertexNumber += planes[pos].vertexCount;
            faceNumber += planes[pos].indices.length;
        }
        for (var k = 0; k < attrList.length; k++) {
            this.attributes[attrList[k]].init(vertexNumber);
        }
        this.indices = new vendor.Uint16Array(faceNumber);
        var faceOffset = 0;
        var vertexOffset = 0;
        for (var pos in planes) {
            var plane = planes[pos];
            for (var k = 0; k < attrList.length; k++) {
                var attrName = attrList[k];
                var attrArray = plane.attributes[attrName].value;
                var attrSize = plane.attributes[attrName].size;
                var isNormal = attrName === 'normal';
                for (var i = 0; i < attrArray.length; i++) {
                    var value = attrArray[i];
                    if (this.inside && isNormal) {
                        value = -value;
                    }
                    this.attributes[attrName].value[i + attrSize * vertexOffset] = value;
                }
            }
            var len = plane.indices.length;
            for (var i = 0; i < plane.indices.length; i++) {
                this.indices[i + faceOffset] = vertexOffset + plane.indices[this.inside ? (len - i - 1) : i];
            }
            faceOffset += plane.indices.length;
            vertexOffset += plane.vertexCount;
        }

        this.boundingBox = new BoundingBox();
        this.boundingBox.max.set(1, 1, 1);
        this.boundingBox.min.set(-1, -1, -1);
    }
247815
function buildScales() {
            colorScale = d3Scale.scaleLinear()
                .range([colorSchema[0], colorSchema[colorSchema.length - 1]])
                .domain(d3Array.extent(data, getValue))
                .interpolate(d3Interpolate.interpolateHcl);
        }
1302137
function (dataLabel, options, alignAttr, bBox, alignTo, isNew) {
		var chart = this.chart,
			align = options.align,
			verticalAlign = options.verticalAlign,
			off,
			justified;

		// Off left
		off = alignAttr.x;
		if (off < 0) {
			if (align === 'right') {
				options.align = 'left';
			} else {
				options.x = -off;
			}
			justified = true;
		}

		// Off right
		off = alignAttr.x + bBox.width;
		if (off > chart.plotWidth) {
			if (align === 'left') {
				options.align = 'right';
			} else {
				options.x = chart.plotWidth - off;
			}
			justified = true;
		}

		// Off top
		off = alignAttr.y;
		if (off < 0) {
			if (verticalAlign === 'bottom') {
				options.verticalAlign = 'top';
			} else {
				options.y = -off;
			}
			justified = true;
		}

		// Off bottom
		off = alignAttr.y + bBox.height;
		if (off > chart.plotHeight) {
			if (verticalAlign === 'top') {
				options.verticalAlign = 'bottom';
			} else {
				options.y = chart.plotHeight - off;
			}
			justified = true;
		}
		
		if (justified) {
			dataLabel.placed = !isNew;
			dataLabel.align(options, null, alignTo);
		}
	}
1312628
function(properties, data) {
            var axisProperties = this.parseUtils.getXAxisProperties(properties),
                orientation = (this.axesAreInverted) ? 'vertical' : 'horizontal',
                colorScheme = this.getAxisColorScheme();

            // add some extra info to the axisProperties as needed
            if(axisProperties.hasOwnProperty('axisTitle.text')){
                axisProperties['axisTitle.text'] = Splunk.JSCharting.ParsingUtils.escapeHtml(axisProperties['axisTitle.text']);
            }
            axisProperties.chartType = properties.chart;
            axisProperties.axisLength = $(this.renderTo).width();

            this.xAxis = new Splunk.JSCharting.NumericAxis(axisProperties, data, orientation, colorScheme);
            this.hcConfig.xAxis = $.extend(true, this.xAxis.getConfig(), {
                startOnTick: true,
                endOnTick: true,
                minPadding: 0,
                maxPadding: 0
            });
        }
881545
function createD3ClusterDendrogram(root, config){

	config = config || {};

	var familyNames = {};

	var fileRoot = config.root || '';

	var width = $(window).width();
	var height = $(window).height();
	var radius = Math.min(width, height)/1.8;

	var cluster = d3.layout.cluster()
		.size([360, radius]);

	var diagonal = d3.svg.diagonal.radial()
		.projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });

	var x = d3.scale.linear().domain([0, width]).range([width, 0]);
	var y = d3.scale.linear().domain([0, height]).range([height, 0]);
	
	var zoom = d3.behavior.zoom().x(x).y(y)
		.scaleExtent([0.1, 2.5])
		.on("zoom", function(a, b, c) {
			var t = zoom.translate();
			svg.attr("transform", "translate(" + (t[0]) + "," + (t[1]) + ") scale( " + zoom.scale() + ")");
		});

	var svg = d3
		.select("#canvas")
		.append("svg")
		.call(zoom)
		.attr("width", width)
		.attr("height", height)
		.append("g");
		
	var nodes = cluster.nodes(root);

    var link = svg.selectAll("path.link")
        .data(cluster.links(nodes))
        .enter()
        .append("path")
        .attr("class", "link-subtle")
        .attr("d", diagonal);

	var node = svg.selectAll("g.node")
		.data(nodes)
		.enter().append("g")
		.attr("class", "step")
		.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })

	var steps = svg.selectAll(".step");

	applyClass(steps, 'isDecision', 'decision');
	applyClass(steps, 'isChanceRoot', 'chanceRoot');
	applyClass(steps, 'isDecisionRoot', 'decisionRoot');
	applyClass(steps, 'isChance', 'chance');
	applyClass(steps, 'isActive', 'active');
	
	applyClass(svg.selectAll(".active"), 'isFailed', 'fail');

	node.append("circle")
		.attr("r", 4);

	var tooltip = d3.select("#canvas")
		.append("div")
		.attr("class", "tooltip")
		.style("position", "absolute")
		.style("z-index", "10")
		.style("visibility", "hidden")
		.text("");

	var tooltipText = tooltip.append("div");
	var tooltipImg = tooltip.append("img");

	steps
		.filter(function(d, i){
			var _this = this;
			var failedScreenshot;

			if(d.screenshot && d.screenshot.original){

				d.originalScreenshot = d.screenshot.original;

				if(d.screenshot.failure){
					d.failedScreenshot = d.screenshot.failure;
					d.latestScreenshot = d.screenshot.latest;
					_this.setAttribute("class", _this.className.baseVal + ' screenshotFail');
				}
			}
			return !!d.screenshot;
		})
		.classed('screenshot',true)
		.on("mouseover", function(e){
			$( "body" ).trigger({
				type:"screenshot",
				name: e.name,
				src: e.screenshot.src,
				diff: e.failedScreenshot,
				latest: e.latestScreenshot,
				original: e.originalScreenshot,
				element: this
			});
		});

	var rootTests = getLeafInfo(root);
	var groups = getGroupInfo(rootTests);
	
	groupPie( radius, svg, groups );
	
	rootPie( radius, svg, rootTests );

	zoom.scale(.75);
	zoom.translate([width/2, height/2]);
	zoom.event(svg);
}
386709
function init(n) {

  n
    .attr("x",function(d){
      return d.d3plus.x;
    })
    .attr("y",function(d){
      return d.d3plus.y;
    })
    .attr("width",0)
    .attr("height",0);

}
62472
function () {
    var dispatch = d3.dispatch ("click", "dblclick", "mouseover", "mouseout");

    ////// Vars exposed in the API
    var config = {
        create   : function () {throw "create_elem is not defined in the base feature object";},
        move    : function () {throw "move_elem is not defined in the base feature object";},
        distribute  : function () {},
        fixed   : function () {},
        //layout   : function () {},
        index    : undefined,
        layout   : layout.identity(),
        color : '#000',
        scale : undefined
    };


    // The returned object
    var feature = {};

    var reset = function () {
    	var track = this;
    	track.g.selectAll(".tnt_elem").remove();
        track.g.selectAll(".tnt_guider").remove();
        track.g.selectAll(".tnt_fixed").remove();
    };

    var init = function (width) {
        var track = this;

        track.g
            .append ("text")
            .attr ("class", "tnt_fixed")
            .attr ("x", 5)
            .attr ("y", 12)
            .attr ("font-size", 11)
            .attr ("fill", "grey")
            .text (track.label());

        config.fixed.call(track, width);
    };

    var plot = function (new_elems, track, xScale) {
        new_elems.on("click", function (d, i) {
            if (d3.event.defaultPrevented) {
                return;
            }
            dispatch.click.call(this, d, i);
        });
        new_elems.on("mouseover", function (d, i) {
            if (d3.event.defaultPrevented) {
                return;
            }
            dispatch.mouseover.call(this, d, i);
        });
        new_elems.on("dblclick", function (d, i) {
            if (d3.event.defaultPrevented) {
                return;
            }
            dispatch.dblclick.call(this, d, i);
        });
        new_elems.on("mouseout", function (d, i) {
            if (d3.event.defaultPrevented) {
                return;
            }
            dispatch.mouseout.call(this, d, i);
        });
        // new_elem is a g element the feature is inserted
        config.create.call(track, new_elems, xScale);
    };

    var update = function (loc, field) {
        var track = this;
        var svg_g = track.g;

        var elements = track.data().elements();

        if (field !== undefined) {
            elements = elements[field];
        }

        var data_elems = config.layout.call(track, elements);


        if (data_elems === undefined) {
            return;
        }

        var vis_sel;
        var vis_elems;
        if (field !== undefined) {
            vis_sel = svg_g.selectAll(".tnt_elem_" + field);
        } else {
            vis_sel = svg_g.selectAll(".tnt_elem");
        }

        if (config.index) { // Indexing by field
            vis_elems = vis_sel
                .data(data_elems, function (d) {
                    if (d !== undefined) {
                        return config.index(d);
                    }
                });
        } else { // Indexing by position in array
            vis_elems = vis_sel
                .data(data_elems);
        }

        config.distribute.call(track, vis_elems, config.scale);

    	var new_elem = vis_elems
    	    .enter();

    	new_elem
    	    .append("g")
    	    .attr("class", "tnt_elem")
    	    .classed("tnt_elem_" + field, field)
    	    .call(feature.plot, track, config.scale);

    	vis_elems
    	    .exit()
    	    .remove();
    };

    var mover = function (field) {
    	var track = this;
    	var svg_g = track.g;
    	var elems;
    	// TODO: Is selecting the elements to move too slow?
    	// It would be nice to profile
    	if (field !== undefined) {
    	    elems = svg_g.selectAll(".tnt_elem_" + field);
    	} else {
    	    elems = svg_g.selectAll(".tnt_elem");
    	}

    	config.move.call(this, elems);
    };

    var mtf = function (elem) {
        elem.parentNode.appendChild(elem);
    };

    var move_to_front = function (field) {
        if (field !== undefined) {
            var track = this;
            var svg_g = track.g;
            svg_g.selectAll(".tnt_elem_" + field)
                .each( function () {
                    mtf(this);
                });
        }
    };

    // API
    apijs (feature)
    	.getset (config)
    	.method ({
    	    reset  : reset,
    	    plot   : plot,
    	    update : update,
    	    mover   : mover,
    	    init   : init,
    	    move_to_front : move_to_front
    	});

    return d3.rebind(feature, dispatch, "on");
}
415581
function createD3Tree(root, config){

	config = config || {};

	var fileRoot = config.root || '';

	var width = $(window).width();
	var height = $(window).height();
	var cluster = d3.layout.cluster().size([height , width - 220]);
	var diagonal = d3.svg.diagonal().projection(function(d) { return [d.y, d.x]; });

	var nodes = cluster.nodes(root);
	var links = cluster.links(nodes);

	var x = d3.scale.linear().domain([0, width]).range([width, 0]);
	var y = d3.scale.linear().domain([0, height]).range([height, 0]);
	
	var zoom = d3.behavior.zoom().x(x).y(y)
		.scaleExtent([0.1, 2.5])
		.on("zoom", function(a, b, c) {
			var t = zoom.translate();
			svg.attr("transform", "translate(" + (t[0]) + "," + (t[1]) + ") scale( " + zoom.scale() + ")");
		});

	var svg = d3
		.select("#canvas")
		.append("svg")
		.call(zoom)
		.attr("width", width)
		.attr("height", height)
		.append("g");

	d3.select(self.frameElement).style("height", height + "px");

	var link = svg.selectAll(".link")
		.data(links)
		.enter().append("path")
		.attr("class", "link")
		.attr("d", diagonal);

	svg.selectAll(".link").filter(function(d, i){
		return !d.target.isDecision && !d.target.isChance && !d.target.name;
	}).remove();

	var node = svg.selectAll(".node")
		.data(nodes)
		.enter().append("g")
		.attr("class", "step")
		.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });

	svg.selectAll(".step").filter(function(d, i){
		return !d.isDecision && !d.isChance && !d.name;
	}).remove();

	svg.selectAll(".step").filter(function(d, i){
		return d.isDecision;
	}).attr("class", "decision");

	svg.selectAll(".step").filter(function(d, i){
		return d.isChanceRoot;
	}).attr("class", "chanceRoot");

	svg.selectAll(".step").filter(function(d, i){
		return d.isDecisionRoot;
	}).attr("class", "decisionRoot");

	svg.selectAll(".step").filter(function(d, i){
		return d.isChance;
	}).attr("class", "chance");

	svg.selectAll(".step").filter(function(d, i){
		return d.isActive;
	}).classed('active',true);

	svg.selectAll(".active")
		.filter(function(d, i){
			return d.isFailed;
		})
		.classed('fail',true);

	var tooltip = d3.select("#canvas")
		.append("div")
		.attr("class", "tooltip")
		.style("position", "absolute")
		.style("z-index", "10")
		.style("visibility", "hidden")
		.text("");

	var tooltipText = tooltip.append("div");
	var tooltipImg = tooltip.append("img");

	node.append("circle").attr("r", 8);

	svg.selectAll(".step")
		.filter(function(d, i){
			var _this = this;
			var failedScreenshot;

			if(d.screenshot && d.screenshot.original){
				d.originalScreenshot = d.screenshot.original;
				if(d.screenshot.failure){
					d.failedScreenshot = d.screenshot.failure;
					d.latestScreenshot = d.screenshot.latest;  
					_this.setAttribute("class", _this.className.baseVal + ' screenshotFail');
				}
			}
			return !!d.screenshot;
		})
		.classed('screenshot',true)
		.on("mouseover", function(e){
			$( "body" ).trigger({
				type:"screenshot",
				name: e.name,
				src: e.screenshot.src,
				diff: e.failedScreenshot,
				latest: e.latestScreenshot,
				original: e.originalScreenshot,
				element: this
			});
		});

	var dy = !!window.chrome ? 6 : 22;

	node.append("text")
		.attr("dx", function(d,e, f) { return d.isBranchRoot ? 8 : d.children ? -15 : 15; })
		.attr("dy", function(d) { return d.isBranchRoot ? 22 : d.children ? dy  : dy ; })
		.attr("class", function(d) { return d.isDecisionRoot ? 'text decisiontext' : d.isChanceRoot ? 'text chancetext' : d.children ? 'text steptext' : 'text endtext'; })
		.attr("transform",  function(d) { return (d.children && !d.isBranchRoot) ? "rotate(330)" : "rotate(0)"; })
		.text(function(d) { return d.name.replace('.json', ''); });

	zoom.scale(1);
	zoom.translate([50, 50]);
	zoom.event(svg);
}
620805
function () {
                        var t = d3.select(this).selectAll("text");
                        if (!axis.measure && axis._max > 0) {
                            if (axis.position === "x") {
                                t.attr("x", (chartWidth / axis._max) / 2);
                            } else if (axis.position === "y") {
                                t.attr("y", -1 * (chartHeight / axis._max) / 2);
                            }
                        }
                        if (axis.categoryFields && axis.categoryFields.length > 0) {
                            // Off set the labels to counter the transform.  This will put the labels along the outside of the chart so they
                            // don't interfere with the chart contents
                            if (axis === firstX && (firstY.categoryFields === null || firstY.categoryFields.length === 0)) {
                                t.attr("y", chartY + chartHeight - firstY._scale(0) + 9);
                            }
                            if (axis === firstY && (firstX.categoryFields === null || firstX.categoryFields.length === 0)) {
                                t.attr("x", -1 * (firstX._scale(0) - chartX) - 9);
                            }
                        }
                        return this;
                    }
291467
function buildBrush() {
            brush = d3Brush.brushX()
                .extent([[0, 0], [chartWidth, chartHeight]])
                .on('brush', handleBrushStart)
                .on('end', handleBrushEnd);
        }
321639
function drawAxis(){
            svg.select('.x-axis-group.axis')
                .attr('transform', `translate(0, ${chartHeight})`)
                .call(xAxis);

            svg.selectAll('.x-axis-group .tick text')
                .style('text-anchor', 'start')
                .attr('transform', 'rotate(45 -1 10)');

            if (xAxisLabel) {
                if (xAxisLabelEl) {
                    svg.selectAll('.x-axis-label-text').remove();
                }
                xAxisLabelEl = svg.select('.x-axis-label')
                  .append('text')
                    .attr('y', xAxisLabelOffset)
                    .attr('text-anchor', 'middle')
                    .classed('x-axis-label-text', true)
                    .attr('x', chartWidth / 2)
                    .text(xAxisLabel);
            }

            svg.select('.y-axis-group.axis')
                .call(yAxis);

            if (yAxisLabel) {
                if (yAxisLabelEl) {
                    svg.selectAll('.y-axis-label-text').remove();
                }
                yAxisLabelEl = svg.select('.y-axis-label')
                  .append('text')
                    .classed('y-axis-label-text', true)
                    .attr('x', -chartHeight / 2)
                    .attr('y', yAxisLabelOffset)
                    .attr('text-anchor', 'middle')
                    .attr('transform', 'rotate(270 0 0)')
                    .text(yAxisLabel);
            }
        }
1079355
function() {
        var heightSegments = this.heightSegments;
        var widthSegments = this.widthSegments;

        var positionAttr = this.attributes.position;
        var texcoordAttr = this.attributes.texcoord0;
        var normalAttr = this.attributes.normal;

        var vertexCount = (widthSegments + 1) * (heightSegments + 1);
        positionAttr.init(vertexCount);
        texcoordAttr.init(vertexCount);
        normalAttr.init(vertexCount);

        var IndicesCtor = vertexCount > 0xffff ? Uint32Array : Uint16Array;
        var indices = this.indices = new IndicesCtor(widthSegments * heightSegments * 6);

        var x, y, z,
            u, v,
            i, j;

        var radius = this.radius;
        var phiStart = this.phiStart;
        var phiLength = this.phiLength;
        var thetaStart = this.thetaStart;
        var thetaLength = this.thetaLength;
        var radius = this.radius;

        var pos = [];
        var uv = [];
        var offset = 0;
        var divider = 1 / radius;
        for (j = 0; j <= heightSegments; j ++) {
            for (i = 0; i <= widthSegments; i ++) {
                u = i / widthSegments;
                v = j / heightSegments;

                // X axis is inverted so texture can be mapped from left to right
                x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
                y = radius * Math.cos(thetaStart + v * thetaLength);
                z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);

                pos[0] = x; pos[1] = y; pos[2] = z;
                uv[0] = u; uv[1] = v;
                positionAttr.set(offset, pos);
                texcoordAttr.set(offset, uv);
                pos[0] *= divider;
                pos[1] *= divider;
                pos[2] *= divider;
                normalAttr.set(offset, pos);
                offset++;
            }
        }

        var i1, i2, i3, i4;

        var len = widthSegments + 1;

        var n = 0;
        for (j = 0; j < heightSegments; j ++) {
            for (i = 0; i < widthSegments; i ++) {
                i2 = j * len + i;
                i1 = (j * len + i + 1);
                i4 = (j + 1) * len + i + 1;
                i3 = (j + 1) * len + i;

                indices[n++] = i1;
                indices[n++] = i2;
                indices[n++] = i4;

                indices[n++] = i2;
                indices[n++] = i3;
                indices[n++] = i4;
            }
        }

        this.boundingBox = new BoundingBox();
        this.boundingBox.max.set(radius, radius, radius);
        this.boundingBox.min.set(-radius, -radius, -radius);
    }
231036
function renderComponent() {
    const data = [[0.1, 0.15], [0.2, 0.3], [0.4, 0.6], [0.8, 0.9]];
    var svg = d3.select('svg')
      .datum(data);
    svg.select('.horizontal')
      .call(horizontalSvgBand);
    svg.select('.vertical')
      .call(verticalSvgBand);

    var canvas = d3.select('canvas').node();
    var ctx = canvas.getContext('2d');
    horizontalCanvasBand.context(ctx)(data);
    verticalCanvasBand.context(ctx)(data);
}
932781
function buildScales(){
            let minX = d3Array.min(dataByTopic, ({dates}) => d3Array.min(dates, getDate)),
                maxX = d3Array.max(dataByTopic, ({dates}) => d3Array.max(dates, getDate)),
                maxY = d3Array.max(dataByTopic, ({dates}) => d3Array.max(dates, getValue)),
                minY = d3Array.min(dataByTopic, ({dates}) => d3Array.min(dates, getValue));
            let yScaleBottomValue = Math.abs(minY) < 0 ? Math.abs(minY) : 0;

            xScale = d3Scale.scaleTime()
                .domain([minX, maxX])
                .rangeRound([0, chartWidth]);

            yScale = d3Scale.scaleLinear()
                .domain([yScaleBottomValue, Math.abs(maxY)])
                .rangeRound([chartHeight, 0])
                .nice();

            colorScale = d3Scale.scaleOrdinal()
                .range(colorSchema)
                .domain(dataByTopic.map(getTopic));

            let range = colorScale.range();

            topicColorMap = colorScale.domain().reduce((memo, item, i) => {
                memo[item] = range[i];

                return memo;
            }, {});
        }