d3.mouse(this) возвращает неперехваченную ошибку типа: не удается прочитать свойство ‘sourceEvent’ из нулевого стека

#javascript #d3.js #svg

#javascript #d3.js #svg

Вопрос:

У меня есть диаграмма bar line symbol, которая преобразуется, когда пользователи нажимают ось y для переключения между linear и sqrt. http://bl.ocks.org/jebeck/9457536. это отлично работает с одним svg, но когда на одной веб-странице более одного svg, это может работать только с одним из svg (ов); на остальных svg (ах) строки и символы перемещаются в одну точку, потому что значения x не являются числом. отладка показывает, что d3.mouse(invisibleRect.node()) получает неперехваченную ошибку типа: не удается прочитать свойство ‘sourceEvent’ из null. Я подозреваю, что это связано с приоритетом последнего элемента, когда на одной странице более одного svg-элемента, но я просто пытаюсь найти хорошее решение. Спасибо.

 d3.csv("data13.csv", function (error, data) {
  if (error) throw error;
  if (data.length == 0) {
    svg.append("text").text("data is empty");
    throw "No Input";
  }

  var attributeName = d3.keys(data[0])[0];
  var metricList = d3.keys(data[0]).slice(1);
  var target = metricList[metricList.length - 1];

  data.forEach(function (d) {
    var maxData = d3.max(data, function (d) { return d3.max(metricList.map(function (name) { return  d[name]; })); });
    var minData = d3.min(data, function (d) { return d3.min(metricList.map(function (name) { return  d[name]; })); });

    x0.domain(metricList);
    x1.domain(data.map(function (d) { return d[attributeName]; })).rangeRoundBands([0, x0.rangeBand()]);
    y.domain([Math.min(0, minData) * space_to_top, Math.max(0, maxData) * space_to_top]);

    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0,"   height   ")")
      .call(xAxis);

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

    var drawBars = svg.selectAll(".bars")
      .data(metricList)
      .enter().append("g")
      .attr("class", "bargroup")
      .attr("transform", function (name) { return "translate("   x0(name)   ",0)"; });

    drawBars.selectAll("rect")
      .data(function (metricName) {
        return data.map(function (d) {
          return {
            name: d[attributeName],
            value:  d[metricName],
            title: metricName
          };
        });
      })
      .enter().append("rect")
      .attr("width", x1.rangeBand())
      .attr("x", function (d) { return x1(d.name); })
      .attr("y", function (d) { return y(Math.max(0, d.value)); })
      .attr("height", function (d) { return Math.abs(y(d.value) - y(0)); })
      .style("fill", function (d) { return color(d.name); })
      .on("mouseover", function (d) {
        d3.select(this).style("fill", "red");
      })
      .on("mouseout", function (d) {
        d3.select(this).style("fill", color(d.name));
      })
      .append("title")
      .text(function (d) {
        return attributeName   ": "   d.name
            "nCategory: "   d.title
            "nValue: "   d.value;
      });

    data.forEach(function (d, i) {
      var lineFunction = d3.svg.line()
        .x(function (k) { return x0(k)   x1(d[attributeName])   x1.rangeBand() / 2; })
        .y(function (k) { return y( d[target]); });

      svg.append("path")
        .attr("class", "targetLine"   i)
        .attr("d", lineFunction(metricList))
        .style("stroke", "#959595")
        .style("stroke-width", 1);

      // create symbols along the line
      svg.append("g")
        .selectAll("path")
        .data(metricList)
        .enter()
        .append("path")
        .attr("class", "symbol"   i)
        .attr("transform", function (k) {
          return "translate("   (x0(k)   x1(d[attributeName])   x1.rangeBand() / 2)   ","
              y( d[target])   ")";
        })
        .attr("d", d3.svg.symbol()
          .type(symbol(d[attributeName]))
          .size(64))
        .style("fill", color(d[attributeName]))
        .style("stroke", "000000")
        .on("mouseover", function (k) {
          d3.select(this).attr("d", d3.svg.symbol().type(symbol(d[attributeName])).size(180));
        })
        .on("mouseout", function (k) {
          d3.select(this).attr("d", d3.svg.symbol().type(symbol(d[attributeName])).size(64));
        })
        .append("title")
        .text(target   " for "   d[attributeName]   ": "   d[target]);
    });
    // toggle between linear and sqrt y axis

    var sqrtScale = d3.scale.sqrt().clamp(true).range([height, 0]);
    sqrtScale.domain([
      Math.min(0, minData) * space_to_top, 
      Math.max(0, maxData) * space_to_top
    ]);

    var sqrtAxis = d3.svg.axis().scale(sqrtScale).orient('left');
    var log = false;
    var transitionDuration = 500;

    var lineFunction_sqrt = d3.svg.line()
      .x(function (k) { return x0(k)   x1(data[i][attributeName])   x1.rangeBand() / 2; })
      .y(function (k) { return sqrtScale( data[i][target]); });

    var lineFunction_linear = d3.svg.line()
      .x(function (k) { return x0(k)   x1(data[i][attributeName])   x1.rangeBand() / 2; })
      .y(function (k) { return y( data[i][target]); });

    invisibleRect = svg.append('rect')
      .attr({
        'x': -margin.left,
        'y': 0,
        'height': height,
        'width': margin.left,
        'fill': '#FFFFFF',
        'opacity': 0.0,
        'id': 'invisibleRect'
      });

    invisibleRect.on('click', function () {
      try {
        hoverHelp.remove();
      }
      catch (ReferenceError) {
        console.log("There's no hoverHelp right now.");
      }
      if (!log) {
        svg.select('.y.axis')
          .transition()
          .duration(transitionDuration)
          .call(sqrtAxis);
        drawBars.selectAll("rect")
          .transition()
          .duration(transitionDuration)
          .attr("y", function (d) { return sqrtScale(Math.max(0, d.value)); })
          .attr("height", function (d) { return Math.abs(sqrtScale(d.value) - sqrtScale(0)); });

        for (i = 0; i < data.length; i  ) {
          svg.select(".targetLine"   i)
            .transition()
            .duration(transitionDuration)
            .attr("d", lineFunction_sqrt(metricList, i));
        };

        for (i = 0; i < data.length; i  ) {
          svg.selectAll(".symbol"   i)
            .transition()
            .duration(transitionDuration)
            .attr("transform", function (k) {
              return "translate("   (x0(k)   x1(data[i][attributeName])   x1.rangeBand() / 2)   ","
                  sqrtScale( data[i][target])   ")";
            });
        };

        log = true;

      } else {
        svg.select('.y.axis')
          .transition()
          .duration(transitionDuration)
          .call(yAxis);

        drawBars.selectAll("rect")
          .transition()
          .duration(transitionDuration)
          .attr("y", function (d) { return y(Math.max(0, d.value)); })
          .attr("height", function (d) { return Math.abs(y(d.value) - y(0)); });

        for (i = 0; i < data.length; i  ) {
          svg.select(".targetLine"   i)
            .transition()
            .duration(transitionDuration)
            .attr("d", lineFunction_linear(metricList, i));
         };

        for (i = 0; i < data.length; i  ) {
          svg.selectAll(".symbol"   i)
            .transition()
            .duration(transitionDuration)
            .attr("transform", function (k) {
              return "translate("   (x0(k)   x1(data[i][attributeName])   x1.rangeBand() / 2)   ","
                  y( data[i][target])   ")";
            });
        };

        log = false;
      }
    });

    invisibleRect.on('mouseover', function () {
      debugger;
      var coords = d3.mouse(invisibleRect.node());
      var hoverHelp = svg.append('g').attr('id', 'hoverHelp');

      var x = coords[0];
      var y = coords[1];

      var triangleSize = 25;
      var rectWidth = 200;
      var rectHeight = 50;

      hoverHelp.append('polygon')
        .attr({
          'fill': '#3F0040',
          'opacity': 0.5,
          'points': x   ','   y   ' '   (x   triangleSize)   ','   (y - triangleSize)   ' '   (x   triangleSize   rectWidth)   ','   (y - triangleSize)   ' '   (x   triangleSize   rectWidth)   ','   (y - triangleSize   rectHeight)   ' '   (x   triangleSize)   ','   (y - triangleSize   rectHeight)   ' '   (x   triangleSize)   ','   (y   triangleSize),
          'stroke-width': 3,
          'stroke': '#FD00FF',
          'stroke-linecap': 'round'
        });

      hoverHelp.append('text')
        .attr({
          'x': x   triangleSize   rectWidth / 2,
          'y': y - triangleSize   rectHeight / 2,
          'text-anchor': 'middle',
          'dominant-baseline': 'central',
          'fill': '#FFFFFF',
          'text-weight': 'bold'
        })
        .text('Click to toggle axis.');
    });

    invisibleRect.on('mouseout', function () {
      try {
        hoverHelp.remove();
      } catch (ReferenceError) {
        console.log("There's no hoverHelp right now.");
      }
    });