D3.v3 刷怪行为

D3.v3 Brush Strange Behavior

我正在尝试在直方图上画笔。画笔控件仅在单击事件后出现(而不是在初始页面加载时)。显然,这不是期望的行为。

如何在第一次点击事件之前在初始页面加载时实例化图表和画笔?

 // TEST Data //
 var caldata = [
 {"cal_start_yr": "1945"}, {"cal_start_yr": "1948"},
 {"cal_start_yr": "1945"}, {"cal_start_yr": "1950"},
 {"cal_start_yr": "1945"}, {"cal_start_yr": "1941"},
 {"cal_start_yr": "1944"}, {"cal_start_yr": "1949"}
 ];
// CROSSFILTER Aggregations //
 var cals = crossfilter(caldata);
 var total = cals.groupAll().reduceCount().value();
 var year = cals.dimension(function(d) {
   return d.cal_start_yr;
 });
 var countYear = year.group().reduceCount();
 var yearCount = countYear.all();

// Some helper AGGREGATION Values
 var keys = countYear.all().map(function(d) {return d.value;}),
   min = d3.min(countYear.all(), function(d) {return d.key;}),
   max = d3.max(countYear.all(), function(d) {return d.key;}),
   range = max - min;

 // Histogram dimensions
 var margin = {top: 10, right: 20, bottom: 10,left: 10 },
   height = 250 - margin.top - margin.bottom,
   width = 450 - margin.left - margin.right,
   barPadding = 5;
  
// Histogram SCALES 
 var xScale = d3.scale.linear()
   .domain([min, max])
   .range([0, width]);
 var yScale = d3.scale.linear()
   .domain([0, d3.max(countYear.all(), function(d) {return d.value;})])
   .range([height / 2, 0]);

// D3 Tool Tip
 var tip = d3.tip()
   .attr('class', 'd3-tip')
   .html(function(d) {return d.key});

// CANVAS setup //
 var histogram1 = d3.select("#histogram1").append("svg:svg")
   .attr("width", width + margin.left + margin.right)
   .attr("height", height + margin.top + margin.bottom)
   .append("g");
// Initiate Tooltip //
 histogram1.call(tip);

// DRAW Histogram //
 histogram1.selectAll("rect")
   .data(yearCount)
   .enter().append("rect")
   .attr("x", function(d) {
     return xScale(d.key) + 0.5 * (width / range)
   })
   .attr("width", width / range)
   .attr("y", function(d) {
     return yScale(d.value);
   })
   .attr("height", function(d) {
     return (height / 2 - yScale(d.value));
   })
   .attr("fill", "green")
   .attr("fill-opacity", .25)
   .attr("stroke", "white")
   .on("mouseover", tip.show)
   .on("mouseout", tip.hide);

// X AXIS //
 var xAxis = d3.svg.axis()
   .scale(xScale)
   .ticks(5)
   .orient("bottom")
   .tickFormat(d3.format("d"));
 histogram1.append("g")
   .attr("class", "axis")
   .call(xAxis)
   .attr("transform", "translate(" + margin.left + "," + height / 2 + ")");

 var brush = d3.svg.brush()
   .x(xScale)
   .extent([xScale(+1945), xScale(+1946)])
   .on("brush", function(d) {console.log(d);});

 var brushg = histogram1.append("g")
   .attr("class", "brush")
   .call(brush)

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

 brushg.selectAll(".resize")
   .append("path")
   .attr("d", resizePath);




 function resizePath(d) {
   // Style the brush resize handles. No idea what these vals do...
   var e = +(d == "e"),
     x = e ? 1 : -1,
     y = height / 4; // Relative positon if handles
   return "M" + (.5 * x) + "," + y + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6) + "V" + (2 * y - 6) + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y) + "Z" + "M" + (2.5 * x) + "," + (y + 8) + "V" + (2 * y - 8) + "M" + (4.5 * x) + "," + (y + 8) + "V" + (2 * y - 8);
 }
/*** d3-tip styles */
.as-console-wrapper { max-height: 20% !important;}

.d3-tip {
  line-height: 1.5;
  padding: 8px;
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
  border-radius: 0px;
  text-align: center;
}

.d3-tip:after {
  box-sizing: border-box;
  display: inline;
  font-size: 10px;
  width: 100%;
  line-height: 1;
  color: rgba(0, 0, 0, 0.8);
  content: "BC";
  position: absolute;
  text-align: center;
}

.d3-tip.n:after {
  top: 100%;
  left: 0;
  margin: -1px 0 0;
}


/*** D3 brush */

.brush .extent {
  stroke: #222;
  fill-opacity: .125;
  shape-rendering: crispEdges;
}
<script src="https://d3js.org/d3.v3.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>


<div id="histogram1"></div>

