简体   繁体   中英

D3.v3 Brush Strange Behavior

I'm trying to draw a brush on my histogram. The brush controls only appear after a click event (not on the initial page load). Obviously, not the desired behavior.

How do I instantiate the chart AND the brushes on the initial page load before the first click event?

  // 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: "\\25BC"; 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> 

The brush's extent is set to a value from the scale's domain, not its range! From the docs :

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

To set the initial extent you have to use

.extent([1945, 1946])

instead of

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

For a working demo have a look at the updated snippet:

 // 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: "\\25BC"; 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> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM