【问题标题】:Content of d3.js chart overflows margins when using brush使用画笔时d3.js图表​​的内容溢出边距
【发布时间】:2016-01-09 17:11:20
【问题描述】:

我在使用 d3.js 条形图时遇到问题。完整代码和工作演示在这里:https://jsfiddle.net/monotasker/yurqkm3n/。问题是当我在下部(上下文)图表上使用画笔时,上部(焦点)图表会溢出其边距。

这是画笔激活的功能:

function brushed() {
    time.domain(brush.empty() ? navTime.domain() : brush.extent())
        .range([0, (width)]);
    x.domain(max_extent_in_days(time))
        .rangeBands([margin.left, (width)], 0.1, 0);
    focus.selectAll('.bar.stack')
        .attr('transform', function(d) {return "translate(" + time(d.date) + ",0)"; })
        .attr('width', x.rangeBand());
    focus.selectAll('.rect')
        .attr('width', x.rangeBand());
    focus.selectAll('.line').attr('d', line);
    focus.select(".x.axis").call(x_axis);
};

图表的一个奇怪之处在于,有两个刻度共同控制 x 轴:“时间”和“x”。 “时间”刻度用于在 x 轴上定位内容,但“x”刻度(将“时间”转换为序数刻度)用于计算条形宽度。我不知道这种方法是否是问题的根源。

非常感谢任何帮助。

