带有滚动和缩放功能的条形图中未显示X轴标签 - d3js,刷牙

时间:2016-07-07 12:32:34

标签: d3.js

我的要求是生成带平移和缩放的条形图通过刷涂来克服x轴标签重叠id数据更多。我实现了条形图平移和基于下面的链接示例通过刷涂进行缩放 http://bl.ocks.org/MartynJones87/7db0d637e178e7204c0a 我能够进行平移和缩放,但x轴标签不会显示在轴上。我不知道我错在哪里。

这是代码的plunker link

在数据加载时,调用的核心代码是:

var xBrush = d3.svg.brush().x(min_x).on("brush", xBrushed);

// Called to re-draw the bars on the main chart when the brush on the x axis
        // has been altered.
        function xBrushed() {
            var originalRange = main_xZoom.range();
            main_xZoom.domain(xBrush.empty() ? originalRange : xBrush.extent());
            x.rangeRoundBands([main_xZoom(originalRange[0]), main_xZoom(originalRange[1])], .2);

            //main_x1.rangeRoundBands([0, x.rangeBand()], 0);

            main.selectAll("rect")
                .data(data)
                .attr("width", function (d) {

                    return x.rangeBand();
                })
                .attr("x", function (d) {
                                    //   alert("d is"+JSON.stringify(d));

                    return x(d.letter);

                });

            main.select("g.x.axis").call(xAxis).selectAll(".tick text").call(wrap, x.rangeBand());
        };

1 个答案:

答案 0 :(得分:0)

