D3js比例图中间有x轴

时间:2016-04-28 13:54:33

标签: javascript d3.js

我正在使用D3js创建一个带有正值和负值的堆积条形图。

这是我目前用于创建图表的代码:

function showChart1(yArray){

        var data = yArray;

        var x = d3.scale.ordinal()
            .domain(['te1', 'te2'])
            .rangeRoundBands([ margin, w - margin ], .1)

        var y = d3.scale.linear()
        .range([h-margin,0+margin]);

        var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom")
            .tickSize(0, 0);

        var yAxis = d3.svg.axis()
            .scale(y)
            .orient("left");

        barStack(data);
        y.domain(data.extent);

        svg = d3.select("#svg1")
            .append("svg")
            .attr("height", h)
            .attr("width", w)
            .attr("class", "graph-svg-component");  

        var gradientVerde1 = svg.append("defs")
        .append("linearGradient")
        .attr("id", "gradient")

        .attr("x1", "0%")
        .attr("y1", "0%")
        .attr("x2", "100%")
        .attr("y2", "0%")
        .attr("spreadMethod", "reflect");

        gradientVerde1.append("stop")
        .attr("offset", "0%")
        .attr("stop-color", "#7ac141")
        .attr("stop-opacity", 1);

        gradientVerde1.append("stop")
        .attr("offset", "50%")
        .attr("stop-color", "#7ac141")
        .attr("stop-opacity", 1);

        gradientVerde1.append("stop")

        .attr("offset", "50%")
        .attr("stop-color", "#6db03c")

        .attr("stop-opacity", 1);

        gradientVerde1.append("stop")
        .attr("offset", "100%")
        .attr("stop-color", "#6db03c")
        .attr("stop-opacity", 1);

        var gradientVerde2 = svg.append("defs")
        .append("linearGradient")
        .attr("id", "gradient2")

        .attr("x1", "0%")
        .attr("y1", "0%")
        .attr("x2", "100%")
        .attr("y2", "0%")
        .attr("spreadMethod", "reflect");

        gradientVerde2.append("stop")
        .attr("offset", "0%")
        .attr("stop-color", "#acd038")
        .attr("stop-opacity", 1);

        gradientVerde2.append("stop")
        .attr("offset", "50%")
        .attr("stop-color", "#acd038")
        .attr("stop-opacity", 1);


        gradientVerde2.append("stop")

        .attr("offset", "50%")
        .attr("stop-color", "#9abd2f")

        .attr("stop-opacity", 1);

        gradientVerde2.append("stop")
        .attr("offset", "100%")
        .attr("stop-color", "#9abd2f")
        .attr("stop-opacity", 1);

        var gradientVerde3 = svg.append("defs")
        .append("linearGradient")
        .attr("id", "gradient3")

        .attr("x1", "0%")
        .attr("y1", "0%")
        .attr("x2", "100%")
        .attr("y2", "0%")
        .attr("spreadMethod", "reflect");

        gradientVerde3.append("stop")
        .attr("offset", "0%")
        .attr("stop-color", "#d1dd31")
        .attr("stop-opacity", 1);

        gradientVerde3.append("stop")
        .attr("offset", "50%")
        .attr("stop-color", "#d1dd31")
        .attr("stop-opacity", 1);

        gradientVerde3.append("stop")

        .attr("offset", "50%")
        .attr("stop-color", "#bdc82b")

        .attr("stop-opacity", 1);

        gradientVerde3.append("stop")
        .attr("offset", "100%")
        .attr("stop-color", "#bdc82b")
        .attr("stop-opacity", 1);

        var gradientRosso = svg.append("defs")
        .append("linearGradient")
        .attr("id", "gradient4")

        .attr("x1", "0%")
        .attr("y1", "0%")
        .attr("x2", "100%")
        .attr("y2", "0%")
        .attr("spreadMethod", "reflect");

        gradientRosso.append("stop")
        .attr("offset", "0%")
        .attr("stop-color", "#c9242b")
        .attr("stop-opacity", 1);

        gradientRosso.append("stop")
        .attr("offset", "50%")
        .attr("stop-color", "#c9242b")
        .attr("stop-opacity", 1);

        gradientRosso.append("stop")

        .attr("offset", "50%")
        .attr("stop-color", "#b72025")

        .attr("stop-opacity", 1);

        gradientRosso.append("stop")
        .attr("offset", "100%")
        .attr("stop-color", "#b72025")
        .attr("stop-opacity", 1);

        var gradientRosso2 = svg.append("defs")
        .append("linearGradient")
        .attr("id", "gradient5")
        .attr("x1", "0%")
        .attr("y1", "0%")
        .attr("x2", "100%")
        .attr("y2", "0%")
        .attr("spreadMethod", "reflect");

        gradientRosso2.append("stop")
        .attr("offset", "0%")
        .attr("stop-color", "#ee1c25")
        .attr("stop-opacity", 1);

        gradientRosso2.append("stop")
        .attr("offset", "50%")
        .attr("stop-color", "#ee1c25")
        .attr("stop-opacity", 1);

        gradientRosso2.append("stop")
        .attr("offset", "50%")
        .attr("stop-color", "#d7181f")
        .attr("stop-opacity", 1);

        gradientRosso2.append("stop")
        .attr("offset", "100%")
        .attr("stop-color", "#d7181f")
        .attr("stop-opacity", 1);

        svg.selectAll(".series")
            .data(data)
            .enter()
            .append("g")
            .classed("series", true)
            .style("fill", function(d,i) { 
                if (i == 0) {
                    return "url(#gradient4)";
                    //return "#c9242b";
                }
                else if (i == 1) {
                    return "url(#gradient5)";
                    //return "#ee1c25";
                }
                else if (i == 2) {
                    return "url(#gradient)";
                    //return "#7ac141";
                }
                else if (i == 3) {
                    return "url(#gradient2)";
                    //return "#aecf36";
                }
                else if (i == 4) {
                    return "url(#gradient3)";
                    //return "#d1dd31";
                }
                else 
                {
                    return color(i) 
                }
                })
            .style("opacity", 1)
                .selectAll("rect")
                .data(Object)
                .enter()
                .append("rect")
                    .attr("x", function(d, i) { return x(x.domain()[i]) })
                    .attr("y", function(d) { return y(d.y0) })
                    .attr("height", function(d) { return y(0) - y(d.size) })
                    //.attr("width", x.rangeBand()) questo allarga le barre al massimo della larghezza possibile
                    .attr("width", "100px")
                    .attr("transform", "translate(50 0)")
                    .on("mouseover", function() { tooltip.style("display", null); })
                .on("mouseout", function() { tooltip.style("display", "none"); })
                .on("mousemove", function(d) {
                    var xPosition = d3.mouse(this)[0] - 35;
                    var yPosition = d3.mouse(this)[1] - 5;
                    tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
                    tooltip.select("text").text(d.y);
                });

        var yScale = d3.scale.linear()
                 .domain([0, d3.max(data, function(d) { return d[1]; })])
                 .range([0, h]);

        console.log(yScale);
        /*console.log("y(0)", y(0));
        console.log("margin", margin); */

        svg.append("g")
            .attr("class", "axis x")
            .attr("transform", "translate(0 " + y(0) + ")")
            .call(xAxis);

        /* svg.append("g")
            .attr("class", "axis y")
            .attr("transform", "translate(" + margin + " 0)")
            .call(yAxis); */

        /* Here we add tooltips */

        // Prep the tooltip bits, initial display is hidden
        var tooltip = svg.append("g")
          .attr("class", "tooltip")
          .style("display", "none");

        tooltip.append("rect")
          .attr("width", 30)
          .attr("height", 20)
          .attr("fill", "white")

          .style("opacity", 0.5);

        tooltip.append("text")
          .attr("x", 15)
          .attr("dy", "1.2em")
          .style("text-anchor", "middle")
          .attr("font-size", "12px")
          .attr("font-weight", "bold");


    }

