无法放大堆积的条形图d3.js V4

时间:2018-07-10 15:44:50

标签: javascript d3.js

我尝试使用d3.js v4用画笔和缩放功能构建一个堆叠的条形图,我能够渲染图表以及画笔。但是,当尝试放大时,仅轴发生变化,实际图形保持不变。我在这里附上摘要。

参考:https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172

谢谢您的帮助。

<!DOCTYPE html>
<meta charset="utf-8">
<style>
   
    .zoom {
      cursor: move;
      fill: none;
      pointer-events: all;
    }
       
    .axis {
      stroke-width: 0.5px;
      stroke: #888;
      font: 10px avenir next, sans-serif;
    }
    
    .axis > path {
      stroke: #888;
    }

</style>


<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var margin = {top: 20, right: 20, bottom: 90, left: 50},
    margin2 = {top: 230, right: 20, bottom: 30, left: 50},
    width = 960 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom,
    height2 = 300 - margin2.top - margin2.bottom;

var parseTime = d3.timeParse("%Y-%m-%d");

var x = d3.scaleTime().range([0, width]),
    x2 = d3.scaleTime().range([0, width]),
    y = d3.scaleLinear().range([height, 0]),
    y2 = d3.scaleLinear().range([height2, 0]);
    z = d3.scaleOrdinal().range(["#a54300","#ec983d", "#ecc43d", "#f9ec86","#cbe989"]);


var xAxis = d3.axisBottom(x),
    xAxis2 = d3.axisBottom(x2),
    yAxis = d3.axisLeft(y);

var brush = d3.brushX()
    .extent([[0, 0], [width, height2]])
    .on("brush", brushed);

var zoom = d3.zoom()
    .scaleExtent([1, Infinity])
    .translateExtent([[0, 0], [width, height]])
    .extent([[0, 0], [width, height]])
    .on("zoom", zoomed);

var svg = d3.select("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);


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(" + margin2.left + "," + margin2.top + ")");


d3.csv("https://gist.githubusercontent.com/Udayshan07/320ea33bacc3e04f9bd77538007527a0/raw/06e65434349e63ed6cf85c4d3e9cb383e888010c/sp500.csv", function(d, i, columns) {
  for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
  d.total = t;
  return d;
}, function(error, data) {
  if (error) throw error;
  
  data.forEach(function(d) {
    d.Week_Num = parseTime(d.Week_Num);
  });

  var xMin = d3.min(data, function(d) { return d.Week_Num; });
  var yMax = Math.max(20, d3.max(data, function(d) { return d.total; }));
  var keys = data.columns.slice(1);
  var data = d3.stack().keys(keys)(data);

  x.domain([xMin, new Date()]);
  y.domain([0, yMax]);
  x2.domain(x.domain());
  y2.domain(y.domain())
  z.domain(keys);
 
  var messages = focus.append("g");
    messages.selectAll("message")
        .data(data)
        .enter().append("g")
        .attr("fill", function(d) { return z(d.key); })	  
        .selectAll("rect")
        .data(function(d) { return d; })
        .enter().append("rect")
        .attr("x", function(d) { return x(d.data.Week_Num); })
        .attr("y", function(d) { return y(d[1]); })
        .attr("height", function(d) { return y(d[0]) - y(d[1]); })
        .attr("width", 15)
	    .on("mouseover", function() { tooltip.style("display", null); })
        .on("mouseout", function() { tooltip.style("display", "none"); })
        .on("mousemove", function(d) {
            console.log(d);
            var xPosition = d3.mouse(this)[0] - 5;
            var yPosition = d3.mouse(this)[1] - 5;
            tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
            tooltip.select("text").text(d[1]-d[0]);
        });

  focus.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis.ticks(10))
      .selectAll("text")	
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        

  focus.append("g")
      .attr("class", "axis axis--y")
      .call(yAxis);

  svg.append("rect")
    .attr("class", "zoom")
    .attr("width", width)
    .attr("height", height)
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .call(zoom);
 
  context.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height2 + ")")
      .call(xAxis2)
      .selectAll("text")	
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        .attr("transform", "rotate(-65)");


  context.append("g")
      .attr("class", "brush")
      .call(brush)
      .call(brush.move, x.range());

  
});

