d3.js鼠标悬停不使用多线图

时间:2017-12-06 07:00:19

标签: javascript d3.js visualization linechart

我一直在尝试创建一个交互式多线d3图表。现在非常简单,这就是它的样子 enter image description here

垂直线将显示每个x点的值。这个鼠标悬停工作。但我想要的鼠标悬停/鼠标移动是选择我所在的行,并模糊其余部分。 我基本上想要这样的东西:http://bl.ocks.org/Matthew-Weber/5645518

但我没有做任何事情...... 这是代码

    // Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 60, left: 50},
    width = 1200 - margin.left - margin.right,
    height = 670 - margin.top - margin.bottom;

// Parse the date / time
var parseDate = d3.time.format("%b %Y").parse;

// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);

// Define the axes
var xAxis = d3.svg.axis().scale(x)
    .orient("bottom").ticks(5);

var yAxis = d3.svg.axis().scale(y)
    .orient("left").ticks(5);

// Define the line
var priceline = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.price); })


// Adds the svg canvas
var svg = d3.select("body")
    .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 + ")");

// Get the data
d3.csv("data.csv", function(error, data) {
    // if (error) return console.error(error);

    data.forEach(function(d) {
        d.date = parseDate(d.date.toString());
        d.price = +d.price;
    });

    // Scale the range of the data
    x.domain(d3.extent(data, function(d) { return d.date; }));
    y.domain([0, d3.max(data, function(d) { return d.price; })]);

    // Nest the entries by symbol
    var dataNest = d3.nest()
        .key(function(d) {return d.symbol;}) //change to name
        .entries(data)


    var color = d3.scale.category10();


    // Loop through each symbol / key
    dataNest.forEach(function(d) {
        console.log("d", d);
        svg.append("path")
            .attr("class", "line")
            .style("stroke", function() { // Add the colours dynamically
                return d.color = color(d.key); })
            .attr("d", priceline(d.values))
            // .on("mouseover", mouseover) this doesn't work! I am thinking it's because I am nesting + using a for loop for each line, but I have to do this since my dataset is quite big and idk how many lines I will be needing
            // .on("mouseout", mouseout)
    });


    function mouseover(d) {
      console.log("no");
      var me = this;
      //d3.select(d.line).classed("line--hover", true);
      d3.selectAll(".line").classed("line--hover", function() {
        return (this === me);
      }).classed("line--fade", function() {
        return (this !== me);
      });
    }

    function mouseout(d) {
      d3.selectAll(".line")
        .classed("line--hover", false)
        .classed("line--fade", false);
    }

    // Add the X Axis
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);


    // Add the Y Axis
    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Price in USD");

    var dataL = 0;
    var offset = 100;

    var legend = d3.select('svg')
      .append("g")
      .selectAll("g")
      .data(color.domain())
      .enter()
      .append('g')
        .attr('class', 'legend')
        .attr("transform", function (d, i) {
             if (i === 0) {
                dataL = d.length + offset
                return "translate(0,0)"
            } else {
             var newdataL = dataL
             dataL +=  d.length + offset
             return "translate(" + (newdataL) + ",0)"
            }
      });

    legend.append('text')
      .attr("x", 68)
      .attr("y", 650)
      .text(function (d, i) {
            return d
        })
      .attr("class", "textselected")
            .style("text-anchor", "start")
            .style("font-size", 15)

    var mouseG = svg.append("g")
      .attr("class", "mouse-over-effects");

    mouseG.append("path") // this is the black vertical line to follow mouse
      .attr("class", "mouse-line")
      .style("stroke", "black")
      .style("stroke-width", "1px")
      .style("opacity", "0");

    var lines = document.getElementsByClassName('line');

    var mousePerLine = mouseG.selectAll('.mouse-per-line')
      .data(dataNest)
      .enter()
      .append("g")
      .attr("class", "mouse-per-line");

    mousePerLine.append("text")
      .attr("transform", "translate(10,3)");


    mouseG.append('svg:rect') // append a rect to catch mouse movements on canvas
      .attr('width', width) // can't catch mouse events on a g element
      .attr('height', height)
      .attr('fill', 'none')
      .attr('pointer-events', 'all')
      .on('mouseout', function() { // on mouse out hide line, circles and text
        // console.log("bye");
        d3.select(".mouse-line")
          .style("opacity", "0");
        d3.selectAll(".mouse-per-line circle")
          .style("opacity", "0");
        d3.selectAll(".mouse-per-line text")
          .style("opacity", "0");
      })
      .on('mouseover', function() { // on mouse in show line, circles and text
        d3.select(".mouse-line")
          .style("opacity", "1");
        d3.selectAll(".mouse-per-line circle")
          .style("opacity", "1");
        d3.selectAll(".mouse-per-line text")
          .style("opacity", "1");

      })
      .on('mousemove', function() { // mouse moving over canvas
        var mouse = d3.mouse(this);
        d3.select(".mouse-line")
          .attr("d", function() {
            var d = "M" + mouse[0] + "," + height;
            d += " " + mouse[0] + "," + 0;
            return d;
          });

        d3.selectAll(".mouse-per-line")
          .attr("transform", function(d, i) {
            var xDate = x.invert(mouse[0]),
                bisect = d3.bisector(function(d) { return d.date; }).right;
                idx = bisect(d.values, xDate);

            var beginning = 0,
                end = lines[i].getTotalLength(),
                target = null;

            while (true){
              target = Math.floor((beginning + end) / 2);
              pos = lines[i].getPointAtLength(target);
              if ((target === end || target === beginning) && pos.x !== mouse[0]) {
                  break;
              }
              if (pos.x > mouse[0])      end = target;
              else if (pos.x < mouse[0]) beginning = target;
              else break; //position found
            }

            d3.select(this).select('text')
              .text(y.invert(pos.y).toFixed(2));

            return "translate(" + 1050 + "," + 620 +")";
          });
    });
});

数据看起来像这样:

symbol,date,price
MSFT,Jan 2000,39.81
MSFT,Feb 2000,36.35
MSFT,Mar 2000,43.22
MSFT,Apr 2000,28.37
MSFT,May 2000,25.45
MSFT,Jun 2000,32.54
MSFT,Jul 2000,28.4
MSFT,Aug 2000,28.4
MSFT,Sep 2000,24.53
MSFT,Oct 2000,28.02
MSFT,Nov 2000,23.34
MSFT,Dec 2000,17.65
MSFT,Jan 2001,24.84
MSFT,Feb 2001,24
MSFT,Mar 2001,22.25
MSFT,Apr 2001,27.56

符号代表公司,我可能拥有大约100个公司。 (这只是样本数据)

css非常简单

body {
  font: 12px Arial;
}

path {
    stroke: steelblue;
    stroke-width: 2;
    fill: none;
}

.axis path,
.axis line {
    fill: none;
    stroke: grey;
    stroke-width: 1;
    shape-rendering: crispEdges;
}

.line--fade {
  opacity: 0.3;
}

.line--hover {
  stroke-width: 4px;
  opacity: 1.0;
}

我也尝试过使用tipsy.js,但我不确定如何将它正确地集成到我的代码中。

谢谢!!

0 个答案:

没有答案