按钮单击时删除D3画笔

时间:2014-07-13 00:04:09

标签: d3.js brush

我正在努力解决在条形图上没有正确移除画笔的问题。您可以看到Bl.ock here并查看哪些内容无效。

简而言之,画笔会突出显示画笔选择的条形,以及捕捉到矩形边缘以便更容易选择时间跨度(这里有一个次要错误,即画笔捕捉不太明显)正确映射到日期 - 如果您尝试将画笔绘制到条形图的边缘,您将看到这一点。一路上的某个地方(可能是直接对齐?)背景点击删除画笔功能停止工作(它现在选择一年的跨度,虽然没有正确突出显示矩形)。为了方便用户,我想添加一个按钮,用户可以在完成后单击以删除画笔(下面的resetBrush()功能)。

我的理解是可以使用brush.extent()清除画笔选择,但是当您清除范围时,则必须重绘画笔。我以为我正确地做到了这一点,但是唉,我遇到了一些我无法追查的问题。关于我绊倒的任何指示都将非常感激!

代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

body {
  font-family: sans-serif;
  color: #000;
  text-rendering: optimizeLegibility;
}

.barchart {
  z-index: 30;
  display: block;
  visibility: visible;
  position: relative;
  padding-top: 15px;
  margin-top: 15px;

}

