“NaN”当按id进行缩放和选择时 [英] "NaN" when zooming and selecting by id

查看:101
本文介绍了“NaN”当按id进行缩放和选择时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm probably doing something wrong but the following fiddle is displaying some really strange behavior:

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

在我解释之前,这里是代码:

Before I explain it, here's the code:

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)

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

So, when the page is first loaded, a rectangle will be visible in the middle. If you try scrolling on the graph, the console.log statements in the draw function will produce output. Notice that the xd: and d: statements all consist of just one object from the data set.

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

Now, if you mouseover the rectangle and try zooming again (using the scroll wheel). A bunch of NaN errors will be displayed. Now some of the d: and xd: statements will now print lists of objects.

为什么会发生这种情况?

Why is this happening? The underlying bound data never changed.

令人困惑的是,如果这些语句:

What puzzles me is that if these statements:

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

到:

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

小提琴表现正常。为什么这会产生影响?这是一个错误,还是我错过了什么?

The fiddle behaves properly. Why does this make a difference? Is this a bug, or am I missing something?

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

For googleability, here's the error I get:

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


推荐答案

用鼠标事件例程中的gMain.select/gMain.selectAll替换为d3.select(this)

The simple solution is to replace gMain.select/gMain.selectAll in the mouse event routines with d3.select(this)

复杂的解决方案似乎是单个选择将父数据绑定到如果您对现有选择进行操作,则选择任何选项。 gMain是一个现有的选择,并有3个数据值作为数组绑定到它 - console.log(gMain.datum())看到 - 所以当你做一个gMain.select(#oneoftherects)你替换单个对象在#oneoftherects与该数组,因此诀窍x,y,width,height等期望一个对象的例程。 (使用d3.select与d3不一样,不是选择)

The complicated solution seems to be that a single select binds a parents data to whatever is selected if you're acting on an existing selection. gMain is an existing selection and has the 3 data values as an array bound to it - console.log (gMain.datum()) to see - so when you do a gMain.select("#oneoftherects") you replace the single object in #oneoftherects with that array, thus knackering the x,y,width,height etc routines that expect one object. (Using d3.select doesn't do the same as d3 isn't a selection)

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

这篇关于“NaN”当按id进行缩放和选择时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