我在你的代码中找到了两个问题。

  1. svg clipPath中使用的defs矩形也在xBrushed函数内更新。问题出在您使用的选择器上。

    您应该使用

    main.selectAll(".rect") //which selects all elements with class rect in main selection.
    

    而不是

    main.selectAll("rect") //which selects all rect elements in main selection which includes clipPath rect also.
    

    xBrushed函数中。

  2. 您需要将clip-path属性应用于包含矩形栏元素的group元素。

  3. 工作代码段

    
    
    var margin = {
        top: 20,
        right: 20,
        bottom: 30,
        left: 40
      },
      width = 860 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;
    
    var min_margin = {
        top: height,
        right: margin.right + 10,
        bottom: margin.bottom,
        left: margin.left + 10
      },
      min_height = 10,
      min_width = 860 - min_margin.left - min_margin.right;
    
    
    
    
    var x = d3.scale.ordinal()
      .rangeRoundBands([0, width], .2);
    
    var min_x = d3.scale.ordinal().rangeRoundBands([0, width], .2);
    
    
    var y = d3.scale.linear()
      .range([height, 0]);
    
    var xAxis = d3.svg.axis()
      .scale(x)
      .orient("bottom");
    
    var min_xAxis = d3.svg.axis()
      .scale(min_x)
      .orient("bottom");
    
    
    
    var main_xZoom = d3.scale.linear()
      .range([0, width])
      .domain([0, width]);
    
    var yAxis = d3.svg.axis()
      .scale(y)
      .orient("left")
      .ticks(10, "%");
    
    var svg = d3.select("body").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom);
    
    var main = svg.append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    main.append("defs").append("clipPath")
      .attr("id", "clip")
      .append("rect")
      .attr("width", width)
      .attr("height", height + min_height + margin.bottom);
    
    
    var mini_x_append = svg.append("g")
      .attr("transform", "translate(" + min_margin.left + "," + (margin.top + height) + ")")
      .attr("width", min_width);
    
    
    var data = [{
      "letter": "A~q112",
      "frequency": 0.08167
    }, {
      "letter": "B~12",
      "frequency": 0.01492
    }, {
      "letter": "C~c",
      "frequency": 0.02782
    }, {
      "letter": "D~1a",
      "frequency": 0.04253
    }, {
      "letter": "E~d",
      "frequency": 0.12702
    }, {
      "letter": "F~x",
      "frequency": 0.02288
    }, {
      "letter": "G~v",
      "frequency": 0.02015
    }, {
      "letter": "H~xs",
      "frequency": 0.06094
    }, {
      "letter": "I~za",
      "frequency": 0.06966
    }, {
      "letter": "J~mj",
      "frequency": 0.00153
    }, {
      "letter": "K~th",
      "frequency": 0.00772
    }, {
      "letter": "L~ws",
      "frequency": 0.04025
    }, {
      "letter": "M~qjl",
      "frequency": 0.02406
    }, {
      "letter": "N~i",
      "frequency": 0.06749
    }, {
      "letter": "O~p",
      "frequency": 0.07507
    }, {
      "letter": "P~zs",
      "frequency": 0.01929
    }, {
      "letter": "Q~rip",
      "frequency": 0.00095
    }, {
      "letter": "R~hi",
      "frequency": 0.05987
    }, {
      "letter": "S~eop",
      "frequency": 0.06327
    }, {
      "letter": "T~tl",
      "frequency": 0.09056
    }, {
      "letter": "U~se",
      "frequency": 0.02758
    }, {
      "letter": "V~wh",
      "frequency": 0.00978
    }, {
      "letter": "W~jl",
      "frequency": 0.0236
    }, {
      "letter": "X~y",
      "frequency": 0.0015
    }, {
      "letter": "Y~ty",
      "frequency": 0.01974
    }, {
      "letter": "Z~o",
      "frequency": 0.00074
    }, {
      "letter": "A~q12",
      "frequency": 0.08167
    }, {
      "letter": "B~122",
      "frequency": 0.01492
    }, {
      "letter": "C~c2",
      "frequency": 0.02782
    }, {
      "letter": "D~1a2",
      "frequency": 0.04253
    }, {
      "letter": "E~d2",
      "frequency": 0.12702
    }, {
      "letter": "F~x2",
      "frequency": 0.02288
    }, {
      "letter": "G~v2",
      "frequency": 0.02015
    }, {
      "letter": "H~xs2",
      "frequency": 0.06094
    }, {
      "letter": "I~za2",
      "frequency": 0.06966
    }, {
      "letter": "J~mj2",
      "frequency": 0.00153
    }, {
      "letter": "K~th2",
      "frequency": 0.00772
    }, {
      "letter": "L~ws2",
      "frequency": 0.04025
    }, {
      "letter": "M~qjl2",
      "frequency": 0.02406
    }, {
      "letter": "N~i2",
      "frequency": 0.06749
    }, {
      "letter": "O~p2",
      "frequency": 0.07507
    }, {
      "letter": "P~zs2",
      "frequency": 0.01929
    }, {
      "letter": "Q~rip2",
      "frequency": 0.00095
    }, {
      "letter": "R~hi2",
      "frequency": 0.05987
    }, {
      "letter": "S~eo2p",
      "frequency": 0.06327
    }, {
      "letter": "T~tl2",
      "frequency": 0.09056
    }, {
      "letter": "U~se2",
      "frequency": 0.02758
    }, {
      "letter": "V~wh2",
      "frequency": 0.00978
    }, {
      "letter": "W~jl2",
      "frequency": 0.0236
    }, {
      "letter": "X~y2",
      "frequency": 0.0015
    }, {
      "letter": "Y~ty2",
      "frequency": 0.01974
    }, {
      "letter": "Z~o2",
      "frequency": 0.00074
    }];
    
    
    
    
    
    x.domain(data.map(function(d) {
      return d.letter;
    }));
    min_x.domain(data.map(function(d) {
      return d.letter;
    }));
    y.domain([0, d3.max(data, function(d) {
      return d.frequency;
    })]);
    
    
    var xBrush = d3.svg.brush().x(min_x).on("brush", xBrushed);
    
    // Add the x axis
    
    
    main.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + (height + min_height) + ")")
      .attr("clip-path", "url(#clip)")
      .call(xAxis)
      .selectAll(".tick text")
      .call(wrap, x.rangeBand());
    
    
    var x_arc = d3.svg.arc()
      .outerRadius(min_height / 2)
      .startAngle(0)
      .endAngle(function(d, i) {
        return i ? -Math.PI : Math.PI;
      });
    
    var brush_x_grab = mini_x_append.append("g")
      .attr("class", "x brush")
      .call(xBrush);
    
    brush_x_grab.selectAll(".resize").append("path")
      .attr("transform", "translate(0," + min_height / 2 + ")")
      .attr("d", x_arc);
    
    brush_x_grab.selectAll("rect").attr("height", min_height);
    
    
    
    
    
    main.append("g")
      .attr("class", "y axis")
      .call(yAxis);
    
    
    var bar = main.append("g")
      .attr("clip-path", "url(#clip)")
      .selectAll(".rect")
      .data(data)
      .enter().append("rect")
      .attr("class", "rect")
      .attr("x", function(d) {
        return x(d.letter);
      })
      .attr("width", x.rangeBand())
      .attr("y", function(d) {
        return y(d.frequency);
      })
      .attr("height", function(d) {
        return height - y(d.frequency);
      });
    
    
    
    // Called to re-draw the bars on the main chart when the brush on the x axis
    // has been altered.
    function xBrushed() {
      var originalRange = main_xZoom.range();
      
      main_xZoom.domain(xBrush.empty() ? originalRange : xBrush.extent());
      
      x.rangeRoundBands([main_xZoom(originalRange[0]), main_xZoom(originalRange[1])], .2);
    
     // min_x.rangeRoundBands([0, x.rangeBand()], 0);
    
      main.selectAll(".rect")
        .data(data)
        .attr("width", function(d) {
    
          return x.rangeBand();
        })
      
        .attr("x", function(d) {
          //   alert("d is"+JSON.stringify(d));
    
    
          return x(d.letter);
    
        
        }); 
    
      main.select("g.x.axis").call(xAxis).selectAll(".tick text").call(wrap, x.rangeBand());
    };
    
    // This comes from the example at http://bl.ocks.org/mbostock/7555321
    // for wrapping long axis tick labels
    function wrap(text, width) {
      text.each(function() {
        var text = d3.select(this),
          words = text.text().split(/\s+/).reverse(),
          word,
          line = [],
          lineNumber = 0,
          lineHeight = 1.1, // ems
          y = text.attr("y"),
          dy = parseFloat(text.attr("dy")),
          tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
        while (word = words.pop()) {
          //   console.log("wrap is"+JSON.stringify(word));
          line.push(word);
          tspan.text(line.join(" "));
          if (tspan.node().getComputedTextLength() > width) {
            line.pop();
            tspan.text(line.join(" "));
            line = [word];
            tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
          }
        }
      });
    };
    
    
    
    // Set the initial brush selections.
    // svg.select(".x.brush").call(xBrush.extent(main_xZoom.domain()));
    svg.select(".x.brush").call(xBrush.extent([0, 110]));
    //svg.select(".y.brush").call(yBrush.extent(mini_y0.domain()));
    
    // Forces a refresh of the brushes and main chart based
    // on the selected extents.
    xBrushed();
    //yBrushed();
    
    
    function type(d) {
      d.frequency = +d.frequency;
      return d;
    }
    
    g.axis path,
    g.axis line {
      fill: none;
      stroke: black;
      shape-rendering: crispEdges;
    }
    g.brush rect.extent {
      fill-opacity: 0.2;
    }
    .resize path {
      fill-opacity: 0.2;
    }
    .bar {
      fill: steelblue;
    }
    .axis {
      font: 10px sans-serif;
    }
    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
    .x.axis path {
      display: none;
    }
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    &#13;
    &#13;
    &#13;

    修改

    我发现通过将您拥有的json数据转换为此link使用的相同格式,可以更轻松地实现此功能。

    &#13;
    &#13;
    var nestedData;
    
    var main_margin = {
        top: 25,
        right: 80,
        bottom: 60,
        left: 70
      },
    
      width = 900 - main_margin.left - main_margin.right,
      mini_x_height = 10;
    main_height = 525 - main_margin.top - main_margin.bottom,
    
      mini_x_margin = {
        top: main_height,
        right: main_margin.right + 10,
        bottom: main_margin.bottom,
        left: main_margin.left + 10
      },
    
      mini_x_width = 900 - mini_x_margin.left - mini_x_margin.right,
    
      mini_y_margin = {
        top: main_margin.top + 10,
        right: 0,
        bottom: main_margin.bottom + 10,
        left: 0
      },
      mini_y_width = 10,
      mini_y_height = 525 - mini_y_margin.top - mini_y_margin.bottom;
    
    
    var color = d3.scale.category10();
    
    // x0 is the groups scale on the x axis.
    var main_x0 = d3.scale.ordinal().rangeRoundBands([0, width], 0.2);
    var mini_x0 = d3.scale.ordinal().rangeRoundBands([0, width], 0.2);
    
    var main_xZoom = d3.scale.linear()
      .range([0, width])
      .domain([0, width]);
    
    // x1 is the series scale on the x axis.
    var main_x1 = d3.scale.ordinal();
    var mini_x1 = d3.scale.ordinal();
    
    // y is the value scale on the y axis.
    var main_y0 = d3.scale.linear().range([main_height, 0]);
    
    var mini_y0 = d3.scale.linear().range([mini_y_height, 0]);
    
    var main_xAxis = d3.svg.axis()
      .scale(main_x0)
      .orient("bottom");
    
    var mini_xAxis = d3.svg.axis()
      .scale(mini_x0)
      .orient("bottom");
    
    var main_yAxis = d3.svg.axis()
      .scale(main_y0)
      .orient("left");
    
    var mini_yAxis = d3.svg.axis()
      .scale(mini_y0)
      .orient("left");
    
    var svg = d3.select("#chart").append("svg")
      .attr("width", width + main_margin.left + main_margin.right)
      .attr("height", main_height + main_margin.top + main_margin.bottom);
    
    var main = svg.append("g")
      .attr("transform", "translate(" + main_margin.left + "," + main_margin.top + ")");
    
    main.append("defs").append("clipPath")
      .attr("id", "clip")
      .append("rect")
      .attr("width", width)
      .attr("height", main_height + mini_x_height + main_margin.bottom);
    
    var mini_x = svg.append("g")
      .attr("transform", "translate(" + mini_x_margin.left + "," + (main_margin.top + main_height) + ")")
      .attr("width", mini_x_width);
    
    var mini_y = svg.append("g")
      .attr("width", mini_y_width)
      .attr("transform", "translate(" + (main_margin.left - mini_y_width) + ", " + mini_y_margin.top + ")")
      .attr("height", mini_y_height);
    
    var data = [{
      key: 'Mechanical',
      values: [{
        key: 'Gear',
        value: 11
    }, {
        key: 'Bearing',
        value: 8
      }, {
        key: 'Motor',
        value: 3
      }, {
        key: 'Bearing',
        value: 8
      }, {
        key: 'Motor',
        value: 3
      }, {
        key: 'Bearing',
        value: 8
      }, {
        key: 'Motor',
        value: 3
      }]
    }, {
      key: 'Electrical',
      values: [{
        key: 'Switch',
        value: 19
      }, {
        key: 'Plug',
        value: 12
      }, {
        key: 'Cord',
        value: 11
      }, {
        key: 'Fuse',
        value: 3
      }, {
        key: 'Bulb',
        value: 2
      }]
    }, {
      key: 'Hydraulic',
      values: [{
        key: 'Pump',
        value: 4
      }, {
        key: 'Leak',
        value: 3
      }, {
        key: 'Seals',
        value: 1
      },{
        key: 'Switch',
        value: 19
      }, {
        key: 'Plug',
        value: 12
      }, {
        key: 'Cord',
        value: 11
      }, {
        key: 'Fuse',
        value: 3
      }, {
        key: 'Bulb',
        value: 2
      }]
    }];
    
    
    var res = [];
    
    data.forEach(function(d){ 
      res.push(d.values.map(function(o){
        o.item=o.key; 
        o.subject = d.key; return o; }));
    });
    
    data = [].concat.apply([], res);
    res.sort(function(a,b){ return a.subject<b.subject });
    
    //console.log(data);
    
      var seriesValues = d3.set(data.map(function(x) {
        return x.item;
      })).values().sort(d3.ascending);
    
      nestedData = d3.nest()
        .key(function(d) {
          return d.subject;
        })
        .sortKeys(d3.ascending)
        .sortValues(function(a, b) {
          return a.item - b.item;
        })
        .entries(data);
    
      var groupValues = d3.set(data.map(function(x) {
        return x.subject;
      })).values();
    
      // Define the axis domains
      main_x0.domain(groupValues);
      mini_x0.domain(groupValues);
    
      main_x1.domain(seriesValues).rangeRoundBands([0, main_x0.rangeBand()], 0);
      mini_x1.domain(seriesValues).rangeRoundBands([0, main_x0.rangeBand()], 0);
    
      main_y0.domain([0, d3.max(nestedData, function(d) {
        return d3.max(d.values, function(d) {
          return d.value;
        });
      })]);
      mini_y0.domain(main_y0.domain());
    
      var xBrush = d3.svg.brush().x(mini_x0).on("brush", xBrushed);
      var yBrush = d3.svg.brush().y(mini_y0).on("brush", yBrushed);
    
      // Add the x axis
      main.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + (main_height + mini_x_height) + ")")
        .attr("clip-path", "url(#clip)")
        .call(main_xAxis)
        .selectAll(".tick text")
        .call(wrap, main_x0.rangeBand());
    
      // Add the y axis
      main.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate(" + (-mini_y_width) + ", 0)")
        .call(main_yAxis)
        .append("text")
        .attr("transform", "rotate(-90), translate(" + -(main_height / 2) + ", " + -(mini_y_width + main_margin.left - 20) + ")")
        .attr("dy", ".71em")
        .style("text-anchor", "middle")
        .text("value");
    
      var x_arc = d3.svg.arc()
        .outerRadius(mini_x_height / 2)
        .startAngle(0)
        .endAngle(function(d, i) {
          return i ? -Math.PI : Math.PI;
        });
    
      var brush_x_grab = mini_x.append("g")
        .attr("class", "x brush")
        .call(xBrush);
    
      brush_x_grab.selectAll(".resize").append("path")
        .attr("transform", "translate(0," + mini_x_height / 2 + ")")
        .attr("d", x_arc);
    
      brush_x_grab.selectAll("rect").attr("height", mini_x_height);
    
      var y_arc = d3.svg.arc()
        .outerRadius(mini_y_width / 2)
        .startAngle(-(Math.PI / 2))
        .endAngle(function(d, i) {
          return i ? -((3 * Math.PI) / 2) : ((Math.PI) / 2);
        });
    
      var brush_y_grab = mini_y.append("g")
        .attr("class", "y brush")
        .call(yBrush);
    
      brush_y_grab.selectAll(".resize").append("path")
        .attr("transform", "translate(" + (mini_y_width / 2) + ", 0)")
        .attr("d", y_arc);
    
      brush_y_grab.selectAll("rect").attr("width", mini_y_width);
    
      // Create the main bars
      var bar = main.selectAll(".bars")
        .data(nestedData)
        .enter().append("g")
        .attr("clip-path", "url(#clip)")
        .attr("class", function(d) {
          return d.key + "-group bar";
        });
    
      bar.selectAll("rect")
        .data(function(d) {
          return d.values;
        })
        .enter().append("rect")
        .attr("class", function(d) {
          return d.item;
        })
        .attr("transform", function(d) {
          return "translate(" + main_x0(d.subject) + ",0)";
        })
        .attr("width", function(d) {
          return main_x1.rangeBand();
        })
        .attr("x", function(d) {
          return main_x1(d.item);
        })
        .attr("y", function(d) {
          return main_y0(d.value);
        })
        .attr("height", function(d) {
          return main_height - main_y0(d.value);
        })
        .style("fill", function(d) {
          return color(d.item);
        });
    
    
      // Draws the series items onto a legend
      var legend = svg.selectAll(".legend")
        .data(seriesValues.slice())
        .enter().append("g")
        .attr("class", "legend")
        .attr("transform", function(d, i) {
          return "translate(50," + (main_margin.top + (i * 20)) + ")";
        });
    
      legend.append("rect")
        .attr("x", width - 18)
        .attr("width", 18)
        .attr("height", 18)
        .style("fill", color);
    
      legend.append("text")
        .attr("x", width - 24)
        .attr("y", 9)
        .attr("dy", ".35em")
        .style("text-anchor", "end")
        .text(function(d) {
          return d;
        });
    
      // Called to re-draw the bars on the main chart when the brush on the x axis
      // has been altered.
      function xBrushed() {
        var originalRange = main_xZoom.range();
        main_xZoom.domain(xBrush.empty() ? originalRange : xBrush.extent());
        main_x0.rangeRoundBands([main_xZoom(originalRange[0]), main_xZoom(originalRange[1])], .1);
    
        main_x1.rangeRoundBands([0, main_x0.rangeBand()], 0);
    
        bar.selectAll("rect")
          .attr("transform", function(d) {
            return "translate(" + main_x0(d.subject) + ",0)";
          })
          .attr("width", function(d) {
            return main_x1.rangeBand();
          })
          .attr("x", function(d) {
            return main_x1(d.item);
          });
    
        main.select("g.x.axis").call(main_xAxis).selectAll(".tick text").call(wrap, main_x0.rangeBand());
      };
    
      // Called to re-draw the bars on the main chart when the
      // brush on the y axis has been altered.
      function yBrushed() {
        main_y0.domain(yBrush.empty() ? mini_y0.domain() : yBrush.extent());
    
        bar.selectAll("rect")
          .attr("y", function(d) {
            return main_y0(d.value);
          })
          .attr("height", function(d) {
            return main_height - main_y0(d.value);
          });
    
        main.select("g.y.axis").call(main_yAxis);
      };
    
      // This comes from the example at http://bl.ocks.org/mbostock/7555321
      // for wrapping long axis tick labels
      function wrap(text, width) {
        text.each(function() {
          var text = d3.select(this),
            words = text.text().split(/\s+/).reverse(),
            word,
            line = [],
            lineNumber = 0,
            lineHeight = 1.1, // ems
            y = text.attr("y"),
            dy = parseFloat(text.attr("dy")),
            tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
          while (word = words.pop()) {
            line.push(word);
            tspan.text(line.join(" "));
            if (tspan.node().getComputedTextLength() > width) {
              line.pop();
              tspan.text(line.join(" "));
              line = [word];
              tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
            }
          }
        });
      };
    
      // Set the initial brush selections.
      // svg.select(".x.brush").call(xBrush.extent(main_xZoom.domain()));
      svg.select(".x.brush").call(xBrush.extent([0, 610]));
      svg.select(".y.brush").call(yBrush.extent(mini_y0.domain()));
    
      // Forces a refresh of the brushes and main chart based
      // on the selected extents.
      xBrushed();
      yBrushed();
    
    //});
    &#13;
    g.axis path,
    g.axis line {
      fill: none;
      stroke: black;
      shape-rendering: crispEdges;
    }
    g.brush rect.extent {
      fill-opacity: 0.2;
    }
    .resize path {
      fill-opacity: 0.2;
    }
    &#13;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    <div id="chart"></div>
    &#13;
    &#13;
    &#13;