这很有效,除了它没有缩放图表以显示x轴始终在中间。 这是结果: 请不要注意背景。

所以我的问题是:是否有可能让x轴始终位于中间?

1 个答案:

答案 0 :(得分:1)

我会根据当前xAxis y位置与容器y位置中间的差异来翻译整个图形。

这样的事情:

var xAxis = document.getElementById('assex'); //get xAxis based on ID

var container = document.getElementById('svg1'); //get container based on ID

var containerCenterY = container.getBoundingClientRect().top + container.getBoundingClientRect().height / 2; //get containers central y position, so get Y and add half the height

var xAxisY = xAxis.getBoundingClientRect().top; //get xAxis y pos

var difference = xAxisY - containerCenterY; //work out difference

关于你的例子:

我使用了上面的代码并使用了这个翻译函数:

 d3.select('#mainSVGContainer').transition().duration(1000).attr("transform", "translate(0 "+(-difference) +")")

我进行了转换,以便您可以看到之前的情况。

现在这首先不起作用,因为某些浏览器(包括Chrome)不支持SVG元素的翻译,但您可以翻译g元素。因此,在您创建g后添加了svg元素,为此元素添加了ID并对其进行了翻译。

新的svg创作:

svg = d3.select("#svg1") 
    .append("svg").attr("height", h)
    .attr("width", w).append('g').attr('id', 'mainSVGContainer')
    .attr("height", h)
    .attr("width", w)
    .attr("class", "graph-svg-component")