function brushed() {
    //console.log('Brush 1');
  if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
   // console.log('Brush 2');
  var s = d3.event.selection || x2.range();
  x.domain(s.map(x2.invert, x2));
  focus.selectAll(".message")
        .attr("x", function(d) { return x(d.Week_Num); })
        .attr("y", function(d) { colsole.log("Brush" + y(d[1])); return  y(d[1]); });
  focus.select(".axis--x").call(xAxis);
  svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
      .scale(width / (s[1] - s[0]))
      .translate(-s[0], 0));
}

function zoomed() {
  //  console.log('Zoom 1');
  if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; 
  // ignore zoom-by-brush
//    console.log('Zoom 2');
  var t = d3.event.transform;
  x.domain(t.rescaleX(x2).domain());
  focus.selectAll(".message")
        .attr("x", function(d) { return x(d.Week_Num); })
        .attr("y", function(d) {  colsole.log("Zoom" + y(d[1])); return  y(d[1]);});
  focus.select(".axis--x").call(xAxis);
  context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}

var tooltip = svg.append("g")
    .attr("class", "tooltip")
    .style("display", "none");
      
  tooltip.append("rect")
    .attr("width", 60)
    .attr("height", 20)
    .attr("fill", "white")
    .style("opacity", 0.5);

  tooltip.append("text")
    .attr("x", 30)
    .attr("dy", "1.2em")
    .style("text-anchor", "middle")
    .attr("font-size", "12px")
    .attr("font-weight", "bold");

</script>

1 个答案:

答案 0 :(得分:0)

关于该问题,您有两个主要问题:

  1. 您没有在缩放/拖动事件上选择任何内容:

在缩放/拖动功能中:

 focus.selectAll(".message")
    .attr("x", function(d) { return x(d.Week_Num); })
    .attr("y", function(d) { colsole.log("Brush" + y(d[1])); return  y(d[1]); });

没有项目具有类message,因此这是一个空选择-这就是为什么命令colsole.log不会触发错误,也永远不会运行的原因。您可以只选择焦点选择中的所有rect(或为每个矩形提供消息类别)。 此外,您无需重新定位y值,也无需重新缩放y值,因此它可以保持不变,我已在下面的代码段中将其删除了

一旦更改,我们就会遇到问题2。

  1. 您已更改了传递x刻度的值。最初给每个rect使用x属性时,使用的是x(d.data.Week_Num);,但是在拖动/缩放功能中使用的是x(d.Week_Num);,这很容易固定。这给了我们

var margin = {top: 20, right: 20, bottom: 90, left: 50},
    margin2 = {top: 230, right: 20, bottom: 30, left: 50},
    width = 960 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom,
    height2 = 300 - margin2.top - margin2.bottom;

var parseTime = d3.timeParse("%Y-%m-%d");

var x = d3.scaleTime().range([0, width]),
    x2 = d3.scaleTime().range([0, width]),
    y = d3.scaleLinear().range([height, 0]),
    y2 = d3.scaleLinear().range([height2, 0]);
    z = d3.scaleOrdinal().range(["#a54300","#ec983d", "#ecc43d", "#f9ec86","#cbe989"]);


var xAxis = d3.axisBottom(x),
    xAxis2 = d3.axisBottom(x2),
    yAxis = d3.axisLeft(y);

var brush = d3.brushX()
    .extent([[0, 0], [width, height2]])
    .on("brush", brushed);

var zoom = d3.zoom()
    .scaleExtent([1, Infinity])
    .translateExtent([[0, 0], [width, height]])
    .extent([[0, 0], [width, height]])
    .on("zoom", zoomed);