【问题讨论】:

    标签: javascript d3.js charts bar-chart


    【解决方案1】:

    example 中,博斯托克先生将剪辑路径应用于区域路径,您需要将一个剪辑路径应用于条形图。最简单的方法是将它们放在自己的 g 中,然后将剪辑路径应用到该位置:

    svg.append("defs").append("clipPath")
        .attr("id", "clip")
        .append("rect")
        .attr("width", width)
        .attr("height", height);
    
    ...
    
    // Plot the stacked bars
    var focus_bar = focus
        .append("g") //<-- g just for the bars to be clipped
        .attr("class","barClipper")
        .style('clip-path', 'url(#clip)') //<-- apply clipping
        .selectAll('.g')
        .data(data.answer_counts)
        .enter().append('g')
        .attr('class', 'g bar stack')
        .attr('transform', function(d) {
          return "translate(" + x(d.date) + ",0)"
        });
    

    完整代码:

    <!DOCTYPE html>
    <html>
    
    <head>
      <script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
      <style>
        #milestones_attempts_combo .context {
          /*fill: #efefef;    */
        }
        
        #milestones_attempts_combo .focus .right,
        #milestones_attempts_combo .context .right {
          fill: #0064cd;
        }
        
        #milestones_attempts_combo .focus .wrong,
        #milestones_attempts_combo .context .wrong {
          fill: #cd001d;
        }
        
        #milestones_attempts_combo .y-axis-label,
        #milestones_attempts_combo .y2-axis-label {
          fill: #aaa;
          font-size: 120%;
        }
        
        #milestones_attempts_combo .focus-line,
        #milestones_attempts_combo .context-line {
          stroke: orange;
          stroke-width: 2;
          fill-opacity: 0;
        }
        
        .brush .extent {
          stroke: #efefef;
          fill: #666;
          fill-opacity: .125;
          shape-rendering: crispEdges;
        }
        
        .stats-container {
          width: 700px;
          margin: 0 auto;
        }
    
        .chart .axis line,
        .chart .axis path,
        .chart .tick line {
          fill: none;
          stroke: #aaa;
          shape-rendering: crispEdges;
        }
      </style>
    </head>
    
    <body>
      <div id="milestones_attempts_combo"></div>
      <script>
        (function() {
          var myjsondata = {
            "answer_counts": [{
              "date": "2012-09-13",
              "ys": [{
                "y1": 9,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 12,
                "y0": 9,
                "class": "wrong"
              }],
              "total": 12
            }, {
              "date": "2012-09-16",
              "ys": [{
                "y1": 16,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 17,
                "y0": 16,
                "class": "wrong"
              }],
              "total": 17
            }, {
              "date": "2012-09-17",
              "ys": [{
                "y1": 12,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 14,
                "y0": 12,
                "class": "wrong"
              }],
              "total": 14
            }, {
              "date": "2012-09-19",
              "ys": [{
                "y1": 2,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 2,
                "y0": 2,
                "class": "wrong"
              }],
              "total": 2
            }, {
              "date": "2012-09-20",
              "ys": [{
                "y1": 12,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 16,
                "y0": 12,
                "class": "wrong"
              }],
              "total": 16
            }, {
              "date": "2012-09-21",
              "ys": [{
                "y1": 20,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 22,
                "y0": 20,
                "class": "wrong"
              }],
              "total": 22
            }, {
              "date": "2012-09-22",
              "ys": [{
                "y1": 1,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 1,
                "y0": 1,
                "class": "wrong"
              }],
              "total": 1
            }, {
              "date": "2012-09-23",
              "ys": [{
                "y1": 10,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 12,
                "y0": 10,
                "class": "wrong"
              }],
              "total": 12
            }, {
              "date": "2012-09-24",
              "ys": [{
                "y1": 9,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 9,
                "y0": 9,
                "class": "wrong"
              }],
              "total": 9
            }, {
              "date": "2012-09-25",
              "ys": [{
                "y1": 2,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 4,
                "y0": 2,
                "class": "wrong"
              }],
              "total": 4
            }, {
              "date": "2012-09-29",
              "ys": [{
                "y1": 26,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 37,
                "y0": 26,
                "class": "wrong"
              }],
              "total": 37
            }, {
              "date": "2012-10-01",
              "ys": [{
                "y1": 44,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 44,
                "y0": 44,
                "class": "wrong"
              }],
              "total": 44
            }, {
              "date": "2012-10-02",
              "ys": [{
                "y1": 2,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 2,
                "y0": 2,
                "class": "wrong"
              }],
              "total": 2
            }, {
              "date": "2012-10-03",
              "ys": [{
                "y1": 13,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 13,
                "y0": 13,
                "class": "wrong"
              }],
              "total": 13
            }, {
              "date": "2012-10-05",
              "ys": [{
                "y1": 47,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 47,
                "y0": 47,
                "class": "wrong"
              }],
              "total": 47
            }, {
              "date": "2012-10-08",
              "ys": [{
                "y1": 17,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 17,
                "y0": 17,
                "class": "wrong"
              }],
              "total": 17
            }, {
              "date": "2012-10-09",
              "ys": [{
                "y1": 19,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 20,
                "y0": 19,
                "class": "wrong"
              }],
              "total": 20
            }, {
              "date": "2012-10-10",
              "ys": [{
                "y1": 31,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 31,
                "y0": 31,
                "class": "wrong"
              }],
              "total": 31
            }, {
              "date": "2012-10-11",
              "ys": [{
                "y1": 6,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 6,
                "y0": 6,
                "class": "wrong"
              }],
              "total": 6
            }, {
              "date": "2012-10-14",
              "ys": [{
                "y1": 6,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 6,
                "y0": 6,
                "class": "wrong"
              }],
              "total": 6
            }, {
              "date": "2012-10-19",
              "ys": [{
                "y1": 30,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 32,
                "y0": 30,
                "class": "wrong"
              }],
              "total": 32
            }, {
              "date": "2012-10-20",
              "ys": [{
                "y1": 20,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 22,
                "y0": 20,
                "class": "wrong"
              }],
              "total": 22
            }, {
              "date": "2012-10-23",
              "ys": [{
                "y1": 20,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 20,
                "y0": 20,
                "class": "wrong"
              }],
              "total": 20
            }, {
              "date": "2012-10-24",
              "ys": [{
                "y1": 20,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 21,
                "y0": 20,
                "class": "wrong"
              }],
              "total": 21
            }, {
              "date": "2012-10-29",
              "ys": [{
                "y1": 22,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 22,
                "y0": 22,
                "class": "wrong"
              }],
              "total": 22
            }, {
              "date": "2012-11-01",
              "ys": [{
                "y1": 1,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 1,
                "y0": 1,
                "class": "wrong"
              }],
              "total": 1
            }, {
              "date": "2012-11-02",
              "ys": [{
                "y1": 26,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 29,
                "y0": 26,
                "class": "wrong"
              }],
              "total": 29
            }, {
              "date": "2012-11-05",
              "ys": [{
                "y1": 23,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 27,
                "y0": 23,
                "class": "wrong"
              }],
              "total": 27
            }, {
              "date": "2012-11-06",
              "ys": [{
                "y1": 10,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 11,
                "y0": 10,
                "class": "wrong"
              }],
              "total": 11
            }, {
              "date": "2012-11-07",
              "ys": [{
                "y1": 15,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 18,
                "y0": 15,
                "class": "wrong"
              }],
              "total": 18
            }, {
              "date": "2012-11-09",
              "ys": [{
                "y1": 26,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 31,
                "y0": 26,
                "class": "wrong"
              }],
              "total": 31
            }, {
              "date": "2012-11-10",
              "ys": [{
                "y1": 2,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 2,
                "y0": 2,
                "class": "wrong"
              }],
              "total": 2
            }, {
              "date": "2012-11-14",
              "ys": [{
                "y1": 15,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 17,
                "y0": 15,
                "class": "wrong"
              }],
              "total": 17
            }, {
              "date": "2012-11-16",
              "ys": [{
                "y1": 20,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 23,
                "y0": 20,
                "class": "wrong"
              }],
              "total": 23
            }, {
              "date": "2012-11-18",
              "ys": [{
                "y1": 2,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 2,
                "y0": 2,
                "class": "wrong"
              }],
              "total": 2
            }, {
              "date": "2012-11-19",
              "ys": [{
                "y1": 23,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 26,
                "y0": 23,
                "class": "wrong"
              }],
              "total": 26
            }, {
              "date": "2012-11-21",
              "ys": [{
                "y1": 2,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 3,
                "y0": 2,
                "class": "wrong"
              }],
              "total": 3
            }, {
              "date": "2012-11-23",
              "ys": [{
                "y1": 9,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 10,
                "y0": 9,
                "class": "wrong"
              }],
              "total": 10
            }, {
              "date": "2012-11-26",
              "ys": [{
                "y1": 2,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 2,
                "y0": 2,
                "class": "wrong"
              }],
              "total": 2
            }, {
              "date": "2012-11-27",
              "ys": [{
                "y1": 25,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 26,
                "y0": 25,
                "class": "wrong"
              }],
              "total": 26
            }, {
              "date": "2012-11-28",
              "ys": [{
                "y1": 73,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 75,
                "y0": 73,
                "class": "wrong"
              }],
              "total": 75
            }, {
              "date": "2012-12-02",
              "ys": [{
                "y1": 19,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 20,
                "y0": 19,
                "class": "wrong"
              }],
              "total": 20
            }, {
              "date": "2012-12-05",
              "ys": [{
                "y1": 1,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 1,
                "y0": 1,
                "class": "wrong"
              }],
              "total": 1
            }, {
              "date": "2013-01-11",
              "ys": [{
                "y1": 2,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 3,
                "y0": 2,
                "class": "wrong"
              }],
              "total": 3
            }, {
              "date": "2013-01-16",
              "ys": [{
                "y1": 8,
                "y0": 0,
                "class": "right"
              }, {
                "y1": 8,
                "y0": 8,
                "class": "wrong"
              }],
              "total": 8
            }],
            "badge_set_reached": [{
              "date": "2014-05-24",
              "set": 3
            }, {
              "date": "2014-09-29",
              "set": 5
            }, {
              "date": "2014-11-10",
              "set": 6
            }, {
              "date": "2014-08-29",
              "set": 7
            }, {
              "date": "2015-08-12",
              "set": 9
            }, {
              "date": "2016-01-09",
              "set": 9
            }]
          }
    
          var data = myjsondata;
          // preprocess data to get usable date objects
          var parse_date = d3.time.format('%Y-%m-%d').parse
          for (var i in data) {
            var myObj = data[i]
            for (var j in myObj) {
              myObj[j].date = parse_date(myObj[j].date);
            }
          }
          console.log(data);
    
          // set variables
          var margin = {
              left: 60,
              right: 60,
              top: 10,
              bottom: 140
            },
            navMargin = {
              top: 300,
              right: 60,
              bottom: 40,
              left: 60
            },
            height = 400 - margin.top - margin.bottom,
            width = 800 - margin.left - margin.right,
            navWidth = width, // for context band
            navHeight = 400 - navMargin.top - navMargin.bottom,
            max_total_counts = d3.max(data.answer_counts, function(d) {
              return d.total;
            }),
            max_extent_dates = d3.extent(data.answer_counts, function(d) {
              return d.date;
            });
          max_extent_in_days = function(timescale) {
            return d3.time.days(timescale.domain()[0], d3.time.day.offset(timescale.domain()[1], 1))
          };
    
          // scales
          var y = d3.scale.linear().domain([0, max_total_counts]).rangeRound([height, 0]),
            navY = d3.scale.linear().domain([0, max_total_counts]).rangeRound([navHeight, 0]),
            time = d3.time.scale().domain(max_extent_dates).range([0, width]),
            navTime = d3.time.scale().domain(max_extent_dates).range([0, width]),
            x = d3.scale.ordinal().domain(max_extent_in_days(time)).rangeBands([0, width], 0.1, 0), // used to calculate bar widths
            navX = d3.scale.ordinal().domain(max_extent_in_days(navTime)).rangeBands([0, width], 0.1, 0),
            y2 = d3.scale.linear().domain([0, d3.max(data.badge_set_reached, function(d) {
              return d.set
            })]).rangeRound([height, 0]);
          navY2 = d3.scale.linear().domain([0, d3.max(data.badge_set_reached, function(d) {
            return d.set
          })]).rangeRound([navHeight, 0]);
    
          // axes
          var x_axis = d3.svg.axis().scale(time).orient('bottom') //    .tickFormat(d3.time.format('%Y-%m-%d'))
            .outerTickSize(0), // at start and end of axis line
            nav_x_axis = d3.svg.axis().scale(navTime).orient('bottom') //    .tickFormat(d3.time.format('%Y-%m-%d'))
            .outerTickSize(0), // at start and end of axis line
            y_axis = d3.svg.axis().scale(y).orient('left').tickFormat(d3.format('d'));
          y2_axis = d3.svg.axis().scale(y2).orient('right').tickFormat(d3.format('d'));
    
          // add brush
          var brush = d3.svg.brush()
            .x(navTime)
            .on("brush", brushed);
    
          // svg context
          var svg = d3.select("#milestones_attempts_combo")
            .append('svg')
            .attr('class', 'chart')
            .attr('width', width + margin.left + margin.right)
            .attr('height', height + margin.top + margin.bottom)
            
          svg.append("defs").append("clipPath")
            .attr("id", "clip")
            .append("rect")
            .attr("width", width)
            .attr("height", height);
    
          var focus = svg.append('g')
            .attr('class', 'focus')
            .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
    
          var context = svg.append('g')
            .attr('class', 'context')
            .attr('transform', 'translate(' + navMargin.left + ',' + navMargin.top + ')');
    
          // Plot the stacked bars
          var focus_bar = focus
            .append("g")
            .attr("class","barClipper")
            .style('clip-path', 'url(#clip)')
            .selectAll('.g')
            .data(data.answer_counts)
            .enter().append('g')
            .attr('class', 'g bar stack')
            .attr('transform', function(d) {
              return "translate(" + x(d.date) + ",0)"
            });
    
          var focus_rects = focus_bar.selectAll('rect')
            .data(function(d) {
              return d.ys;
            })
            .enter().append('rect')
            .attr('width', x.rangeBand())
            .attr('height', function(d) {
              return y(d.y0) - y(d.y1);
            })
            .attr('y', function(d) {
              return y(d.y1);
            })
            .attr('class', function(d) {
              return 'rect ' + d['class'];
            });
    
          var context_bar = context.selectAll('.g')
            .data(data.answer_counts)
            .enter().append('g')
            .attr('class', 'g')
            .attr('transform', function(d) {
              return "translate(" + navTime(d.date) + ",0)"
            });
    
          var context_rects = context_bar.selectAll('rect')
            .data(function(d) {
              return d.ys;
            })
            .enter().append('rect')
            .attr('width', navX.rangeBand())
            .attr('height', function(d) {
              return navY(d.y0) - navY(d.y1);
            })
            .attr('y', function(d) {
              return navY(d.y1);
            })
            .attr('class', function(d) {
              return 'rect ' + d['class'];
            });
    
          // Plot lines
    
          var line = d3.svg.line()
            .x(function(d) {
              return time(d.date)
            })
            .y(function(d) {
              return y2(d.set)
            })
            .interpolate('step-after');
          var focus_line = focus.append('path')
            .datum(data.badge_set_reached)
            .attr('class', 'line focus-line')
            .attr('d', line);
    
          var line2 = d3.svg.line()
            .x(function(d) {
              return time(d.date)
            })
            .y(function(d) {
              return navY2(d.set)
            })
            .interpolate('step-after');
          var context_line = context.append('path')
            .datum(data.badge_set_reached)
            .attr('class', 'line context-line')
            .attr('d', line2);
    
          // Plot axes
          focus.append('g')
            .attr('class', 'x axis')
            .attr('transform', 'translate(0, ' + height + ')')
            .call(x_axis)
            .selectAll('text')
            .style('text-anchor', 'end')
            // .attr('transform', 'rotate(-45)')
            //         .attr('dx', '-.5em')
            //         .attr('dy', '.5em');
    
          focus.append('g')
            .attr('class', 'y axis')
            .attr('transform', 'translate(0, 0)')
            .call(y_axis);
    
          focus.append('g')
            .attr('class', 'y2 axis')
            .attr('transform', 'translate(' + width + ', 0)')
            .call(y2_axis);
    
          context.append('g')
            .attr('class', 'navX axis')
            .attr('transform', 'translate(0, ' + navHeight + ')')
            .call(nav_x_axis);
    
          // Label axes
          svg.append('text')
            .attr('class', 'label y-axis-label')
            .attr('transform', 'rotate(-90)')
            .attr('x', 0 - ((height + margin.top) / 2))
            .attr('y', 0)
            .attr('dy', 20)
            .style('text-anchor', 'middle')
            .text('Paths Attempted');
    
          svg.append('text')
            .attr('class', 'label y2-axis-label')
            .attr('transform', 'rotate(+90)')
            .attr('y', 0 - (width + margin.left + margin.right))
            .attr('x', 0 + ((height + margin.top) / 2))
            .attr('dy', '2em')
            .style('text-anchor', 'middle')
            .text('Badge Set Reached');
    
          // Add brush to svg
          context.append('g')
            .attr('class', 'x brush')
            .call(brush)
            .selectAll("rect")
            .attr("y", -6)
            .attr("height", navHeight + 7);
    
          function brushed() {
            time.domain(brush.empty() ? navTime.domain() : brush.extent())
              .range([0, (width)]);
            x.domain(max_extent_in_days(time))
              .rangeBands([margin.left, (width)], 0.1, 0);
            focus.selectAll('.bar.stack')
              .attr('transform', function(d) {
                return "translate(" + time(d.date) + ",0)";
              })
              .attr('width', x.rangeBand());
            focus.selectAll('.rect')
              .attr('width', x.rangeBand());
            focus.selectAll('.line').attr('d', line);
            focus.select(".x.axis").call(x_axis);
          };
        })();
      </script>
    </body>
    
    </html>

    【讨论】:

    • 非常感谢。这是一个巨大的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    相关资源
    最近更新 更多