" NaN的"当缩放并按id选择时

时间:2016-01-18 21:36:17

标签: javascript d3.js

我可能做错了,但下面的小提琴显示出一些非常奇怪的行为:

https://jsfiddle.net/pkerpedjiev/42w01t3e/8/

在我解释之前,请参阅以下代码:

function skiAreaElevationsPlot() {
  var width = 550;
  var height = 400;
  var margin = {
    'top': 30,
    'left': 30,
    'bottom': 30,
    'right': 40
  };

  function chart(selection) {
    selection.each(function(data) {
      // Select the svg element, if it exists.
      var svg = d3.select(this).selectAll("svg").data([data]);

      // Otherwise, create the skeletal chart.
      var gEnter = svg.enter().append("svg").append("g");

      svg.attr('width', width)
        .attr('height', height);

      var zoom = d3.behavior.zoom()
        .on("zoom", draw);

      data = Object.keys(data).map(function(key) {
        return data[key];
      }).sort(function(a, b) {
        return b.max_elev - a.max_elev;
      });

      svg.insert("rect", "g")
        .attr("class", "pane")
        .attr("width", width)
        .attr("height", height)
        .attr('pointer-events', 'all')
        .call(zoom);

      var yScale = d3.scale.linear()
        .domain([0, d3.max(data.map(function(d) {
          return d.max_elev;
        }))])
        .range([height - margin.top - margin.bottom, 0]);

      var xScale = d3.scale.linear()
        .domain([0, data.length])
        .range([0, width - margin.left - margin.right]);

      var widthScale = d3.scale.linear()
        .domain(d3.extent(data.map(function(d) {
          return d.area;
        })))
        .range([10, 30]);

      zoom.x(xScale).scaleExtent([1, data.length / 30]);

      var gMain = gEnter.append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

      gMain.append("clipPath")
        .attr("id", "clip")
        .append("rect")
        .attr("x", 0)
        .attr("y", 0)
        .attr("width", width - margin.left - margin.right)
        .attr("height", height - margin.top - margin.bottom);

      function skiAreaMouseover(d) {
        gMain.select('#n-' + d.uid)
          .attr('visibility', 'visible');
      }

      function skiAreaMouseout(d) {
        gMain.select('#n-' + d.uid)
          .attr('visibility', 'visible');
      }

      // the rectangle showing each rect
      gMain.selectAll('.resort-rect')
        .data(data)
        .enter()
        .append('rect')
        .classed('resort-rect', true)
        .attr("clip-path", "url(#clip)")
        .attr('id', function(d) {
          return 'n-' + d.uid;
        })
        .on('mouseover', skiAreaMouseover)
        .on('mouseout', skiAreaMouseout);

      var gYAxis = svg.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate(" + (width - margin.right) + "," + margin.top + ")");

      var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient("right")
        .tickSize(-(width - margin.left - margin.right))
        .tickPadding(6);

      gYAxis.call(yAxis);

      draw();

      function draw() {
        function scaledX(d, i) {
         console.log('xd', d);
          return xScale(i);
        }

        function rectWidth(d, i) {
          return widthScale(d.area);
        }

        gMain.selectAll('.resort-rect')
          .attr('x', scaledX)
          .attr('y', function(d) {
           console.log('d', d);
            return yScale(d.max_elev);
          })
          .attr('width', 20)
          .attr('height', function(d) {
            console.log('d:', d)
            return yScale(d.min_elev) - yScale(d.max_elev);
          })
          .classed('resort-rect', true);
      }
    });
  }

  chart.width = function(_) {
    if (!arguments.length) return width;
    width = _;
    return chart;
  };

  chart.height = function(_) {
    if (!arguments.length) return height;
    height = _;
    return chart;
  };

  return chart;
}

var elevationsPlot = skiAreaElevationsPlot()
  .width(550)
  .height(300);

data = [{
  "min_elev": 46,
  "max_elev": 54,
  "uid": "9809641c-ab03-4dec-8d51-d387c7e4f114",
  "num_lifts": 1,
  "area": "0.00"
}, {
  "min_elev": 1354,
  "max_elev": 1475,
  "uid": "93eb6ade-8d78-4923-9806-c8522578843f",
  "num_lifts": 1,
  "area": "0.00"
}, {
  "min_elev": 2067,
  "max_elev": 2067,
  "uid": "214fdca9-ae62-473b-b463-0ba3c5755476",
  "num_lifts": 1,
  "area": "0.00"
}];

d3.select('#ski-area-elevations')
  .datum(data)
  .call(elevationsPlot)

因此,首次加载页面时,中间会显示一个矩形。如果您尝试在图表上滚动,console.log函数中的draw语句将生成输出。请注意,xd:d:语句都只包含数据集中的一个对象。

现在,如果您将鼠标悬停在矩形上并再次尝试缩放(使用滚轮)。将显示一堆NaN错误。现在,一些d:xd:语句现在将打印对象列表。

为什么会这样?底层绑定数据从未改变过。

令我困惑的是,如果这些陈述:

gMain.select('#n-' + d.uid)

更改为:

gMain.selectAll('#n-' + d.uid)

小提琴表现得很好。为什么这会有所不同?这是一个错误,还是我错过了什么?

对于googleability,这是我得到的错误:

Error: Invalid value for <rect> attribute y="NaN"

1 个答案:

答案 0 :(得分:1)

简单的解决方案是用d3.select替换鼠标事件例程中的gMain.select/gMain.selectAll(this)

复杂的解决方案似乎是,如果您正在对现有选择进行操作,则单个选择会将父数据绑定到所选的任何内容。 gMain是一个现有的选择,并且有3个数据值作为绑定到它的数组 - console.log(gMain.datum())来查看 - 所以当你执行gMain.select时(&#34;#oneoftherects&#34;)将#oneoftherects中的单个对象替换为该数组,从而解决了期望一个对象的x,y,width,height等例程。 (使用d3.select并不像d3那样做选择)

http://bost.ocks.org/mike/selection/#non-grouping