笔刷的范围设置为比例域的值,而不是范围!来自 docs:

The scale is typically defined as a quantitative scale, in which case the extent is in data space from the scale's domain

要设置您必须使用的初始范围

.extent([1945, 1946])

而不是

.extent([xScale(+1945), xScale(+1946)])

有关工作演示,请查看更新后的代码段:

// TEST Data //
 var caldata = [
 {"cal_start_yr": "1945"}, {"cal_start_yr": "1948"},
 {"cal_start_yr": "1945"}, {"cal_start_yr": "1950"},
 {"cal_start_yr": "1945"}, {"cal_start_yr": "1941"},
 {"cal_start_yr": "1944"}, {"cal_start_yr": "1949"}
 ];
// CROSSFILTER Aggregations //
 var cals = crossfilter(caldata);
 var total = cals.groupAll().reduceCount().value();
 var year = cals.dimension(function(d) {
   return d.cal_start_yr;
 });
 var countYear = year.group().reduceCount();
 var yearCount = countYear.all();

// Some helper AGGREGATION Values
 var keys = countYear.all().map(function(d) {return d.value;}),
   min = d3.min(countYear.all(), function(d) {return d.key;}),
   max = d3.max(countYear.all(), function(d) {return d.key;}),
   range = max - min;

 // Histogram dimensions
 var margin = {top: 10, right: 20, bottom: 10,left: 10 },
   height = 250 - margin.top - margin.bottom,
   width = 450 - margin.left - margin.right,
   barPadding = 5;
  
// Histogram SCALES 
 var xScale = d3.scale.linear()
   .domain([min, max])
   .range([0, width]);
 var yScale = d3.scale.linear()
   .domain([0, d3.max(countYear.all(), function(d) {return d.value;})])
   .range([height / 2, 0]);

// D3 Tool Tip
 var tip = d3.tip()
   .attr('class', 'd3-tip')
   .html(function(d) {return d.key});

// CANVAS setup //
 var histogram1 = d3.select("#histogram1").append("svg:svg")
   .attr("width", width + margin.left + margin.right)
   .attr("height", height + margin.top + margin.bottom)
   .append("g");
// Initiate Tooltip //
 histogram1.call(tip);

// DRAW Histogram //
 histogram1.selectAll("rect")
   .data(yearCount)
   .enter().append("rect")
   .attr("x", function(d) {
     return xScale(d.key) + 0.5 * (width / range)
   })
   .attr("width", width / range)
   .attr("y", function(d) {
     return yScale(d.value);
   })
   .attr("height", function(d) {
     return (height / 2 - yScale(d.value));
   })
   .attr("fill", "green")
   .attr("fill-opacity", .25)
   .attr("stroke", "white")
   .on("mouseover", tip.show)
   .on("mouseout", tip.hide);

// X AXIS //
 var xAxis = d3.svg.axis()
   .scale(xScale)
   .ticks(5)
   .orient("bottom")
   .tickFormat(d3.format("d"));
 histogram1.append("g")
   .attr("class", "axis")
   .call(xAxis)
   .attr("transform", "translate(" + margin.left + "," + height / 2 + ")");

 var brush = d3.svg.brush()
   .x(xScale)
   .extent([1945, 1946])
   .on("brush", function(d) {console.log(brush.extent());});

 var brushg = histogram1.append("g")
   .attr("class", "brush")
   .call(brush)

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

 brushg.selectAll(".resize")
   .append("path")
   .attr("d", resizePath);




 function resizePath(d) {
   // Style the brush resize handles. No idea what these vals do...
   var e = +(d == "e"),
     x = e ? 1 : -1,
     y = height / 4; // Relative positon if handles
   return "M" + (.5 * x) + "," + y + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6) + "V" + (2 * y - 6) + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y) + "Z" + "M" + (2.5 * x) + "," + (y + 8) + "V" + (2 * y - 8) + "M" + (4.5 * x) + "," + (y + 8) + "V" + (2 * y - 8);
 }
/*** d3-tip styles */

.d3-tip {
  line-height: 1.5;
  padding: 8px;
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
  border-radius: 0px;
  text-align: center;
}

.d3-tip:after {
  box-sizing: border-box;
  display: inline;
  font-size: 10px;
  width: 100%;
  line-height: 1;
  color: rgba(0, 0, 0, 0.8);
  content: "BC";
  position: absolute;
  text-align: center;
}

.d3-tip.n:after {
  top: 100%;
  left: 0;
  margin: -1px 0 0;
}


/*** D3 brush */

.brush .extent {
  stroke: #222;
  fill-opacity: .125;
  shape-rendering: crispEdges;
}

.as-console-wrapper { max-height: 30% !important;}
<script src="https://d3js.org/d3.v3.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>


<div id="histogram1"></div>