.axis {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.x.axis path {
  display: none;
}

.resize path {
  fill: #666;
  fill-opacity: .8;
  stroke: #000;
  stroke-width: 1.5px;
}

.brush .extent {
  stroke: #fff;
  stroke-opacity: .6;
  stroke-width: 2px;
  fill-opacity: .1;
  shape-rendering: crispEdges;
}

</style>

<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/d3.geo.projection.v0.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>

var margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = 960 - margin.left - margin.right,
    height = 200 - margin.top - margin.bottom;

brushYearStart = 1848;
brushYearEnd = 1905;

// Scales
var x = d3.scale.ordinal().rangeRoundBands([0, width - 60], .1);
var y = d3.scale.linear().range([height, 0]);

// Prepare the barchart canvas
var barchart = d3.select("body").append("svg")
    .attr("class", "barchart")
    .attr("width", "100%")
.attr("height", height + margin.top + margin.bottom)
    .attr("y", height - height - 100)
    .append("g");

var z = d3.scale.ordinal().range(["steelblue", "indianred"]);

var brushYears = barchart.append("g")
brushYears.append("text")
    .attr("id", "brushYears")
    .classed("yearText", true)
    .text(brushYearStart + " - " + brushYearEnd)
    .attr("x", 35)
    .attr("y", 12);

d3.csv("years_count.csv", function (error, post) {

    // Coercion since CSV is untyped
    post.forEach(function (d) {
        d["frequency"] = +d["frequency"];
        d["frequency_discontinued"] = +d["frequency_discontinued"];
        d["year"] = d3.time.format("%Y").parse(d["year"]).getFullYear();
    });

    var freqs = d3.layout.stack()(["frequency", "frequency_discontinued"].map(function (type) {
        return post.map(function (d) {
            return {
                x: d["year"],
                y: +d[type]
            };
        });
    }));

    x.domain(freqs[0].map(function (d) {
        return d.x;
    }));
    y.domain([0, d3.max(freqs[freqs.length - 1], function (d) {
        return d.y0 + d.y;
    })]);

    // Axis variables for the bar chart
    x_axis = d3.svg.axis().scale(x).tickValues([1850, 1855, 1860, 1865, 1870, 1875, 1880, 1885, 1890, 1895, 1900]).orient("bottom");
    y_axis = d3.svg.axis().scale(y).orient("right");

    // x axis
    barchart.append("g")
        .attr("class", "x axis")
        .style("fill", "#000")
        .attr("transform", "translate(0," + height + ")")
        .call(x_axis);

    // y axis
    barchart.append("g")
        .attr("class", "y axis")
        .style("fill", "#000")
        .attr("transform", "translate(" + (width - 85) + ",0)")
        .call(y_axis);

    // Add a group for each cause.
    var freq = barchart.selectAll("g.freq")
        .data(freqs)
      .enter().append("g")
        .attr("class", "freq")
        .style("fill", function (d, i) {
            return z(i);
        })
        .style("stroke", "#CCE5E5");

    // Add a rect for each date.
    rect = freq.selectAll("rect")
        .data(Object)
      .enter().append("rect")
        .attr("class", "bar")
        .attr("x", function (d) {
            return x(d.x);
        })
        .attr("y", function (d) {
            return y(d.y0) + y(d.y) - height;
        })
        .attr("height", function (d) {
            return height - y(d.y);
        })
        .attr("width", x.rangeBand())
        .attr("id", function (d) {
            return d["year"];
        });

    // Draw the brush
    brush = d3.svg.brush()
        .x(x)
        .on("brush", brushmove)
        .on("brushend", brushend);

    var arc = d3.svg.arc()
      .outerRadius(height / 15)
      .startAngle(0)
      .endAngle(function(d, i) { return i ? -Math.PI : Math.PI; });

    brushg = barchart.append("g")
      .attr("class", "brush")
      .call(brush);

    brushg.selectAll(".resize").append("path")
        .attr("transform", "translate(0," +  height / 2 + ")")
        .attr("d", arc);

    brushg.selectAll("rect")
        .attr("height", height);

});

// ****************************************
// Brush functions
// ****************************************

function brushmove() {
    y.domain(x.range()).range(x.domain()).clamp(true);
    b = brush.extent();

    brushYearStart = Math.ceil(y(b[0]));
    brushYearEnd = Math.ceil(y(b[1]));

    // Snap to rect edge
    d3.select("g.brush").call(brush.extent([y.invert(brushYearStart), y.invert(brushYearEnd)]));

    // Fade all years in the histogram not within the brush
    d3.selectAll("rect.bar").style("opacity", function (d, i) {
      return d.x >= brushYearStart && d.x < brushYearEnd ? "1" : ".4"
  });
}

function brushend() {

  // Additional calculations happen here...
  // filterPoints();
  // colorPoints();
  // styleOpacity();

  // Update start and end years in upper right-hand corner of the map
  d3.select("#brushYears").text(brushYearStart + " - " + brushYearEnd);

}

function resetBrush() {
  d3.selectAll(".brush").remove();
  d3.selectAll("brushg.resize").remove();
  brush.clear();
  brushg.call(brush);
}

</script>

<div id="resetMap">
    <button
      id="returnBrush"
      class="btn btn-default"
      onclick="resetBrush()"/>Remove Brush
</div>

</body>
</html>

2 个答案:

答案 0 :(得分:1)

如果您执行d3.selectAll(".brush").remove();,则会删除<g class="brush"></g>及其孩子。 这个d3.selectAll("brushg.resize").remove();是一个错误。必须为brushg.selectAll(".resize").remove();,但与d3.selectAll(".brush").remove();相同。

你必须这样做:

  1. 要重置brush.extent()并触发brush事件。

    function resetBrush() {
      brush
        .clear()
        .event(d3.select(".brush"));
    }
    
  2. #brushYears重置为初始状态

    function brushend() {
      var localBrushYearStart = (brush.empty()) ? brushYearStart : Math.ceil(y(b[0])),
          localBrushYearEnd = (brush.empty()) ? brushYearEnd : Math.ceil(y(b[1]));
    
      // Update start and end years in upper right-hand corner of the map
      d3.select("#brushYears").text(localBrushYearStart + " - " + localBrushYearEnd);
    }
    
  3. 要重置为brush事件

    上的初始值
    function brushmove() {
      y.domain(x.range()).range(x.domain()).clamp(true);
      b = brush.extent();
    

    3.1。要将localBrushYearStartlocalBrushYearEnd变量设置为brush.empty()上的初始状态或设置为Math.ceil(brush.extent()))

      var localBrushYearStart = (brush.empty()) ? brushYearStart : Math.ceil(y(b[0])),
        localBrushYearEnd = (brush.empty()) ? brushYearEnd : Math.ceil(y(b[1]));
    

    3.2。在选择时执行brush.extent(),或在brush.clear()

    上执行brush.empty()
      // Snap to rect edge
      d3.select("g.brush").call((brush.empty()) ? brush.clear() : brush.extent([y.invert(localBrushYearStart), y.invert(localBrushYearEnd)]));
    

    3.3。在opacity=1或选择上设置brush.empty()年,在未选定年份设置opacity=.4

      // Fade all years in the histogram not within the brush
      d3.selectAll("rect.bar").style("opacity", function(d, i) {
        return d.x >= localBrushYearStart && d.x < localBrushYearEnd || brush.empty() ? "1" : ".4";
      });
    }
    
  4. 检查BL.OCKS

    上的更正

答案 1 :(得分:0)

就这样做

function resetBrush() {
   d3.select("g.brush").call(brush.extent([0, 0]))
   d3.selectAll("rect.bar").style("opacity", "0.4");
   //reset year labels at top
}