在D3中创建缩放功能

时间:2019-05-26 17:28:34

标签: javascript d3.js

我有一个功能,当按下一个按钮时(几个按钮代表几种动物类型),该动物类型SVG会用其相应的数据进行更新。我正在尝试复制this zoom函数,但是在用代码实现该函数时遇到了问题。像这样在全球范围内使用的几种SVG(每种动物一种):

let x = d3.scaleLinear()
  .domain([0, 1000])
  .range([ 0, width ]);

var xAxis = d3.axisBottom(x);

svgReptile.append("g")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)

const yAxis = d3.scaleLinear()
  .domain([0, 220])
  .range([ height, 0])

svgReptile.append("g")
  .call(d3.axisLeft(yAxis))

按下其中一个动物按钮时,将调用以下功能。

 function update(animal, whatSVG, xAxis, yAxis, color) {   

      const points = whatSVG
        .selectAll("circle")
        .data(data);

      points.enter()
        .append("circle")
        .attr("cx", function(d) {
          return xAxis(d.state);
        })
        .attr("cy", function(d) {
          return yAxis(d.percentage);
        })
        .merge(points)
        .attr("r", 3)
        .attr("cx", function(d) {
          return xAxis(d.decade)
        })
        .attr("cy", function(d) {
          return yAxis(d.count)
        })
        .style("fill", function (d) { return colour(d.animal) } );

      points.exit()
        .attr('r', 0)
        .remove();

    }

问题:

如何实现缩放功能(如上面链接的那样)在放大(或类似结果)时扩展x轴?

1 个答案:

答案 0 :(得分:1)

我认为您正在寻找问题最后一行的“画笔缩放”。

以下源代码(来自d3 graph gallery

中的示例)

十字准线允许您选择要扩展的区域。如果您单击该链接,则其上方将有一个标题为“用轴缩放”的图形,但是它没有按照您所描述的方式进行缩放,它只是移动了该轴,而没有使用它来放大图形内容。也许两者都会有用!

希望这会有所帮助

// set the dimensions and margins of the graph
var margin = {top: 10, right: 20, bottom: 20, left: 20},
    width = 500 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var Svg = d3.select("#brushZoom")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/iris.csv", function(data) {

  // Add X axis
  var x = d3.scaleLinear()
    .domain([4, 8])
    .range([ 0, width ]);
  var xAxis = Svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  // Add Y axis
  var y = d3.scaleLinear()
    .domain([0, 9])
    .range([ height, 0]);
  Svg.append("g")
    .call(d3.axisLeft(y));

  // Add a clipPath: everything out of this area won't be drawn.
  var clip = Svg.append("defs").append("svg:clipPath")
      .attr("id", "clip")
      .append("svg:rect")
      .attr("width", width )
      .attr("height", height )
      .attr("x", 0)
      .attr("y", 0);

  // Color scale: give me a specie name, I return a color
  var color = d3.scaleOrdinal()
    .domain(["setosa", "versicolor", "virginica" ])
    .range([ "#440154ff", "#21908dff", "#fde725ff"])

  // Add brushing
  var brush = d3.brushX()                 // Add the brush feature using the d3.brush function
      .extent( [ [0,0], [width,height] ] ) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
      .on("end", updateChart) // Each time the brush selection changes, trigger the 'updateChart' function

  // Create the scatter variable: where both the circles and the brush take place
  var scatter = Svg.append('g')
    .attr("clip-path", "url(#clip)")

  // Add circles
  scatter
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
      .attr("cx", function (d) { return x(d.Sepal_Length); } )
      .attr("cy", function (d) { return y(d.Petal_Length); } )
      .attr("r", 8)
      .style("fill", function (d) { return color(d.Species) } )
      .style("opacity", 0.5)

  // Add the brushing
  scatter
    .append("g")
      .attr("class", "brush")
      .call(brush);

  // A function that set idleTimeOut to null
  var idleTimeout
  function idled() { idleTimeout = null; }

  // A function that update the chart for given boundaries
  function updateChart() {

    extent = d3.event.selection

    // If no selection, back to initial coordinate. Otherwise, update X axis domain
    if(!extent){
      if (!idleTimeout) return idleTimeout = setTimeout(idled, 350); // This allows to wait a little bit
      x.domain([ 4,8])
    }else{
      x.domain([ x.invert(extent[0]), x.invert(extent[1]) ])
      scatter.select(".brush").call(brush.move, null) // This remove the grey brush area as soon as the selection has been done
    }

    // Update axis and circle position
    xAxis.transition().duration(1000).call(d3.axisBottom(x))
    scatter
      .selectAll("circle")
      .transition().duration(1000)
      .attr("cx", function (d) { return x(d.Sepal_Length); } )
      .attr("cy", function (d) { return y(d.Petal_Length); } )

    }



})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>



<div id="brushZoom"></div>