block by harrystevens f1e0de06f1e3f014e9233b80e3514849

Positive-Negative Bar Chart

Full Screen

Create a bar chart with positive and negative values along the horizontal axis with D3.js.

index.html

<html>
	<head>
		<style>

			body {
			  font-family: "Helvetica Neue", sans-serif;
				margin: 0 auto;
				display: table;
			}
			.name, .value {
				font-size: .7em;
			}

		</style>
	</head>
	<body>
  	<div class="chart"></div>
		<script src="https://d3js.org/d3.v4.min.js"></script>
		<script>

      var margin = {top: 10, right: 0, bottom: 0, left: 0},
        width = 400 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

      var svg = d3.select(".chart").append("svg")
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)
        .append("g")
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

      var x = d3.scaleLinear()
          .range([0,width]);

      var y = d3.scaleBand()
          .rangeRound([height,0])
          .padding(0.2);

      d3.csv("data.csv",types,function(error,data){

        if (error) throw error;

        data.sort(function(a,b){
          return b.value - a.value;
        });

        x.domain(d3.extent(data, function(d){ return d.value; }));
        y.domain(data.map(function(d) { return d.name; }));

        svg.selectAll(".bar")
            .data(data)
          .enter().append("rect")
            .attr("class", "bar")
            .attr("x", function(d){ return d.value < 0 ? x(d.value) : x(0); })
						.attr("width", function(d){ return d.value < 0 ? x(d.value * -1) - x(0) : x(d.value) - x(0); })
            .attr("y", function(d){ return y(d.name); })
						.attr("height", y.bandwidth())
						.attr("fill", function(d){ return d.value < 0 ? "#d7191c": "#1a9641"; });

				svg.selectAll(".value")
						.data(data)
					.enter().append("text")
						.attr("class", "value")
						.attr("x", function(d){
							if (d.value < 0){
								return (x(d.value * -1) - x(0)) > 20 ? x(d.value) + 2 : x(d.value) - 1;
							} else {
								return (x(d.value) - x(0)) > 20 ? x(d.value) - 2 : x(d.value) + 1;
							}
						})
						.attr("y", function(d){ return y(d.name); })
						.attr("dy", y.bandwidth() - 2.55)
						.attr("text-anchor", function(d){
							if (d.value < 0){
								return (x(d.value * -1) - x(0)) > 20 ? "start" : "end";
							} else {
								return (x(d.value) - x(0)) > 20 ? "end" : "start";
							}
						})
						.style("fill", function(d){
							if (d.value < 0){
								return (x(d.value * -1) - x(0)) > 20 ? "#fff" : "#3a403d";
							} else {
								return (x(d.value) - x(0)) > 20 ? "#fff" : "#3a403d";
							}
						})
						.text(function(d){ return d.value; });

				svg.selectAll(".name")
						.data(data)
					.enter().append("text")
						.attr("class", "name")
						.attr("x", function(d){ return d.value < 0 ? x(0) + 2.55 : x(0) - 2.55 })
						.attr("y", function(d){ return y(d.name); })
						.attr("dy", y.bandwidth() - 2.55)
						.attr("text-anchor", function(d){ return d.value < 0 ? "start" : "end"; })
						.text(function(d){ return d.name; });

				svg.append("line")
						.attr("x1", x(0))
						.attr("x2", x(0))
						.attr("y1", 0 + margin.top)
						.attr("y2", height - margin.top)
						.attr("stroke", "#3a403d")
						.attr("stroke-width", "1px");

      });

      function types(d){
				d.value = +d.value;
				return d;
      }

    </script>

	</body>
</html>

data.csv