var svg = d3.select("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);


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(" + margin2.left + "," + margin2.top + ")");


d3.csv("https://gist.githubusercontent.com/Udayshan07/320ea33bacc3e04f9bd77538007527a0/raw/06e65434349e63ed6cf85c4d3e9cb383e888010c/sp500.csv", function(d, i, columns) {
  for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
  d.total = t;
  return d;
}, function(error, data) {
  if (error) throw error;
  
  data.forEach(function(d) {
    d.Week_Num = parseTime(d.Week_Num);
  });

  var xMin = d3.min(data, function(d) { return d.Week_Num; });
  var yMax = Math.max(20, d3.max(data, function(d) { return d.total; }));
  var keys = data.columns.slice(1);
  var data = d3.stack().keys(keys)(data);

  x.domain([xMin, new Date()]);
  y.domain([0, yMax]);
  x2.domain(x.domain());
  y2.domain(y.domain())
  z.domain(keys);
 
  var messages = focus.append("g");
    messages.selectAll("message")
        .data(data)
        .enter().append("g")
        .attr("fill", function(d) { return z(d.key); })	  
        .selectAll("rect")
        .data(function(d) { return d; })
        .enter().append("rect")
        .attr("x", function(d) { return x(d.data.Week_Num); })
        .attr("y", function(d) { return y(d[1]); })
        .attr("height", function(d) { return y(d[0]) - y(d[1]); })
        .attr("width", 15)
	    .on("mouseover", function() { tooltip.style("display", null); })
        .on("mouseout", function() { tooltip.style("display", "none"); })
        .on("mousemove", function(d) {
            console.log(d);
            var xPosition = d3.mouse(this)[0] - 5;
            var yPosition = d3.mouse(this)[1] - 5;
            tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
            tooltip.select("text").text(d[1]-d[0]);
        });

  focus.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis.ticks(10))
      .selectAll("text")	
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        

  focus.append("g")
      .attr("class", "axis axis--y")
      .call(yAxis);

  svg.append("rect")
    .attr("class", "zoom")
    .attr("width", width)
    .attr("height", height)
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .call(zoom);
 
  context.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height2 + ")")
      .call(xAxis2)
      .selectAll("text")	
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        .attr("transform", "rotate(-65)");


  context.append("g")
      .attr("class", "brush")
      .call(brush)
      .call(brush.move, x.range());

  
});

function brushed() {
  if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
  var s = d3.event.selection || x2.range();
  x.domain(s.map(x2.invert, x2));
  
  focus.selectAll("rect")
        .attr("x", function(d) { return x(d.data.Week_Num); })
		
  focus.select(".axis--x").call(xAxis);
  svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
      .scale(width / (s[1] - s[0]))
      .translate(-s[0], 0));
}

function zoomed() {
  if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; 
  var t = d3.event.transform;
  x.domain(t.rescaleX(x2).domain());
  
  focus.selectAll("rect")
        .attr("x", function(d) { return x(d.data.Week_Num); });
		
  focus.select(".axis--x").call(xAxis);
  context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}

var tooltip = svg.append("g")
    .attr("class", "tooltip")
    .style("display", "none");
      
  tooltip.append("rect")
    .attr("width", 60)
    .attr("height", 20)
    .attr("fill", "white")
    .style("opacity", 0.5);

  tooltip.append("text")
    .attr("x", 30)
    .attr("dy", "1.2em")
    .style("text-anchor", "middle")
    .attr("font-size", "12px")
    .attr("font-weight", "bold");
    .zoom {
      cursor: move;
      fill: none;
      pointer-events: all;
    }
       
    .axis {
      stroke-width: 0.5px;
      stroke: #888;
      font: 10px avenir next, sans-serif;
    }
    
    .axis > path {
      stroke: #888;
    }
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>

该问题并未解决对剪切路径的需求,因此我没有将其包含在答案中,但是关于该主题的问题很多,例如{{3} }。几天前。