更新了小提琴:https://jsfiddle.net/thatOneGuy/8k8ggpcn/6/

我会把代码放在这里,以防JSFiddle崩溃:

function barStack(d) {
  var l = d[0].length
  while (l--) {
    var posBase = 0,
      negBase = 0;
    d.forEach(function(d) {
      d = d[l]
      d.size = Math.abs(d.y)
      if (d.y < 0) {
        d.y0 = negBase
        negBase -= d.size
      } else {
        d.y0 = posBase = posBase + d.size
      }
    })
  }
  d.extent = d3.extent(d3.merge(d3.merge(d.map(function(e) {
    return e.map(function(f) {
      return [f.y0, f.y0 - f.size]
    })
  }))))
  return d
}

var h = 548;
var w = 408;
var margin = 0;
var color = d3.scale.category10();

/* Here is an example */
function chart() {
  var data = [
    [{
      y: 3
    }, {
      y: 6
    }],
    [{
      y: 4
    }, {
      y: -2
    }],
    [{
      y: 10
    }, {
      y: -3
    }]
  ]


  var x = d3.scale.ordinal()
    .domain(['te1', 'te2'])
    .rangeRoundBands([margin, w - margin], .1)

  var y = d3.scale.linear()
    .range([h - 30, 0 + 30]);

  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .tickSize(0, 0);

  var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

  barStack(data);
  y.domain(data.extent); 
  
  svg = d3.select("#svg1") 
    .append("svg").attr("height", h)
    .attr("width", w)
    .append('g')
    .attr('id', 'mainSVGContainer')
    .attr("height", h)
    .attr("width", w)
    .attr("class", "graph-svg-component")

  var gradientVerde1 = svg.append("defs")
    .append("linearGradient")
    .attr("id", "gradient")

  .attr("x1", "0%")
    .attr("y1", "0%")
    .attr("x2", "100%")
    .attr("y2", "0%")
    .attr("spreadMethod", "reflect");

  gradientVerde1.append("stop")
    .attr("offset", "0%")
    .attr("stop-color", "#7ac141")
    .attr("stop-opacity", 1);

  gradientVerde1.append("stop")
    .attr("offset", "50%")
    .attr("stop-color", "#7ac141")
    .attr("stop-opacity", 1);

  gradientVerde1.append("stop")

  .attr("offset", "50%")
    .attr("stop-color", "#6db03c")

  .attr("stop-opacity", 1);

  gradientVerde1.append("stop")
    .attr("offset", "100%")
    .attr("stop-color", "#6db03c")
    .attr("stop-opacity", 1);

  var gradientVerde2 = svg.append("defs")
    .append("linearGradient")
    .attr("id", "gradient2")

  .attr("x1", "0%")
    .attr("y1", "0%")
    .attr("x2", "100%")
    .attr("y2", "0%")
    .attr("spreadMethod", "reflect");

  gradientVerde2.append("stop")
    .attr("offset", "0%")
    .attr("stop-color", "#acd038")
    .attr("stop-opacity", 1);

  gradientVerde2.append("stop")
    .attr("offset", "50%")
    .attr("stop-color", "#acd038")
    .attr("stop-opacity", 1);


  gradientVerde2.append("stop")

  .attr("offset", "50%")
    .attr("stop-color", "#9abd2f")

  .attr("stop-opacity", 1);

  gradientVerde2.append("stop")
    .attr("offset", "100%")
    .attr("stop-color", "#9abd2f")
    .attr("stop-opacity", 1);

  var gradientVerde3 = svg.append("defs")
    .append("linearGradient")
    .attr("id", "gradient3")

  .attr("x1", "0%")
    .attr("y1", "0%")
    .attr("x2", "100%")
    .attr("y2", "0%")
    .attr("spreadMethod", "reflect");

  gradientVerde3.append("stop")
    .attr("offset", "0%")
    .attr("stop-color", "#d1dd31")
    .attr("stop-opacity", 1);

  gradientVerde3.append("stop")
    .attr("offset", "50%")
    .attr("stop-color", "#d1dd31")
    .attr("stop-opacity", 1);

  gradientVerde3.append("stop")

  .attr("offset", "50%")
    .attr("stop-color", "#bdc82b")

  .attr("stop-opacity", 1);

  gradientVerde3.append("stop")
    .attr("offset", "100%")
    .attr("stop-color", "#bdc82b")
    .attr("stop-opacity", 1);

  var gradientRosso = svg.append("defs")
    .append("linearGradient")
    .attr("id", "gradient4")

  .attr("x1", "0%")
    .attr("y1", "0%")
    .attr("x2", "100%")
    .attr("y2", "0%")
    .attr("spreadMethod", "reflect");

  gradientRosso.append("stop")
    .attr("offset", "0%")
    .attr("stop-color", "#c9242b")
    .attr("stop-opacity", 1);

  gradientRosso.append("stop")
    .attr("offset", "50%")
    .attr("stop-color", "#c9242b")
    .attr("stop-opacity", 1);

  gradientRosso.append("stop")

  .attr("offset", "50%")
    .attr("stop-color", "#b72025")

  .attr("stop-opacity", 1);

  gradientRosso.append("stop")
    .attr("offset", "100%")
    .attr("stop-color", "#b72025")
    .attr("stop-opacity", 1);

  var gradientRosso2 = svg.append("defs")
    .append("linearGradient")
    .attr("id", "gradient5")
    .attr("x1", "0%")
    .attr("y1", "0%")
    .attr("x2", "100%")
    .attr("y2", "0%")
    .attr("spreadMethod", "reflect");

  gradientRosso2.append("stop")
    .attr("offset", "0%")
    .attr("stop-color", "#ee1c25")
    .attr("stop-opacity", 1);

  gradientRosso2.append("stop")
    .attr("offset", "50%")
    .attr("stop-color", "#ee1c25")
    .attr("stop-opacity", 1);

  gradientRosso2.append("stop")
    .attr("offset", "50%")
    .attr("stop-color", "#d7181f")
    .attr("stop-opacity", 1);

  gradientRosso2.append("stop")
    .attr("offset", "100%")
    .attr("stop-color", "#d7181f")
    .attr("stop-opacity", 1);

  svg.selectAll(".series")
    .data(data)
    .enter()
    .append("g")
    .classed("series", true)
    .style("fill", function(d, i) {
      if (i == 0) {
        return "url(#gradient4)";
        //return "#c9242b";
      } else if (i == 1) {
        return "url(#gradient5)";
        //return "#ee1c25";
      } else if (i == 2) {
        return "url(#gradient)";
        //return "#7ac141";
      } else if (i == 3) {
        return "url(#gradient2)";
        //return "#aecf36";
      } else if (i == 4) {
        return "url(#gradient3)";
        //return "#d1dd31";
      } else {
        return color(i)
      }
    })
    .style("opacity", 1)
    .selectAll("rect")
    .data(Object)
    .enter()
    .append("rect")
    .attr("x", function(d, i) {
      return x(x.domain()[i])
    })
    .attr("y", function(d) {
      return y(d.y0)
    })
    .attr("height", function(d) {
      return y(0) - y(d.size)
    })
    //.attr("width", x.rangeBand()) questo allarga le barre al massimo della larghezza possibile
    .attr("width", "100px")
    .attr("transform", "translate(50 0)")
    .on("mouseover", function() {
      tooltip.style("display", null);
    })
    .on("mouseout", function() {
      tooltip.style("display", "none");
    })
    .on("mousemove", function(d) {
      var xPosition = d3.mouse(this)[0] - 35;
      var yPosition = d3.mouse(this)[1] - 5;
      tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
      tooltip.select("text").text(d.y);
    });

  var yScale = d3.scale.linear()
    .domain([0, d3.max(data, function(d) {
      return d[1];
    })])
    .range([0, h]);

  console.log(yScale);
  /*console.log("y(0)", y(0));
  console.log("margin", margin); */

  svg.append("g")
    .attr("class", "axis x")
    .attr("id", "assex")
    .attr("transform", "translate(0 " + y(0) + ")")
    .call(xAxis);

  /* svg.append("g")
  	.attr("class", "axis y")
  	.attr("transform", "translate(" + margin + " 0)")
  	.call(yAxis); */

  /* Here we add tooltips */
  // Prep the tooltip bits, initial display is hidden
  var tooltip = svg.append("g")
    .attr("class", "tooltip")
    .style("display", "none");

  tooltip.append("rect")
    .attr("width", 30)
    .attr("height", 20)
    .attr("fill", "white")

  .style("opacity", 0.5);

  tooltip.append("text")
    .attr("x", 15)
    .attr("dy", "1.2em")
    .style("text-anchor", "middle")
    .attr("font-size", "12px")
    .attr("font-weight", "bold");

  var xAxis = document.getElementById('assex'); //get xAxis based on ID

  var container = document.getElementById('svg1'); //get container based on ID

  var containerCenterY = container.getBoundingClientRect().top + container.getBoundingClientRect().height / 2; //get containers central y position, so get Y and add half the height

  var xAxisY = xAxis.getBoundingClientRect().top; //get xAxis y pos

  var difference = xAxisY - containerCenterY; //work out difference
  
 d3.select('#mainSVGContainer').transition().duration(1000).attr("transform", "translate(0 "+(-difference) +")")
 
  






};

chart();
.axis text {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #82c5cb;
  stroke-width: 5px;
  shape-rendering: crispEdges;
}

#svg1{
  border: black 2px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="svg1">

</div>